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 ---- + ecpg is thread-safe if it is compiled using + the --with-threads configure + command-line option. (You might need to use other threading + command-line options to compile your client code.) + + + The preprocessor program is called ecpg and is included in a normal 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 **** ! Allow separate libpq threads to safely control their private connection handles. --- 918,925 ---- ! Allow separate libpq and ecpg threads to safely control their ! private connection handles. 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 + #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 : "", *************** *** 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 *************** *** 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 *************** *** 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 on Feb. 5th, 1998 */ + #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" #include *************** *** 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 #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 + #ifdef USE_THREADS + #include + #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 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 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) \