Re: COPY table FROM STDIN doesn't show count tag

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: COPY table FROM STDIN doesn't show count tag
Дата
Msg-id 20099.1394481008@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: COPY table FROM STDIN doesn't show count tag  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
I wrote:
> Also, I'm thinking we should back-patch the aspects of the patch
> needed to fix the wrong-line-number issue.  That appears to have been
> introduced in 9.2; older versions of PG get the above example right.

I've done that.  For reference' sake, here's an updated patch against
HEAD with just the uncommitted changes.

            regards, tom lane

diff -c new/common.c new-wholepatch/common.c
*** new/common.c    Mon Mar 10 14:55:49 2014
--- new-wholepatch/common.c    Mon Mar 10 12:49:02 2014
***************
*** 631,638 ****
   * When the command string contained no such COPY command, this function
   * degenerates to an AcceptResult() call.
   *
!  * Changes its argument to point to the last PGresult of the command string,
!  * or NULL if that result was for a COPY FROM STDIN or COPY TO STDOUT.
   *
   * Returns true on complete success, false otherwise.  Possible failure modes
   * include purely client-side problems; check the transaction status for the
--- 631,637 ----
   * When the command string contained no such COPY command, this function
   * degenerates to an AcceptResult() call.
   *
!  * Changes its argument to point to the last PGresult of the command string.
   *
   * Returns true on complete success, false otherwise.  Possible failure modes
   * include purely client-side problems; check the transaction status for the
***************
*** 641,654 ****
  static bool
  ProcessResult(PGresult **results)
  {
-     PGresult   *next_result;
      bool        success = true;
      bool        first_cycle = true;

!     do
      {
          ExecStatusType result_status;
          bool        is_copy;

          if (!AcceptResult(*results))
          {
--- 640,653 ----
  static bool
  ProcessResult(PGresult **results)
  {
      bool        success = true;
      bool        first_cycle = true;

!     for (;;)
      {
          ExecStatusType result_status;
          bool        is_copy;
+         PGresult   *next_result;

          if (!AcceptResult(*results))
          {
***************
*** 693,698 ****
--- 692,698 ----
               * otherwise use queryFout or cur_cmd_source as appropriate.
               */
              FILE       *copystream = pset.copyStream;
+             PGresult   *copy_result;

              SetCancelConn();
              if (result_status == PGRES_COPY_OUT)
***************
*** 700,706 ****
                  if (!copystream)
                      copystream = pset.queryFout;
                  success = handleCopyOut(pset.db,
!                                         copystream) && success;
              }
              else
              {
--- 700,707 ----
                  if (!copystream)
                      copystream = pset.queryFout;
                  success = handleCopyOut(pset.db,
!                                         copystream,
!                                         ©_result) && success;
              }
              else
              {
***************
*** 708,737 ****
                      copystream = pset.cur_cmd_source;
                  success = handleCopyIn(pset.db,
                                         copystream,
!                                        PQbinaryTuples(*results)) && success;
              }
              ResetCancelConn();

!             /*
!              * Call PQgetResult() once more.  In the typical case of a
!              * single-command string, it will return NULL.    Otherwise, we'll
!              * have other results to process that may include other COPYs.
!              */
              PQclear(*results);
!             *results = next_result = PQgetResult(pset.db);
          }
          else if (first_cycle)
              /* fast path: no COPY commands; PQexec visited all results */
              break;
-         else if ((next_result = PQgetResult(pset.db)))
-         {
-             /* non-COPY command(s) after a COPY: keep the last one */
-             PQclear(*results);
-             *results = next_result;
          }

          first_cycle = false;
!     } while (next_result);

      /* may need this to recover from conn loss during COPY */
      if (!first_cycle && !CheckConnection())
--- 709,742 ----
                      copystream = pset.cur_cmd_source;
                  success = handleCopyIn(pset.db,
                                         copystream,
!                                        PQbinaryTuples(*results),
!                                        ©_result) && success;
              }
              ResetCancelConn();

!             /* replace the COPY_OUT/IN result with COPY command exit status */
              PQclear(*results);
!             *results = copy_result;
          }
          else if (first_cycle)
+         {
              /* fast path: no COPY commands; PQexec visited all results */
              break;
          }

+         /*
+          * Check PQgetResult() again.  In the typical case of a single-command
+          * string, it will return NULL.  Otherwise, we'll have other results
+          * to process that may include other COPYs.  We keep the last result.
+          */
+         next_result = PQgetResult(pset.db);
+         if (!next_result)
+             break;
+
+         PQclear(*results);
+         *results = next_result;
          first_cycle = false;
!     }

      /* may need this to recover from conn loss during COPY */
      if (!first_cycle && !CheckConnection())
