3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
10 #include "ecpgerrno.h"
14 struct prepared_statement
18 struct statement
*stmt
;
19 struct prepared_statement
*next
;
22 #define STMTID_SIZE 32
27 char stmtID
[STMTID_SIZE
];
29 long execs
; /* # of executions */
30 char *connection
; /* connection for the statement */
33 static int nextStmtID
= 1;
34 static const int stmtCacheNBuckets
= 2039; /* # buckets - a prime # */
35 static const int stmtCacheEntPerBucket
= 8; /* # entries/bucket */
36 static stmtCacheEntry stmtCacheEntries
[16384] = {{0, {0}, 0, 0, 0}};
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);
44 isvarchar(unsigned char c
)
49 if (c
== '_' || c
== '>' || c
== '-' || c
== '.')
59 replace_variables(char **text
, int lineno
, bool questionmarks
)
65 for (; (*text
)[ptr
] != '\0'; ptr
++)
67 if ((*text
)[ptr
] == '\'')
68 string
= string
? false : true;
70 if (string
|| (((*text
)[ptr
] != ':') && ((*text
)[ptr
] != '?')))
73 if (((*text
)[ptr
] == ':') && ((*text
)[ptr
+ 1] == ':'))
74 ptr
+= 2; /* skip '::' */
78 int buffersize
= sizeof(int) * CHAR_BIT
* 10 / 3; /* a rough guess of the
83 if (!(buffer
= (char *) ecpg_alloc(buffersize
, lineno
)))
86 snprintf(buffer
, buffersize
, "$%d", counter
++);
88 for (len
= 1; (*text
)[ptr
+ len
] && isvarchar((*text
)[ptr
+ len
]); len
++);
89 if (!(newcopy
= (char *) ecpg_alloc(strlen(*text
) -len
+ strlen(buffer
) + 1, lineno
)))
95 strncpy(newcopy
, *text
, ptr
);
96 strcpy(newcopy
+ ptr
, buffer
);
97 strcat(newcopy
, (*text
) +ptr
+ len
);
104 if ((*text
)[ptr
] == '\0') /* we reached the end */
105 ptr
--; /* since we will (*text)[ptr]++ in the top
112 /* handle the EXEC SQL PREPARE statement */
114 ECPGprepare(int lineno
, const char *connection_name
, const int questionmarks
, const char *name
, const char *variable
)
116 struct connection
*con
;
117 struct statement
*stmt
;
118 struct prepared_statement
*this,
122 con
= ecpg_get_connection(connection_name
);
124 if (!ecpg_init(con
, connection_name
, lineno
))
127 /* check if we already have prepared this statement */
128 this = find_prepared_statement(name
, con
, &prev
);
129 if (this && !deallocate_one(lineno
, ECPG_COMPAT_PGSQL
, con
, prev
, this))
132 /* allocate new statement */
133 this = (struct prepared_statement
*) ecpg_alloc(sizeof(struct prepared_statement
), lineno
);
137 stmt
= (struct statement
*) ecpg_alloc(sizeof(struct statement
), lineno
);
144 /* create statement */
145 stmt
->lineno
= lineno
;
146 stmt
->connection
= con
;
147 stmt
->command
= ecpg_strdup(variable
, lineno
);
148 stmt
->inlist
= stmt
->outlist
= NULL
;
150 /* if we have C variables in our statment replace them with '?' */
151 replace_variables(&(stmt
->command
), lineno
, questionmarks
);
153 /* add prepared statement to our list */
154 this->name
= (char *) name
;
157 /* and finally really prepare the statement */
158 query
= PQprepare(stmt
->connection
->connection
, name
, stmt
->command
, 0, NULL
);
159 if (!ecpg_check_PQresult(query
, stmt
->lineno
, stmt
->connection
->connection
, stmt
->compat
))
161 ecpg_free(stmt
->command
);
167 ecpg_log("ECPGprepare on line %d: name %s; query: \"%s\"\n", stmt
->lineno
, name
, stmt
->command
);
169 this->prepared
= true;
171 if (con
->prep_stmts
== NULL
)
174 this->next
= con
->prep_stmts
;
176 con
->prep_stmts
= this;
180 static struct prepared_statement
*
181 find_prepared_statement(const char *name
,
182 struct connection
* con
, struct prepared_statement
** prev_
)
184 struct prepared_statement
*this,
187 for (this = con
->prep_stmts
, prev
= NULL
; this != NULL
; prev
= this, this = this->next
)
189 if (strcmp(this->name
, name
) == 0)
200 deallocate_one(int lineno
, enum COMPAT_MODE c
, struct connection
* con
, struct prepared_statement
* prev
, struct prepared_statement
* this)
204 ecpg_log("ECPGdeallocate on line %d: name %s\n", lineno
, this->name
);
206 /* first deallocate the statement in the backend */
212 text
= (char *) ecpg_alloc(strlen("deallocate \"\" ") + strlen(this->name
), this->stmt
->lineno
);
216 sprintf(text
, "deallocate \"%s\"", this->name
);
217 query
= PQexec(this->stmt
->connection
->connection
, text
);
219 if (ecpg_check_PQresult(query
, lineno
, this->stmt
->connection
->connection
, this->stmt
->compat
))
228 * Just ignore all errors since we do not know the list of cursors we are
229 * allowed to free. We have to trust the software.
231 if (!r
&& !INFORMIX_MODE(c
))
233 ecpg_raise(lineno
, ECPG_INVALID_STMT
, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME
, this->name
);
237 /* okay, free all the resources */
238 ecpg_free(this->stmt
->command
);
239 ecpg_free(this->stmt
);
241 prev
->next
= this->next
;
243 con
->prep_stmts
= this->next
;
249 /* handle the EXEC SQL DEALLOCATE PREPARE statement */
251 ECPGdeallocate(int lineno
, int c
, const char *connection_name
, const char *name
)
253 struct connection
*con
;
254 struct prepared_statement
*this,
257 con
= ecpg_get_connection(connection_name
);
259 if (!ecpg_init(con
, connection_name
, lineno
))
262 this = find_prepared_statement(name
, con
, &prev
);
264 return deallocate_one(lineno
, c
, con
, prev
, this);
266 /* prepared statement is not found */
267 if (INFORMIX_MODE(c
))
269 ecpg_raise(lineno
, ECPG_INVALID_STMT
, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME
, name
);
274 ecpg_deallocate_all_conn(int lineno
, enum COMPAT_MODE c
, struct connection
* con
)
276 /* deallocate all prepared statements */
277 while (con
->prep_stmts
)
279 if (!deallocate_one(lineno
, c
, con
, NULL
, con
->prep_stmts
))
287 ECPGdeallocate_all(int lineno
, int compat
, const char *connection_name
)
289 return ecpg_deallocate_all_conn(lineno
, compat
, ecpg_get_connection(connection_name
));
293 ecpg_prepared(const char *name
, struct connection
* con
, int lineno
)
295 struct prepared_statement
*this;
297 this = find_prepared_statement(name
, con
, NULL
);
298 return this ? this->stmt
->command
: NULL
;
301 /* return the prepared statement */
303 ECPGprepared_statement(const char *connection_name
, const char *name
, int lineno
)
305 return ecpg_prepared(name
, ecpg_get_connection(connection_name
), lineno
);
309 * hash a SQL statement - returns entry # of first entry in the bucket
312 HashStmt(const char *ecpgQuery
)
321 stmtLeng
= strlen(ecpgQuery
);
322 hashLeng
= 50; /* use 1st 50 characters of statement */
323 if (hashLeng
> stmtLeng
) /* if the statement isn't that long */
324 hashLeng
= stmtLeng
; /* use its actual length */
327 for (stmtIx
= 0; stmtIx
< hashLeng
; ++stmtIx
)
329 hashVal
= hashVal
+ (int) ecpgQuery
[stmtIx
];
330 hashVal
= hashVal
<< 13;
331 rotVal
= (hashVal
& 0x1fff00000000LL
) >> 32;
332 hashVal
= (hashVal
& 0xffffffffLL
) | rotVal
;
335 bucketNo
= hashVal
% stmtCacheNBuckets
;
336 bucketNo
+= 1; /* don't use bucket # 0 */
338 return (bucketNo
* stmtCacheEntPerBucket
);
342 * search the statement cache - search for entry with matching ECPG-format query
343 * Returns entry # in cache if found
344 * OR zero if not present (zero'th entry isn't used)
347 SearchStmtCache(const char *ecpgQuery
)
352 /* hash the statement */
353 entNo
= HashStmt(ecpgQuery
);
355 /* search the cache */
356 for (entIx
= 0; entIx
< stmtCacheEntPerBucket
; ++entIx
)
358 if (stmtCacheEntries
[entNo
].stmtID
[0]) /* check if entry is in use */
360 if (!strcmp(ecpgQuery
, stmtCacheEntries
[entNo
].ecpgQuery
))
361 break; /* found it */
363 ++entNo
; /* incr entry # */
366 /* if entry wasn't found - set entry # to zero */
367 if (entIx
>= stmtCacheEntPerBucket
)
374 * free an entry in the statement cache
375 * Returns entry # in cache used
376 * OR negative error code
379 ecpg_freeStmtCacheEntry(int lineno
, int compat
, int entNo
) /* entry # to free */
381 stmtCacheEntry
*entry
;
382 struct connection
*con
;
383 struct prepared_statement
*this, *prev
;
385 entry
= &stmtCacheEntries
[entNo
];
386 if (!entry
->stmtID
[0]) /* return if the entry isn't in use */
389 con
= ecpg_get_connection(entry
->connection
);
391 /* free the 'prepared_statement' list entry */
392 this = find_prepared_statement(entry
->stmtID
, con
, &prev
);
393 if (this && !deallocate_one(lineno
, compat
, con
, prev
, this))
396 entry
->stmtID
[0] = '\0';
398 /* free the memory used by the cache entry */
399 if (entry
->ecpgQuery
)
401 ecpg_free(entry
->ecpgQuery
);
402 entry
->ecpgQuery
= 0;
409 * add an entry to the statement cache
410 * returns entry # in cache used OR negative error code
413 AddStmtToCache(int lineno
, /* line # of statement */
414 char *stmtID
, /* statement ID */
415 const char *connection
, /* connection */
416 int compat
, /* compatibility level */
417 const char *ecpgQuery
) /* query */
423 stmtCacheEntry
*entry
;
425 /* hash the statement */
426 initEntNo
= HashStmt(ecpgQuery
);
428 /* search for an unused entry */
429 entNo
= initEntNo
; /* start with the initial entry # for the
431 luEntNo
= initEntNo
; /* use it as the initial 'least used' entry */
432 for (ix
= 0; ix
< stmtCacheEntPerBucket
; ++ix
)
434 entry
= &stmtCacheEntries
[entNo
];
435 if (!entry
->stmtID
[0]) /* unused entry - use it */
437 if (entry
->execs
< stmtCacheEntries
[luEntNo
].execs
)
438 luEntNo
= entNo
; /* save new 'least used' entry */
439 ++entNo
; /* increment entry # */
442 /* if no unused entries were found - use the 'least used' entry found in the bucket */
443 if (ix
>= stmtCacheEntPerBucket
) /* if no unused entries were found */
444 entNo
= luEntNo
; /* re-use the 'least used' entry */
446 /* 'entNo' is the entry to use - make sure its free */
447 if (ecpg_freeStmtCacheEntry(lineno
, compat
, entNo
) < 0)
450 /* add the query to the entry */
451 entry
= &stmtCacheEntries
[entNo
];
452 entry
->lineno
= lineno
;
453 entry
->ecpgQuery
= ecpg_strdup(ecpgQuery
, lineno
);
454 entry
->connection
= (char *) connection
;
456 memcpy(entry
->stmtID
, stmtID
, sizeof(entry
->stmtID
));
461 /* handle cache and preparation of statments in auto-prepare mode */
463 ecpg_auto_prepare(int lineno
, const char *connection_name
, int compat
, const int questionmarks
, char **name
, const char *query
)
467 /* search the statement cache for this statement */
468 entNo
= SearchStmtCache(query
);
470 /* if not found - add the statement to the cache */
473 ecpg_log("ecpg_auto_prepare on line %d: statement found in cache; entry %d\n", lineno
, entNo
);
474 *name
= ecpg_strdup(stmtCacheEntries
[entNo
].stmtID
, lineno
);
478 ecpg_log("ecpg_auto_prepare on line %d: statement not in cache; inserting\n", lineno
);
480 /* generate a statement ID */
481 *name
= (char *) ecpg_alloc(STMTID_SIZE
, lineno
);
482 sprintf(*name
, "ecpg%d", nextStmtID
++);
484 if (!ECPGprepare(lineno
, connection_name
, questionmarks
, ecpg_strdup(*name
, lineno
), query
))
486 if (AddStmtToCache(lineno
, *name
, connection_name
, compat
, query
) < 0)
490 /* increase usage counter */
491 stmtCacheEntries
[entNo
].execs
++;