Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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