Skip to content

Commit d49b20f

Browse files
author
Michael Meskes
committed
Applied patch by ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp> to get prepare thread-safe.
1 parent 689df1b commit d49b20f

20 files changed

+512
-120
lines changed

src/interfaces/ecpg/ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,5 +2237,10 @@ Wed, 29 Aug 2007 15:41:58 +0200
22372237
Tue, 04 Sep 2007 11:13:55 +0200
22382238

22392239
- Synced parser and keyword list.
2240+
2241+
Mi 26. Sep 12:45:51 CEST 2007
2242+
2243+
- Applied patch by ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp>
2244+
to get prepare thread-safe.
22402245
- Set ecpg library version to 6.0.
22412246
- Set ecpg version to 4.4.

src/interfaces/ecpg/ecpglib/connect.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.42 2007/08/14 10:01:52 meskes Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.43 2007/09/26 10:57:00 meskes Exp $ */
22

33
#define POSTGRES_ECPG_INTERNAL
44
#include "postgres_fe.h"
@@ -460,6 +460,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
460460
this->name = ECPGstrdup(realname, lineno);
461461

462462
this->cache_head = NULL;
463+
this->prep_stmts = NULL;
463464

464465
if (all_connections == NULL)
465466
this->next = NULL;

src/interfaces/ecpg/ecpglib/execute.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.69 2007/09/21 10:59:27 meskes Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.70 2007/09/26 10:57:00 meskes Exp $ */
22

33
/*
44
* The aim is to get a simpler inteface to the database routines.
@@ -1515,7 +1515,7 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
15151515
if (statement_type == ECPGst_execute)
15161516
{
15171517
/* if we have an EXECUTE command, only the name is send */
1518-
char *command = ECPGprepared(stmt->command, lineno);
1518+
char *command = ECPGprepared(stmt->command, con, lineno);
15191519

15201520
if (command)
15211521
{

src/interfaces/ecpg/ecpglib/extern.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.26 2007/08/14 10:54:57 meskes Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.27 2007/09/26 10:57:00 meskes Exp $ */
22

33
#ifndef _ECPG_LIB_EXTERN_H
44
#define _ECPG_LIB_EXTERN_H
@@ -91,6 +91,7 @@ struct connection
9191
bool committed;
9292
int autocommit;
9393
struct ECPGtype_information_cache *cache_head;
94+
struct prepared_statement *prep_stmts;
9495
struct connection *next;
9596
};
9697

@@ -144,7 +145,7 @@ bool ECPGstore_input(const int, const bool, const struct variable *, const char
144145
bool ECPGcheck_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE);
145146
void ECPGraise(int line, int code, const char *sqlstate, const char *str);
146147
void ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat);
147-
char *ECPGprepared(const char *, int);
148+
char *ECPGprepared(const char *, struct connection *, int);
148149

149150
/* SQLSTATE values generated or processed by ecpglib (intentionally
150151
* not exported -- users should refer to the codes directly) */

src/interfaces/ecpg/ecpglib/prepare.c

Lines changed: 109 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.19 2007/08/14 10:01:52 meskes Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.20 2007/09/26 10:57:00 meskes Exp $ */
22

33
#define POSTGRES_ECPG_INTERNAL
44
#include "postgres_fe.h"
@@ -11,13 +11,13 @@
1111
#include "extern.h"
1212
#include "sqlca.h"
1313

14-
static struct prepared_statement
14+
struct prepared_statement
1515
{
16-
char *name;
17-
bool prepared;
18-
struct statement *stmt;
19-
struct prepared_statement *next;
20-
} *prep_stmts = NULL;
16+
char *name;
17+
bool prepared;
18+
struct statement *stmt;
19+
struct prepared_statement *next;
20+
};
2121

2222
#define STMTID_SIZE 32
2323

@@ -35,6 +35,11 @@ static int stmtCacheNBuckets = 2039; /* # buckets - a pri
3535
static int stmtCacheEntPerBucket = 8; /* # entries/bucket */
3636
static stmtCacheEntry stmtCacheEntries[16384] = {{0,{0},0,0,0}};
3737

