Re: [HACKERS] ECPG, threading and pooling - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [HACKERS] ECPG, threading and pooling
Date
Msg-id 200306150407.h5F47CY27920@candle.pha.pa.us
Whole thread Raw
List pgsql-patches
Patch applied.  I made adjustments to use the new configure thread
settings, and I added documentation.  I also updated the interface
version numbers as included in the patch.

---------------------------------------------------------------------------

Lee Kindness wrote:
Content-Description: message body text

> Michael,
>
> Michael Meskes writes:
>  > On Thu, Jan 23, 2003 at 02:40:33PM +0530, Shridhar Daithankar<shridhar_daithankar@persistent.co.in> wrote:
>  > > I would like to use ECPG as it is relatively easy to code. However my
>  > > application is multithreaded and also uses connecion pools.
>  >
>  > I'm afraid it needs some work to be thread-safe. sqlca is defined
>  > statically. No big deal it seems to implement a thread safe version but
>  > I haven't yet found the time.
>
> I've spent a bit of time on making ecpg thread safe over Christmas,
> while it's not finished i'm sure the attached patch is at least useful
> and a step in the right direction.
>
> Lee.
>

[ Attachment, skipping... ]

>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
> subscribe-nomail command to majordomo@postgresql.org so that your
> message can get through to the mailing list cleanly

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: configure.in
===================================================================
RCS file: /cvsroot/pgsql-server/configure.in,v
retrieving revision 1.264
diff -c -c -r1.264 configure.in
*** configure.in    14 Jun 2003 19:21:42 -0000    1.264
--- configure.in    15 Jun 2003 04:02:55 -0000
***************
*** 323,330 ****
  # Enable libpq to be thread-safe
  #
  AC_MSG_CHECKING([allow threaded libpq])
! PGAC_ARG_BOOL(with, threads, no, [  --with-threads          allow libpq to be thread-safe],
!               [AC_DEFINE([USE_THREADS], 1, [Define to 1 to build libpq with threads. (--with-threads)])])

  AC_MSG_RESULT([$with_threads])
  AC_SUBST(with_threads)
--- 323,330 ----
  # Enable libpq to be thread-safe
  #
  AC_MSG_CHECKING([allow threaded libpq])
! PGAC_ARG_BOOL(with, threads, no, [  --with-threads          allow libpq and ecpg to be thread-safe],
!               [AC_DEFINE([USE_THREADS], 1, [Define to 1 to build libpq and ecpg to be thread-safe.
(--with-threads)])])

  AC_MSG_RESULT([$with_threads])
  AC_SUBST(with_threads)
Index: doc/src/sgml/ecpg.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/ecpg.sgml,v
retrieving revision 1.43
diff -c -c -r1.43 ecpg.sgml
*** doc/src/sgml/ecpg.sgml    25 Mar 2003 16:15:35 -0000    1.43
--- doc/src/sgml/ecpg.sgml    15 Jun 2003 04:02:56 -0000
***************
*** 750,755 ****
--- 750,762 ----
    </para>

    <para>
+    <application>ecpg</application> is thread-safe if it is compiled using
+    the <literal>--with-threads</> <filename>configure</filename>
+    command-line option.  (You might need to use other threading
+    command-line options to compile your client code.)
+   </para>
+
+   <para>
     The preprocessor program is called <filename>ecpg</filename> and is
     included in a normal <productname>PostgreSQL</> installation.
     Embedded SQL programs are typically named with an extension
Index: doc/src/sgml/installation.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/installation.sgml,v
retrieving revision 1.134
diff -c -c -r1.134 installation.sgml
*** doc/src/sgml/installation.sgml    13 Jun 2003 23:10:07 -0000    1.134
--- doc/src/sgml/installation.sgml    15 Jun 2003 04:02:59 -0000
***************
*** 918,924 ****
         <term><option>--with-threads</option></term>
         <listitem>
          <para>
!      Allow separate libpq threads to safely control their private connection handles.
          </para>
         </listitem>
        </varlistentry>
--- 918,925 ----
         <term><option>--with-threads</option></term>
         <listitem>
          <para>
!      Allow separate libpq and ecpg threads to safely control their
!          private connection handles.
          </para>
         </listitem>
        </varlistentry>
Index: src/interfaces/ecpg/ecpglib/Makefile
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/Makefile,v
retrieving revision 1.3
diff -c -c -r1.3 Makefile
*** src/interfaces/ecpg/ecpglib/Makefile    22 May 2003 17:20:44 -0000    1.3
--- src/interfaces/ecpg/ecpglib/Makefile    15 Jun 2003 04:03:01 -0000
***************
*** 13,27 ****
  include $(top_builddir)/src/Makefile.global

  NAME= ecpg
! SO_MAJOR_VERSION= 3
! SO_MINOR_VERSION= 4.2

! override CPPFLAGS := -I$(top_srcdir)/src/interfaces/ecpg/include -I$(libpq_srcdir) $(CPPFLAGS)

  OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
      connect.o misc.o

! SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq)

  all: all-lib

--- 13,27 ----
  include $(top_builddir)/src/Makefile.global

  NAME= ecpg
! SO_MAJOR_VERSION= 4
! SO_MINOR_VERSION= 1.1

