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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy