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"
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
3535static int stmtCacheEntPerBucket = 8 ;/* # entries/bucket */
3636static 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+
3843static bool
3944isvarchar (unsignedchar c )
4045{
@@ -105,23 +110,23 @@ replace_variables(char **text, int lineno, bool questionmarks)
105110bool
106111ECPGprepare (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 ;
110117struct sqlca_t * sqlca = ECPGget_sqlca ();
111118PGresult * query ;
112119
113120ECPGinit_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 */
125130this = (struct prepared_statement * )ECPGalloc (sizeof (struct prepared_statement ),lineno );
126131if (!this )
127132return false;
@@ -135,7 +140,7 @@ ECPGprepare(int lineno, const char *connection_name, const int questionmarks, co
135140
136141/* create statement */
137142stmt -> lineno = lineno ;
138- stmt -> connection = ECPGget_connection ( connection_name ) ;
143+ stmt -> connection = con ;
139144stmt -> command = ECPGstrdup (variable ,lineno );
140145stmt -> inlist = stmt -> outlist = NULL ;
141146
@@ -160,113 +165,133 @@ ECPGprepare(int lineno, const char *connection_name, const int questionmarks, co
160165PQclear (query );
161166this -> prepared = true;
162167
163- if (prep_stmts == NULL )
168+ if (con -> prep_stmts == NULL )
164169this -> next = NULL ;
165170else
166- this -> next = prep_stmts ;
171+ this -> next = con -> prep_stmts ;
167172
168- prep_stmts = this ;
173+ con -> prep_stmts = this ;
169174return 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+
172195static 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;
197216PQclear (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 */
216245bool
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
238265bool
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 ))
247276return false;
248277}
249278
250279return true;
251280}
252281
253282char *
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 */
263291char *
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
426451entNo = 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}
434459else
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
451476return (true);
452477}
453-