! override CPPFLAGS := -I$(top_srcdir)/src/interfaces/ecpg/include -I$(libpq_srcdir) $(CPPFLAGS) $(THREAD_CFLAGS)

  OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
      connect.o misc.o

! SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq) $(THREAD_LIBS)

  all: all-lib

Index: src/interfaces/ecpg/ecpglib/connect.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/connect.c,v
retrieving revision 1.6
diff -c -c -r1.6 connect.c
*** src/interfaces/ecpg/ecpglib/connect.c    13 Jun 2003 10:50:57 -0000    1.6
--- src/interfaces/ecpg/ecpglib/connect.c    15 Jun 2003 04:03:01 -0000
***************
*** 1,29 ****
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/connect.c,v 1.6 2003/06/13 10:50:57 meskes Exp $ */

  #include "postgres_fe.h"

  #include "ecpgtype.h"
  #include "ecpglib.h"
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"

! static struct connection *all_connections = NULL,
!            *actual_connection = NULL;

  struct connection *
  ECPGget_connection(const char *connection_name)
  {
!     struct connection *con = all_connections;

!     if (connection_name == NULL || strcmp(connection_name, "CURRENT") == 0)
!         return actual_connection;

!     for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
!     if (con)
!         return con;
!     else
!         return NULL;
  }

  static void
--- 1,53 ----
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/connect.c,v 1.6 2003/06/13 10:50:57 meskes Exp $ */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

+ #ifdef USE_THREADS
+ #include <pthread.h>
+ #endif
  #include "ecpgtype.h"
  #include "ecpglib.h"
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"

! #ifdef USE_THREADS
! static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
! #endif
! static struct connection *all_connections   = NULL;
! static struct connection *actual_connection = NULL;

  struct connection *
  ECPGget_connection(const char *connection_name)
  {
!   struct connection *ret = NULL;

! #ifdef USE_THREADS
!   pthread_mutex_lock(&connections_mutex);
! #endif
!
!   if( (connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0) )
!     {
!       ret = actual_connection;
!     }
!   else
!     {
!       struct connection *con;
!
!       for( con = all_connections; con != NULL; con = con->next)
!     {
!       if( strcmp(connection_name, con->name) == 0 )
!         break;
!     }
!       ret = con;
!     }
!
! #ifdef USE_THREADS
!   pthread_mutex_unlock(&connections_mutex);
! #endif

!   return( ret );
  }

  static void
***************
*** 37,42 ****
--- 61,70 ----
          ECPGlog("ecpg_finish: finishing %s.\n", act->name);
          PQfinish(act->connection);

+         /* no need to lock connections_mutex - we're always called
+            by ECPGdisconnect or ECPGconnect, which are holding
+            the lock */
+
          /* remove act from the list */
          if (act == all_connections)
              all_connections = act->next;
***************
*** 118,134 ****
  static void
  ECPGnoticeProcessor_raise(int code, const char *message)
  {
!     sqlca.sqlcode = code;
!     strncpy(sqlca.sqlerrm.sqlerrmc, message, sizeof(sqlca.sqlerrm.sqlerrmc));
!     sqlca.sqlerrm.sqlerrmc[sizeof(sqlca.sqlerrm.sqlerrmc) - 1] = 0;
!     sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc);

      /* remove trailing newline */
!     if (sqlca.sqlerrm.sqlerrml
!         && sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] == '\n')
      {
!         sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] = 0;
!         sqlca.sqlerrm.sqlerrml--;
      }

      ECPGlog("raising sqlcode %d\n", code);
--- 146,163 ----
  static void
  ECPGnoticeProcessor_raise(int code, const char *message)
  {
!     struct sqlca_t *sqlca = ECPGget_sqlca();
!     sqlca->sqlcode = code;
!     strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
!     sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
!     sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);

      /* remove trailing newline */
!     if (sqlca->sqlerrm.sqlerrml
!         && sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml - 1] == '\n')
      {
!         sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml - 1] = 0;
!         sqlca->sqlerrm.sqlerrml--;
      }

      ECPGlog("raising sqlcode %d\n", code);
