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

From Bruce Momjian
Subject Re: [HACKERS] ECPG, threading and pooling
Date
Msg-id 200306150456.h5F4uW401699@candle.pha.pa.us
Whole thread Raw
List pgsql-patches
I had to make the following changes to the patch.  You had this:

    sqlca = pthread_getspecific(&sqlca_key);

but my prototypes say it should be:

    sqlca = pthread_getspecific(sqlca_key);

The applied patch also includes some prototype cleanups.


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

pgman wrote:
>
> 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) \

--
  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: src/interfaces/ecpg/ecpglib/misc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/ecpglib/misc.c,v
retrieving revision 1.3
diff -c -c -r1.3 misc.c
*** src/interfaces/ecpg/ecpglib/misc.c    15 Jun 2003 04:07:58 -0000    1.3
--- src/interfaces/ecpg/ecpglib/misc.c    15 Jun 2003 04:46:37 -0000
***************
*** 78,84 ****
  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));
  }
--- 78,85 ----
  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));
  }
***************
*** 98,122 ****
  }

  #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
--- 99,125 ----
  }

  #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
Index: src/interfaces/ecpg/include/ecpglib.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/ecpg/include/ecpglib.h,v
retrieving revision 1.49
diff -c -c -r1.49 ecpglib.h
*** src/interfaces/ecpg/include/ecpglib.h    13 Jun 2003 10:50:57 -0000    1.49
--- src/interfaces/ecpg/include/ecpglib.h    15 Jun 2003 04:46:37 -0000
***************
*** 38,43 ****
--- 38,46 ----
  {
  #endif

+ struct sqlca_t;
+
+ void        ECPGinit_sqlca(struct sqlca_t *sqlca);
  void        ECPGdebug(int, FILE *);
  bool        ECPGstatus(int, const char *);
  bool        ECPGsetcommit(int, const char *, const char *);
***************
*** 49,58 ****
  bool        ECPGprepare(int, char *, char *);
  bool        ECPGdeallocate(int, char *);
  bool        ECPGdeallocate_all(int);
! char           *ECPGprepared_statement(char *);

  void        ECPGlog(const char *format,...);
! char           *ECPGerrmsg(void);

   /* print an error message */
  void        sqlprint(void);
--- 52,61 ----
  bool        ECPGprepare(int, char *, char *);
  bool        ECPGdeallocate(int, char *);
  bool        ECPGdeallocate_all(int);
! char       *ECPGprepared_statement(char *);

  void        ECPGlog(const char *format,...);
! char       *ECPGerrmsg(void);

   /* print an error message */
  void        sqlprint(void);

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] ECPG, threading and pooling
Next
From: Peter Eisentraut
Date:
Subject: Re: Doc updates (minor)