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
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 */
35} stmtCacheEntry;
36
37static int nextStmtID = 1;
38static stmtCacheEntry *stmtCacheEntries = NULL;
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
59ecpg_register_prepared_stmt(struct statement *stmt)
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
103static bool
104replace_variables(char **text, int lineno)
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
158static bool
159prepare_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 */
216bool
217ECPGprepare(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
238struct prepared_statement *
239ecpg_find_prepared_statement(const char *name,
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
259static bool
260deallocate_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 {
296 ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, this->name);
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 */
314bool
315ECPGdeallocate(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;
332 ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
333 return false;
334}
335
336bool
337ecpg_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
349bool
350ECPGdeallocate_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
356char *
357ecpg_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 */
367char *
368ECPGprepared_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 */
378static int
379HashStmt(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 */
414static int
415SearchStmtCache(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 */
450static int
451ecpg_freeStmtCacheEntry(int lineno, int compat,
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 */
490static int
491AddStmtToCache(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 */
552bool
553ecpg_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}
603