***************
*** 141,146 ****
--- 170,177 ----
  static void
  ECPGnoticeProcessor(void *arg, const char *message)
  {
+     struct sqlca_t *sqlca = ECPGget_sqlca();
+
      /* these notices raise an error */
      if (strncmp(message, "WARNING: ", 9))
      {
***************
*** 245,251 ****
      if (strstr(message, "cannot be rolled back"))
          return;

!     /* these and other unmentioned should set sqlca.sqlwarn[2] */
      /* WARNING: The ':' operator is deprecated.  Use exp(x) instead. */
      /* WARNING: Rel *: Uninitialized page 0 - fixing */
      /* WARNING: PortalHeapMemoryFree: * not in alloc set! */
--- 276,282 ----
      if (strstr(message, "cannot be rolled back"))
          return;

!     /* these and other unmentioned should set sqlca->sqlwarn[2] */
      /* WARNING: The ':' operator is deprecated.  Use exp(x) instead. */
      /* WARNING: Rel *: Uninitialized page 0 - fixing */
      /* WARNING: PortalHeapMemoryFree: * not in alloc set! */
***************
*** 253,266 ****
      /* WARNING: identifier "*" will be truncated to "*" */
      /* WARNING: InvalidateSharedInvalid: cache state reset */
      /* WARNING: RegisterSharedInvalid: SI buffer overflow */
!     sqlca.sqlwarn[2] = 'W';
!     sqlca.sqlwarn[0] = 'W';
  }

  /* this contains some quick hacks, needs to be cleaned up, but it works */
  bool
  ECPGconnect(int lineno, const char *name, const char *user, const char *passwd, const char *connection_name, int
autocommit)
  {
      struct connection *this;
      char       *dbname = strdup(name),
                 *host = NULL,
--- 284,298 ----
      /* WARNING: identifier "*" will be truncated to "*" */
      /* WARNING: InvalidateSharedInvalid: cache state reset */
      /* WARNING: RegisterSharedInvalid: SI buffer overflow */
!     sqlca->sqlwarn[2] = 'W';
!     sqlca->sqlwarn[0] = 'W';
  }

  /* this contains some quick hacks, needs to be cleaned up, but it works */
  bool
  ECPGconnect(int lineno, const char *name, const char *user, const char *passwd, const char *connection_name, int
autocommit)
  {
+     struct sqlca_t *sqlca = ECPGget_sqlca();
      struct connection *this;
      char       *dbname = strdup(name),
                 *host = NULL,
***************
*** 269,275 ****
                 *realname = NULL,
                 *options = NULL;

!     ECPGinit_sqlca();

      if ((this = (struct connection *) ECPGalloc(sizeof(struct connection), lineno)) == NULL)
          return false;
--- 301,307 ----
                 *realname = NULL,
                 *options = NULL;

!     ECPGinit_sqlca(sqlca);

      if ((this = (struct connection *) ECPGalloc(sizeof(struct connection), lineno)) == NULL)
          return false;
***************
*** 394,399 ****
--- 426,434 ----
          realname = strdup(dbname);

      /* add connection to our list */
+ #ifdef USE_THREADS
+     pthread_mutex_lock(&connections_mutex);
+ #endif
      if (connection_name != NULL)
          this->name = ECPGstrdup(connection_name, lineno);
      else
***************
*** 424,429 ****
--- 459,467 ----

          set_backend_err(errmsg, lineno);
          ecpg_finish(this);
+ #ifdef USE_THREADS
+         pthread_mutex_unlock(&connections_mutex);
+ #endif
          ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n\t%s\n",
                  db,
                  host ? host : "<DEFAULT>",
***************
*** 445,450 ****
--- 483,491 ----
              ECPGfree(dbname);
          return false;
      }
+ #ifdef USE_THREADS
+     pthread_mutex_unlock(&connections_mutex);
+ #endif

      if (host)
          ECPGfree(host);
***************
*** 468,478 ****
  bool
  ECPGdisconnect(int lineno, const char *connection_name)
  {
      struct connection *con;

      if (strcmp(connection_name, "ALL") == 0)
      {
!         ECPGinit_sqlca();
          for (con = all_connections; con;)
          {
              struct connection *f = con;
--- 509,524 ----
  bool
  ECPGdisconnect(int lineno, const char *connection_name)
  {
+     struct sqlca_t *sqlca = ECPGget_sqlca();
      struct connection *con;

+ #ifdef USE_THREADS
+     pthread_mutex_lock(&connections_mutex);
+ #endif
+
      if (strcmp(connection_name, "ALL") == 0)
      {
!         ECPGinit_sqlca(sqlca);
          for (con = all_connections; con;)
          {
              struct connection *f = con;
***************
*** 486,495 ****
          con = ECPGget_connection(connection_name);

          if (!ECPGinit(con, connection_name, lineno))
!             return (false);
          else
!             ecpg_finish(con);
      }

      return true;
  }
--- 532,550 ----
          con = ECPGget_connection(connection_name);

          if (!ECPGinit(con, connection_name, lineno))
!           {
! #ifdef USE_THREADS
!             pthread_mutex_unlock(&connections_mutex);
! #endif
!             return (false);
!           }
          else
!           ecpg_finish(con);
      }
+
+ #ifdef USE_THREADS
+     pthread_mutex_unlock(&connections_mutex);
+ #endif

      return true;
  }
Index: src/interfaces/ecpg/ecpglib/data.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/data.c,v
retrieving revision 1.4
diff -c -c -r1.4 data.c
*** src/interfaces/ecpg/ecpglib/data.c    1 Apr 2003 14:37:25 -0000    1.4
--- src/interfaces/ecpg/ecpglib/data.c    15 Jun 2003 04:03:01 -0000
***************
*** 1,5 ****
--- 1,6 ----
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/data.c,v 1.4 2003/04/01 14:37:25 meskes Exp $ */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

  #include <stdlib.h>
***************
*** 21,26 ****
--- 22,28 ----
               char *var, char *ind, long varcharsize, long offset,
               long ind_offset, bool isarray)
  {
+     struct sqlca_t *sqlca = ECPGget_sqlca();
      char       *pval = (char *) PQgetvalue(results, act_tuple, act_field);

      ECPGlog("ECPGget_data line %d: RESULT: %s offset: %ld\n", lineno, pval ? pval : "", offset);
***************
*** 328,334 ****
                              default:
                                  break;
                          }
!                         sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W';
                      }
                  }
                  break;
