Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4f70680

Browse files
committed
Make ecpg thread safe.
Lee Kindness
1 parent ffa3bfb commit 4f70680

File tree

16 files changed

+274
-133
lines changed

16 files changed

+274
-133
lines changed

configure.in

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
dnl Process this file with autoconf to produce a configure script.
2-
dnl $Header: /cvsroot/pgsql/configure.in,v 1.264 2003/06/14 19:21:42 momjian Exp $
2+
dnl $Header: /cvsroot/pgsql/configure.in,v 1.265 2003/06/15 04:07:58 momjian Exp $
33
dnl
44
dnl Developers, please strive to achieve this order:
55
dnl
@@ -323,8 +323,8 @@ IFS=$ac_save_IFS
323323
# Enable libpq to be thread-safe
324324
#
325325
AC_MSG_CHECKING([allow threaded libpq])
326-
PGAC_ARG_BOOL(with, threads, no, [ --with-threads allow libpq to be thread-safe],
327-
[AC_DEFINE([USE_THREADS], 1, [Define to 1 to build libpq with threads. (--with-threads)])])
326+
PGAC_ARG_BOOL(with, threads, no, [ --with-threads allow libpq and ecpg to be thread-safe],
327+
[AC_DEFINE([USE_THREADS], 1, [Define to 1 to build libpq and ecpg to be thread-safe. (--with-threads)])])
328328

329329
AC_MSG_RESULT([$with_threads])
330330
AC_SUBST(with_threads)

doc/src/sgml/ecpg.sgml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/ecpg.sgml,v 1.43 2003/03/25 16:15:35 petere Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/ecpg.sgml,v 1.44 2003/06/15 04:07:58 momjian Exp $
33
-->
44

55
<chapter id="ecpg">
@@ -749,6 +749,13 @@ EXEC SQL INCLUDE <replaceable>filename</replaceable>;
749749
in the arguments specified for output.
750750
</para>
751751

752+
<para>
753+
<application>ecpg</application> is thread-safe if it is compiled using
754+
the <literal>--with-threads</> <filename>configure</filename>
755+
command-line option. (You might need to use other threading
756+
command-line options to compile your client code.)
757+
</para>
758+
752759
<para>
753760
The preprocessor program is called <filename>ecpg</filename> and is
754761
included in a normal <productname>PostgreSQL</> installation.

doc/src/sgml/installation.sgml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/installation.sgml,v 1.134 2003/06/13 23:10:07 momjian Exp $ -->
1+
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/installation.sgml,v 1.135 2003/06/15 04:07:58 momjian Exp $ -->
22

33
<chapter id="installation">
44
<title><![%standalone-include[<productname>PostgreSQL</>]]>
@@ -918,7 +918,8 @@ JAVACMD=$JAVA_HOME/bin/java
918918
<term><option>--with-threads</option></term>
919919
<listitem>
920920
<para>
921-
Allow separate libpq threads to safely control their private connection handles.
921+
Allow separate libpq and ecpg threads to safely control their
922+
private connection handles.
922923
</para>
923924
</listitem>
924925
</varlistentry>

src/interfaces/ecpg/ecpglib/Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55
# Copyright (c) 1994, Regents of the University of California
66
#
7-
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/Makefile,v 1.3 2003/05/22 17:20:44 petere Exp $
7+
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/Makefile,v 1.4 2003/06/15 04:07:58 momjian Exp $
88
#
99
#-------------------------------------------------------------------------
1010

@@ -13,15 +13,15 @@ top_builddir = ../../../..
1313
include $(top_builddir)/src/Makefile.global
1414

1515
NAME= ecpg
16-
SO_MAJOR_VERSION= 3
17-
SO_MINOR_VERSION= 4.2
16+
SO_MAJOR_VERSION= 4
17+
SO_MINOR_VERSION= 1.1
1818

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

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

24-
SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq)
24+
SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq) $(THREAD_LIBS)
2525

2626
all: all-lib
2727

src/interfaces/ecpg/ecpglib/connect.c

Lines changed: 81 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,53 @@
1-
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.6 2003/06/13 10:50:57 meskes Exp $ */
1+
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.7 2003/06/15 04:07:58 momjian Exp $ */
22

3+
#define POSTGRES_ECPG_INTERNAL
34
#include "postgres_fe.h"
45

