PostgreSQL Source Code  git master
prepare.c
Go to the documentation of this file.
1 /* src/interfaces/ecpg/ecpglib/prepare.c */
2 
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
5 
6 #include <ctype.h>
7 
8 #include "ecpgtype.h"
9 #include "ecpglib.h"
10 #include "ecpgerrno.h"
11 #include "ecpglib_extern.h"
12 #include "sqlca.h"
13 
14 #define STMTID_SIZE 32
15 
16 /*
17  * The statement cache contains stmtCacheNBuckets hash buckets, each
18  * having stmtCacheEntPerBucket entries, which we recycle as needed,
19  * giving up the least-executed entry in the bucket.
20  * stmtCacheEntries[0] is never used, so that zero can be a "not found"
21  * indicator.
22  */
23 #define stmtCacheNBuckets 2039 /* should be a prime number */
24 #define stmtCacheEntPerBucket 8
25 
26 #define stmtCacheArraySize (stmtCacheNBuckets * stmtCacheEntPerBucket + 1)
27 
28 typedef struct
29 {
30  int lineno;
31  char stmtID[STMTID_SIZE];
32  char *ecpgQuery;
33  long execs; /* # of executions */
34  const char *connection; /* connection for the statement */
36 
37 static int nextStmtID = 1;
39 
40 static bool deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
41  struct prepared_statement *prev, struct prepared_statement *this);
42 
43 static bool
44 isvarchar(unsigned char c)
45 {
46  if (isalnum(c))
47  return true;
48 
49  if (c == '_' || c == '>' || c == '-' || c == '.')
50  return true;
51 
52  if (c >= 128)
53  return true;
54 
55  return false;
56 }
57 
58 bool
60 {
61  struct statement *prep_stmt;
62  struct prepared_statement *this;
63  struct connection *con = stmt->connection;
64  struct prepared_statement *prev = NULL;
65  int lineno = stmt->lineno;
66 
67  /* check if we already have prepared this statement */
68  this = ecpg_find_prepared_statement(stmt->name, con, &prev);
69  if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
70  return false;
71 
72  /* allocate new statement */
73  this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
74  if (!this)
75  return false;
76 
77  prep_stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
78  if (!prep_stmt)
79  {
80  ecpg_free(this);
81  return false;
82  }
83  memset(prep_stmt, 0, sizeof(struct statement));
84 
85  /* create statement */
86  prep_stmt->lineno = lineno;
87  prep_stmt->connection = con;
88  prep_stmt->command = ecpg_strdup(stmt->command, lineno);
89  prep_stmt->inlist = prep_stmt->outlist = NULL;
90  this->name = ecpg_strdup(stmt->name, lineno);
91  this->stmt = prep_stmt;
92  this->prepared = true;
93 
94  if (con->prep_stmts == NULL)
95  this->next = NULL;
96  else
97  this->next = con->prep_stmts;
98 
99  con->prep_stmts = this;
100  return true;
101 }
102 
103 static bool
105 {
106  bool string = false;
107  int counter = 1,
108  ptr = 0;
109 
110  for (; (*text)[ptr] != '\0'; ptr++)
111  {
112  if ((*text)[ptr] == '\'')
113  string = string ? false : true;
114 
115  if (string || (((*text)[ptr] != ':') && ((*text)[ptr] != '?')))
116  continue;
117 
118  if (((*text)[ptr] == ':') && ((*text)[ptr + 1] == ':'))
119  ptr += 2; /* skip '::' */
120  else
121  {
122  /* a rough guess of the size we need: */
123  int buffersize = sizeof(int) * CHAR_BIT * 10 / 3;
124  int len;
125  char *buffer,
126  *newcopy;
127 
128  if (!(buffer = (char *) ecpg_alloc(buffersize, lineno)))
129  return false;
130 
131  snprintf(buffer, buffersize, "$%d", counter++);
132 
133  for (len = 1; (*text)[ptr + len] && isvarchar((*text)[ptr + len]); len++)
134  /* skip */ ;
135  if (!(newcopy = (char *) ecpg_alloc(strlen(*text) -len + strlen(buffer) + 1, lineno)))
136  {
137  ecpg_free(buffer);
138  return false;
139  }
140 
141  memcpy(newcopy, *text, ptr);
142  strcpy(newcopy + ptr, buffer);
143  strcat(newcopy, (*text) +ptr + len);
144 
145  ecpg_free(*text);
146  ecpg_free(buffer);
147 
148  *text = newcopy;
149 
150  if ((*text)[ptr] == '\0') /* we reached the end */
151  ptr--; /* since we will (*text)[ptr]++ in the top
152  * level for loop */
153  }
154  }
155  return true;
156 }
157 
158 static bool
159 prepare_common(int lineno, struct connection *con, const char *name, const char *variable)
160 {
161  struct statement *stmt;
162  struct prepared_statement *this;
163  PGresult *query;
164 
165  /* allocate new statement */
166  this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
167  if (!this)
168  return false;
169 
170  stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
171  if (!stmt)
172  {
173  ecpg_free(this);
174  return false;
175  }
176 
177  /* create statement */
178  stmt->lineno = lineno;
179  stmt->connection = con;
180  stmt->command = ecpg_strdup(variable, lineno);
181  stmt->inlist = stmt->outlist = NULL;
182 
183  /* if we have C variables in our statement replace them with '?' */
184  replace_variables(&(stmt->command), lineno);
185 
186  /* add prepared statement to our list */
187  this->name = ecpg_strdup(name, lineno);
188  this->stmt = stmt;
189 
190  /* and finally really prepare the statement */
191  query = PQprepare(stmt->connection->connection, name, stmt->command, 0, NULL);
192  if (!ecpg_check_PQresult(query, stmt->lineno, stmt->connection->connection, stmt->compat))
193  {
194  ecpg_free(stmt->command);
195  ecpg_free(this->name);
196  ecpg_free(this);
197  ecpg_free(stmt);
198  return false;
199  }
200 
201  ecpg_log("prepare_common on line %d: name %s; query: \"%s\"\n", stmt->lineno, name, stmt->command);
202  PQclear(query);
203  this->prepared = true;
204 
205  if (con->prep_stmts == NULL)
206  this->next = NULL;
207  else
208  this->next = con->prep_stmts;
209 
210  con->prep_stmts = this;
211  return true;
212 }
213 
214 /* handle the EXEC SQL PREPARE statement */
215 /* questionmarks is not needed but remains in there for the time being to not change the API */
216 bool
217 ECPGprepare(int lineno, const char *connection_name, const bool questionmarks,
218  const char *name, const char *variable)
219 {
220  struct connection *con;
221  struct prepared_statement *this,
222  *prev;
223 
224  (void) questionmarks; /* quiet the compiler */
225 
226  con = ecpg_get_connection(connection_name);
227  if (!ecpg_init(con, connection_name, lineno))
228  return false;
229 
230  /* check if we already have prepared this statement */
231  this = ecpg_find_prepared_statement(name, con, &prev);
232  if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
233  return false;
234 
235  return prepare_common(lineno, con, name, variable);
236 }
237 
238 struct prepared_statement *
240  struct connection *con, struct prepared_statement **prev_)
241 {
242  struct prepared_statement *this,
243  *prev;
244 
245  for (this = con->prep_stmts, prev = NULL;
246  this != NULL;
247  prev = this, this = this->next)
248  {
249  if (strcmp(this->name, name) == 0)
250  {
251  if (prev_)
252  *prev_ = prev;
253  return this;
254  }
255  }
256  return NULL;
257 }
258 
259 static bool
260 deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
261  struct prepared_statement *prev, struct prepared_statement *this)
262 {
263  bool r = false;
264 
265  ecpg_log("deallocate_one on line %d: name %s\n", lineno, this->name);
266 
267  /* first deallocate the statement in the backend */
268  if (this->prepared)
269  {
270  char *text;
271  PGresult *query;
272 
273  text = (char *) ecpg_alloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno);
274 
275  if (text)
276  {
277  sprintf(text, "deallocate \"%s\"", this->name);
278  query = PQexec(this->stmt->connection->connection, text);
279  ecpg_free(text);
280  if (ecpg_check_PQresult(query, lineno,
281  this->stmt->connection->connection,
282  this->stmt->compat))
283  {
284  PQclear(query);
285  r = true;
286  }
287  }
288  }
289 
290  /*
291  * Just ignore all errors since we do not know the list of cursors we are
292  * allowed to free. We have to trust the software.
293  */
294  if (!r && !INFORMIX_MODE(c))
295  {
297  return false;
298  }
299 
300  /* okay, free all the resources */
301  ecpg_free(this->stmt->command);
302  ecpg_free(this->stmt);
303  ecpg_free(this->name);
304  if (prev != NULL)
305  prev->next = this->next;
306  else
307  con->prep_stmts = this->next;
308 
309  ecpg_free(this);
310  return true;
311 }
312 
313 /* handle the EXEC SQL DEALLOCATE PREPARE statement */
314 bool
315 ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
316 {
317  struct connection *con;
318  struct prepared_statement *this,
319  *prev;
320 
321  con = ecpg_get_connection(connection_name);
322  if (!ecpg_init(con, connection_name, lineno))
323  return false;
324 
325  this = ecpg_find_prepared_statement(name, con, &prev);
326  if (this)
327  return deallocate_one(lineno, c, con, prev, this);
328 
329  /* prepared statement is not found */
330  if (INFORMIX_MODE(c))
331  return true;
333  return false;
334 }
335 
336 bool
337 ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
338 {
339  /* deallocate all prepared statements */
340  while (con->prep_stmts)
341  {
342  if (!deallocate_one(lineno, c, con, NULL, con->prep_stmts))
343  return false;
344  }
345 
346  return true;
347 }
348 
349 bool
350 ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
351 {
352  return ecpg_deallocate_all_conn(lineno, compat,
353  ecpg_get_connection(connection_name));
354 }
355 
356 char *
357 ecpg_prepared(const char *name, struct connection *con)
358 {
359  struct prepared_statement *this;
360 
361  this = ecpg_find_prepared_statement(name, con, NULL);
362  return this ? this->stmt->command : NULL;
363 }
364 
365 /* return the prepared statement */
366 /* lineno is not used here, but kept in to not break API */
367 char *
368 ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
369 {
370  (void) lineno; /* keep the compiler quiet */
371 
372  return ecpg_prepared(name, ecpg_get_connection(connection_name));
373 }
374 
375 /*
376  * hash a SQL statement - returns entry # of first entry in the bucket
377  */
378 static int
379 HashStmt(const char *ecpgQuery)
380 {
381  int stmtIx,
382  bucketNo,
383  hashLeng,
384  stmtLeng;
385  uint64 hashVal,
386  rotVal;
387 
388  stmtLeng = strlen(ecpgQuery);
389  hashLeng = 50; /* use 1st 50 characters of statement */
390  if (hashLeng > stmtLeng) /* if the statement isn't that long */
391  hashLeng = stmtLeng; /* use its actual length */
392 
393  hashVal = 0;
394  for (stmtIx = 0; stmtIx < hashLeng; ++stmtIx)
395  {
396  hashVal = hashVal + (unsigned char) ecpgQuery[stmtIx];
397  /* rotate 32-bit hash value left 13 bits */
398  hashVal = hashVal << 13;
399  rotVal = (hashVal & UINT64CONST(0x1fff00000000)) >> 32;
400  hashVal = (hashVal & UINT64CONST(0xffffffff)) | rotVal;
401  }
402 
403  bucketNo = hashVal % stmtCacheNBuckets;
404 
405  /* Add 1 so that array entry 0 is never used */
406  return bucketNo * stmtCacheEntPerBucket + 1;
407 }
408 
409 /*
410  * search the statement cache - search for entry with matching ECPG-format query
411  * Returns entry # in cache if found
412  * OR zero if not present (zero'th entry isn't used)
413  */
414 static int
415 SearchStmtCache(const char *ecpgQuery)
416 {
417  int entNo,
418  entIx;
419 
420  /* quick failure if cache not set up */
421  if (stmtCacheEntries == NULL)
422  return 0;
423 
424  /* hash the statement */
425  entNo = HashStmt(ecpgQuery);
426 
427  /* search the cache */
428  for (entIx = 0; entIx < stmtCacheEntPerBucket; ++entIx)
429  {
430  if (stmtCacheEntries[entNo].stmtID[0]) /* check if entry is in use */
431  {
432  if (strcmp(ecpgQuery, stmtCacheEntries[entNo].ecpgQuery) == 0)
433  break; /* found it */
434  }
435  ++entNo; /* incr entry # */
436  }
437 
438  /* if entry wasn't found - set entry # to zero */
439  if (entIx >= stmtCacheEntPerBucket)
440  entNo = 0;
441 
442  return entNo;
443 }
444 
445 /*
446  * free an entry in the statement cache
447  * Returns entry # in cache used
448  * OR negative error code
449  */
450 static int
452  int entNo) /* entry # to free */
453 {
454  stmtCacheEntry *entry;
455  struct connection *con;
456  struct prepared_statement *this,
457  *prev;
458 
459  /* fail if cache isn't set up */
460  if (stmtCacheEntries == NULL)
461  return -1;
462 
463  entry = &stmtCacheEntries[entNo];
464  if (!entry->stmtID[0]) /* return if the entry isn't in use */
465  return 0;
466 
467  con = ecpg_get_connection(entry->connection);
468 
469  /* free the 'prepared_statement' list entry */
470  this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
471  if (this && !deallocate_one(lineno, compat, con, prev, this))
472  return -1;
473 
474  entry->stmtID[0] = '\0';
475 
476  /* free the memory used by the cache entry */
477  if (entry->ecpgQuery)
478  {
479  ecpg_free(entry->ecpgQuery);
480  entry->ecpgQuery = 0;
481  }
482 
483  return entNo;
484 }
485 
486 /*
487  * add an entry to the statement cache
488  * returns entry # in cache used OR negative error code
489  */
490 static int
491 AddStmtToCache(int lineno, /* line # of statement */
492  const char *stmtID, /* statement ID */
493  const char *connection, /* connection */
494  int compat, /* compatibility level */
495  const char *ecpgQuery) /* query */
496 {
497  int ix,
498  initEntNo,
499  luEntNo,
500  entNo;
501  stmtCacheEntry *entry;
502 
503  /* allocate and zero cache array if we haven't already */
504  if (stmtCacheEntries == NULL)
505  {
506  stmtCacheEntries = (stmtCacheEntry *)
507  ecpg_alloc(sizeof(stmtCacheEntry) * stmtCacheArraySize, lineno);
508  if (stmtCacheEntries == NULL)
509  return -1;
510  }
511 
512  /* hash the statement */
513  initEntNo = HashStmt(ecpgQuery);
514 
515  /* search for an unused entry */
516  entNo = initEntNo; /* start with the initial entry # for the
517  * bucket */
518  luEntNo = initEntNo; /* use it as the initial 'least used' entry */
519  for (ix = 0; ix < stmtCacheEntPerBucket; ++ix)
520  {
521  entry = &stmtCacheEntries[entNo];
522  if (!entry->stmtID[0]) /* unused entry - use it */
523  break;
524  if (entry->execs < stmtCacheEntries[luEntNo].execs)
525  luEntNo = entNo; /* save new 'least used' entry */
526  ++entNo; /* increment entry # */
527  }
528 
529  /*
530  * if no unused entries were found, re-use the 'least used' entry found in
531  * the bucket
532  */
533  if (ix >= stmtCacheEntPerBucket)
534  entNo = luEntNo;
535 
536  /* 'entNo' is the entry to use - make sure its free */
537  if (ecpg_freeStmtCacheEntry(lineno, compat, entNo) < 0)
538  return -1;
539 
540  /* add the query to the entry */
541  entry = &stmtCacheEntries[entNo];
542  entry->lineno = lineno;
543  entry->ecpgQuery = ecpg_strdup(ecpgQuery, lineno);
544  entry->connection = connection;
545  entry->execs = 0;
546  memcpy(entry->stmtID, stmtID, sizeof(entry->stmtID));
547 
548  return entNo;
549 }
550 
551 /* handle cache and preparation of statements in auto-prepare mode */
552 bool
553 ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, char **name, const char *query)
554 {
555  int entNo;
556 
557  /* search the statement cache for this statement */
558  entNo = SearchStmtCache(query);
559 
560  /* if not found - add the statement to the cache */
561  if (entNo)
562  {
563  char *stmtID;
564  struct connection *con;
565  struct prepared_statement *prep;
566 
567  ecpg_log("ecpg_auto_prepare on line %d: statement found in cache; entry %d\n", lineno, entNo);
568 
569  stmtID = stmtCacheEntries[entNo].stmtID;
570 
571  con = ecpg_get_connection(connection_name);
572  prep = ecpg_find_prepared_statement(stmtID, con, NULL);
573  /* This prepared name doesn't exist on this connection. */
574  if (!prep && !prepare_common(lineno, con, stmtID, query))
575  return false;
576 
577  *name = ecpg_strdup(stmtID, lineno);
578  }
579  else
580  {
581  char stmtID[STMTID_SIZE];
582 
583  ecpg_log("ecpg_auto_prepare on line %d: statement not in cache; inserting\n", lineno);
584 
585  /* generate a statement ID */
586  sprintf(stmtID, "ecpg%d", nextStmtID++);
587 
588  if (!ECPGprepare(lineno, connection_name, 0, stmtID, query))
589  return false;
590 
591  entNo = AddStmtToCache(lineno, stmtID, connection_name, compat, query);
592  if (entNo < 0)
593  return false;
594 
595  *name = ecpg_strdup(stmtID, lineno);
596  }
597 
598  /* increase usage counter */
599  stmtCacheEntries[entNo].execs++;
600 
601  return true;
602 }
static int SearchStmtCache(const char *ecpgQuery)
Definition: prepare.c:415
char * ecpgQuery
Definition: prepare.c:32
PGresult * PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes)
Definition: fe-exec.c:1984
COMPAT_MODE
char * ecpg_prepared(const char *name, struct connection *con)
Definition: prepare.c:357
static int32 next
Definition: blutils.c:215
void ecpg_raise(int line, int code, const char *sqlstate, const char *str)
Definition: error.c:13
const char * connection
Definition: prepare.c:34
void ecpg_free(void *)
Definition: memory.c:13
bool ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, char **name, const char *query)
Definition: prepare.c:553
#define ECPG_INVALID_STMT
Definition: ecpgerrno.h:39
Definition: type.h:102
char * ecpg_strdup(const char *, int)
Definition: memory.c:47
bool ECPGprepare(int lineno, const char *connection_name, const bool questionmarks, const char *name, const char *variable)
Definition: prepare.c:217
#define INFORMIX_MODE(X)
long execs
Definition: prepare.c:33
char stmtID[STMTID_SIZE]
Definition: prepare.c:31
#define false
Definition: c.h:316
bool ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
Definition: prepare.c:350
static int AddStmtToCache(int lineno, const char *stmtID, const char *connection, int compat, const char *ecpgQuery)
Definition: prepare.c:491
#define stmtCacheEntPerBucket
Definition: prepare.c:24
#define sprintf
Definition: port.h:194
struct connection * connection
enum COMPAT_MODE compat
static bool deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con, struct prepared_statement *prev, struct prepared_statement *this)
Definition: prepare.c:260
char * c
struct statement * stmt
#define stmtCacheNBuckets
Definition: prepare.c:23
bool ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
Definition: prepare.c:337
bool questionmarks
Definition: ecpg.c:19
struct varlena text
Definition: c.h:563
void ecpg_log(const char *format,...) pg_attribute_printf(1
enum COMPAT_MODE compat
Definition: ecpg.c:25
char * ecpg_alloc(long, int)
Definition: memory.c:19
static bool prepare_common(int lineno, struct connection *con, const char *name, const char *variable)
Definition: prepare.c:159
#define stmtCacheArraySize
Definition: prepare.c:26
struct prepared_statement * next
#define ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME
bool ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
Definition: prepare.c:315
static int nextStmtID
Definition: prepare.c:37
char * command
void PQclear(PGresult *res)
Definition: fe-exec.c:695
struct variable * inlist
bool ecpg_check_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE)
Definition: error.c:283
PGconn * connection
static stmtCacheEntry * stmtCacheEntries
Definition: prepare.c:38
static int HashStmt(const char *ecpgQuery)
Definition: prepare.c:379
char * name
struct prepared_statement * ecpg_find_prepared_statement(const char *name, struct connection *con, struct prepared_statement **prev_)
Definition: prepare.c:239
char * ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
Definition: prepare.c:368
const char * name
Definition: encode.c:521
static bool replace_variables(char **text, int lineno)
Definition: prepare.c:104
struct connection * ecpg_get_connection(const char *connection_name)
Definition: connect.c:74
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1940
Definition: c.h:549
char * connection
static bool isvarchar(unsigned char c)
Definition: prepare.c:44
static int ecpg_freeStmtCacheEntry(int lineno, int compat, int entNo)
Definition: prepare.c:451
#define snprintf
Definition: port.h:192
bool ecpg_init(const struct connection *, const char *, const int)
Definition: misc.c:105
bool ecpg_register_prepared_stmt(struct statement *stmt)
Definition: prepare.c:59
struct variable * outlist
struct prepared_statement * prep_stmts
#define STMTID_SIZE
Definition: prepare.c:14