--- 330,336 ----
                              default:
                                  break;
                          }
!                         sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
                      }
                  }
                  break;
***************
*** 373,379 ****
                              default:
                                  break;
                          }
!                         sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W';

                          variable->len = varcharsize;
                      }
--- 375,381 ----
                              default:
                                  break;
                          }
!                         sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';

                          variable->len = varcharsize;
                      }
Index: src/interfaces/ecpg/ecpglib/descriptor.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/descriptor.c,v
retrieving revision 1.2
diff -c -c -r1.2 descriptor.c
*** src/interfaces/ecpg/ecpglib/descriptor.c    30 May 2003 13:22:02 -0000    1.2
--- src/interfaces/ecpg/ecpglib/descriptor.c    15 Jun 2003 04:03:02 -0000
***************
*** 3,8 ****
--- 3,9 ----
   * $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.2 2003/05/30 13:22:02 meskes Exp $
   */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"
  #include "pg_type.h"

***************
*** 51,64 ****
  ECPGget_desc_header(int lineno, char *desc_name, int *count)
  {
      PGresult   *ECPGresult;

!     ECPGinit_sqlca();
      ECPGresult = ECPGresultByDescriptor(lineno, desc_name);
      if (!ECPGresult)
          return false;

      *count = PQnfields(ECPGresult);
!     sqlca.sqlerrd[2] = 1;
      ECPGlog("ECPGget_desc_header: found %d attributes.\n", *count);
      return true;
  }
--- 52,66 ----
  ECPGget_desc_header(int lineno, char *desc_name, int *count)
  {
      PGresult   *ECPGresult;
+     struct sqlca_t *sqlca = ECPGget_sqlca();

!     ECPGinit_sqlca(sqlca);
      ECPGresult = ECPGresultByDescriptor(lineno, desc_name);
      if (!ECPGresult)
          return false;

      *count = PQnfields(ECPGresult);
!     sqlca->sqlerrd[2] = 1;
      ECPGlog("ECPGget_desc_header: found %d attributes.\n", *count);
      return true;
  }
***************
*** 149,157 ****
      int            ntuples,
                  act_tuple;
      struct variable data_var;

      va_start(args, index);
!     ECPGinit_sqlca();
      ECPGresult = ECPGresultByDescriptor(lineno, desc_name);
      if (!ECPGresult)
          return (false);
--- 151,160 ----
      int            ntuples,
                  act_tuple;
      struct variable data_var;
+     struct sqlca_t *sqlca = ECPGget_sqlca();

      va_start(args, index);
!     ECPGinit_sqlca(sqlca);
      ECPGresult = ECPGresultByDescriptor(lineno, desc_name);
      if (!ECPGresult)
          return (false);
***************
*** 378,384 ****
              ECPGlog("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
          }
      }
!     sqlca.sqlerrd[2] = ntuples;
      return (true);
  }

--- 381,387 ----
              ECPGlog("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index));
          }
      }
!     sqlca->sqlerrd[2] = ntuples;
      return (true);
  }

