1 2 /* 3 * exec.c 4 * Query execution and data retrieval functions. 5 * 6 * Copyright (c) 2009 eSilo, LLC. All rights reserved. 7 * This is free software; see the source for copying conditions. There is 8 * NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 9 * PURPOSE. 10 */ 11 12 #include "libpqtypes-int.h" 13 14 /* 15 * Each param value requires an oid, ptr and 2 ints (oid, value, length, format). 16 * This makes the maximum size of a param 20 bytes. A stack size of 4k 17 * would allow for 204 query params. If more params are needed, 18 * heap memory is used. Needing more than 204 param values in a query 19 * is very rare, although possible. 20 */ 21 #define PARAM_STACKSIZE 4096 22 23 #define BUILD_ARRAYS(rettype) \ 24 rettype r; \ 25 char *buf = NULL; \ 26 Oid *oids = NULL; \ 27 char **vals = NULL; \ 28 int *lens = NULL; \ 29 int *fmts = NULL; \ 30 int vcnt = 0; \ 31 char stackbuffer[PARAM_STACKSIZE]; \ 32 \ 33 PQseterror(NULL); \ 34 if (!conn) \ 35 { \ 36 PQseterror("PGconn cannot be NULL"); \ 37 return (rettype)(0); \ 38 } \ 39 \ 40 if (param) \ 41 { \ 42 buf = stackbuffer; \ 43 if (!buildArrays(param, &buf, &oids, &vals, &lens, &fmts)) \ 44 return (rettype) (0); \ 45 vcnt = param->vcnt; \ 46 } 47 48 #define RETURN_RESULT \ 49 if (param) \ 50 { \ 51 if (buf && buf != stackbuffer) \ 52 free(buf); \ 53 } \ 54 return r 55 56 static int 57 buildArrays(PGparam *param, char **buf, Oid **oids, 58 char ***vals, int **lens, int **fmts); 59 60 static PGresult * 61 copyExecError(PGconn *conn, PGresult *r); 62 63 static const char * 64 getCommand(PGconn *conn, PGparam *param, const char *command); 65 66 static int 67 _execvf(PGconn *conn, const char *cmdspec, va_list ap, PGresult **resp); 68 69 int 70 PQgetf(const PGresult *res, int tup_num, const char *format, ...) 71 { 72 int n; 73 va_list ap; 74 75 va_start(ap, format); 76 n = PQgetvf(res, tup_num, format, ap); 77 va_end(ap); 78 79 return n; 80 } 81 82 int 83 PQgetvf(const PGresult *res, int tup_num, const char *format, va_list ap) 84 { 85 int r; 86 PGtypeHandler *h; 87 PGtypeArgs args; 88 int typpos = 0; 89 int flags; 90 Oid ftype; 91 PGtypeData *resData; 92 PGtypeSpec *spec = NULL; 93 char tmp[200]; 94 95 PQseterror(NULL); 96 97 if (!res) 98 { 99 PQseterror("PGresult cannot be NULL"); 100 return FALSE; 101 } 102 103 if (!(resData = (PGtypeData *) PQresultInstanceData(res, pqt_eventproc))) 104 { 105 PQseterror("PGresult at %p has no event data", res); 106 return FALSE; 107 } 108 109 va_copy(args.ap, ap); 110 111 /* "@name" format, lookup typeSpec in cache */ 112 if(format && *format == '@') 113 { 114 spec = pqt_getspec(resData->typspecs, resData->typspeccnt, format + 1); 115 116 /* If we didn't find a type spec, this is an error. A format string 117 * with a '@' as its first character is reserved. 118 */ 119 if (!spec) 120 { 121 PQseterror("No such prepared specifier name: '%s'", format + 1); 122 va_end(args.ap); 123 return FALSE; 124 } 125 } 126 127 while (format && *format) 128 { 129 if (spec) 130 { 131 /* done, no more handlers in cached spec string. */ 132 if (typpos == spec->idcnt) 133 break; 134 135 h = pqt_gethandlerbyid(resData->typhandlers, resData->typhcnt, 136 spec->idlist[typpos]); 137 138 /* should be an unusual, or a "will never happen", situation */ 139 if (!h) 140 { 141 va_end(args.ap); 142 PQseterror("Unknown type handler id at position %d", typpos+1); 143 return FALSE; 144 } 145 146 flags = (int) spec->flags[typpos]; 147 typpos++; 148 } 149 else 150 { 151 format = pqt_parse(format, resData->typhandlers, resData->typhcnt, 152 NULL, 0, &h, NULL, &typpos, &flags); 153 154 if (!format) 155 { 156 va_end(args.ap); 157 return FALSE; 158 } 159 160 if (!h) 161 continue; 162 } 163 164 if (flags & TYPFLAG_BYNAME) 165 args.get.field_num = PQfnumber(res, va_arg(args.ap, const char *)); 166 else 167 args.get.field_num = va_arg(args.ap, int); 168 169 /* simplify life for handlers by checking getvalue's return here. */ 170 if (args.get.field_num < 0 || !PQgetvalue(res, tup_num, args.get.field_num)) 171 { 172 PQseterror( 173 "Invalid tup_num[%d].field_num[%d] (position %d)", 174 tup_num, args.get.field_num, typpos); 175 va_end(args.ap); 176 return FALSE; 177 } 178 179 ftype = PQftype(res, args.get.field_num); 180 if (((flags & TYPFLAG_ARRAY) && ftype != h->typoid_array) || 181 (!(flags & TYPFLAG_ARRAY) && ftype != h->typoid)) 182 { 183 Oid oid = (flags & TYPFLAG_ARRAY) ? h->typoid_array : h->typoid; 184 PQseterror( 185 "Trying to get type %u '%s' but server returned %u (position %d)", 186 oid, pqt_fqtn(tmp, sizeof(tmp), h->typschema, h->typname), 187 ftype, typpos); 188 va_end(args.ap); 189 return FALSE; 190 } 191 192 args.is_put = 0; 193 args.get.result = (PGresult *) res; 194 args.format = PQfformat(res, args.get.field_num); 195 args.fmtinfo = &resData->fmtinfo; 196 args.get.tup_num = tup_num; 197 args.is_ptr = (flags & TYPFLAG_POINTER) ? 1 : 0; 198 args.typpos = typpos; 199 args.typhandler = h; 200 args.errorf = pqt_argserrorf; 201 args.super = pqt_argssuper; 202 203 if (flags & TYPFLAG_ARRAY) 204 r = pqt_get_array(&args); 205 else 206 r = h->typget(&args); 207 208 if (r == -1) 209 { 210 va_end(args.ap); 211 return FALSE; 212 } 213 } 214 215 va_end(args.ap); 216 217 return TRUE; 218 } 219 220 /* -------------------------------- 221 * Exec and Send functions 222 */ 223 224 PGresult * 225 PQexecf(PGconn *conn, const char *cmdspec, ...) 226 { 227 va_list ap; 228 PGresult *res; 229 230 va_start(ap, cmdspec); 231 res = PQexecvf(conn, cmdspec, ap); 232 va_end(ap); 233 234 return res; 235 } 236 237 PGresult * 238 PQexecvf(PGconn *conn, const char *cmdspec, va_list ap) 239 { 240 PGresult *res; 241 (void) _execvf(conn, cmdspec, ap, &res); 242 return res; 243 } 244 245 int 246 PQsendf(PGconn *conn, const char *cmdspec, ...) 247 { 248 int n; 249 va_list ap; 250 251 va_start(ap, cmdspec); 252 n = PQsendvf(conn, cmdspec, ap); 253 va_end(ap); 254 255 return n; 256 } 257 258 int 259 PQsendvf(PGconn *conn, const char *cmdspec, va_list ap) 260 { 261 return _execvf(conn, cmdspec, ap, NULL); 262 } 263 264 PGresult * 265 PQparamExec(PGconn *conn, PGparam *param, const char *command, 266 int resultFormat) 267 { 268 BUILD_ARRAYS(PGresult *); 269 270 command = getCommand(conn, param, command); 271 if (!command) 272 { 273 r = NULL; 274 } 275 else 276 { 277 r = PQexecParams(conn, command, vcnt, oids, 278 (const char *const * ) vals, lens, fmts, resultFormat); 279 280 pqt_setresultfields(r); 281 r = copyExecError(conn, r); 282 } 283 284 RETURN_RESULT; 285 } 286 287 int 288 PQparamSendQuery(PGconn *conn, PGparam *param, const char *command, 289 int resultFormat) 290 { 291 BUILD_ARRAYS(int); 292 293 command = getCommand(conn, param, command); 294 if (!command) 295 { 296 r = FALSE; 297 } 298 else 299 { 300 r = PQsendQueryParams(conn, command, vcnt, oids, 301 (const char *const * ) vals, lens, fmts, resultFormat); 302 303 if (!r) 304 PQseterror("PGconn: %s", PQerrorMessage(conn)); 305 } 306 307 RETURN_RESULT; 308 } 309 310 PGresult * 311 PQparamExecPrepared(PGconn *conn, PGparam *param, const char *stmtName, 312 int resultFormat) 313 { 314 BUILD_ARRAYS(PGresult *); 315 316 r = PQexecPrepared(conn, stmtName, vcnt, (const char *const * ) vals, 317 lens, fmts, resultFormat); 318 319 pqt_setresultfields(r); 320 r = copyExecError(conn, r); 321 322 RETURN_RESULT; 323 } 324 325 int 326 PQparamSendQueryPrepared(PGconn *conn, PGparam *param, const char *stmtName, 327 int resultFormat) 328 { 329 BUILD_ARRAYS(int); 330 331 r = PQsendQueryPrepared(conn, stmtName, vcnt, 332 (const char *const * ) vals, lens, fmts, resultFormat); 333 334 if (!r) 335 PQseterror("PGconn: %s", PQerrorMessage(conn)); 336 337 RETURN_RESULT; 338 } 339 340 /* Called by PQexecvf and PQsendvf. When resp is NULL, PQparamSendQuery 341 * is used to execute the command. Otherwise, PQparamExec is used. The 342 * return value is always zero when resp is not NULL. When resp is NULL, 343 * the return value is zero for error and non-zero for success (identical 344 * to PQparamSendQuery). 345 */ 346 static int 347 _execvf(PGconn *conn, const char *cmdspec, va_list ap, PGresult **resp) 348 { 349 int retval = 0; 350 size_t stmt_len=0; 351 char buffer[8192]; /* could be larger these days but be conservative */ 352 char *stmt = NULL; 353 PGparam *param = NULL; 354 355 if (resp) 356 *resp = NULL; 357 358 if(!conn) 359 { 360 PQseterror("PGconn cannot be NULL"); 361 return FALSE; 362 } 363 364 if(!cmdspec || !*cmdspec) 365 { 366 PQseterror("cmdspec cannot be NULL or an empty string"); 367 return FALSE; 368 } 369 370 /* No stmt buf required for preapred type specs */ 371 if (*cmdspec != '@') 372 { 373 /* The resulting parameterized command is guarenteed to be smaller 374 * than the cmdspec. When needed, enlarge stmt buf to cmdspec length. 375 */ 376 stmt_len = strlen(cmdspec) + 1; 377 378 /* stack buffer is too small, use heap */ 379 if (stmt_len > sizeof(buffer)) 380 { 381 if (!(stmt = (char *) malloc(stmt_len))) 382 { 383 PQseterror(PQT_OUTOFMEMORY); 384 return FALSE; 385 } 386 } 387 else 388 { 389 stmt = buffer; 390 stmt_len = sizeof(buffer); 391 } 392 } 393 394 if ((param = PQparamCreate(conn))) 395 { 396 if (PQputvf(param, stmt, stmt_len, cmdspec, ap)) 397 { 398 const char *s = stmt ? stmt : cmdspec; 399 400 if (resp) 401 *resp = PQparamExec(conn, param, s, 1); 402 else 403 retval = PQparamSendQuery(conn, param, s, 1); 404 } 405 406 PQparamClear(param); 407 } 408 409 if (stmt && stmt != buffer) 410 free(stmt); 411 412 return retval; 413 } 414 415 /* 416 * Assigns param values to param arrays, for use with postgres 417 * parameter API. 'buf' is expected to be PARAM_STACKSIZE bytes. If more 418 * memory is required, memory is allocated and assigned to *buf, which 419 * must be freed by caller. To determine if *buf was allocated, compare 420 * its address to the initially provided stack address. 421 * Returns 1 on success and 0 on error. 422 */ 423 static int 424 buildArrays(PGparam *param, char **buf, Oid **oids, 425 char ***vals, int **lens, int **fmts) 426 { 427 int n; 428 429 /* no params to assign */ 430 if (param->vcnt == 0) 431 return 1; 432 433 /* required memory size for the 4 param arrays */ 434 n = (int) ((sizeof(void *) * param->vcnt) + /* values */ 435 ((sizeof(int) * 2) * param->vcnt) + /* lengths and formats */ 436 (sizeof(Oid) * param->vcnt)); /* oids */ 437 438 /* required memory is too large for stack buffer, get some heap */ 439 if (n > PARAM_STACKSIZE) 440 { 441 char *p; 442 443 if (!(p = (char *) malloc(n))) 444 { 445 PQseterror(PQT_OUTOFMEMORY); 446 return 0; 447 } 448 449 *buf = p; 450 } 451 452 /* give arrays memory from buffer, which could be stack or heap. */ 453 *vals = (char **) *buf; 454 *lens = (int *) (*buf + (sizeof(void *) * param->vcnt)); 455 *fmts = (*lens) + param->vcnt; 456 *oids = (Oid *) ((*fmts) + param->vcnt); 457 458 /* loop param values and assign value, length, format and oid to arrays. */ 459 for (n=0; n < param->vcnt; n++) 460 { 461 (*oids)[n] = param->vals[n].oid; 462 (*vals)[n] = param->vals[n].data; 463 (*lens)[n] = param->vals[n].datal; 464 (*fmts)[n] = param->vals[n].format; 465 } 466 467 return 1; 468 } 469 470 static PGresult * 471 copyExecError(PGconn *conn, PGresult *r) 472 { 473 if (!r) 474 { 475 PQseterror("PGconn: %s", PQerrorMessage(conn)); 476 return NULL; 477 } 478 479 switch (PQresultStatus(r)) 480 { 481 case PGRES_COMMAND_OK: 482 case PGRES_TUPLES_OK: 483 case PGRES_EMPTY_QUERY: 484 break; 485 486 default: 487 { 488 PQseterror("PGresult: %s", PQresultErrorMessage(r)); 489 PQclear(r); 490 r = NULL; 491 break; 492 } 493 } 494 495 return r; 496 } 497 498 /* Using the param is preferred when both conn and param are provided. 499 * The conn is there in case the exec has no parameters, NULL param. 500 */ 501 static const char * 502 getCommand(PGconn *conn, PGparam *param, const char *command) 503 { 504 PGtypeSpec *spec; 505 int typspeccnt = 0; 506 PGtypeSpec *typspecs = NULL; 507 508 if (!command) 509 { 510 PQseterror("command to execute cannot be NULL"); 511 return NULL; 512 } 513 514 if (*command != '@') 515 return command; 516 517 if (param) 518 { 519 typspecs = param->typspecs; 520 typspeccnt = param->typspeccnt; 521 } 522 523 /* Try to get instance data from the conn */ 524 if (!typspecs || typspeccnt == 0) 525 { 526 PGtypeData *data = PQinstanceData(conn, pqt_eventproc); 527 528 if (!data) 529 { 530 PQseterror("PGconn at %p has no event data", conn); 531 return NULL; 532 } 533 534 typspecs = data->typspecs; 535 typspeccnt = data->typspeccnt; 536 } 537 538 spec = pqt_getspec(typspecs, typspeccnt, command + 1); 539 540 /* If we didn't find a type spec, this is an error. A format string 541 * with an '@' as its first character is reserved. 542 */ 543 if (!spec) 544 { 545 PQseterror("No such prepared specifier name: '%s'", command + 1); 546 return NULL; 547 } 548 549 /* make sure type spec was prepared with a statement */ 550 if (!spec->stmt || !*spec->stmt) 551 { 552 PQseterror("Prepared specifier name '%s' has no statement", command + 1); 553 return NULL; 554 } 555 556 return (const char *) spec->stmt; 557 } |