38+
static struct prepared_statement *find_prepared_statement(const char *name,
39+
struct connection *con, struct prepared_statement **prev);
40+
static bool deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
41+
struct prepared_statement *prev, struct prepared_statement *this);
42+
3843
static bool
3944
isvarchar(unsigned char c)
4045
{
@@ -105,23 +110,23 @@ replace_variables(char **text, int lineno, bool questionmarks)
105110
bool
106111
ECPGprepare(int lineno, const char *connection_name, const int questionmarks, const char *name, const char *variable)
107112
{
108-
struct statement *stmt;
109-
struct prepared_statement *this;
113+
struct connection *con;
114+
struct statement *stmt;
115+
struct prepared_statement *this,
116+
*prev;
110117
struct sqlca_t *sqlca = ECPGget_sqlca();
111118
PGresult *query;
112119

113120
ECPGinit_sqlca(sqlca);
114121

115-
/* check if we already have prepared this statement */
116-
for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
117-
if (this)
118-
{
119-
bool b = ECPGdeallocate(lineno, ECPG_COMPAT_PGSQL, name);
122+
con = ECPGget_connection(connection_name);
120123

121-
if (!b)
122-
return false;
123-
}
124+
/* check if we already have prepared this statement */
125+
this = find_prepared_statement(name, con, &prev);
126+
if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
127+
return false;
124128

129+
/* allocate new statement */
125130
this = (struct prepared_statement *) ECPGalloc(sizeof(struct prepared_statement), lineno);
126131
if (!this)
127132
return false;
@@ -135,7 +140,7 @@ ECPGprepare(int lineno, const char *connection_name, const int questionmarks, co
135140

136141
/* create statement */
137142
stmt->lineno = lineno;
138-
stmt->connection = ECPGget_connection(connection_name);
143+
stmt->connection = con;
139144
stmt->command = ECPGstrdup(variable, lineno);
140145
stmt->inlist = stmt->outlist = NULL;
141146

@@ -160,113 +165,133 @@ ECPGprepare(int lineno, const char *connection_name, const int questionmarks, co
160165
PQclear(query);
161166
this->prepared = true;
162167

163-
if (prep_stmts == NULL)
168+
if (con->prep_stmts == NULL)
164169
this->next = NULL;
165170
else
166-
this->next = prep_stmts;
171+
this->next = con->prep_stmts;
167172

168-
prep_stmts = this;
173+
con->prep_stmts = this;
169174
return true;
170175
}
171176

177+
static struct prepared_statement *find_prepared_statement(const char *name,
178+
struct connection *con, struct prepared_statement **prev_)
179+
{
180+
struct prepared_statement *this,
181+
*prev;
182+
183+
for (this = con->prep_stmts, prev = NULL; this != NULL; prev = this, this = this->next)
184+
{
185+
if (strcmp(this->name, name) == 0)
186+
{
187+
if (prev_)
188+
*prev_ = prev;
189+
return this;
190+
}
191+
}
192+
return NULL;
193+
}
194+
172195
static bool
173-
deallocate_one(int lineno, const char *name)
196+
deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con, struct prepared_statement *prev, struct prepared_statement *this)
174197
{
175-
struct prepared_statement *this,
176-
*prev;
198+
bool r = false;
177199

178-
/* check if we really have prepared this statement */
179-
for (this = prep_stmts, prev = NULL; this != NULL && strcmp(this->name, name) != 0; prev = this, this = this->next);
180-
if (this)
200+
ECPGlog("ECPGdeallocate line %d: NAME: %s\n", lineno, this->name);
201+
202+
/* first deallocate the statement in the backend */
203+
if (this->prepared)
181204
{
182-
/* first deallocate the statement in the backend */
183-
if (this->prepared)
205+
char *text;
206+
PGresult *query;
207+
208+
text = (char *) ECPGalloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno);
209+
if (text)
184210
{
185-
char *text;
186-
PGresult *query;
187-
188-
if (!(text = (char *) ECPGalloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno)))
189-
return false;
190-
else
211+
sprintf(text, "deallocate \"%s\"", this->name);
212+
query = PQexec(this->stmt->connection->connection, text);
213+
ECPGfree(text);
214+
if (ECPGcheck_PQresult(query, lineno, this->stmt->connection->connection, this->stmt->compat))
191215
{
192-
sprintf(text, "deallocate \"%s\"", this->name);
193-
query = PQexec(this->stmt->connection->connection, text);
194-
ECPGfree(text);
195-
if (!ECPGcheck_PQresult(query, lineno, this->stmt->connection->connection, this->stmt->compat))
196-
return false;
197216
PQclear(query);
217+
r = true;
198218
}
199219
}
200-
201-
/* okay, free all the resources */
202-
ECPGfree(this->stmt->command);
203-
ECPGfree(this->stmt);
204-
if (prev != NULL)
205-
prev->next = this->next;
206-
else
207-
prep_stmts = this->next;
220+
}
208221

209-
ECPGfree(this);
210-
return true;
222+
/*
223+
* Just ignore all errors since we do not know the list of cursors we
224+
* are allowed to free. We have to trust the software.
225+
*/
226+
if (!r && !INFORMIX_MODE(c))
227+
{
228+
ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, this->name);
229+
return false;
211230
}
212-
return false;
231+
232+
/* okay, free all the resources */
233+
ECPGfree(this->stmt->command);
234+
ECPGfree(this->stmt);
235+
if (prev != NULL)
236+
prev->next = this->next;
237+
else
238+
con->prep_stmts = this->next;
239+
240+
ECPGfree(this);
241+
return true;
213242
}
214243