6+
#ifdef USE_THREADS
7+
#include <pthread.h>
8+
#endif
59
#include "ecpgtype.h"
610
#include "ecpglib.h"
711
#include "ecpgerrno.h"
812
#include "extern.h"
913
#include "sqlca.h"
1014

11-
static struct connection *all_connections = NULL,
12-
*actual_connection = NULL;
15+
#ifdef USE_THREADS
16+
static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
17+
#endif
18+
static struct connection *all_connections = NULL;
19+
static struct connection *actual_connection = NULL;
1320

1421
struct connection *
1522
ECPGget_connection(const char *connection_name)
1623
{
17-
struct connection *con = all_connections;
24+
struct connection *ret = NULL;
25+
26+
#ifdef USE_THREADS
27+
pthread_mutex_lock(&connections_mutex);
28+
#endif
29+
30+
if( (connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0) )
31+
{
32+
ret = actual_connection;
33+
}
34+
else
35+
{
36+
struct connection *con;
37+
38+
for( con = all_connections; con != NULL; con = con->next)
39+
{
40+
if( strcmp(connection_name, con->name) == 0 )
41+
break;
42+
}
43+
ret = con;
44+
}
1845

19-
if (connection_name == NULL || strcmp(connection_name, "CURRENT") == 0)
20-
return actual_connection;
46+
#ifdef USE_THREADS
47+
pthread_mutex_unlock(&connections_mutex);
48+
#endif
2149

22-
for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
23-
if (con)
24-
return con;
25-
else
26-
return NULL;
50+
return( ret );
2751
}
2852

2953
static void
@@ -37,6 +61,10 @@ ecpg_finish(struct connection * act)
3761
ECPGlog("ecpg_finish: finishing %s.\n", act->name);
3862
PQfinish(act->connection);
3963

64+
/* no need to lock connections_mutex - we're always called
65+
by ECPGdisconnect or ECPGconnect, which are holding
66+
the lock */
67+
4068
/* remove act from the list */
4169
if (act == all_connections)
4270
all_connections = act->next;
@@ -118,17 +146,18 @@ ECPGsetconn(int lineno, const char *connection_name)
118146
static void
119147
ECPGnoticeProcessor_raise(int code, const char *message)
120148
{
121-
sqlca.sqlcode = code;
122-
strncpy(sqlca.sqlerrm.sqlerrmc, message, sizeof(sqlca.sqlerrm.sqlerrmc));
123-
sqlca.sqlerrm.sqlerrmc[sizeof(sqlca.sqlerrm.sqlerrmc) - 1] = 0;
124-
sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc);
149+
struct sqlca_t *sqlca = ECPGget_sqlca();
150+
sqlca->sqlcode = code;
151+
strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
152+
sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
153+
sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
125154

126155
/* remove trailing newline */
127-
if (sqlca.sqlerrm.sqlerrml
128-
&& sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] == '\n')
156+
if (sqlca->sqlerrm.sqlerrml
157+
&& sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml - 1] == '\n')
129158
{
130-
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml - 1] = 0;
131-
sqlca.sqlerrm.sqlerrml--;
159+
sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml - 1] = 0;
160+
sqlca->sqlerrm.sqlerrml--;
132161
}
133162

