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 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 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 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 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 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 * 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 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 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 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 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 * 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 * 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 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 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 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 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 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