215244
/* handle the EXEC SQL DEALLOCATE PREPARE statement */
216245
bool
217-
ECPGdeallocate(int lineno, int c, const char *name)
246+
ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
218247
{
219-
bool ret = deallocate_one(lineno, name);
220-
enum COMPAT_MODE compat = c;
248+
struct connection *con;
249+
struct prepared_statement *this,
250+
*prev;
221251

222-
ECPGlog("ECPGdeallocate line %d: NAME: %s\n", lineno, name);
223-
if (INFORMIX_MODE(compat))
224-
{
225-
/*
226-
* Just ignore all errors since we do not know the list of cursors we
227-
* are allowed to free. We have to trust the software.
228-
*/
229-
return true;
230-
}
252+
con = ECPGget_connection(connection_name);
231253

232-
if (!ret)
233-
ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
254+
this = find_prepared_statement(name, con, &prev);
255+
if (this)
256+
return deallocate_one(lineno, c, con, prev, this);
234257

235-
return ret;
258+
/* prepared statement is not found */
259+
if (INFORMIX_MODE(c))
260+
return true;
261+
ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
262+
return false;
236263
}
237264

238265
bool
239-
ECPGdeallocate_all(int lineno, int compat)
266+
ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
240267
{
268+
struct connection *con;
269+
270+
con = ECPGget_connection(connection_name);
271+
241272
/* deallocate all prepared statements */
242-
while (prep_stmts != NULL)
273+
while (con->prep_stmts)
243274
{
244-
bool b = ECPGdeallocate(lineno, compat, prep_stmts->name);
245-
246-
if (!b)
275+
if (!deallocate_one(lineno, compat, con, NULL, con->prep_stmts))
247276
return false;
248277
}
249278

250279
return true;
251280
}
252281

253282
char *
254-
ECPGprepared(const char *name, int lineno)
283+
ECPGprepared(const char *name, struct connection *con, int lineno)
255284
{
256-
struct prepared_statement *this;
257-
258-
for (this = prep_stmts; this != NULL && ((strcmp(this->name, name) != 0) || this->prepared == false); this = this->next);
259-
return (this) ? this->stmt->command : NULL;
285+
struct prepared_statement *this;
286+
this = find_prepared_statement(name, con, NULL);
287+
return this ? this->stmt->command : NULL;
260288
}
261289

262290
/* return the prepared statement */
263291
char *
264-
ECPGprepared_statement(const char *name, int lineno)
292+
ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
265293
{
266-
struct prepared_statement *this;
267-
268-
for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
269-
return (this) ? this->stmt->command : NULL;
294+
return ECPGprepared(name, ECPGget_connection(connection_name), lineno);
270295
}
271296

272297
/*
@@ -426,14 +451,14 @@ ECPGauto_prepare(int lineno, const char *connection_name, const int questionmark
426451
entNo = SearchStmtCache(query);
427452

428453
/* if not found - add the statement to the cache */
429-
if(entNo)
454+
if(entNo)
430455
{
431-
ECPGlog("ECPGauto_prepare line %d: stmt found in cache, entry %d\n", lineno, entNo);
456+
ECPGlog("ECPGauto_prepare line %d: stmt found in cache, entry %d\n", lineno, entNo);
432457
*name = ECPGstrdup(stmtCacheEntries[entNo].stmtID, lineno);
433458
}
434459
else
435460
{
436-
ECPGlog("ECPGauto_prepare line %d: stmt not in cache; inserting\n", lineno);
461+
ECPGlog("ECPGauto_prepare line %d: stmt not in cache; inserting\n", lineno);
437462

438463
/* generate a statement ID */
439464
*name = (char *) ECPGalloc(STMTID_SIZE, lineno);
@@ -450,4 +475,3 @@ ECPGauto_prepare(int lineno, const char *connection_name, const int questionmark
450475

451476
return(true);
452477
}
453-

src/interfaces/ecpg/include/ecpglib.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* this is a small part of c.h since we don't want to leak all postgres
33
* definitions into ecpg programs
4-
* $PostgreSQL: pgsql/src/interfaces/ecpg/include/ecpglib.h,v 1.71 2007/08/14 10:01:52 meskes Exp $
4+
* $PostgreSQL: pgsql/src/interfaces/ecpg/include/ecpglib.h,v 1.72 2007/09/26 10:57:00 meskes Exp $
55
*/
66

77
#ifndef _ECPGLIB_H
@@ -49,9 +49,9 @@ bool ECPGtrans(int, const char *, const char *);
4949
bool ECPGdisconnect(int, const char *);
5050
bool ECPGprepare(int, const char *, const int, const char *, const char *);
5151
bool ECPGauto_prepare(int, const char *, const int, char **, const char *);
52-
bool ECPGdeallocate(int, int, const char *);
53-
bool ECPGdeallocate_all(int, int);
54-
char *ECPGprepared_statement(const char *, int);
52+
bool ECPGdeallocate(int, int, const char *connection_name, const char *name);
53+
bool ECPGdeallocate_all(int, int, const char *connection_name);
54+
char *ECPGprepared_statement(const char *connection_name, const char *name, int);
5555

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

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