***************
*** 387,394 ****
  {
      struct descriptor *i;
      struct descriptor **lastptr = &all_descriptors;

!     ECPGinit_sqlca();
      for (i = all_descriptors; i; lastptr = &i->next, i = i->next)
      {
          if (!strcmp(name, i->name))
--- 390,398 ----
  {
      struct descriptor *i;
      struct descriptor **lastptr = &all_descriptors;
+     struct sqlca_t *sqlca = ECPGget_sqlca();

!     ECPGinit_sqlca(sqlca);
      for (i = all_descriptors; i; lastptr = &i->next, i = i->next)
      {
          if (!strcmp(name, i->name))
***************
*** 408,415 ****
  ECPGallocate_desc(int line, const char *name)
  {
      struct descriptor *new;

!     ECPGinit_sqlca();
      new = (struct descriptor *) ECPGalloc(sizeof(struct descriptor), line);
      if (!new)
          return false;
--- 412,420 ----
  ECPGallocate_desc(int line, const char *name)
  {
      struct descriptor *new;
+     struct sqlca_t *sqlca = ECPGget_sqlca();

!     ECPGinit_sqlca(sqlca);
      new = (struct descriptor *) ECPGalloc(sizeof(struct descriptor), line);
      if (!new)
          return false;
Index: src/interfaces/ecpg/ecpglib/error.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/error.c,v
retrieving revision 1.1
diff -c -c -r1.1 error.c
*** src/interfaces/ecpg/ecpglib/error.c    16 Mar 2003 10:42:53 -0000    1.1
--- src/interfaces/ecpg/ecpglib/error.c    15 Jun 2003 04:03:02 -0000
***************
*** 1,5 ****
--- 1,6 ----
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/error.c,v 1.1 2003/03/16 10:42:53 meskes Exp $ */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

  #include <stdio.h>
***************
*** 17,133 ****
  void
  ECPGraise(int line, int code, const char *str)
  {
!     sqlca.sqlcode = code;

      switch (code)
      {
          case ECPG_NOT_FOUND:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "No data found in line %d.", line);
              break;

          case ECPG_OUT_OF_MEMORY:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Out of memory in line %d.", line);
              break;

          case ECPG_UNSUPPORTED:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Unsupported type %s in line %d.", str, line);
              break;

          case ECPG_TOO_MANY_ARGUMENTS:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Too many arguments in line %d.", line);
              break;

          case ECPG_TOO_FEW_ARGUMENTS:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Too few arguments in line %d.", line);
              break;

          case ECPG_INT_FORMAT:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
               "Not correctly formatted int type: %s line %d.", str, line);
              break;

          case ECPG_UINT_FORMAT:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Not correctly formatted unsigned type: %s in line %d.", str, line);
              break;

          case ECPG_FLOAT_FORMAT:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Not correctly formatted floating-point type: %s in line %d.", str, line);
              break;

          case ECPG_CONVERT_BOOL:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                    "Unable to convert %s to bool on line %d.", str, line);
              break;

          case ECPG_EMPTY:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Empty query in line %d.", line);
              break;

          case ECPG_MISSING_INDICATOR:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "NULL value without indicator in line %d.", line);
              break;

          case ECPG_NO_ARRAY:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Variable is not an array in line %d.", line);
              break;

          case ECPG_DATA_NOT_ARRAY:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
               "Data read from backend is not an array in line %d.", line);
              break;

          case ECPG_ARRAY_INSERT:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
               "Trying to insert an array of variables in line %d.", line);
              break;

          case ECPG_NO_CONN:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "No such connection %s in line %d.", str, line);
              break;

          case ECPG_NOT_CONN:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Not connected to '%s' in line %d.", str, line);
              break;

          case ECPG_INVALID_STMT:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Invalid statement name %s in line %d.", str, line);
              break;

          case ECPG_UNKNOWN_DESCRIPTOR:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Descriptor %s not found in line %d.", str, line);
              break;

          case ECPG_INVALID_DESCRIPTOR_INDEX:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Descriptor index out of range in line %d.", line);
              break;

          case ECPG_UNKNOWN_DESCRIPTOR_ITEM:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Unknown descriptor item %s in line %d.", str, line);
              break;

          case ECPG_VAR_NOT_NUMERIC:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Variable is not a numeric type in line %d.", line);
              break;

          case ECPG_VAR_NOT_CHAR:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                     "Variable is not a character type in line %d.", line);
              break;

--- 18,135 ----
  void
  ECPGraise(int line, int code, const char *str)
  {
!     struct sqlca_t *sqlca = ECPGget_sqlca();
!     sqlca->sqlcode = code;

      switch (code)
      {
          case ECPG_NOT_FOUND:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "No data found in line %d.", line);
              break;

          case ECPG_OUT_OF_MEMORY:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Out of memory in line %d.", line);
              break;

          case ECPG_UNSUPPORTED:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Unsupported type %s in line %d.", str, line);
              break;

          case ECPG_TOO_MANY_ARGUMENTS:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Too many arguments in line %d.", line);
              break;

          case ECPG_TOO_FEW_ARGUMENTS:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Too few arguments in line %d.", line);
              break;

          case ECPG_INT_FORMAT:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
               "Not correctly formatted int type: %s line %d.", str, line);
              break;

          case ECPG_UINT_FORMAT:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Not correctly formatted unsigned type: %s in line %d.", str, line);
              break;

          case ECPG_FLOAT_FORMAT:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Not correctly formatted floating-point type: %s in line %d.", str, line);
              break;

          case ECPG_CONVERT_BOOL:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                    "Unable to convert %s to bool on line %d.", str, line);
              break;

          case ECPG_EMPTY:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Empty query in line %d.", line);
              break;

          case ECPG_MISSING_INDICATOR:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "NULL value without indicator in line %d.", line);
              break;

          case ECPG_NO_ARRAY:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Variable is not an array in line %d.", line);
              break;

          case ECPG_DATA_NOT_ARRAY:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
               "Data read from backend is not an array in line %d.", line);
              break;

          case ECPG_ARRAY_INSERT:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
               "Trying to insert an array of variables in line %d.", line);
              break;

          case ECPG_NO_CONN:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "No such connection %s in line %d.", str, line);
              break;

          case ECPG_NOT_CONN:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Not connected to '%s' in line %d.", str, line);
              break;

          case ECPG_INVALID_STMT:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Invalid statement name %s in line %d.", str, line);
              break;

          case ECPG_UNKNOWN_DESCRIPTOR:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Descriptor %s not found in line %d.", str, line);
              break;

          case ECPG_INVALID_DESCRIPTOR_INDEX:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Descriptor index out of range in line %d.", line);
              break;

          case ECPG_UNKNOWN_DESCRIPTOR_ITEM:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Unknown descriptor item %s in line %d.", str, line);
              break;

          case ECPG_VAR_NOT_NUMERIC:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Variable is not a numeric type in line %d.", line);
              break;

          case ECPG_VAR_NOT_CHAR:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                     "Variable is not a character type in line %d.", line);
              break;

***************
*** 138,166 ****
                  /* strip trailing newline */
                  if (slen > 0 && str[slen - 1] == '\n')
                      slen--;
