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
isvarchar(unsigned char c)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
ecpg_register_prepared_stmt(struct statement * stmt)59 ecpg_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 
103 static bool
replace_variables(char ** text,int lineno)104 replace_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 
158 static bool
prepare_common(int lineno,struct connection * con,const char * name,const char * variable)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
ECPGprepare(int lineno,const char * connection_name,const bool questionmarks,const char * name,const char * variable)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 *
ecpg_find_prepared_statement(const char * name,struct connection * con,struct prepared_statement ** prev_)239 ecpg_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 
259 static bool
deallocate_one(int lineno,enum COMPAT_MODE c,struct connection * con,struct prepared_statement * prev,struct prepared_statement * this)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 	{
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 */
314 bool
ECPGdeallocate(int lineno,int c,const char * connection_name,const char * name)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;
332 	ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
333 	return false;
334 }
335 
336 bool
ecpg_deallocate_all_conn(int lineno,enum COMPAT_MODE c,struct connection * con)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
ECPGdeallocate_all(int lineno,int compat,const char * connection_name)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 *
ecpg_prepared(const char * name,struct connection * con)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 *
ECPGprepared_statement(const char * connection_name,const char * name,int lineno)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
HashStmt(const char * ecpgQuery)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
SearchStmtCache(const char * ecpgQuery)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
ecpg_freeStmtCacheEntry(int lineno,int compat,int entNo)451 ecpg_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  */
490 static int
AddStmtToCache(int lineno,const char * stmtID,const char * connection,int compat,const char * ecpgQuery)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
ecpg_auto_prepare(int lineno,const char * connection_name,const int compat,char ** name,const char * query)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 }
603