diff -c new/copy.c new-wholepatch/copy.c
*** new/copy.c    Mon Mar 10 14:56:21 2014
--- new-wholepatch/copy.c    Mon Mar 10 12:50:27 2014
***************
*** 429,444 ****
   * conn should be a database connection that you just issued COPY TO on
   * and got back a PGRES_COPY_OUT result.
   * copystream is the file stream for the data to go to.
   *
   * result is true if successful, false if not.
   */
  bool
! handleCopyOut(PGconn *conn, FILE *copystream)
  {
      bool        OK = true;
      char       *buf;
      int            ret;
-     PGresult   *res;

      for (;;)
      {
--- 429,445 ----
   * conn should be a database connection that you just issued COPY TO on
   * and got back a PGRES_COPY_OUT result.
   * copystream is the file stream for the data to go to.
+  * The final status for the COPY is returned into *res (but note
+  * we already reported the error, if it's not a success result).
   *
   * result is true if successful, false if not.
   */
  bool
! handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res)
  {
      bool        OK = true;
      char       *buf;
      int            ret;

      for (;;)
      {
***************
*** 485,497 ****
       * but hasn't exited COPY_OUT state internally.  So we ignore the
       * possibility here.
       */
!     res = PQgetResult(conn);
!     if (PQresultStatus(res) != PGRES_COMMAND_OK)
      {
          psql_error("%s", PQerrorMessage(conn));
          OK = false;
      }
-     PQclear(res);

      return OK;
  }
--- 486,497 ----
       * but hasn't exited COPY_OUT state internally.  So we ignore the
       * possibility here.
       */
!     *res = PQgetResult(conn);
!     if (PQresultStatus(*res) != PGRES_COMMAND_OK)
      {
          psql_error("%s", PQerrorMessage(conn));
          OK = false;
      }

      return OK;
  }
***************
*** 504,509 ****
--- 504,511 ----
   * and got back a PGRES_COPY_IN result.
   * copystream is the file stream to read the data from.
   * isbinary can be set from PQbinaryTuples().
+  * The final status for the COPY is returned into *res (but note
+  * we already reported the error, if it's not a success result).
   *
   * result is true if successful, false if not.
   */
***************
*** 512,523 ****
  #define COPYBUFSIZ 8192

  bool
! handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
  {
      bool        OK;
      const char *prompt;
      char        buf[COPYBUFSIZ];
-     PGresult   *res;

      /*
       * Establish longjmp destination for exiting from wait-for-input. (This is
--- 514,524 ----
  #define COPYBUFSIZ 8192

  bool
! handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
  {
      bool        OK;
      const char *prompt;
      char        buf[COPYBUFSIZ];

      /*
       * Establish longjmp destination for exiting from wait-for-input. (This is
***************
*** 679,699 ****
       * connection is lost.    But that's fine; it will get us out of COPY_IN
       * state, which is what we need.)
       */
!     while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_IN)
      {
          OK = false;
!         PQclear(res);
          /* We can't send an error message if we're using protocol version 2 */
          PQputCopyEnd(conn,
                       (PQprotocolVersion(conn) < 3) ? NULL :
                       _("trying to exit copy mode"));
      }
!     if (PQresultStatus(res) != PGRES_COMMAND_OK)
      {
          psql_error("%s", PQerrorMessage(conn));
          OK = false;
      }
-     PQclear(res);

      return OK;
  }
--- 680,699 ----
       * connection is lost.    But that's fine; it will get us out of COPY_IN
       * state, which is what we need.)
       */
!     while (*res = PQgetResult(conn), PQresultStatus(*res) == PGRES_COPY_IN)
      {
          OK = false;
!         PQclear(*res);
          /* We can't send an error message if we're using protocol version 2 */
          PQputCopyEnd(conn,
                       (PQprotocolVersion(conn) < 3) ? NULL :
                       _("trying to exit copy mode"));
      }
!     if (PQresultStatus(*res) != PGRES_COMMAND_OK)
      {
          psql_error("%s", PQerrorMessage(conn));
          OK = false;
      }

      return OK;
  }
diff -c new/copy.h new-wholepatch/copy.h
*** new/copy.h    Mon Mar 10 14:55:49 2014
--- new-wholepatch/copy.h    Mon Mar 10 12:49:03 2014
***************
*** 12,22 ****


  /* handler for \copy */
! bool        do_copy(const char *args);

  /* lower level processors for copy in/out streams */

! bool        handleCopyOut(PGconn *conn, FILE *copystream);
! bool        handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary);

  #endif
--- 12,24 ----


  /* handler for \copy */
! extern bool do_copy(const char *args);

  /* lower level processors for copy in/out streams */

! extern bool handleCopyOut(PGconn *conn, FILE *copystream,
!               PGresult **res);
! extern bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary,
!              PGresult **res);

  #endif

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Robert Haas
Дата:
Сообщение: Re: Changeset Extraction v7.9.1
Следующее
От: Thom Brown
Дата:
Сообщение: Re: GSoC 2014 - mentors, students and admins