!                 snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                           "'%.*s' in line %d.", slen, str, line);
                  break;
              }

          case ECPG_TRANS:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "Error in transaction processing in line %d.", line);
              break;

          case ECPG_CONNECT:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                "Could not connect to database %s in line %d.", str, line);
              break;

          default:
!             snprintf(sqlca.sqlerrm.sqlerrmc, sizeof(sqlca.sqlerrm.sqlerrmc),
                       "SQL error #%d in line %d.", code, line);
              break;
      }

!     sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc);
!     ECPGlog("raising sqlcode %d in line %d, '%s'.\n", code, line, sqlca.sqlerrm.sqlerrmc);

      /* free all memory we have allocated for the user */
      ECPGfree_auto_mem();
--- 140,168 ----
                  /* strip trailing newline */
                  if (slen > 0 && str[slen - 1] == '\n')
                      slen--;
!                 snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                           "'%.*s' in line %d.", slen, str, line);
                  break;
              }

          case ECPG_TRANS:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "Error in transaction processing in line %d.", line);
              break;

          case ECPG_CONNECT:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                "Could not connect to database %s in line %d.", str, line);
              break;

          default:
!             snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                       "SQL error #%d in line %d.", code, line);
              break;
      }

!     sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
!     ECPGlog("raising sqlcode %d in line %d, '%s'.\n", code, line, sqlca->sqlerrm.sqlerrmc);

      /* free all memory we have allocated for the user */
      ECPGfree_auto_mem();
***************
*** 193,198 ****
  void
  sqlprint(void)
  {
!     sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
!     fprintf(stderr, "sql error %s\n", sqlca.sqlerrm.sqlerrmc);
  }
--- 195,202 ----
  void
  sqlprint(void)
  {
!     struct sqlca_t *sqlca = ECPGget_sqlca();
!
!     sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml] = '\0';
!     fprintf(stderr, "sql error %s\n", sqlca->sqlerrm.sqlerrmc);
  }
Index: src/interfaces/ecpg/ecpglib/execute.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/execute.c,v
retrieving revision 1.9
diff -c -c -r1.9 execute.c
*** src/interfaces/ecpg/ecpglib/execute.c    13 Jun 2003 10:50:57 -0000    1.9
--- src/interfaces/ecpg/ecpglib/execute.c    15 Jun 2003 04:03:02 -0000
***************
*** 13,18 ****
--- 13,19 ----
  /* Taken over as part of PostgreSQL by Michael Meskes <meskes@postgresql.org>
     on Feb. 5th, 1998 */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

  #include <stdio.h>
***************
*** 31,64 ****
  #include "pgtypes_timestamp.h"
  #include "pgtypes_interval.h"

- /* variables visible to the programs */
- struct sqlca sqlca =
- {
-     {
-         'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
-     },
-     sizeof(struct sqlca),
-     0,
-     {
-         0,
-         {
-             0
-         }
-     },
-     {
-         'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
-     },
-     {
-         0, 0, 0, 0, 0, 0
-     },
-     {
-         0, 0, 0, 0, 0, 0, 0, 0
-     },
-     {
-         0, 0, 0, 0, 0, 0, 0, 0
-     }
- };
-
  /* This function returns a newly malloced string that has the  \
     in the argument quoted with \ and the ' quoted with ' as SQL92 says.
   */
--- 32,37 ----
***************
*** 1130,1135 ****
--- 1103,1110 ----
           */
      {
          bool        clear_result = TRUE;
+         struct sqlca_t *sqlca = ECPGget_sqlca();
+
          errmsg = PQresultErrorMessage(results);
          set_backend_err(errmsg, stmt->lineno);

***************
*** 1142,1148 ****

              case PGRES_TUPLES_OK:
                  nfields = PQnfields(results);
!                 sqlca.sqlerrd[2] = ntuples = PQntuples(results);
                  status = true;

                  if (ntuples < 1)
--- 1117,1123 ----

              case PGRES_TUPLES_OK:
                  nfields = PQnfields(results);
!                 sqlca->sqlerrd[2] = ntuples = PQntuples(results);
                  status = true;

                  if (ntuples < 1)
***************
*** 1199,1208 ****
              case PGRES_COMMAND_OK:
                  status = true;
                  cmdstat = PQcmdStatus(results);
!                 sqlca.sqlerrd[1] = PQoidValue(results);
!                 sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
                  ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, cmdstat);
!                 if (!sqlca.sqlerrd[2] && (   !strncmp(cmdstat, "UPDATE", 6)
                                || !strncmp(cmdstat, "INSERT", 6)
                                || !strncmp(cmdstat, "DELETE", 6)))
                      ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL);
--- 1174,1183 ----
              case PGRES_COMMAND_OK:
                  status = true;
                  cmdstat = PQcmdStatus(results);
!                 sqlca->sqlerrd[1] = PQoidValue(results);
!                 sqlca->sqlerrd[2] = atol(PQcmdTuples(results));
                  ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, cmdstat);
!                 if (!sqlca->sqlerrd[2] && (   !strncmp(cmdstat, "UPDATE", 6)
                                || !strncmp(cmdstat, "INSERT", 6)
                                || !strncmp(cmdstat, "DELETE", 6)))
                      ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL);
