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