134163
ECPGlog("raising sqlcode %d\n", code);
@@ -141,6 +170,8 @@ ECPGnoticeProcessor_raise(int code, const char *message)
141170
static void
142171
ECPGnoticeProcessor(void *arg, const char *message)
143172
{
173+
struct sqlca_t *sqlca = ECPGget_sqlca();
174+
144175
/* these notices raise an error */
145176
if (strncmp(message, "WARNING: ", 9))
146177
{
@@ -245,22 +276,23 @@ ECPGnoticeProcessor(void *arg, const char *message)
245276
if (strstr(message, "cannot be rolled back"))
246277
return;
247278

248-
/* these and other unmentioned should set sqlca.sqlwarn[2] */
279+
/* these and other unmentioned should set sqlca->sqlwarn[2] */
249280
/* WARNING: The ':' operator is deprecated. Use exp(x) instead. */
250281
/* WARNING: Rel *: Uninitialized page 0 - fixing */
251282
/* WARNING: PortalHeapMemoryFree: * not in alloc set! */
252283
/* WARNING: Too old parent tuple found - can't continue vc_repair_frag */
253284
/* WARNING: identifier "*" will be truncated to "*" */
254285
/* WARNING: InvalidateSharedInvalid: cache state reset */
255286
/* WARNING: RegisterSharedInvalid: SI buffer overflow */
256-
sqlca.sqlwarn[2] = 'W';
257-
sqlca.sqlwarn[0] = 'W';
287+
sqlca->sqlwarn[2] = 'W';
288+
sqlca->sqlwarn[0] = 'W';
258289
}
259290

260291
/* this contains some quick hacks, needs to be cleaned up, but it works */
261292
bool
262293
ECPGconnect(int lineno, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
263294
{
295+
struct sqlca_t *sqlca = ECPGget_sqlca();
264296
struct connection *this;
265297
char *dbname = strdup(name),
266298
*host = NULL,
@@ -269,7 +301,7 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd,
269301
*realname = NULL,
270302
*options = NULL;
271303

272-
ECPGinit_sqlca();
304+
ECPGinit_sqlca(sqlca);
273305

274306
if ((this = (struct connection *) ECPGalloc(sizeof(struct connection), lineno)) == NULL)
275307
return false;
@@ -394,6 +426,9 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd,
394426
realname = strdup(dbname);
395427

396428
/* add connection to our list */
429+
#ifdef USE_THREADS
430+
pthread_mutex_lock(&connections_mutex);
431+
#endif
397432
if (connection_name != NULL)
398433
this->name = ECPGstrdup(connection_name, lineno);
399434
else
@@ -424,6 +459,9 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd,
424459

425460
set_backend_err(errmsg, lineno);
426461
ecpg_finish(this);
462+
#ifdef USE_THREADS
463+
pthread_mutex_unlock(&connections_mutex);
464+
#endif
427465
ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n\t%s\n",
428466
db,
429467
host ? host : "<DEFAULT>",
@@ -445,6 +483,9 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd,
445483
ECPGfree(dbname);
446484
return false;
447485
}
486+
#ifdef USE_THREADS
487+
pthread_mutex_unlock(&connections_mutex);
488+
#endif
448489

449490
if (host)
450491
ECPGfree(host);
@@ -468,11 +509,16 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd,
468509
bool
469510
ECPGdisconnect(int lineno, const char *connection_name)
470511
{
512+
struct sqlca_t *sqlca = ECPGget_sqlca();
471513
struct connection *con;
472514

515+
#ifdef USE_THREADS
516+
pthread_mutex_lock(&connections_mutex);
517+
#endif
518+
473519
if (strcmp(connection_name, "ALL") == 0)
474520
{
475-
ECPGinit_sqlca();
521+
ECPGinit_sqlca(sqlca);
476522
for (con = all_connections; con;)
477523
{
478524
struct connection *f = con;
@@ -486,10 +532,19 @@ ECPGdisconnect(int lineno, const char *connection_name)
486532
con = ECPGget_connection(connection_name);
487533

488534
if (!ECPGinit(con, connection_name, lineno))
489-
return (false);
535+
{
536+
#ifdef USE_THREADS
537+
pthread_mutex_unlock(&connections_mutex);
538+
#endif
539+
return (false);
540+
}
490541
else
491-
ecpg_finish(con);
542+
ecpg_finish(con);
492543
}
493544

545+
#ifdef USE_THREADS
546+
pthread_mutex_unlock(&connections_mutex);
547+
#endif
548+
494549
return true;
495550
}

src/interfaces/ecpg/ecpglib/data.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.4 2003/04/01 14:37:25 meskes Exp $ */
1+
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.5 2003/06/15 04:07:58 momjian Exp $ */
22

3+
#define POSTGRES_ECPG_INTERNAL
34
#include "postgres_fe.h"
45

56
#include <stdlib.h>
@@ -21,6 +22,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
2122
char *var, char *ind, long varcharsize, long offset,
2223
long ind_offset, bool isarray)
2324
{
25+
struct sqlca_t *sqlca = ECPGget_sqlca();
2426
char *pval = (char *) PQgetvalue(results, act_tuple, act_field);
2527

2628
ECPGlog("ECPGget_data line %d: RESULT: %s offset: %ld\n", lineno, pval ? pval : "", offset);
@@ -328,7 +330,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
328330
default:
329331
break;
330332
}
331-
sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W';
333+
sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
332334
}
333335
}
334336
break;
@@ -373,7 +375,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
373375
default:
374376
break;
375377
}
376-
sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W';
378+
sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
377379

378380
variable->len = varcharsize;
379381
}

0 commit comments

Comments
 (0)