Index: src/interfaces/ecpg/ecpglib/extern.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/extern.h,v
retrieving revision 1.1
diff -c -c -r1.1 extern.h
*** src/interfaces/ecpg/ecpglib/extern.h    16 Mar 2003 10:42:53 -0000    1.1
--- src/interfaces/ecpg/ecpglib/extern.h    15 Jun 2003 04:03:02 -0000
***************
*** 3,8 ****
--- 3,9 ----

  #include "postgres_fe.h"
  #include "libpq-fe.h"
+ #include "sqlca.h"

  /* Here are some methods used by the lib. */

***************
*** 19,25 ****
  bool ECPGget_data(const PGresult *, int, int, int, enum ECPGttype type,
               enum ECPGttype, char *, char *, long, long, long, bool);
  struct connection *ECPGget_connection(const char *);
- void        ECPGinit_sqlca(void);
  char       *ECPGalloc(long, int);
  char       *ECPGrealloc(void *, long, int);
  void        ECPGfree(void *);
--- 20,25 ----
Index: src/interfaces/ecpg/ecpglib/memory.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/memory.c,v
retrieving revision 1.1
diff -c -c -r1.1 memory.c
*** src/interfaces/ecpg/ecpglib/memory.c    16 Mar 2003 10:42:53 -0000    1.1
--- src/interfaces/ecpg/ecpglib/memory.c    15 Jun 2003 04:03:02 -0000
***************
*** 1,5 ****
--- 1,6 ----
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/memory.c,v 1.1 2003/03/16 10:42:53 meskes Exp $ */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

  #include "ecpgtype.h"
Index: src/interfaces/ecpg/ecpglib/misc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/misc.c,v
retrieving revision 1.2
diff -c -c -r1.2 misc.c
*** src/interfaces/ecpg/ecpglib/misc.c    21 Mar 2003 15:31:04 -0000    1.2
--- src/interfaces/ecpg/ecpglib/misc.c    15 Jun 2003 04:03:03 -0000
***************
*** 1,20 ****
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/misc.c,v 1.2 2003/03/21 15:31:04 meskes Exp $ */

  #include "postgres_fe.h"

  #include <unistd.h>
  #include "ecpgtype.h"
  #include "ecpglib.h"
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"

! static struct sqlca sqlca_init =
  {
      {
          'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
      },
!     sizeof(struct sqlca),
      0,
      {
          0,
--- 1,24 ----
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/misc.c,v 1.2 2003/03/21 15:31:04 meskes Exp $ */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

  #include <unistd.h>
+ #ifdef USE_THREADS
+ #include <pthread.h>
+ #endif
  #include "ecpgtype.h"
  #include "ecpglib.h"
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"

! static struct sqlca_t sqlca_init =
  {
      {
          'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
      },
!     sizeof(struct sqlca_t),
      0,
      {
          0,
***************
*** 36,54 ****
      }
  };

! static int    simple_debug = 0;
  static FILE *debugstream = NULL;

! void
! ECPGinit_sqlca(void)
  {
!     memcpy((char *) &sqlca, (char *) &sqlca_init, sizeof(sqlca));
  }

  bool
  ECPGinit(const struct connection * con, const char *connection_name, const int lineno)
  {
!     ECPGinit_sqlca();
      if (con == NULL)
      {
          ECPGraise(lineno, ECPG_NO_CONN, connection_name ? connection_name : "NULL");
--- 40,93 ----
      }
  };

! #ifdef USE_THREADS
! static pthread_key_t   sqlca_key;
! static pthread_once_t  sqlca_key_once = PTHREAD_ONCE_INIT;
! #else
! static struct sqlca_t sqlca =
! {
!     {
!         'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
!     },
!     sizeof(struct sqlca_t),
!     0,
!     {
!         0,
!         {
!             0
!         }
!     },
!     {
!         'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
!     },
!     {
!         0, 0, 0, 0, 0, 0
!     },
!     {
!         0, 0, 0, 0, 0, 0, 0, 0
!     },
!     {
!         0, 0, 0, 0, 0, 0, 0, 0
!     }
! };
! #endif
!
! #ifdef USE_THREADS
! static pthread_mutex_t debug_mutex    = PTHREAD_MUTEX_INITIALIZER;
! #endif
! static int simple_debug = 0;
  static FILE *debugstream = NULL;

! void ECPGinit_sqlca(struct sqlca_t *sqlca)
  {
!     memcpy((char *)sqlca, (char *)&sqlca_init, sizeof(struct sqlca_t));
  }

  bool
  ECPGinit(const struct connection * con, const char *connection_name, const int lineno)
  {
!     struct sqlca_t *sqlca = ECPGget_sqlca();
!     ECPGinit_sqlca(sqlca);
      if (con == NULL)
      {
          ECPGraise(lineno, ECPG_NO_CONN, connection_name ? connection_name : "NULL");
***************
*** 58,63 ****
--- 97,129 ----
      return (true);
  }

+ #ifdef USE_THREADS
+ static void ecpg_sqlca_key_init(void)
+ {
+   pthread_key_create(&sqlca_key, NULL);
+ }
+ #endif
+
+ struct sqlca_t *ECPGget_sqlca(void)
+ {
+ #ifdef USE_THREADS
+   struct sqlca_t *sqlca;
+
+   pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
+
+   sqlca = pthread_getspecific(&sqlca_key);
+   if( sqlca == NULL )
+     {
+       sqlca = malloc(sizeof(struct sqlca_t));
+       ECPGinit_sqlca(sqlca);
+       pthread_setspecific(&sqlca_key, sqlca);
+     }
+   return( sqlca );
+ #else
+   return( &sqlca );
+ #endif
+ }
+
  bool
  ECPGstatus(int lineno, const char *connection_name)
  {
***************
*** 123,131 ****
--- 189,205 ----
  void
  ECPGdebug(int n, FILE *dbgs)
  {
+ #ifdef USE_THREADS
+     pthread_mutex_lock(&debug_mutex);
+ #endif
+
      simple_debug = n;
      debugstream = dbgs;
      ECPGlog("ECPGdebug: set to %d\n", simple_debug);
+
+ #ifdef USE_THREADS
+     pthread_mutex_unlock(&debug_mutex);
+ #endif
  }

  void
***************
*** 133,144 ****
  {
      va_list        ap;

!     if (simple_debug)
!     {
!         char       *f = (char *) malloc(strlen(format) + 100);

!         if (!f)
              return;

          sprintf(f, "[%d]: %s", (int) getpid(), format);

--- 207,226 ----
  {
      va_list        ap;

! #ifdef USE_THREADS
!     pthread_mutex_lock(&debug_mutex);
! #endif

!     if( simple_debug )
!     {
!         char *f = (char *)malloc(strlen(format) + 100);
!         if( f == NULL )
!           {
! #ifdef USE_THREADS
!             pthread_mutex_unlock(&debug_mutex);
! #endif
              return;
+           }

          sprintf(f, "[%d]: %s", (int) getpid(), format);

***************
*** 148,151 ****
--- 230,237 ----

          ECPGfree(f);
      }
+
+ #ifdef USE_THREADS
+     pthread_mutex_unlock(&debug_mutex);
+ #endif
  }
Index: src/interfaces/ecpg/ecpglib/prepare.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/prepare.c,v
retrieving revision 1.1
diff -c -c -r1.1 prepare.c
*** src/interfaces/ecpg/ecpglib/prepare.c    16 Mar 2003 10:42:53 -0000    1.1
--- src/interfaces/ecpg/ecpglib/prepare.c    15 Jun 2003 04:03:03 -0000
***************
*** 1,5 ****
--- 1,6 ----
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/prepare.c,v 1.1 2003/03/16 10:42:53 meskes Exp $ */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

  #include <ctype.h>
Index: src/interfaces/ecpg/ecpglib/typename.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/typename.c,v
retrieving revision 1.3
diff -c -c -r1.3 typename.c
*** src/interfaces/ecpg/ecpglib/typename.c    27 Mar 2003 14:29:17 -0000    1.3
--- src/interfaces/ecpg/ecpglib/typename.c    15 Jun 2003 04:03:03 -0000
***************
*** 1,5 ****
--- 1,6 ----
  /* $Header: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/typename.c,v 1.3 2003/03/27 14:29:17 meskes Exp $ */

+ #define POSTGRES_ECPG_INTERNAL
  #include "postgres_fe.h"

  #include <stdlib.h>
Index: src/interfaces/ecpg/include/sqlca.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/include/sqlca.h,v
retrieving revision 1.23
diff -c -c -r1.23 sqlca.h
*** src/interfaces/ecpg/include/sqlca.h    18 Apr 2003 01:03:42 -0000    1.23
--- src/interfaces/ecpg/include/sqlca.h    15 Jun 2003 04:03:03 -0000
***************
*** 16,22 ****
  {
  #endif

! struct sqlca
  {
      char        sqlcaid[8];
      long        sqlabc;
--- 16,22 ----
  {
  #endif

! struct sqlca_t
  {
      char        sqlcaid[8];
      long        sqlabc;
***************
*** 53,60 ****
      char        sqlext[8];
  };

! extern DLLIMPORT struct sqlca sqlca;


  #ifdef __cplusplus
  }
--- 53,63 ----
      char        sqlext[8];
  };

! struct sqlca_t *ECPGget_sqlca(void);

+ #ifndef POSTGRES_ECPG_INTERNAL
+ # define sqlca (*ECPGget_sqlca())
+ #endif

  #ifdef __cplusplus
  }
Index: src/interfaces/ecpg/preproc/Makefile
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/preproc/Makefile,v
retrieving revision 1.91
diff -c -c -r1.91 Makefile
*** src/interfaces/ecpg/preproc/Makefile    18 Mar 2003 10:46:39 -0000    1.91
--- src/interfaces/ecpg/preproc/Makefile    15 Jun 2003 04:03:03 -0000
***************
*** 4,11 ****
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global

! MAJOR_VERSION=2
! MINOR_VERSION=12
  PATCHLEVEL=0

  override CPPFLAGS := -I$(srcdir)/../include -I$(srcdir) $(CPPFLAGS) \
--- 4,11 ----
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global

! MAJOR_VERSION=3
! MINOR_VERSION=0
  PATCHLEVEL=0

  override CPPFLAGS := -I$(srcdir)/../include -I$(srcdir) $(CPPFLAGS) \

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Add thread.c and linkage
Next
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] ECPG, threading and pooling