Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * fe-exec.c
4 : : * functions related to sending a query down to the backend
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/interfaces/libpq/fe-exec.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres_fe.h"
16 : :
17 : : #include <ctype.h>
18 : : #include <fcntl.h>
19 : : #include <limits.h>
20 : :
21 : : #ifdef WIN32
22 : : #include "win32.h"
23 : : #else
24 : : #include <unistd.h>
25 : : #endif
26 : :
27 : : #include "common/int.h"
28 : : #include "libpq-fe.h"
29 : : #include "libpq-int.h"
30 : : #include "mb/pg_wchar.h"
31 : :
32 : : /* keep this in same order as ExecStatusType in libpq-fe.h */
33 : : char *const pgresStatus[] = {
34 : : "PGRES_EMPTY_QUERY",
35 : : "PGRES_COMMAND_OK",
36 : : "PGRES_TUPLES_OK",
37 : : "PGRES_COPY_OUT",
38 : : "PGRES_COPY_IN",
39 : : "PGRES_BAD_RESPONSE",
40 : : "PGRES_NONFATAL_ERROR",
41 : : "PGRES_FATAL_ERROR",
42 : : "PGRES_COPY_BOTH",
43 : : "PGRES_SINGLE_TUPLE",
44 : : "PGRES_PIPELINE_SYNC",
45 : : "PGRES_PIPELINE_ABORTED",
46 : : "PGRES_TUPLES_CHUNK"
47 : : };
48 : :
49 : : /* We return this if we're unable to make a PGresult at all */
50 : : static const PGresult OOM_result = {
51 : : .resultStatus = PGRES_FATAL_ERROR,
52 : : .client_encoding = PG_SQL_ASCII,
53 : : .errMsg = "out of memory\n",
54 : : };
55 : :
56 : : /*
57 : : * static state needed by PQescapeString and PQescapeBytea; initialize to
58 : : * values that result in backward-compatible behavior
59 : : */
60 : : static int static_client_encoding = PG_SQL_ASCII;
61 : : static bool static_std_strings = false;
62 : :
63 : :
64 : : static PGEvent *dupEvents(PGEvent *events, int count, size_t *memSize);
65 : : static bool pqAddTuple(PGresult *res, PGresAttValue *tup,
66 : : const char **errmsgp);
67 : : static int PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery);
68 : : static bool PQsendQueryStart(PGconn *conn, bool newQuery);
69 : : static int PQsendQueryGuts(PGconn *conn,
70 : : const char *command,
71 : : const char *stmtName,
72 : : int nParams,
73 : : const Oid *paramTypes,
74 : : const char *const *paramValues,
75 : : const int *paramLengths,
76 : : const int *paramFormats,
77 : : int resultFormat);
78 : : static void parseInput(PGconn *conn);
79 : : static PGresult *getCopyResult(PGconn *conn, ExecStatusType copytype);
80 : : static bool PQexecStart(PGconn *conn);
81 : : static PGresult *PQexecFinish(PGconn *conn);
82 : : static int PQsendTypedCommand(PGconn *conn, char command, char type,
83 : : const char *target);
84 : : static int check_field_number(const PGresult *res, int field_num);
85 : : static void pqPipelineProcessQueue(PGconn *conn);
86 : : static int pqPipelineSyncInternal(PGconn *conn, bool immediate_flush);
87 : : static int pqPipelineFlush(PGconn *conn);
88 : :
89 : :
90 : : /* ----------------
91 : : * Space management for PGresult.
92 : : *
93 : : * Formerly, libpq did a separate malloc() for each field of each tuple
94 : : * returned by a query. This was remarkably expensive --- malloc/free
95 : : * consumed a sizable part of the application's runtime. And there is
96 : : * no real need to keep track of the fields separately, since they will
97 : : * all be freed together when the PGresult is released. So now, we grab
98 : : * large blocks of storage from malloc and allocate space for query data
99 : : * within these blocks, using a trivially simple allocator. This reduces
100 : : * the number of malloc/free calls dramatically, and it also avoids
101 : : * fragmentation of the malloc storage arena.
102 : : * The PGresult structure itself is still malloc'd separately. We could
103 : : * combine it with the first allocation block, but that would waste space
104 : : * for the common case that no extra storage is actually needed (that is,
105 : : * the SQL command did not return tuples).
106 : : *
107 : : * We also malloc the top-level array of tuple pointers separately, because
108 : : * we need to be able to enlarge it via realloc, and our trivial space
109 : : * allocator doesn't handle that effectively. (Too bad the FE/BE protocol
110 : : * doesn't tell us up front how many tuples will be returned.)
111 : : * All other subsidiary storage for a PGresult is kept in PGresult_data blocks
112 : : * of size PGRESULT_DATA_BLOCKSIZE. The overhead at the start of each block
113 : : * is just a link to the next one, if any. Free-space management info is
114 : : * kept in the owning PGresult.
115 : : * A query returning a small amount of data will thus require three malloc
116 : : * calls: one for the PGresult, one for the tuples pointer array, and one
117 : : * PGresult_data block.
118 : : *
119 : : * Only the most recently allocated PGresult_data block is a candidate to
120 : : * have more stuff added to it --- any extra space left over in older blocks
121 : : * is wasted. We could be smarter and search the whole chain, but the point
122 : : * here is to be simple and fast. Typical applications do not keep a PGresult
123 : : * around very long anyway, so some wasted space within one is not a problem.
124 : : *
125 : : * Tuning constants for the space allocator are:
126 : : * PGRESULT_DATA_BLOCKSIZE: size of a standard allocation block, in bytes
127 : : * PGRESULT_ALIGN_BOUNDARY: assumed alignment requirement for binary data
128 : : * PGRESULT_SEP_ALLOC_THRESHOLD: objects bigger than this are given separate
129 : : * blocks, instead of being crammed into a regular allocation block.
130 : : * Requirements for correct function are:
131 : : * PGRESULT_ALIGN_BOUNDARY must be a multiple of the alignment requirements
132 : : * of all machine data types. (Currently this is set from configure
133 : : * tests, so it should be OK automatically.)
134 : : * PGRESULT_SEP_ALLOC_THRESHOLD + PGRESULT_BLOCK_OVERHEAD <=
135 : : * PGRESULT_DATA_BLOCKSIZE
136 : : * pqResultAlloc assumes an object smaller than the threshold will fit
137 : : * in a new block.
138 : : * The amount of space wasted at the end of a block could be as much as
139 : : * PGRESULT_SEP_ALLOC_THRESHOLD, so it doesn't pay to make that too large.
140 : : * ----------------
141 : : */
142 : :
143 : : #define PGRESULT_DATA_BLOCKSIZE 2048
144 : : #define PGRESULT_ALIGN_BOUNDARY MAXIMUM_ALIGNOF /* from configure */
145 : : #define PGRESULT_BLOCK_OVERHEAD Max(sizeof(PGresult_data), PGRESULT_ALIGN_BOUNDARY)
146 : : #define PGRESULT_SEP_ALLOC_THRESHOLD (PGRESULT_DATA_BLOCKSIZE / 2)
147 : :
148 : :
149 : : /*
150 : : * PQmakeEmptyPGresult
151 : : * returns a newly allocated, initialized PGresult with given status.
152 : : * If conn is not NULL and status indicates an error, the conn's
153 : : * errorMessage is copied. Also, any PGEvents are copied from the conn.
154 : : *
155 : : * Note: the logic to copy the conn's errorMessage is now vestigial;
156 : : * no internal caller uses it. However, that behavior is documented for
157 : : * outside callers, so we'd better keep it.
158 : : */
159 : : PGresult *
10220 bruce@momjian.us 160 :CBC 1267385 : PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
161 : : {
162 : : PGresult *result;
163 : :
10581 164 : 1267385 : result = (PGresult *) malloc(sizeof(PGresult));
7746 neilc@samurai.com 165 [ - + ]: 1267385 : if (!result)
7746 neilc@samurai.com 166 :UBC 0 : return NULL;
167 : :
10581 bruce@momjian.us 168 :CBC 1267385 : result->ntups = 0;
169 : 1267385 : result->numAttributes = 0;
170 : 1267385 : result->attDescs = NULL;
171 : 1267385 : result->tuples = NULL;
172 : 1267385 : result->tupArrSize = 0;
7314 tgl@sss.pgh.pa.us 173 : 1267385 : result->numParameters = 0;
174 : 1267385 : result->paramDescs = NULL;
10581 bruce@momjian.us 175 : 1267385 : result->resultStatus = status;
176 : 1267385 : result->cmdStatus[0] = '\0';
177 : 1267385 : result->binary = 0;
6553 tgl@sss.pgh.pa.us 178 : 1267385 : result->events = NULL;
179 : 1267385 : result->nEvents = 0;
10192 180 : 1267385 : result->errMsg = NULL;
8468 181 : 1267385 : result->errFields = NULL;
3798 182 : 1267385 : result->errQuery = NULL;
10144 183 : 1267385 : result->null_field[0] = '\0';
184 : 1267385 : result->curBlock = NULL;
185 : 1267385 : result->curOffset = 0;
186 : 1267385 : result->spaceLeft = 0;
2907 187 : 1267385 : result->memorySize = sizeof(PGresult);
188 : :
9665 189 [ + + ]: 1267385 : if (conn)
190 : : {
191 : : /* copy connection data we might need for operations on PGresult */
8468 192 : 464751 : result->noticeHooks = conn->noticeHooks;
9662 193 : 464751 : result->client_encoding = conn->client_encoding;
194 : :
195 : : /* consider copying conn's errorMessage */
10192 196 [ + + ]: 464751 : switch (status)
197 : : {
198 : 464086 : case PGRES_EMPTY_QUERY:
199 : : case PGRES_COMMAND_OK:
200 : : case PGRES_TUPLES_OK:
201 : : case PGRES_COPY_OUT:
202 : : case PGRES_COPY_IN:
203 : : case PGRES_COPY_BOTH:
204 : : case PGRES_SINGLE_TUPLE:
205 : : case PGRES_TUPLES_CHUNK:
206 : : /* non-error cases */
207 : 464086 : break;
208 : 665 : default:
209 : : /* we intentionally do not use or modify errorReported here */
1651 210 : 665 : pqSetResultError(result, &conn->errorMessage, 0);
10192 211 : 665 : break;
212 : : }
213 : :
214 : : /* copy events last; result must be valid if we need to PQclear */
6553 215 [ - + ]: 464751 : if (conn->nEvents > 0)
216 : : {
2907 tgl@sss.pgh.pa.us 217 :UBC 0 : result->events = dupEvents(conn->events, conn->nEvents,
218 : : &result->memorySize);
6553 219 [ # # ]: 0 : if (!result->events)
220 : : {
221 : 0 : PQclear(result);
222 : 0 : return NULL;
223 : : }
224 : 0 : result->nEvents = conn->nEvents;
225 : : }
226 : : }
227 : : else
228 : : {
229 : : /* defaults... */
8468 tgl@sss.pgh.pa.us 230 :CBC 802634 : result->noticeHooks.noticeRec = NULL;
231 : 802634 : result->noticeHooks.noticeRecArg = NULL;
232 : 802634 : result->noticeHooks.noticeProc = NULL;
233 : 802634 : result->noticeHooks.noticeProcArg = NULL;
234 : 802634 : result->client_encoding = PG_SQL_ASCII;
235 : : }
236 : :
10581 bruce@momjian.us 237 : 1267385 : return result;
238 : : }
239 : :
240 : : /*
241 : : * PQsetResultAttrs
242 : : *
243 : : * Set the attributes for a given result. This function fails if there are
244 : : * already attributes contained in the provided result. The call is
245 : : * ignored if numAttributes is zero or attDescs is NULL. If the
246 : : * function fails, it returns zero. If the function succeeds, it
247 : : * returns a non-zero value.
248 : : */
249 : : int
6553 tgl@sss.pgh.pa.us 250 : 2615 : PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs)
251 : : {
252 : : int i;
253 : :
254 : : /* Fail if argument is NULL or OOM_result */
1651 255 [ + - - + ]: 2615 : if (!res || (const PGresult *) res == &OOM_result)
1651 tgl@sss.pgh.pa.us 256 :UBC 0 : return false;
257 : :
258 : : /* If attrs already exist, they cannot be overwritten. */
1651 tgl@sss.pgh.pa.us 259 [ - + ]:CBC 2615 : if (res->numAttributes > 0)
3298 peter_e@gmx.net 260 :UBC 0 : return false;
261 : :
262 : : /* ignore no-op request */
6553 tgl@sss.pgh.pa.us 263 [ + - - + ]:CBC 2615 : if (numAttributes <= 0 || !attDescs)
3298 peter_e@gmx.net 264 :UBC 0 : return true;
265 : :
6553 tgl@sss.pgh.pa.us 266 :CBC 2615 : res->attDescs = (PGresAttDesc *)
267 : 2615 : PQresultAlloc(res, numAttributes * sizeof(PGresAttDesc));
268 : :
269 [ - + ]: 2615 : if (!res->attDescs)
3298 peter_e@gmx.net 270 :UBC 0 : return false;
271 : :
6553 tgl@sss.pgh.pa.us 272 :CBC 2615 : res->numAttributes = numAttributes;
273 : 2615 : memcpy(res->attDescs, attDescs, numAttributes * sizeof(PGresAttDesc));
274 : :
275 : : /* deep-copy the attribute names, and determine format */
276 : 2615 : res->binary = 1;
277 [ + + ]: 10300 : for (i = 0; i < res->numAttributes; i++)
278 : : {
279 [ + - ]: 7685 : if (res->attDescs[i].name)
280 : 7685 : res->attDescs[i].name = pqResultStrdup(res, res->attDescs[i].name);
281 : : else
6553 tgl@sss.pgh.pa.us 282 :UBC 0 : res->attDescs[i].name = res->null_field;
283 : :
6553 tgl@sss.pgh.pa.us 284 [ - + ]:CBC 7685 : if (!res->attDescs[i].name)
3298 peter_e@gmx.net 285 :UBC 0 : return false;
286 : :
6553 tgl@sss.pgh.pa.us 287 [ + + ]:CBC 7685 : if (res->attDescs[i].format == 0)
288 : 527 : res->binary = 0;
289 : : }
290 : :
3298 peter_e@gmx.net 291 : 2615 : return true;
292 : : }
293 : :
294 : : /*
295 : : * PQcopyResult
296 : : *
297 : : * Returns a deep copy of the provided 'src' PGresult, which cannot be NULL.
298 : : * The 'flags' argument controls which portions of the result will or will
299 : : * NOT be copied. The created result is always put into the
300 : : * PGRES_TUPLES_OK status. The source result error message is not copied,
301 : : * although cmdStatus is.
302 : : *
303 : : * To set custom attributes, use PQsetResultAttrs. That function requires
304 : : * that there are no attrs contained in the result, so to use that
305 : : * function you cannot use the PG_COPYRES_ATTRS or PG_COPYRES_TUPLES
306 : : * options with this function.
307 : : *
308 : : * Options:
309 : : * PG_COPYRES_ATTRS - Copy the source result's attributes
310 : : *
311 : : * PG_COPYRES_TUPLES - Copy the source result's tuples. This implies
312 : : * copying the attrs, seeing how the attrs are needed by the tuples.
313 : : *
314 : : * PG_COPYRES_EVENTS - Copy the source result's events.
315 : : *
316 : : * PG_COPYRES_NOTICEHOOKS - Copy the source result's notice hooks.
317 : : */
318 : : PGresult *
6553 tgl@sss.pgh.pa.us 319 : 2615 : PQcopyResult(const PGresult *src, int flags)
320 : : {
321 : : PGresult *dest;
322 : : int i;
323 : :
324 [ - + ]: 2615 : if (!src)
6553 tgl@sss.pgh.pa.us 325 :UBC 0 : return NULL;
326 : :
6553 tgl@sss.pgh.pa.us 327 :CBC 2615 : dest = PQmakeEmptyPGresult(NULL, PGRES_TUPLES_OK);
328 [ - + ]: 2615 : if (!dest)
6553 tgl@sss.pgh.pa.us 329 :UBC 0 : return NULL;
330 : :
331 : : /* Always copy these over. Is cmdStatus really useful here? */
6553 tgl@sss.pgh.pa.us 332 :CBC 2615 : dest->client_encoding = src->client_encoding;
333 : 2615 : strcpy(dest->cmdStatus, src->cmdStatus);
334 : :
335 : : /* Wants attrs? */
336 [ + - ]: 2615 : if (flags & (PG_COPYRES_ATTRS | PG_COPYRES_TUPLES))
337 : : {
338 [ - + ]: 2615 : if (!PQsetResultAttrs(dest, src->numAttributes, src->attDescs))
339 : : {
6553 tgl@sss.pgh.pa.us 340 :UBC 0 : PQclear(dest);
341 : 0 : return NULL;
342 : : }
343 : : }
344 : :
345 : : /* Wants to copy tuples? */
6553 tgl@sss.pgh.pa.us 346 [ - + ]:CBC 2615 : if (flags & PG_COPYRES_TUPLES)
347 : : {
348 : : int tup,
349 : : field;
350 : :
6553 tgl@sss.pgh.pa.us 351 [ # # ]:UBC 0 : for (tup = 0; tup < src->ntups; tup++)
352 : : {
353 [ # # ]: 0 : for (field = 0; field < src->numAttributes; field++)
354 : : {
355 [ # # ]: 0 : if (!PQsetvalue(dest, tup, field,
356 : 0 : src->tuples[tup][field].value,
357 : 0 : src->tuples[tup][field].len))
358 : : {
359 : 0 : PQclear(dest);
360 : 0 : return NULL;
361 : : }
362 : : }
363 : : }
364 : : }
365 : :
366 : : /* Wants to copy notice hooks? */
6553 tgl@sss.pgh.pa.us 367 [ + - ]:CBC 2615 : if (flags & PG_COPYRES_NOTICEHOOKS)
368 : 2615 : dest->noticeHooks = src->noticeHooks;
369 : :
370 : : /* Wants to copy PGEvents? */
371 [ + - - + ]: 2615 : if ((flags & PG_COPYRES_EVENTS) && src->nEvents > 0)
372 : : {
2907 tgl@sss.pgh.pa.us 373 :UBC 0 : dest->events = dupEvents(src->events, src->nEvents,
374 : : &dest->memorySize);
6553 375 [ # # ]: 0 : if (!dest->events)
376 : : {
377 : 0 : PQclear(dest);
378 : 0 : return NULL;
379 : : }
380 : 0 : dest->nEvents = src->nEvents;
381 : : }
382 : :
383 : : /* Okay, trigger PGEVT_RESULTCOPY event */
6553 tgl@sss.pgh.pa.us 384 [ - + ]:CBC 2615 : for (i = 0; i < dest->nEvents; i++)
385 : : {
386 : : /* We don't fire events that had some previous failure */
6551 tgl@sss.pgh.pa.us 387 [ # # ]:UBC 0 : if (src->events[i].resultInitialized)
388 : : {
389 : : PGEventResultCopy evt;
390 : :
391 : 0 : evt.src = src;
392 : 0 : evt.dest = dest;
1651 393 [ # # ]: 0 : if (dest->events[i].proc(PGEVT_RESULTCOPY, &evt,
394 : 0 : dest->events[i].passThrough))
395 : 0 : dest->events[i].resultInitialized = true;
396 : : }
397 : : }
398 : :
6553 tgl@sss.pgh.pa.us 399 :CBC 2615 : return dest;
400 : : }
401 : :
402 : : /*
403 : : * Copy an array of PGEvents (with no extra space for more).
404 : : * Does not duplicate the event instance data, sets this to NULL.
405 : : * Also, the resultInitialized flags are all cleared.
406 : : * The total space allocated is added to *memSize.
407 : : */
408 : : static PGEvent *
2907 tgl@sss.pgh.pa.us 409 :UBC 0 : dupEvents(PGEvent *events, int count, size_t *memSize)
410 : : {
411 : : PGEvent *newEvents;
412 : : size_t msize;
413 : : int i;
414 : :
6553 415 [ # # # # ]: 0 : if (!events || count <= 0)
416 : 0 : return NULL;
417 : :
2907 418 : 0 : msize = count * sizeof(PGEvent);
419 : 0 : newEvents = (PGEvent *) malloc(msize);
6553 420 [ # # ]: 0 : if (!newEvents)
421 : 0 : return NULL;
422 : :
423 [ # # ]: 0 : for (i = 0; i < count; i++)
424 : : {
6551 425 : 0 : newEvents[i].proc = events[i].proc;
426 : 0 : newEvents[i].passThrough = events[i].passThrough;
6553 427 : 0 : newEvents[i].data = NULL;
3298 peter_e@gmx.net 428 : 0 : newEvents[i].resultInitialized = false;
6551 tgl@sss.pgh.pa.us 429 : 0 : newEvents[i].name = strdup(events[i].name);
6553 430 [ # # ]: 0 : if (!newEvents[i].name)
431 : : {
432 [ # # ]: 0 : while (--i >= 0)
433 : 0 : free(newEvents[i].name);
434 : 0 : free(newEvents);
435 : 0 : return NULL;
436 : : }
2907 437 : 0 : msize += strlen(events[i].name) + 1;
438 : : }
439 : :
440 : 0 : *memSize += msize;
6553 441 : 0 : return newEvents;
442 : : }
443 : :
444 : :
445 : : /*
446 : : * Sets the value for a tuple field. The tup_num must be less than or
447 : : * equal to PQntuples(res). If it is equal, a new tuple is created and
448 : : * added to the result.
449 : : * Returns a non-zero value for success and zero for failure.
450 : : * (On failure, we report the specific problem via pqInternalNotice.)
451 : : */
452 : : int
453 : 0 : PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
454 : : {
455 : : PGresAttValue *attval;
3285 456 : 0 : const char *errmsg = NULL;
457 : :
458 : : /* Fail if argument is NULL or OOM_result */
1651 459 [ # # # # ]: 0 : if (!res || (const PGresult *) res == &OOM_result)
460 : 0 : return false;
461 : :
462 : : /* Invalid field_num? */
6553 463 [ # # ]: 0 : if (!check_field_number(res, field_num))
3298 peter_e@gmx.net 464 : 0 : return false;
465 : :
466 : : /* Invalid tup_num, must be <= ntups */
6553 tgl@sss.pgh.pa.us 467 [ # # # # ]: 0 : if (tup_num < 0 || tup_num > res->ntups)
468 : : {
3285 469 : 0 : pqInternalNotice(&res->noticeHooks,
470 : : "row number %d is out of range 0..%d",
471 : : tup_num, res->ntups);
3298 peter_e@gmx.net 472 : 0 : return false;
473 : : }
474 : :
475 : : /* need to allocate a new tuple? */
5516 tgl@sss.pgh.pa.us 476 [ # # ]: 0 : if (tup_num == res->ntups)
477 : : {
478 : : PGresAttValue *tup;
479 : : int i;
480 : :
481 : : tup = (PGresAttValue *)
6553 482 : 0 : pqResultAlloc(res, res->numAttributes * sizeof(PGresAttValue),
483 : : true);
484 : :
485 [ # # ]: 0 : if (!tup)
3285 486 : 0 : goto fail;
487 : :
488 : : /* initialize each column to NULL */
6553 489 [ # # ]: 0 : for (i = 0; i < res->numAttributes; i++)
490 : : {
491 : 0 : tup[i].len = NULL_LEN;
492 : 0 : tup[i].value = res->null_field;
493 : : }
494 : :
495 : : /* add it to the array */
3285 496 [ # # ]: 0 : if (!pqAddTuple(res, tup, &errmsg))
497 : 0 : goto fail;
498 : : }
499 : :
6553 500 : 0 : attval = &res->tuples[tup_num][field_num];
501 : :
502 : : /* treat either NULL_LEN or NULL value pointer as a NULL field */
503 [ # # # # ]: 0 : if (len == NULL_LEN || value == NULL)
504 : : {
505 : 0 : attval->len = NULL_LEN;
506 : 0 : attval->value = res->null_field;
507 : : }
508 [ # # ]: 0 : else if (len <= 0)
509 : : {
510 : 0 : attval->len = 0;
511 : 0 : attval->value = res->null_field;
512 : : }
513 : : else
514 : : {
290 jchampion@postgresql 515 : 0 : attval->value = (char *) pqResultAlloc(res, (size_t) len + 1, true);
6553 tgl@sss.pgh.pa.us 516 [ # # ]: 0 : if (!attval->value)
3285 517 : 0 : goto fail;
6553 518 : 0 : attval->len = len;
519 : 0 : memcpy(attval->value, value, len);
520 : 0 : attval->value[len] = '\0';
521 : : }
522 : :
3298 peter_e@gmx.net 523 : 0 : return true;
524 : :
525 : : /*
526 : : * Report failure via pqInternalNotice. If preceding code didn't provide
527 : : * an error message, assume "out of memory" was meant.
528 : : */
3285 tgl@sss.pgh.pa.us 529 : 0 : fail:
530 [ # # ]: 0 : if (!errmsg)
531 : 0 : errmsg = libpq_gettext("out of memory");
532 : 0 : pqInternalNotice(&res->noticeHooks, "%s", errmsg);
533 : :
3298 peter_e@gmx.net 534 : 0 : return false;
535 : : }
536 : :
537 : : /*
538 : : * pqResultAlloc - exported routine to allocate local storage in a PGresult.
539 : : *
540 : : * We force all such allocations to be maxaligned, since we don't know
541 : : * whether the value might be binary.
542 : : */
543 : : void *
6553 tgl@sss.pgh.pa.us 544 :CBC 2615 : PQresultAlloc(PGresult *res, size_t nBytes)
545 : : {
546 : : /* Fail if argument is NULL or OOM_result */
1651 547 [ + - - + ]: 2615 : if (!res || (const PGresult *) res == &OOM_result)
1651 tgl@sss.pgh.pa.us 548 :UBC 0 : return NULL;
549 : :
3298 peter_e@gmx.net 550 :CBC 2615 : return pqResultAlloc(res, nBytes, true);
551 : : }
552 : :
553 : : /*
554 : : * pqResultAlloc -
555 : : * Allocate subsidiary storage for a PGresult.
556 : : *
557 : : * nBytes is the amount of space needed for the object.
558 : : * If isBinary is true, we assume that we need to align the object on
559 : : * a machine allocation boundary.
560 : : * If isBinary is false, we assume the object is a char string and can
561 : : * be allocated on any byte boundary.
562 : : */
563 : : void *
9786 bruce@momjian.us 564 : 24243531 : pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
565 : : {
566 : : char *space;
567 : : PGresult_data *block;
568 : :
9956 569 [ - + ]: 24243531 : if (!res)
10144 tgl@sss.pgh.pa.us 570 :UBC 0 : return NULL;
571 : :
10144 tgl@sss.pgh.pa.us 572 [ + + ]:CBC 24243531 : if (nBytes <= 0)
573 : 280 : return res->null_field;
574 : :
575 : : /*
576 : : * If alignment is needed, round up the current position to an alignment
577 : : * boundary.
578 : : */
579 [ + + ]: 24243251 : if (isBinary)
580 : : {
9956 bruce@momjian.us 581 : 4574535 : int offset = res->curOffset % PGRESULT_ALIGN_BOUNDARY;
582 : :
10144 tgl@sss.pgh.pa.us 583 [ + + ]: 4574535 : if (offset)
584 : : {
585 : 3321193 : res->curOffset += PGRESULT_ALIGN_BOUNDARY - offset;
586 : 3321193 : res->spaceLeft -= PGRESULT_ALIGN_BOUNDARY - offset;
587 : : }
588 : : }
589 : :
590 : : /* If there's enough space in the current block, no problem. */
9072 bruce@momjian.us 591 [ + + ]: 24243251 : if (nBytes <= (size_t) res->spaceLeft)
592 : : {
10144 tgl@sss.pgh.pa.us 593 : 23756757 : space = res->curBlock->space + res->curOffset;
594 : 23756757 : res->curOffset += nBytes;
595 : 23756757 : res->spaceLeft -= nBytes;
596 : 23756757 : return space;
597 : : }
598 : :
599 : : /*
600 : : * If the requested object is very large, give it its own block; this
601 : : * avoids wasting what might be most of the current block to start a new
602 : : * block. (We'd have to special-case requests bigger than the block size
603 : : * anyway.) The object is always given binary alignment in this case.
604 : : */
605 [ + + ]: 486494 : if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD)
606 : : {
607 : : size_t alloc_size;
608 : :
609 : : /* Don't wrap around with overly large requests. */
290 jchampion@postgresql 610 [ - + ]: 2775 : if (nBytes > SIZE_MAX - PGRESULT_BLOCK_OVERHEAD)
290 jchampion@postgresql 611 :UBC 0 : return NULL;
612 : :
290 jchampion@postgresql 613 :CBC 2775 : alloc_size = nBytes + PGRESULT_BLOCK_OVERHEAD;
2907 tgl@sss.pgh.pa.us 614 : 2775 : block = (PGresult_data *) malloc(alloc_size);
9956 bruce@momjian.us 615 [ - + ]: 2775 : if (!block)
10144 tgl@sss.pgh.pa.us 616 :UBC 0 : return NULL;
2907 tgl@sss.pgh.pa.us 617 :CBC 2775 : res->memorySize += alloc_size;
9969 618 : 2775 : space = block->space + PGRESULT_BLOCK_OVERHEAD;
10144 619 [ + + ]: 2775 : if (res->curBlock)
620 : : {
621 : : /*
622 : : * Tuck special block below the active block, so that we don't
623 : : * have to waste the free space in the active block.
624 : : */
625 : 2544 : block->next = res->curBlock->next;
626 : 2544 : res->curBlock->next = block;
627 : : }
628 : : else
629 : : {
630 : : /* Must set up the new block as the first active block. */
631 : 231 : block->next = NULL;
632 : 231 : res->curBlock = block;
9956 bruce@momjian.us 633 : 231 : res->spaceLeft = 0; /* be sure it's marked full */
634 : : }
10144 tgl@sss.pgh.pa.us 635 : 2775 : return space;
636 : : }
637 : :
638 : : /* Otherwise, start a new block. */
639 : 483719 : block = (PGresult_data *) malloc(PGRESULT_DATA_BLOCKSIZE);
9956 bruce@momjian.us 640 [ - + ]: 483719 : if (!block)
10144 tgl@sss.pgh.pa.us 641 :UBC 0 : return NULL;
2907 tgl@sss.pgh.pa.us 642 :CBC 483719 : res->memorySize += PGRESULT_DATA_BLOCKSIZE;
10144 643 : 483719 : block->next = res->curBlock;
644 : 483719 : res->curBlock = block;
645 [ + + ]: 483719 : if (isBinary)
646 : : {
647 : : /* object needs full alignment */
9969 648 : 447682 : res->curOffset = PGRESULT_BLOCK_OVERHEAD;
649 : 447682 : res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - PGRESULT_BLOCK_OVERHEAD;
650 : : }
651 : : else
652 : : {
653 : : /* we can cram it right after the overhead pointer */
10144 654 : 36037 : res->curOffset = sizeof(PGresult_data);
655 : 36037 : res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - sizeof(PGresult_data);
656 : : }
657 : :
658 : 483719 : space = block->space + res->curOffset;
659 : 483719 : res->curOffset += nBytes;
660 : 483719 : res->spaceLeft -= nBytes;
661 : 483719 : return space;
662 : : }
663 : :
664 : : /*
665 : : * PQresultMemorySize -
666 : : * Returns total space allocated for the PGresult.
667 : : */
668 : : size_t
2907 tgl@sss.pgh.pa.us 669 :UBC 0 : PQresultMemorySize(const PGresult *res)
670 : : {
671 [ # # ]: 0 : if (!res)
672 : 0 : return 0;
673 : 0 : return res->memorySize;
674 : : }
675 : :
676 : : /*
677 : : * pqResultStrdup -
678 : : * Like strdup, but the space is subsidiary PGresult space.
679 : : */
680 : : char *
10144 tgl@sss.pgh.pa.us 681 :CBC 673399 : pqResultStrdup(PGresult *res, const char *str)
682 : : {
3298 peter_e@gmx.net 683 : 673399 : char *space = (char *) pqResultAlloc(res, strlen(str) + 1, false);
684 : :
10144 tgl@sss.pgh.pa.us 685 [ + - ]: 673399 : if (space)
686 : 673399 : strcpy(space, str);
687 : 673399 : return space;
688 : : }
689 : :
690 : : /*
691 : : * pqSetResultError -
692 : : * assign a new error message to a PGresult
693 : : *
694 : : * Copy text from errorMessage buffer beginning at given offset
695 : : * (it's caller's responsibility that offset is valid)
696 : : */
697 : : void
1651 698 : 32683 : pqSetResultError(PGresult *res, PQExpBuffer errorMessage, int offset)
699 : : {
700 : : char *msg;
701 : :
10192 702 [ - + ]: 32683 : if (!res)
10192 tgl@sss.pgh.pa.us 703 :UBC 0 : return;
704 : :
705 : : /*
706 : : * We handle two OOM scenarios here. The errorMessage buffer might be
707 : : * marked "broken" due to having previously failed to allocate enough
708 : : * memory for the message, or it might be fine but pqResultStrdup fails
709 : : * and returns NULL. In either case, just make res->errMsg point directly
710 : : * at a constant "out of memory" string.
711 : : */
1855 tgl@sss.pgh.pa.us 712 [ + - + - ]:CBC 32683 : if (!PQExpBufferBroken(errorMessage))
1651 713 : 32683 : msg = pqResultStrdup(res, errorMessage->data + offset);
714 : : else
1855 tgl@sss.pgh.pa.us 715 :UBC 0 : msg = NULL;
1855 tgl@sss.pgh.pa.us 716 [ + - ]:CBC 32683 : if (msg)
717 : 32683 : res->errMsg = msg;
718 : : else
1855 tgl@sss.pgh.pa.us 719 :UBC 0 : res->errMsg = libpq_gettext("out of memory\n");
720 : : }
721 : :
722 : : /*
723 : : * PQclear -
724 : : * free's the memory associated with a PGresult
725 : : */
726 : : void
10340 bruce@momjian.us 727 :CBC 2382699 : PQclear(PGresult *res)
728 : : {
729 : : PGresult_data *block;
730 : : int i;
731 : :
732 : : /* As a convenience, do nothing for a NULL pointer */
733 [ + + ]: 2382699 : if (!res)
734 : 1117292 : return;
735 : : /* Also, do nothing if the argument is OOM_result */
1651 tgl@sss.pgh.pa.us 736 [ - + ]: 1265407 : if ((const PGresult *) res == &OOM_result)
1651 tgl@sss.pgh.pa.us 737 :UBC 0 : return;
738 : :
739 : : /* Close down any events we may have */
6553 tgl@sss.pgh.pa.us 740 [ - + ]:CBC 1265407 : for (i = 0; i < res->nEvents; i++)
741 : : {
742 : : /* only send DESTROY to successfully-initialized event procs */
6551 tgl@sss.pgh.pa.us 743 [ # # ]:UBC 0 : if (res->events[i].resultInitialized)
744 : : {
745 : : PGEventResultDestroy evt;
746 : :
747 : 0 : evt.result = res;
748 : 0 : (void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt,
749 : 0 : res->events[i].passThrough);
750 : : }
6553 751 : 0 : free(res->events[i].name);
752 : : }
753 : :
1533 peter@eisentraut.org 754 :CBC 1265407 : free(res->events);
755 : :
756 : : /* Free all the subsidiary blocks */
9956 bruce@momjian.us 757 [ + + ]: 1749826 : while ((block = res->curBlock) != NULL)
758 : : {
10144 tgl@sss.pgh.pa.us 759 : 484419 : res->curBlock = block->next;
760 : 484419 : free(block);
761 : : }
762 : :
763 : : /* Free the top-level tuple pointer array */
1533 peter@eisentraut.org 764 : 1265407 : free(res->tuples);
765 : :
766 : : /* zero out the pointer fields to catch programming errors */
7396 alvherre@alvh.no-ip. 767 : 1265407 : res->attDescs = NULL;
768 : 1265407 : res->tuples = NULL;
7314 tgl@sss.pgh.pa.us 769 : 1265407 : res->paramDescs = NULL;
7396 alvherre@alvh.no-ip. 770 : 1265407 : res->errFields = NULL;
6553 tgl@sss.pgh.pa.us 771 : 1265407 : res->events = NULL;
772 : 1265407 : res->nEvents = 0;
773 : : /* res->curBlock was zeroed out earlier */
774 : :
775 : : /* Free the PGresult structure itself */
10340 bruce@momjian.us 776 : 1265407 : free(res);
777 : : }
778 : :
779 : : /*
780 : : * Handy subroutine to deallocate any partially constructed async result.
781 : : *
782 : : * Any "saved" result gets cleared too.
783 : : */
784 : : void
10237 scrappy@hub.org 785 : 508287 : pqClearAsyncResult(PGconn *conn)
786 : : {
1516 peter@eisentraut.org 787 : 508287 : PQclear(conn->result);
10340 bruce@momjian.us 788 : 508287 : conn->result = NULL;
1651 tgl@sss.pgh.pa.us 789 : 508287 : conn->error_result = false;
873 790 : 508287 : PQclear(conn->saved_result);
791 : 508287 : conn->saved_result = NULL;
11006 scrappy@hub.org 792 : 508287 : }
793 : :
794 : : /*
795 : : * pqSaveErrorResult -
796 : : * remember that we have an error condition
797 : : *
798 : : * In much of libpq, reporting an error just requires appending text to
799 : : * conn->errorMessage and returning a failure code to one's caller.
800 : : * Where returning a failure code is impractical, instead call this
801 : : * function to remember that an error needs to be reported.
802 : : *
803 : : * (It might seem that appending text to conn->errorMessage should be
804 : : * sufficient, but we can't rely on that working under out-of-memory
805 : : * conditions. The OOM hazard is also why we don't try to make a new
806 : : * PGresult right here.)
807 : : */
808 : : void
8481 tgl@sss.pgh.pa.us 809 : 71 : pqSaveErrorResult(PGconn *conn)
810 : : {
811 : : /* Drop any pending result ... */
2054 812 : 71 : pqClearAsyncResult(conn);
813 : : /* ... and set flag to remember to make an error result later */
1651 814 : 71 : conn->error_result = true;
9858 815 : 71 : }
816 : :
817 : : /*
818 : : * pqSaveWriteError -
819 : : * report a write failure
820 : : *
821 : : * As above, after appending conn->write_err_msg to whatever other error we
822 : : * have. This is used when we've detected a write failure and have exhausted
823 : : * our chances of reporting something else instead.
824 : : */
825 : : static void
2718 826 : 4 : pqSaveWriteError(PGconn *conn)
827 : : {
828 : : /*
829 : : * If write_err_msg is null because of previous strdup failure, do what we
830 : : * can. (It's likely our machinations here will get OOM failures as well,
831 : : * but might as well try.)
832 : : */
2054 833 [ + - ]: 4 : if (conn->write_err_msg)
834 : : {
835 : 4 : appendPQExpBufferStr(&conn->errorMessage, conn->write_err_msg);
836 : : /* Avoid possibly appending the same message twice */
837 : 4 : conn->write_err_msg[0] = '\0';
838 : : }
839 : : else
1381 peter@eisentraut.org 840 :UBC 0 : libpq_append_conn_error(conn, "write to server failed");
841 : :
2054 tgl@sss.pgh.pa.us 842 :CBC 4 : pqSaveErrorResult(conn);
2718 843 : 4 : }
844 : :
845 : : /*
846 : : * pqPrepareAsyncResult -
847 : : * prepare the current async result object for return to the caller
848 : : *
849 : : * If there is not already an async result object, build an error object
850 : : * using whatever is in conn->errorMessage. In any case, clear the async
851 : : * result storage, and update our notion of how much error text has been
852 : : * returned to the application.
853 : : *
854 : : * Note that in no case (not even OOM) do we return NULL.
855 : : */
856 : : PGresult *
8481 857 : 444051 : pqPrepareAsyncResult(PGconn *conn)
858 : : {
859 : : PGresult *res;
860 : :
9858 861 : 444051 : res = conn->result;
1651 862 [ + + ]: 444051 : if (res)
863 : : {
864 : : /*
865 : : * If the pre-existing result is an ERROR (presumably something
866 : : * received from the server), assume that it represents whatever is in
867 : : * conn->errorMessage, and advance errorReported.
868 : : */
869 [ + + ]: 443980 : if (res->resultStatus == PGRES_FATAL_ERROR)
870 : 31653 : conn->errorReported = conn->errorMessage.len;
871 : : }
872 : : else
873 : : {
874 : : /*
875 : : * We get here after internal-to-libpq errors. We should probably
876 : : * always have error_result = true, but if we don't, gin up some error
877 : : * text.
878 : : */
879 [ - + ]: 71 : if (!conn->error_result)
1381 peter@eisentraut.org 880 :UBC 0 : libpq_append_conn_error(conn, "no error text available");
881 : :
882 : : /* Paranoia: be sure errorReported offset is sane */
1651 tgl@sss.pgh.pa.us 883 [ + - ]:CBC 71 : if (conn->errorReported < 0 ||
884 [ - + ]: 71 : conn->errorReported >= conn->errorMessage.len)
1651 tgl@sss.pgh.pa.us 885 :UBC 0 : conn->errorReported = 0;
886 : :
887 : : /*
888 : : * Make a PGresult struct for the error. We temporarily lie about the
889 : : * result status, so that PQmakeEmptyPGresult doesn't uselessly copy
890 : : * all of conn->errorMessage.
891 : : */
1651 tgl@sss.pgh.pa.us 892 :CBC 71 : res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
893 [ + - ]: 71 : if (res)
894 : : {
895 : : /*
896 : : * Report whatever new error text we have, and advance
897 : : * errorReported.
898 : : */
899 : 71 : res->resultStatus = PGRES_FATAL_ERROR;
900 : 71 : pqSetResultError(res, &conn->errorMessage, conn->errorReported);
901 : 71 : conn->errorReported = conn->errorMessage.len;
902 : : }
903 : : else
904 : : {
905 : : /*
906 : : * Ouch, not enough memory for a PGresult. Fortunately, we have a
907 : : * card up our sleeve: we can use the static OOM_result. Casting
908 : : * away const here is a bit ugly, but it seems best to declare
909 : : * OOM_result as const, in hopes it will be allocated in read-only
910 : : * storage.
911 : : */
1651 tgl@sss.pgh.pa.us 912 :UBC 0 : res = unconstify(PGresult *, &OOM_result);
913 : :
914 : : /*
915 : : * Don't advance errorReported. Perhaps we'll be able to report
916 : : * the text later.
917 : : */
918 : : }
919 : : }
920 : :
921 : : /*
922 : : * Replace conn->result with saved_result, if any. In the normal case
923 : : * there isn't a saved result and we're just dropping ownership of the
924 : : * current result. In partial-result mode this restores the situation to
925 : : * what it was before we created the current partial result.
926 : : */
873 tgl@sss.pgh.pa.us 927 :CBC 444051 : conn->result = conn->saved_result;
928 : 444051 : conn->error_result = false; /* saved_result is never an error */
929 : 444051 : conn->saved_result = NULL;
930 : :
9858 931 : 444051 : return res;
932 : : }
933 : :
934 : : /*
935 : : * pqInternalNotice - produce an internally-generated notice message
936 : : *
937 : : * A format string and optional arguments can be passed. Note that we do
938 : : * libpq_gettext() here, so callers need not.
939 : : *
940 : : * The supplied text is taken as primary message (ie., it should not include
941 : : * a trailing newline, and should not be more than one line).
942 : : */
943 : : void
106 tgl@sss.pgh.pa.us 944 :UBC 0 : pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt, ...)
945 : : {
946 : : char msgBuf[1024];
947 : : va_list args;
948 : : PGresult *res;
949 : :
8468 950 [ # # ]: 0 : if (hooks->noticeRec == NULL)
8466 951 : 0 : return; /* nobody home to receive notice? */
952 : :
953 : : /* Format the message */
954 : 0 : va_start(args, fmt);
955 : 0 : vsnprintf(msgBuf, sizeof(msgBuf), libpq_gettext(fmt), args);
956 : 0 : va_end(args);
8424 bruce@momjian.us 957 : 0 : msgBuf[sizeof(msgBuf) - 1] = '\0'; /* make real sure it's terminated */
958 : :
959 : : /* Make a PGresult to pass to the notice receiver */
8468 tgl@sss.pgh.pa.us 960 : 0 : res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR);
7746 neilc@samurai.com 961 [ # # ]: 0 : if (!res)
962 : 0 : return;
8468 tgl@sss.pgh.pa.us 963 : 0 : res->noticeHooks = *hooks;
964 : :
965 : : /*
966 : : * Set up fields of notice.
967 : : */
8401 peter_e@gmx.net 968 : 0 : pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, msgBuf);
969 : 0 : pqSaveMessageField(res, PG_DIAG_SEVERITY, libpq_gettext("NOTICE"));
3653 tgl@sss.pgh.pa.us 970 : 0 : pqSaveMessageField(res, PG_DIAG_SEVERITY_NONLOCALIZED, "NOTICE");
971 : : /* XXX should provide a SQLSTATE too? */
972 : :
973 : : /*
974 : : * Result text is always just the primary message + newline. If we can't
975 : : * allocate it, substitute "out of memory", as in pqSetResultError.
976 : : */
3298 peter_e@gmx.net 977 : 0 : res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, false);
7746 neilc@samurai.com 978 [ # # ]: 0 : if (res->errMsg)
979 : 0 : sprintf(res->errMsg, "%s\n", msgBuf);
980 : : else
1855 tgl@sss.pgh.pa.us 981 : 0 : res->errMsg = libpq_gettext("out of memory\n");
982 : :
983 : : /*
984 : : * Pass to receiver, then free it.
985 : : */
986 : 0 : res->noticeHooks.noticeRec(res->noticeHooks.noticeRecArg, res);
8468 987 : 0 : PQclear(res);
988 : : }
989 : :
990 : : /*
991 : : * pqAddTuple
992 : : * add a row pointer to the PGresult structure, growing it if necessary
993 : : * Returns true if OK, false if an error prevented adding the row
994 : : *
995 : : * On error, *errmsgp can be set to an error string to be returned.
996 : : * If it is left NULL, the error is presumed to be "out of memory".
997 : : */
998 : : static bool
3285 tgl@sss.pgh.pa.us 999 :CBC 3965761 : pqAddTuple(PGresult *res, PGresAttValue *tup, const char **errmsgp)
1000 : : {
10340 bruce@momjian.us 1001 [ + + ]: 3965761 : if (res->ntups >= res->tupArrSize)
1002 : : {
1003 : : /*
1004 : : * Try to grow the array.
1005 : : *
1006 : : * We can use realloc because shallow copying of the structure is
1007 : : * okay. Note that the first time through, res->tuples is NULL. While
1008 : : * ANSI says that realloc() should act like malloc() in that case,
1009 : : * some old C libraries (like SunOS 4.1.x) coredump instead. On
1010 : : * failure realloc is supposed to return NULL without damaging the
1011 : : * existing allocation. Note that the positions beyond res->ntups are
1012 : : * garbage, not necessarily NULL.
1013 : : */
1014 : : int newSize;
1015 : : PGresAttValue **newTuples;
1016 : :
1017 : : /*
1018 : : * Since we use integers for row numbers, we can't support more than
1019 : : * INT_MAX rows. Make sure we allow that many, though.
1020 : : */
3285 tgl@sss.pgh.pa.us 1021 [ + - ]: 176242 : if (res->tupArrSize <= INT_MAX / 2)
1022 [ + + ]: 176242 : newSize = (res->tupArrSize > 0) ? res->tupArrSize * 2 : 128;
3285 tgl@sss.pgh.pa.us 1023 [ # # ]:UBC 0 : else if (res->tupArrSize < INT_MAX)
1024 : 0 : newSize = INT_MAX;
1025 : : else
1026 : : {
1027 : 0 : *errmsgp = libpq_gettext("PGresult cannot support more than INT_MAX tuples");
3298 peter_e@gmx.net 1028 : 0 : return false;
1029 : : }
1030 : :
1031 : : /*
1032 : : * Also, on 32-bit platforms we could, in theory, overflow size_t even
1033 : : * before newSize gets to INT_MAX. (In practice we'd doubtless hit
1034 : : * OOM long before that, but let's check.)
1035 : : */
1036 : : #if INT_MAX >= (SIZE_MAX / 2)
1037 : : if (newSize > SIZE_MAX / sizeof(PGresAttValue *))
1038 : : {
1039 : : *errmsgp = libpq_gettext("size_t overflow");
1040 : : return false;
1041 : : }
1042 : : #endif
1043 : :
10133 tgl@sss.pgh.pa.us 1044 [ + + ]:CBC 176242 : if (res->tuples == NULL)
1045 : : newTuples = (PGresAttValue **)
1046 : 169095 : malloc(newSize * sizeof(PGresAttValue *));
1047 : : else
1048 : : newTuples = (PGresAttValue **)
1049 : 7147 : realloc(res->tuples, newSize * sizeof(PGresAttValue *));
9956 bruce@momjian.us 1050 [ - + ]: 176242 : if (!newTuples)
3298 peter_e@gmx.net 1051 :UBC 0 : return false; /* malloc or realloc failed */
2907 tgl@sss.pgh.pa.us 1052 :CBC 176242 : res->memorySize +=
1053 : 176242 : (newSize - res->tupArrSize) * sizeof(PGresAttValue *);
10192 1054 : 176242 : res->tupArrSize = newSize;
1055 : 176242 : res->tuples = newTuples;
1056 : : }
10581 bruce@momjian.us 1057 : 3965761 : res->tuples[res->ntups] = tup;
1058 : 3965761 : res->ntups++;
3298 peter_e@gmx.net 1059 : 3965761 : return true;
1060 : : }
1061 : :
1062 : : /*
1063 : : * pqSaveMessageField - save one field of an error or notice message
1064 : : */
1065 : : void
8468 tgl@sss.pgh.pa.us 1066 : 389398 : pqSaveMessageField(PGresult *res, char code, const char *value)
1067 : : {
1068 : : PGMessageField *pfield;
1069 : :
1070 : : pfield = (PGMessageField *)
1071 : 389398 : pqResultAlloc(res,
1072 : : offsetof(PGMessageField, contents) +
4205 1073 : 389398 : strlen(value) + 1,
1074 : : true);
8468 1075 [ - + ]: 389398 : if (!pfield)
8468 tgl@sss.pgh.pa.us 1076 :UBC 0 : return; /* out of memory? */
8468 tgl@sss.pgh.pa.us 1077 :CBC 389398 : pfield->code = code;
1078 : 389398 : strcpy(pfield->contents, value);
1079 : 389398 : pfield->next = res->errFields;
1080 : 389398 : res->errFields = pfield;
1081 : : }
1082 : :
1083 : : /*
1084 : : * pqSaveParameterStatus - remember parameter status sent by backend
1085 : : *
1086 : : * Returns 1 on success, 0 on out-of-memory. (Note that on out-of-memory, we
1087 : : * have already released the old value of the parameter, if any. The only
1088 : : * really safe way to recover is to terminate the connection.)
1089 : : */
1090 : : int
8481 1091 : 241351 : pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
1092 : : {
1093 : : pgParameterStatus *pstatus;
1094 : : pgParameterStatus *prev;
1095 : :
1096 : : /*
1097 : : * Forget any old information about the parameter
1098 : : */
1099 : 241351 : for (pstatus = conn->pstatus, prev = NULL;
1100 [ + + ]: 1909777 : pstatus != NULL;
1101 : 1668426 : prev = pstatus, pstatus = pstatus->next)
1102 : : {
1103 [ + + ]: 1677637 : if (strcmp(pstatus->name, name) == 0)
1104 : : {
1105 [ + + ]: 9211 : if (prev)
1106 : 6156 : prev->next = pstatus->next;
1107 : : else
1108 : 3055 : conn->pstatus = pstatus->next;
1109 : 9211 : free(pstatus); /* frees name and value strings too */
1110 : 9211 : break;
1111 : : }
1112 : : }
1113 : :
1114 : : /*
1115 : : * Store new info as a single malloc block
1116 : : */
1117 : 241351 : pstatus = (pgParameterStatus *) malloc(sizeof(pgParameterStatus) +
3354 1118 : 241351 : strlen(name) + strlen(value) + 2);
8481 1119 [ + - ]: 241351 : if (pstatus)
1120 : : {
1121 : : char *ptr;
1122 : :
1123 : 241351 : ptr = ((char *) pstatus) + sizeof(pgParameterStatus);
1124 : 241351 : pstatus->name = ptr;
1125 : 241351 : strcpy(ptr, name);
1126 : 241351 : ptr += strlen(name) + 1;
1127 : 241351 : pstatus->value = ptr;
1128 : 241351 : strcpy(ptr, value);
1129 : 241351 : pstatus->next = conn->pstatus;
1130 : 241351 : conn->pstatus = pstatus;
1131 : : }
1132 : : else
1133 : : {
1134 : : /* out of memory */
370 heikki.linnakangas@i 1135 :UBC 0 : return 0;
1136 : : }
1137 : :
1138 : : /*
1139 : : * Save values of settings that are of interest to libpq in fields of the
1140 : : * PGconn object. We keep client_encoding and standard_conforming_strings
1141 : : * in static variables as well, so that PQescapeString and PQescapeBytea
1142 : : * can behave somewhat sanely (at least in single-connection-using
1143 : : * programs).
1144 : : */
8481 tgl@sss.pgh.pa.us 1145 [ + + ]:CBC 241351 : if (strcmp(name, "client_encoding") == 0)
1146 : : {
1147 : 15520 : conn->client_encoding = pg_char_to_encoding(value);
1148 : : /* if we don't recognize the encoding name, fall back to SQL_ASCII */
6893 1149 [ - + ]: 15520 : if (conn->client_encoding < 0)
6893 tgl@sss.pgh.pa.us 1150 :UBC 0 : conn->client_encoding = PG_SQL_ASCII;
7403 tgl@sss.pgh.pa.us 1151 :CBC 15520 : static_client_encoding = conn->client_encoding;
1152 : : }
1153 [ + + ]: 225831 : else if (strcmp(name, "standard_conforming_strings") == 0)
1154 : : {
1155 : 15476 : conn->std_strings = (strcmp(value, "on") == 0);
1156 : 15476 : static_std_strings = conn->std_strings;
1157 : : }
8210 1158 [ + + ]: 210355 : else if (strcmp(name, "server_version") == 0)
1159 : : {
1160 : : /* We convert the server version to numeric form. */
1161 : : int cnt;
1162 : : int vmaj,
1163 : : vmin,
1164 : : vrev;
1165 : :
1166 : 15476 : cnt = sscanf(value, "%d.%d.%d", &vmaj, &vmin, &vrev);
1167 : :
3674 1168 [ - + ]: 15476 : if (cnt == 3)
1169 : : {
1170 : : /* old style, e.g. 9.6.1 */
8210 tgl@sss.pgh.pa.us 1171 :UBC 0 : conn->sversion = (100 * vmaj + vmin) * 100 + vrev;
1172 : : }
3674 tgl@sss.pgh.pa.us 1173 [ - + ]:CBC 15476 : else if (cnt == 2)
1174 : : {
3674 tgl@sss.pgh.pa.us 1175 [ # # ]:UBC 0 : if (vmaj >= 10)
1176 : : {
1177 : : /* new style, e.g. 10.1 */
1178 : 0 : conn->sversion = 100 * 100 * vmaj + vmin;
1179 : : }
1180 : : else
1181 : : {
1182 : : /* old style without minor version, e.g. 9.6devel */
1183 : 0 : conn->sversion = (100 * vmaj + vmin) * 100;
1184 : : }
1185 : : }
3674 tgl@sss.pgh.pa.us 1186 [ + - ]:CBC 15476 : else if (cnt == 1)
1187 : : {
1188 : : /* new style without minor version, e.g. 10devel */
1189 : 15476 : conn->sversion = 100 * 100 * vmaj;
1190 : : }
1191 : : else
3674 tgl@sss.pgh.pa.us 1192 :UBC 0 : conn->sversion = 0; /* unknown */
1193 : : }
2004 tgl@sss.pgh.pa.us 1194 [ + + ]:CBC 194879 : else if (strcmp(name, "default_transaction_read_only") == 0)
1195 : : {
1196 : 15501 : conn->default_transaction_read_only =
1197 [ + + ]: 15501 : (strcmp(value, "on") == 0) ? PG_BOOL_YES : PG_BOOL_NO;
1198 : : }
1199 [ + + ]: 179378 : else if (strcmp(name, "in_hot_standby") == 0)
1200 : : {
1201 : 15487 : conn->in_hot_standby =
1202 [ + + ]: 15487 : (strcmp(value, "on") == 0) ? PG_BOOL_YES : PG_BOOL_NO;
1203 : : }
1249 dgustafsson@postgres 1204 [ + + ]: 163891 : else if (strcmp(name, "scram_iterations") == 0)
1205 : : {
1206 : 15483 : conn->scram_sha_256_iterations = atoi(value);
1207 : : }
1208 : :
370 heikki.linnakangas@i 1209 : 241351 : return 1;
1210 : : }
1211 : :
1212 : :
1213 : : /*
1214 : : * pqRowProcessor
1215 : : * Add the received row to the current async result (conn->result).
1216 : : * Returns 1 if OK, 0 if error occurred.
1217 : : *
1218 : : * On error, *errmsgp can be set to an error string to be returned.
1219 : : * (Such a string should already be translated via libpq_gettext().)
1220 : : * If it is left NULL, the error is presumed to be "out of memory".
1221 : : */
1222 : : int
5138 tgl@sss.pgh.pa.us 1223 : 3965761 : pqRowProcessor(PGconn *conn, const char **errmsgp)
1224 : : {
1225 : 3965761 : PGresult *res = conn->result;
5258 1226 : 3965761 : int nfields = res->numAttributes;
5138 1227 : 3965761 : const PGdataValue *columns = conn->rowBuf;
1228 : : PGresAttValue *tup;
1229 : : int i;
1230 : :
1231 : : /*
1232 : : * In partial-result mode, if we don't already have a partial PGresult
1233 : : * then make one by cloning conn->result (which should hold the correct
1234 : : * result metadata by now). Then the original conn->result is moved over
1235 : : * to saved_result so that we can re-use it as a reference for future
1236 : : * partial results. The saved result will become active again after
1237 : : * pqPrepareAsyncResult() returns the partial result to the application.
1238 : : */
873 1239 [ + + + + ]: 3965761 : if (conn->partialResMode && conn->saved_result == NULL)
1240 : : {
1241 : : /* Copy everything that should be in the result at this point */
5138 1242 : 2615 : res = PQcopyResult(res,
1243 : : PG_COPYRES_ATTRS | PG_COPYRES_EVENTS |
1244 : : PG_COPYRES_NOTICEHOOKS);
1245 [ - + ]: 2615 : if (!res)
5138 tgl@sss.pgh.pa.us 1246 :UBC 0 : return 0;
1247 : : /* Change result status to appropriate special value */
873 tgl@sss.pgh.pa.us 1248 [ + + ]:CBC 2615 : res->resultStatus = (conn->singleRowMode ? PGRES_SINGLE_TUPLE : PGRES_TUPLES_CHUNK);
1249 : : /* And stash it as the active result */
1250 : 2615 : conn->saved_result = conn->result;
1251 : 2615 : conn->result = res;
1252 : : }
1253 : :
1254 : : /*
1255 : : * Basically we just allocate space in the PGresult for each field and
1256 : : * copy the data over.
1257 : : *
1258 : : * Note: on malloc failure, we return 0 leaving *errmsgp still NULL, which
1259 : : * caller will take to mean "out of memory". This is preferable to trying
1260 : : * to set up such a message here, because evidently there's not enough
1261 : : * memory for gettext() to do anything.
1262 : : */
1263 : : tup = (PGresAttValue *)
3298 peter_e@gmx.net 1264 : 3965761 : pqResultAlloc(res, nfields * sizeof(PGresAttValue), true);
5258 tgl@sss.pgh.pa.us 1265 [ - + ]: 3965761 : if (tup == NULL)
873 tgl@sss.pgh.pa.us 1266 :UBC 0 : return 0;
1267 : :
5258 tgl@sss.pgh.pa.us 1268 [ + + ]:CBC 24157934 : for (i = 0; i < nfields; i++)
1269 : : {
5191 bruce@momjian.us 1270 : 20192173 : int clen = columns[i].len;
1271 : :
5258 tgl@sss.pgh.pa.us 1272 [ + + ]: 20192173 : if (clen < 0)
1273 : : {
1274 : : /* null field */
1275 : 1189677 : tup[i].len = NULL_LEN;
1276 : 1189677 : tup[i].value = res->null_field;
1277 : : }
1278 : : else
1279 : : {
1280 : 19002496 : bool isbinary = (res->attDescs[i].format != 0);
1281 : : char *val;
1282 : :
290 jchampion@postgresql 1283 : 19002496 : val = (char *) pqResultAlloc(res, (size_t) clen + 1, isbinary);
5258 tgl@sss.pgh.pa.us 1284 [ - + ]: 19002496 : if (val == NULL)
873 tgl@sss.pgh.pa.us 1285 :UBC 0 : return 0;
1286 : :
1287 : : /* copy and zero-terminate the data (even if it's binary) */
5258 tgl@sss.pgh.pa.us 1288 :CBC 19002496 : memcpy(val, columns[i].value, clen);
1289 : 19002496 : val[clen] = '\0';
1290 : :
1291 : 19002496 : tup[i].len = clen;
1292 : 19002496 : tup[i].value = val;
1293 : : }
1294 : : }
1295 : :
1296 : : /* And add the tuple to the PGresult's tuple array */
3285 1297 [ - + ]: 3965761 : if (!pqAddTuple(res, tup, errmsgp))
873 tgl@sss.pgh.pa.us 1298 :UBC 0 : return 0;
1299 : :
1300 : : /*
1301 : : * Success. In partial-result mode, if we have enough rows then make the
1302 : : * result available to the client immediately.
1303 : : */
873 tgl@sss.pgh.pa.us 1304 [ + + + + ]:CBC 3965761 : if (conn->partialResMode && res->ntups >= conn->maxChunkSize)
1991 alvherre@alvh.no-ip. 1305 : 2598 : conn->asyncStatus = PGASYNC_READY_MORE;
1306 : :
5258 tgl@sss.pgh.pa.us 1307 : 3965761 : return 1;
1308 : : }
1309 : :
1310 : :
1311 : : /*
1312 : : * pqAllocCmdQueueEntry
1313 : : * Get a command queue entry for caller to fill.
1314 : : *
1315 : : * If the recycle queue has a free element, that is returned; if not, a
1316 : : * fresh one is allocated. Caller is responsible for adding it to the
1317 : : * command queue (pqAppendCmdQueueEntry) once the struct is filled in, or
1318 : : * releasing the memory (pqRecycleCmdQueueEntry) if an error occurs.
1319 : : *
1320 : : * If allocation fails, sets the error message and returns NULL.
1321 : : */
1322 : : static PGcmdQueueEntry *
1991 alvherre@alvh.no-ip. 1323 : 412304 : pqAllocCmdQueueEntry(PGconn *conn)
1324 : : {
1325 : : PGcmdQueueEntry *entry;
1326 : :
1327 [ + + ]: 412304 : if (conn->cmd_queue_recycle == NULL)
1328 : : {
1329 : 16152 : entry = (PGcmdQueueEntry *) malloc(sizeof(PGcmdQueueEntry));
1330 [ - + ]: 16152 : if (entry == NULL)
1331 : : {
1381 peter@eisentraut.org 1332 :UBC 0 : libpq_append_conn_error(conn, "out of memory");
1991 alvherre@alvh.no-ip. 1333 : 0 : return NULL;
1334 : : }
1335 : : }
1336 : : else
1337 : : {
1991 alvherre@alvh.no-ip. 1338 :CBC 396152 : entry = conn->cmd_queue_recycle;
1339 : 396152 : conn->cmd_queue_recycle = entry->next;
1340 : : }
1341 : 412304 : entry->next = NULL;
1342 : 412304 : entry->query = NULL;
1343 : :
1344 : 412304 : return entry;
1345 : : }
1346 : :
1347 : : /*
1348 : : * pqAppendCmdQueueEntry
1349 : : * Append a caller-allocated entry to the command queue, and update
1350 : : * conn->asyncStatus to account for it.
1351 : : *
1352 : : * The query itself must already have been put in the output buffer by the
1353 : : * caller.
1354 : : */
1355 : : static void
1356 : 412304 : pqAppendCmdQueueEntry(PGconn *conn, PGcmdQueueEntry *entry)
1357 : : {
1358 [ - + ]: 412304 : Assert(entry->next == NULL);
1359 : :
1360 [ + + ]: 412304 : if (conn->cmd_queue_head == NULL)
1361 : 409789 : conn->cmd_queue_head = entry;
1362 : : else
1363 : 2515 : conn->cmd_queue_tail->next = entry;
1364 : :
1365 : 412304 : conn->cmd_queue_tail = entry;
1366 : :
1875 1367 [ + + - ]: 412304 : switch (conn->pipelineStatus)
1368 : : {
1369 : 412216 : case PQ_PIPELINE_OFF:
1370 : : case PQ_PIPELINE_ON:
1371 : :
1372 : : /*
1373 : : * When not in pipeline aborted state, if there's a result ready
1374 : : * to be consumed, let it be so (that is, don't change away from
1375 : : * READY or READY_MORE); otherwise set us busy to wait for
1376 : : * something to arrive from the server.
1377 : : */
1378 [ + + ]: 412216 : if (conn->asyncStatus == PGASYNC_IDLE)
1379 : 409776 : conn->asyncStatus = PGASYNC_BUSY;
1380 : 412216 : break;
1381 : :
1382 : 88 : case PQ_PIPELINE_ABORTED:
1383 : :
1384 : : /*
1385 : : * In aborted pipeline state, we don't expect anything from the
1386 : : * server (since we don't send any queries that are queued).
1387 : : * Therefore, if IDLE then do what PQgetResult would do to let
1388 : : * itself consume commands from the queue; if we're in any other
1389 : : * state, we don't have to do anything.
1390 : : */
1514 1391 [ + + ]: 88 : if (conn->asyncStatus == PGASYNC_IDLE ||
1392 [ - + ]: 75 : conn->asyncStatus == PGASYNC_PIPELINE_IDLE)
1875 1393 : 13 : pqPipelineProcessQueue(conn);
1394 : 88 : break;
1395 : : }
1991 1396 : 412304 : }
1397 : :
1398 : : /*
1399 : : * pqRecycleCmdQueueEntry
1400 : : * Push a command queue entry onto the freelist.
1401 : : */
1402 : : static void
1403 : 410983 : pqRecycleCmdQueueEntry(PGconn *conn, PGcmdQueueEntry *entry)
1404 : : {
1405 [ - + ]: 410983 : if (entry == NULL)
1991 alvherre@alvh.no-ip. 1406 :UBC 0 : return;
1407 : :
1408 : : /* recyclable entries should not have a follow-on command */
1991 alvherre@alvh.no-ip. 1409 [ - + ]:CBC 410983 : Assert(entry->next == NULL);
1410 : :
1411 [ + + ]: 410983 : if (entry->query)
1412 : : {
1413 : 401339 : free(entry->query);
1414 : 401339 : entry->query = NULL;
1415 : : }
1416 : :
1417 : 410983 : entry->next = conn->cmd_queue_recycle;
1418 : 410983 : conn->cmd_queue_recycle = entry;
1419 : : }
1420 : :
1421 : :
1422 : : /*
1423 : : * PQsendQuery
1424 : : * Submit a query, but don't wait for it to finish
1425 : : *
1426 : : * Returns: 1 if successfully submitted
1427 : : * 0 if error (conn->errorMessage is set)
1428 : : *
1429 : : * PQsendQueryContinue is a non-exported version that behaves identically
1430 : : * except that it doesn't reset conn->errorMessage.
1431 : : */
1432 : : int
10340 bruce@momjian.us 1433 : 397937 : PQsendQuery(PGconn *conn, const char *query)
1434 : : {
2054 tgl@sss.pgh.pa.us 1435 : 397937 : return PQsendQueryInternal(conn, query, true);
1436 : : }
1437 : :
1438 : : int
2054 tgl@sss.pgh.pa.us 1439 :UBC 0 : PQsendQueryContinue(PGconn *conn, const char *query)
1440 : : {
1441 : 0 : return PQsendQueryInternal(conn, query, false);
1442 : : }
1443 : :
1444 : : static int
2054 tgl@sss.pgh.pa.us 1445 :CBC 397937 : PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery)
1446 : : {
1991 alvherre@alvh.no-ip. 1447 : 397937 : PGcmdQueueEntry *entry = NULL;
1448 : :
2054 tgl@sss.pgh.pa.us 1449 [ + + ]: 397937 : if (!PQsendQueryStart(conn, newQuery))
10340 bruce@momjian.us 1450 : 1 : return 0;
1451 : :
1452 : : /* check the argument */
1453 [ - + ]: 397936 : if (!query)
1454 : : {
1381 peter@eisentraut.org 1455 :UBC 0 : libpq_append_conn_error(conn, "command string is a null pointer");
10245 bruce@momjian.us 1456 : 0 : return 0;
1457 : : }
1458 : :
1514 alvherre@alvh.no-ip. 1459 [ + + ]:CBC 397936 : if (conn->pipelineStatus != PQ_PIPELINE_OFF)
1460 : : {
1381 peter@eisentraut.org 1461 : 1 : libpq_append_conn_error(conn, "%s not allowed in pipeline mode",
1462 : : "PQsendQuery");
1434 alvherre@alvh.no-ip. 1463 : 1 : return 0;
1464 : : }
1465 : :
1466 : 397935 : entry = pqAllocCmdQueueEntry(conn);
1467 [ - + ]: 397935 : if (entry == NULL)
1434 alvherre@alvh.no-ip. 1468 :UBC 0 : return 0; /* error msg already set */
1469 : :
1470 : : /* Send the query message(s) */
1471 : : /* construct the outgoing Query message */
1101 nathan@postgresql.or 1472 [ + - + - ]:CBC 795870 : if (pqPutMsgStart(PqMsg_Query, conn) < 0 ||
1434 alvherre@alvh.no-ip. 1473 [ - + ]: 795870 : pqPuts(query, conn) < 0 ||
1474 : 397935 : pqPutMsgEnd(conn) < 0)
1475 : : {
1476 : : /* error message should be set up already */
1434 alvherre@alvh.no-ip. 1477 :UBC 0 : pqRecycleCmdQueueEntry(conn, entry);
1478 : 0 : return 0;
1479 : : }
1480 : :
1481 : : /* remember we are using simple query protocol */
1434 alvherre@alvh.no-ip. 1482 :CBC 397935 : entry->queryclass = PGQUERY_SIMPLE;
1483 : : /* and remember the query text too, if possible */
1484 : 397935 : entry->query = strdup(query);
1485 : :
1486 : : /*
1487 : : * Give the data a push. In nonblock mode, don't complain if we're unable
1488 : : * to send it all; PQgetResult() will do any additional flushing needed.
1489 : : */
1490 [ - + ]: 397935 : if (pqFlush(conn) < 0)
1991 alvherre@alvh.no-ip. 1491 :UBC 0 : goto sendFailed;
1492 : :
1493 : : /* OK, it's launched! */
1991 alvherre@alvh.no-ip. 1494 :CBC 397935 : pqAppendCmdQueueEntry(conn, entry);
1495 : :
10340 bruce@momjian.us 1496 : 397935 : return 1;
1497 : :
1991 alvherre@alvh.no-ip. 1498 :UBC 0 : sendFailed:
1499 : 0 : pqRecycleCmdQueueEntry(conn, entry);
1500 : : /* error message should be set up already */
1501 : 0 : return 0;
1502 : : }
1503 : :
1504 : : /*
1505 : : * PQsendQueryParams
1506 : : * Like PQsendQuery, but use extended query protocol so we can pass parameters
1507 : : */
1508 : : int
8468 tgl@sss.pgh.pa.us 1509 :CBC 3274 : PQsendQueryParams(PGconn *conn,
1510 : : const char *command,
1511 : : int nParams,
1512 : : const Oid *paramTypes,
1513 : : const char *const *paramValues,
1514 : : const int *paramLengths,
1515 : : const int *paramFormats,
1516 : : int resultFormat)
1517 : : {
2054 1518 [ + + ]: 3274 : if (!PQsendQueryStart(conn, true))
8415 1519 : 1 : return 0;
1520 : :
1521 : : /* check the arguments */
1522 [ - + ]: 3273 : if (!command)
1523 : : {
1381 peter@eisentraut.org 1524 :UBC 0 : libpq_append_conn_error(conn, "command string is a null pointer");
8415 tgl@sss.pgh.pa.us 1525 : 0 : return 0;
1526 : : }
1906 tomas.vondra@postgre 1527 [ + - - + ]:CBC 3273 : if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT)
1528 : : {
1381 peter@eisentraut.org 1529 :UBC 0 : libpq_append_conn_error(conn, "number of parameters must be between 0 and %d",
1530 : : PQ_QUERY_PARAM_MAX_LIMIT);
5127 heikki.linnakangas@i 1531 : 0 : return 0;
1532 : : }
1533 : :
8415 tgl@sss.pgh.pa.us 1534 :CBC 3273 : return PQsendQueryGuts(conn,
1535 : : command,
1536 : : "", /* use unnamed statement */
1537 : : nParams,
1538 : : paramTypes,
1539 : : paramValues,
1540 : : paramLengths,
1541 : : paramFormats,
1542 : : resultFormat);
1543 : : }
1544 : :
1545 : : /*
1546 : : * PQsendPrepare
1547 : : * Submit a Parse message, but don't wait for it to finish
1548 : : *
1549 : : * Returns: 1 if successfully submitted
1550 : : * 0 if error (conn->errorMessage is set)
1551 : : */
1552 : : int
7983 1553 : 1444 : PQsendPrepare(PGconn *conn,
1554 : : const char *stmtName, const char *query,
1555 : : int nParams, const Oid *paramTypes)
1556 : : {
1991 alvherre@alvh.no-ip. 1557 : 1444 : PGcmdQueueEntry *entry = NULL;
1558 : :
2054 tgl@sss.pgh.pa.us 1559 [ - + ]: 1444 : if (!PQsendQueryStart(conn, true))
7983 tgl@sss.pgh.pa.us 1560 :UBC 0 : return 0;
1561 : :
1562 : : /* check the arguments */
7983 tgl@sss.pgh.pa.us 1563 [ - + ]:CBC 1444 : if (!stmtName)
1564 : : {
1381 peter@eisentraut.org 1565 :UBC 0 : libpq_append_conn_error(conn, "statement name is a null pointer");
7983 tgl@sss.pgh.pa.us 1566 : 0 : return 0;
1567 : : }
7983 tgl@sss.pgh.pa.us 1568 [ - + ]:CBC 1444 : if (!query)
1569 : : {
1381 peter@eisentraut.org 1570 :UBC 0 : libpq_append_conn_error(conn, "command string is a null pointer");
7983 tgl@sss.pgh.pa.us 1571 : 0 : return 0;
1572 : : }
1906 tomas.vondra@postgre 1573 [ + - - + ]:CBC 1444 : if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT)
1574 : : {
1381 peter@eisentraut.org 1575 :UBC 0 : libpq_append_conn_error(conn, "number of parameters must be between 0 and %d",
1576 : : PQ_QUERY_PARAM_MAX_LIMIT);
5127 heikki.linnakangas@i 1577 : 0 : return 0;
1578 : : }
1579 : :
1991 alvherre@alvh.no-ip. 1580 :CBC 1444 : entry = pqAllocCmdQueueEntry(conn);
1581 [ - + ]: 1444 : if (entry == NULL)
1991 alvherre@alvh.no-ip. 1582 :UBC 0 : return 0; /* error msg already set */
1583 : :
1584 : : /* construct the Parse message */
1101 nathan@postgresql.or 1585 [ + - + - ]:CBC 2888 : if (pqPutMsgStart(PqMsg_Parse, conn) < 0 ||
7983 tgl@sss.pgh.pa.us 1586 [ - + ]: 2888 : pqPuts(stmtName, conn) < 0 ||
1587 : 1444 : pqPuts(query, conn) < 0)
7983 tgl@sss.pgh.pa.us 1588 :UBC 0 : goto sendFailed;
1589 : :
7983 tgl@sss.pgh.pa.us 1590 [ + + + + ]:CBC 1444 : if (nParams > 0 && paramTypes)
1591 : 3 : {
1592 : : int i;
1593 : :
1594 [ - + ]: 3 : if (pqPutInt(nParams, 2, conn) < 0)
7983 tgl@sss.pgh.pa.us 1595 :UBC 0 : goto sendFailed;
7983 tgl@sss.pgh.pa.us 1596 [ + + ]:CBC 8 : for (i = 0; i < nParams; i++)
1597 : : {
1598 [ - + ]: 5 : if (pqPutInt(paramTypes[i], 4, conn) < 0)
7983 tgl@sss.pgh.pa.us 1599 :UBC 0 : goto sendFailed;
1600 : : }
1601 : : }
1602 : : else
1603 : : {
7983 tgl@sss.pgh.pa.us 1604 [ - + ]:CBC 1441 : if (pqPutInt(0, 2, conn) < 0)
7983 tgl@sss.pgh.pa.us 1605 :UBC 0 : goto sendFailed;
1606 : : }
7983 tgl@sss.pgh.pa.us 1607 [ - + ]:CBC 1444 : if (pqPutMsgEnd(conn) < 0)
7983 tgl@sss.pgh.pa.us 1608 :UBC 0 : goto sendFailed;
1609 : :
1610 : : /* Add a Sync, unless in pipeline mode. */
1991 alvherre@alvh.no-ip. 1611 [ + + ]:CBC 1444 : if (conn->pipelineStatus == PQ_PIPELINE_OFF)
1612 : : {
1101 nathan@postgresql.or 1613 [ + - - + ]: 2794 : if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
1991 alvherre@alvh.no-ip. 1614 : 1397 : pqPutMsgEnd(conn) < 0)
1991 alvherre@alvh.no-ip. 1615 :UBC 0 : goto sendFailed;
1616 : : }
1617 : :
1618 : : /* remember we are doing just a Parse */
1991 alvherre@alvh.no-ip. 1619 :CBC 1444 : entry->queryclass = PGQUERY_PREPARE;
1620 : :
1621 : : /* and remember the query text too, if possible */
1622 : : /* if insufficient memory, query just winds up NULL */
1623 : 1444 : entry->query = strdup(query);
1624 : :
1625 : : /*
1626 : : * Give the data a push (in pipeline mode, only if we're past the size
1627 : : * threshold). In nonblock mode, don't complain if we're unable to send
1628 : : * it all; PQgetResult() will do any additional flushing needed.
1629 : : */
1630 [ - + ]: 1444 : if (pqPipelineFlush(conn) < 0)
7983 tgl@sss.pgh.pa.us 1631 :UBC 0 : goto sendFailed;
1632 : :
1633 : : /* OK, it's launched! */
1875 alvherre@alvh.no-ip. 1634 :CBC 1444 : pqAppendCmdQueueEntry(conn, entry);
1635 : :
7983 tgl@sss.pgh.pa.us 1636 : 1444 : return 1;
1637 : :
7983 tgl@sss.pgh.pa.us 1638 :UBC 0 : sendFailed:
1991 alvherre@alvh.no-ip. 1639 : 0 : pqRecycleCmdQueueEntry(conn, entry);
1640 : : /* error message should be set up already */
7983 tgl@sss.pgh.pa.us 1641 : 0 : return 0;
1642 : : }
1643 : :
1644 : : /*
1645 : : * PQsendQueryPrepared
1646 : : * Like PQsendQuery, but execute a previously prepared statement,
1647 : : * using extended query protocol so we can pass parameters
1648 : : */
1649 : : int
8415 tgl@sss.pgh.pa.us 1650 :CBC 9169 : PQsendQueryPrepared(PGconn *conn,
1651 : : const char *stmtName,
1652 : : int nParams,
1653 : : const char *const *paramValues,
1654 : : const int *paramLengths,
1655 : : const int *paramFormats,
1656 : : int resultFormat)
1657 : : {
2054 1658 [ - + ]: 9169 : if (!PQsendQueryStart(conn, true))
8468 tgl@sss.pgh.pa.us 1659 :UBC 0 : return 0;
1660 : :
1661 : : /* check the arguments */
8415 tgl@sss.pgh.pa.us 1662 [ - + ]:CBC 9169 : if (!stmtName)
1663 : : {
1381 peter@eisentraut.org 1664 :UBC 0 : libpq_append_conn_error(conn, "statement name is a null pointer");
8468 tgl@sss.pgh.pa.us 1665 : 0 : return 0;
1666 : : }
1906 tomas.vondra@postgre 1667 [ + - - + ]:CBC 9169 : if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT)
1668 : : {
1381 peter@eisentraut.org 1669 :UBC 0 : libpq_append_conn_error(conn, "number of parameters must be between 0 and %d",
1670 : : PQ_QUERY_PARAM_MAX_LIMIT);
5127 heikki.linnakangas@i 1671 : 0 : return 0;
1672 : : }
1673 : :
8415 tgl@sss.pgh.pa.us 1674 :CBC 9169 : return PQsendQueryGuts(conn,
1675 : : NULL, /* no command to parse */
1676 : : stmtName,
1677 : : nParams,
1678 : : NULL, /* no param types */
1679 : : paramValues,
1680 : : paramLengths,
1681 : : paramFormats,
1682 : : resultFormat);
1683 : : }
1684 : :
1685 : : /*
1686 : : * PQsendQueryStart
1687 : : * Common startup code for PQsendQuery and sibling routines
1688 : : */
1689 : : static bool
2054 1690 : 411914 : PQsendQueryStart(PGconn *conn, bool newQuery)
1691 : : {
8415 1692 [ - + ]: 411914 : if (!conn)
8415 tgl@sss.pgh.pa.us 1693 :UBC 0 : return false;
1694 : :
1695 : : /*
1696 : : * If this is the beginning of a query cycle, reset the error state.
1697 : : * However, in pipeline mode with something already queued, the error
1698 : : * buffer belongs to that command and we shouldn't clear it.
1699 : : */
1641 tgl@sss.pgh.pa.us 1700 [ + - + + ]:CBC 411914 : if (newQuery && conn->cmd_queue_head == NULL)
1651 1701 : 409742 : pqClearConnErrorState(conn);
1702 : :
1703 : : /* Don't try to send if we know there's no live connection. */
8415 1704 [ + + ]: 411914 : if (conn->status != CONNECTION_OK)
1705 : : {
1381 peter@eisentraut.org 1706 : 2 : libpq_append_conn_error(conn, "no connection to the server");
8415 tgl@sss.pgh.pa.us 1707 : 2 : return false;
1708 : : }
1709 : :
1710 : : /* Can't send while already busy, either, unless enqueuing for later */
1991 alvherre@alvh.no-ip. 1711 [ + + ]: 411912 : if (conn->asyncStatus != PGASYNC_IDLE &&
1712 [ - + ]: 2172 : conn->pipelineStatus == PQ_PIPELINE_OFF)
1713 : : {
1381 peter@eisentraut.org 1714 :UBC 0 : libpq_append_conn_error(conn, "another command is already in progress");
8415 tgl@sss.pgh.pa.us 1715 : 0 : return false;
1716 : : }
1717 : :
1991 alvherre@alvh.no-ip. 1718 [ + + ]:CBC 411912 : if (conn->pipelineStatus != PQ_PIPELINE_OFF)
1719 : : {
1720 : : /*
1721 : : * When enqueuing commands we don't change much of the connection
1722 : : * state since it's already in use for the current command. The
1723 : : * connection state will get updated when pqPipelineProcessQueue()
1724 : : * advances to start processing the queued message.
1725 : : *
1726 : : * Just make sure we can safely enqueue given the current connection
1727 : : * state. We can enqueue behind another queue item, or behind a
1728 : : * non-queue command (one that sends its own sync), but we can't
1729 : : * enqueue if the connection is in a copy state.
1730 : : */
1731 [ + - - ]: 2468 : switch (conn->asyncStatus)
1732 : : {
1733 : 2468 : case PGASYNC_IDLE:
1734 : : case PGASYNC_PIPELINE_IDLE:
1735 : : case PGASYNC_READY:
1736 : : case PGASYNC_READY_MORE:
1737 : : case PGASYNC_BUSY:
1738 : : /* ok to queue */
1739 : 2468 : break;
1740 : :
1991 alvherre@alvh.no-ip. 1741 :UBC 0 : case PGASYNC_COPY_IN:
1742 : : case PGASYNC_COPY_OUT:
1743 : : case PGASYNC_COPY_BOTH:
1381 peter@eisentraut.org 1744 : 0 : libpq_append_conn_error(conn, "cannot queue commands during COPY");
1991 alvherre@alvh.no-ip. 1745 : 0 : return false;
1746 : : }
1747 : : }
1748 : : else
1749 : : {
1750 : : /*
1751 : : * This command's results will come in immediately. Initialize async
1752 : : * result-accumulation state
1753 : : */
1991 alvherre@alvh.no-ip. 1754 :CBC 409444 : pqClearAsyncResult(conn);
1755 : :
1756 : : /* reset partial-result mode */
873 tgl@sss.pgh.pa.us 1757 : 409444 : conn->partialResMode = false;
1991 alvherre@alvh.no-ip. 1758 : 409444 : conn->singleRowMode = false;
873 tgl@sss.pgh.pa.us 1759 : 409444 : conn->maxChunkSize = 0;
1760 : : }
1761 : :
1762 : : /* ready to send command message */
8415 1763 : 411912 : return true;
1764 : : }
1765 : :
1766 : : /*
1767 : : * PQsendQueryGuts
1768 : : * Common code for sending a query with extended query protocol
1769 : : * PQsendQueryStart should be done already
1770 : : *
1771 : : * command may be NULL to indicate we use an already-prepared statement
1772 : : */
1773 : : static int
1774 : 12442 : PQsendQueryGuts(PGconn *conn,
1775 : : const char *command,
1776 : : const char *stmtName,
1777 : : int nParams,
1778 : : const Oid *paramTypes,
1779 : : const char *const *paramValues,
1780 : : const int *paramLengths,
1781 : : const int *paramFormats,
1782 : : int resultFormat)
1783 : : {
1784 : : int i;
1785 : : PGcmdQueueEntry *entry;
1786 : :
1991 alvherre@alvh.no-ip. 1787 : 12442 : entry = pqAllocCmdQueueEntry(conn);
1788 [ - + ]: 12442 : if (entry == NULL)
1991 alvherre@alvh.no-ip. 1789 :UBC 0 : return 0; /* error msg already set */
1790 : :
1791 : : /*
1792 : : * We will send Parse (if needed), Bind, Describe Portal, Execute, Sync
1793 : : * (if not in pipeline mode), using specified statement name and the
1794 : : * unnamed portal.
1795 : : */
1796 : :
8415 tgl@sss.pgh.pa.us 1797 [ + + ]:CBC 12442 : if (command)
1798 : : {
1799 : : /* construct the Parse message */
1101 nathan@postgresql.or 1800 [ + - + - ]: 6546 : if (pqPutMsgStart(PqMsg_Parse, conn) < 0 ||
8415 tgl@sss.pgh.pa.us 1801 [ - + ]: 6546 : pqPuts(stmtName, conn) < 0 ||
1802 : 3273 : pqPuts(command, conn) < 0)
8468 tgl@sss.pgh.pa.us 1803 :UBC 0 : goto sendFailed;
8415 tgl@sss.pgh.pa.us 1804 [ + + + + ]:CBC 3273 : if (nParams > 0 && paramTypes)
1805 : : {
1806 [ - + ]: 44 : if (pqPutInt(nParams, 2, conn) < 0)
8468 tgl@sss.pgh.pa.us 1807 :UBC 0 : goto sendFailed;
8415 tgl@sss.pgh.pa.us 1808 [ + + ]:CBC 112 : for (i = 0; i < nParams; i++)
1809 : : {
1810 [ - + ]: 68 : if (pqPutInt(paramTypes[i], 4, conn) < 0)
8415 tgl@sss.pgh.pa.us 1811 :UBC 0 : goto sendFailed;
1812 : : }
1813 : : }
1814 : : else
1815 : : {
8415 tgl@sss.pgh.pa.us 1816 [ - + ]:CBC 3229 : if (pqPutInt(0, 2, conn) < 0)
8415 tgl@sss.pgh.pa.us 1817 :UBC 0 : goto sendFailed;
1818 : : }
8415 tgl@sss.pgh.pa.us 1819 [ - + ]:CBC 3273 : if (pqPutMsgEnd(conn) < 0)
8468 tgl@sss.pgh.pa.us 1820 :UBC 0 : goto sendFailed;
1821 : : }
1822 : :
1823 : : /* Construct the Bind message */
1101 nathan@postgresql.or 1824 [ + - + - ]:CBC 24884 : if (pqPutMsgStart(PqMsg_Bind, conn) < 0 ||
8468 tgl@sss.pgh.pa.us 1825 [ - + ]: 24884 : pqPuts("", conn) < 0 ||
8415 1826 : 12442 : pqPuts(stmtName, conn) < 0)
8468 tgl@sss.pgh.pa.us 1827 :UBC 0 : goto sendFailed;
1828 : :
1829 : : /* Send parameter formats */
8468 tgl@sss.pgh.pa.us 1830 [ + + + + ]:CBC 12442 : if (nParams > 0 && paramFormats)
1831 : : {
1832 [ - + ]: 1284 : if (pqPutInt(nParams, 2, conn) < 0)
8468 tgl@sss.pgh.pa.us 1833 :UBC 0 : goto sendFailed;
8468 tgl@sss.pgh.pa.us 1834 [ + + ]:CBC 3028 : for (i = 0; i < nParams; i++)
1835 : : {
1836 [ - + ]: 1744 : if (pqPutInt(paramFormats[i], 2, conn) < 0)
8468 tgl@sss.pgh.pa.us 1837 :UBC 0 : goto sendFailed;
1838 : : }
1839 : : }
1840 : : else
1841 : : {
8468 tgl@sss.pgh.pa.us 1842 [ - + ]:CBC 11158 : if (pqPutInt(0, 2, conn) < 0)
8468 tgl@sss.pgh.pa.us 1843 :UBC 0 : goto sendFailed;
1844 : : }
1845 : :
8468 tgl@sss.pgh.pa.us 1846 [ - + ]:CBC 12442 : if (pqPutInt(nParams, 2, conn) < 0)
8468 tgl@sss.pgh.pa.us 1847 :UBC 0 : goto sendFailed;
1848 : :
1849 : : /* Send parameters */
8468 tgl@sss.pgh.pa.us 1850 [ + + ]:CBC 27926 : for (i = 0; i < nParams; i++)
1851 : : {
1852 [ + - + + ]: 15484 : if (paramValues && paramValues[i])
1853 : 14887 : {
1854 : : int nbytes;
1855 : :
1856 [ + + + + ]: 14887 : if (paramFormats && paramFormats[i] != 0)
1857 : : {
1858 : : /* binary parameter */
7749 1859 [ + - ]: 13 : if (paramLengths)
1860 : 13 : nbytes = paramLengths[i];
1861 : : else
1862 : : {
1381 peter@eisentraut.org 1863 :UBC 0 : libpq_append_conn_error(conn, "length must be given for binary parameter");
7749 tgl@sss.pgh.pa.us 1864 : 0 : goto sendFailed;
1865 : : }
1866 : : }
1867 : : else
1868 : : {
1869 : : /* text parameter, do not use paramLengths */
8468 tgl@sss.pgh.pa.us 1870 :CBC 14874 : nbytes = strlen(paramValues[i]);
1871 : : }
1872 [ + - - + ]: 29774 : if (pqPutInt(nbytes, 4, conn) < 0 ||
1873 : 14887 : pqPutnchar(paramValues[i], nbytes, conn) < 0)
8468 tgl@sss.pgh.pa.us 1874 :UBC 0 : goto sendFailed;
1875 : : }
1876 : : else
1877 : : {
1878 : : /* take the param as NULL */
8468 tgl@sss.pgh.pa.us 1879 [ - + ]:CBC 597 : if (pqPutInt(-1, 4, conn) < 0)
8468 tgl@sss.pgh.pa.us 1880 :UBC 0 : goto sendFailed;
1881 : : }
1882 : : }
8468 tgl@sss.pgh.pa.us 1883 [ + - - + ]:CBC 24884 : if (pqPutInt(1, 2, conn) < 0 ||
1884 : 12442 : pqPutInt(resultFormat, 2, conn))
8468 tgl@sss.pgh.pa.us 1885 :UBC 0 : goto sendFailed;
8468 tgl@sss.pgh.pa.us 1886 [ - + ]:CBC 12442 : if (pqPutMsgEnd(conn) < 0)
8468 tgl@sss.pgh.pa.us 1887 :UBC 0 : goto sendFailed;
1888 : :
1889 : : /* construct the Describe Portal message */
1101 nathan@postgresql.or 1890 [ + - + - ]:CBC 24884 : if (pqPutMsgStart(PqMsg_Describe, conn) < 0 ||
8468 tgl@sss.pgh.pa.us 1891 [ + - ]: 24884 : pqPutc('P', conn) < 0 ||
1892 [ - + ]: 24884 : pqPuts("", conn) < 0 ||
1893 : 12442 : pqPutMsgEnd(conn) < 0)
8468 tgl@sss.pgh.pa.us 1894 :UBC 0 : goto sendFailed;
1895 : :
1896 : : /* construct the Execute message */
1101 nathan@postgresql.or 1897 [ + - + - ]:CBC 24884 : if (pqPutMsgStart(PqMsg_Execute, conn) < 0 ||
8468 tgl@sss.pgh.pa.us 1898 [ + - ]: 24884 : pqPuts("", conn) < 0 ||
1899 [ - + ]: 24884 : pqPutInt(0, 4, conn) < 0 ||
1900 : 12442 : pqPutMsgEnd(conn) < 0)
8468 tgl@sss.pgh.pa.us 1901 :UBC 0 : goto sendFailed;
1902 : :
1903 : : /* construct the Sync message if not in pipeline mode */
1991 alvherre@alvh.no-ip. 1904 [ + + ]:CBC 12442 : if (conn->pipelineStatus == PQ_PIPELINE_OFF)
1905 : : {
1101 nathan@postgresql.or 1906 [ + - - + ]: 20076 : if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
1991 alvherre@alvh.no-ip. 1907 : 10038 : pqPutMsgEnd(conn) < 0)
1991 alvherre@alvh.no-ip. 1908 :UBC 0 : goto sendFailed;
1909 : : }
1910 : :
1911 : : /* remember we are using extended query protocol */
1991 alvherre@alvh.no-ip. 1912 :CBC 12442 : entry->queryclass = PGQUERY_EXTENDED;
1913 : :
1914 : : /* and remember the query text too, if possible */
1915 : : /* if insufficient memory, query just winds up NULL */
7471 tgl@sss.pgh.pa.us 1916 [ + + ]: 12442 : if (command)
1991 alvherre@alvh.no-ip. 1917 : 3273 : entry->query = strdup(command);
1918 : :
1919 : : /*
1920 : : * Give the data a push (in pipeline mode, only if we're past the size
1921 : : * threshold). In nonblock mode, don't complain if we're unable to send
1922 : : * it all; PQgetResult() will do any additional flushing needed.
1923 : : */
1924 [ - + ]: 12442 : if (pqPipelineFlush(conn) < 0)
8468 tgl@sss.pgh.pa.us 1925 :UBC 0 : goto sendFailed;
1926 : :
1927 : : /* OK, it's launched! */
1991 alvherre@alvh.no-ip. 1928 :CBC 12442 : pqAppendCmdQueueEntry(conn, entry);
1929 : :
8468 tgl@sss.pgh.pa.us 1930 : 12442 : return 1;
1931 : :
8468 tgl@sss.pgh.pa.us 1932 :UBC 0 : sendFailed:
1991 alvherre@alvh.no-ip. 1933 : 0 : pqRecycleCmdQueueEntry(conn, entry);
1934 : : /* error message should be set up already */
8468 tgl@sss.pgh.pa.us 1935 : 0 : return 0;
1936 : : }
1937 : :
1938 : : /*
1939 : : * Is it OK to change partial-result mode now?
1940 : : */
1941 : : static bool
873 tgl@sss.pgh.pa.us 1942 :CBC 103 : canChangeResultMode(PGconn *conn)
1943 : : {
1944 : : /*
1945 : : * Only allow changing the mode when we have launched a query and not yet
1946 : : * received any results.
1947 : : */
5138 1948 [ - + ]: 103 : if (!conn)
873 tgl@sss.pgh.pa.us 1949 :UBC 0 : return false;
5138 tgl@sss.pgh.pa.us 1950 [ + + ]:CBC 103 : if (conn->asyncStatus != PGASYNC_BUSY)
873 1951 : 4 : return false;
1991 alvherre@alvh.no-ip. 1952 [ + - ]: 99 : if (!conn->cmd_queue_head ||
1953 [ + + ]: 99 : (conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE &&
1954 [ - + ]: 23 : conn->cmd_queue_head->queryclass != PGQUERY_EXTENDED))
873 tgl@sss.pgh.pa.us 1955 :UBC 0 : return false;
1589 tgl@sss.pgh.pa.us 1956 [ + - - + ]:CBC 99 : if (pgHavePendingResult(conn))
873 tgl@sss.pgh.pa.us 1957 :UBC 0 : return false;
873 tgl@sss.pgh.pa.us 1958 :CBC 99 : return true;
1959 : : }
1960 : :
1961 : : /*
1962 : : * Select row-by-row processing mode
1963 : : */
1964 : : int
1965 : 33 : PQsetSingleRowMode(PGconn *conn)
1966 : : {
1967 [ + - ]: 33 : if (canChangeResultMode(conn))
1968 : : {
1969 : 33 : conn->partialResMode = true;
1970 : 33 : conn->singleRowMode = true;
1971 : 33 : conn->maxChunkSize = 1;
1972 : 33 : return 1;
1973 : : }
1974 : : else
5138 tgl@sss.pgh.pa.us 1975 :UBC 0 : return 0;
1976 : : }
1977 : :
1978 : : /*
1979 : : * Select chunked results processing mode
1980 : : */
1981 : : int
873 tgl@sss.pgh.pa.us 1982 :CBC 70 : PQsetChunkedRowsMode(PGconn *conn, int chunkSize)
1983 : : {
1984 [ + - + + ]: 70 : if (chunkSize > 0 && canChangeResultMode(conn))
1985 : : {
1986 : 66 : conn->partialResMode = true;
1987 : 66 : conn->singleRowMode = false;
1988 : 66 : conn->maxChunkSize = chunkSize;
1989 : 66 : return 1;
1990 : : }
1991 : : else
1992 : 4 : return 0;
1993 : : }
1994 : :
1995 : : /*
1996 : : * Consume any available input from the backend
1997 : : * 0 return: some kind of trouble
1998 : : * 1 return: no problem
1999 : : */
2000 : : int
10340 bruce@momjian.us 2001 : 591552 : PQconsumeInput(PGconn *conn)
2002 : : {
2003 [ - + ]: 591552 : if (!conn)
10220 bruce@momjian.us 2004 :UBC 0 : return 0;
2005 : :
2006 : : /*
2007 : : * for non-blocking connections try to flush the send-queue, otherwise we
2008 : : * may never get a response for something that may not have already been
2009 : : * sent because it's in our write buffer!
2010 : : */
8531 tgl@sss.pgh.pa.us 2011 [ + + ]:CBC 591552 : if (pqIsnonblocking(conn))
2012 : : {
2013 [ - + ]: 7 : if (pqFlush(conn) < 0)
8531 tgl@sss.pgh.pa.us 2014 :UBC 0 : return 0;
2015 : : }
2016 : :
2017 : : /*
2018 : : * Load more data, if available. We do this no matter what state we are
2019 : : * in, since we are probably getting called because the application wants
2020 : : * to get rid of a read-select condition. Note that we will NOT block
2021 : : * waiting for more input.
2022 : : */
10192 tgl@sss.pgh.pa.us 2023 [ + + ]:CBC 591552 : if (pqReadData(conn) < 0)
10220 bruce@momjian.us 2024 : 111 : return 0;
2025 : :
2026 : : /* Parsing of the data waits till later. */
2027 : 591441 : return 1;
2028 : : }
2029 : :
2030 : :
2031 : : /*
2032 : : * parseInput: if appropriate, parse input data from backend
2033 : : * until input is exhausted or a stopping state is reached.
2034 : : * Note that this function will NOT attempt to read more data from the backend.
2035 : : */
2036 : : static void
10340 2037 : 2179898 : parseInput(PGconn *conn)
2038 : : {
2002 heikki.linnakangas@i 2039 : 2179898 : pqParseInput3(conn);
11006 scrappy@hub.org 2040 : 2179898 : }
2041 : :
2042 : : /*
2043 : : * PQisBusy
2044 : : * Return true if PQgetResult would block waiting for input.
2045 : : */
2046 : :
2047 : : int
10340 bruce@momjian.us 2048 : 161713 : PQisBusy(PGconn *conn)
2049 : : {
10581 2050 [ - + ]: 161713 : if (!conn)
3298 peter_e@gmx.net 2051 :UBC 0 : return false;
2052 : :
2053 : : /* Parse any available data, if our state permits. */
10340 bruce@momjian.us 2054 :CBC 161713 : parseInput(conn);
2055 : :
2056 : : /*
2057 : : * PQgetResult will return immediately in all states except BUSY. Also,
2058 : : * if we've detected read EOF and dropped the connection, we can expect
2059 : : * that PQgetResult will fail immediately. Note that we do *not* check
2060 : : * conn->write_failed here --- once that's become set, we know we have
2061 : : * trouble, but we need to keep trying to read until we have a complete
2062 : : * server message or detect read EOF.
2063 : : */
1657 tgl@sss.pgh.pa.us 2064 [ + + + - ]: 161713 : return conn->asyncStatus == PGASYNC_BUSY && conn->status != CONNECTION_BAD;
2065 : : }
2066 : :
2067 : : /*
2068 : : * PQgetResult
2069 : : * Get the next PGresult produced by a query. Returns NULL if no
2070 : : * query work remains or an error has occurred (e.g. out of
2071 : : * memory).
2072 : : *
2073 : : * In pipeline mode, once all the result of a query have been returned,
2074 : : * PQgetResult returns NULL to let the user know that the next
2075 : : * query is being processed. At the end of the pipeline, returns a
2076 : : * result with PQresultStatus(result) == PGRES_PIPELINE_SYNC.
2077 : : */
2078 : : PGresult *
10340 bruce@momjian.us 2079 : 973068 : PQgetResult(PGconn *conn)
2080 : : {
2081 : : PGresult *res;
2082 : :
2083 [ - + ]: 973068 : if (!conn)
10340 bruce@momjian.us 2084 :UBC 0 : return NULL;
2085 : :
2086 : : /* Parse any available data, if our state permits. */
10340 bruce@momjian.us 2087 :CBC 973068 : parseInput(conn);
2088 : :
2089 : : /* If not ready to return something, block until we are. */
2090 [ + + ]: 1389941 : while (conn->asyncStatus == PGASYNC_BUSY)
2091 : : {
2092 : : int flushResult;
2093 : :
2094 : : /*
2095 : : * If data remains unsent, send it. Else we might be waiting for the
2096 : : * result of a command the backend hasn't even got yet.
2097 : : */
8468 tgl@sss.pgh.pa.us 2098 [ - + ]: 416944 : while ((flushResult = pqFlush(conn)) > 0)
2099 : : {
3298 peter_e@gmx.net 2100 [ # # ]:UBC 0 : if (pqWait(false, true, conn))
2101 : : {
8468 tgl@sss.pgh.pa.us 2102 : 0 : flushResult = -1;
2103 : 0 : break;
2104 : : }
2105 : : }
2106 : :
2107 : : /*
2108 : : * Wait for some more data, and load it. (Note: if the connection has
2109 : : * been lost, pqWait should return immediately because the socket
2110 : : * should be read-ready, either with the last server data or with an
2111 : : * EOF indication. We expect therefore that this won't result in any
2112 : : * undue delay in reporting a previous write failure.)
2113 : : */
8468 tgl@sss.pgh.pa.us 2114 [ + - + + ]:CBC 833888 : if (flushResult ||
3298 peter_e@gmx.net 2115 [ + + ]: 833836 : pqWait(true, false, conn) ||
10340 bruce@momjian.us 2116 : 416892 : pqReadData(conn) < 0)
2117 : : {
2118 : : /* Report the error saved by pqWait or pqReadData */
8481 tgl@sss.pgh.pa.us 2119 : 67 : pqSaveErrorResult(conn);
10340 bruce@momjian.us 2120 : 67 : conn->asyncStatus = PGASYNC_IDLE;
8481 tgl@sss.pgh.pa.us 2121 : 67 : return pqPrepareAsyncResult(conn);
2122 : : }
2123 : :
2124 : : /* Parse it. */
10340 bruce@momjian.us 2125 : 416877 : parseInput(conn);
2126 : :
2127 : : /*
2128 : : * If we had a write error, but nothing above obtained a query result
2129 : : * or detected a read error, report the write error.
2130 : : */
2718 tgl@sss.pgh.pa.us 2131 [ + + + - ]: 416877 : if (conn->write_failed && conn->asyncStatus == PGASYNC_BUSY)
2132 : : {
2133 : 4 : pqSaveWriteError(conn);
2134 : 4 : conn->asyncStatus = PGASYNC_IDLE;
2135 : 4 : return pqPrepareAsyncResult(conn);
2136 : : }
2137 : : }
2138 : :
2139 : : /* Return the appropriate thing. */
10340 bruce@momjian.us 2140 [ + + + + : 972997 : switch (conn->asyncStatus)
+ + + - ]
2141 : : {
2142 : 527643 : case PGASYNC_IDLE:
2143 : 527643 : res = NULL; /* query is complete */
2144 : 527643 : break;
1514 alvherre@alvh.no-ip. 2145 : 2491 : case PGASYNC_PIPELINE_IDLE:
2146 [ - + ]: 2491 : Assert(conn->pipelineStatus != PQ_PIPELINE_OFF);
2147 : :
2148 : : /*
2149 : : * We're about to return the NULL that terminates the round of
2150 : : * results from the current query; prepare to send the results of
2151 : : * the next query, if any, when we're called next. If there's no
2152 : : * next element in the command queue, this gets us in IDLE state.
2153 : : */
2154 : 2491 : pqPipelineProcessQueue(conn);
2155 : 2491 : res = NULL; /* query is complete */
2156 : 2491 : break;
2157 : :
10340 bruce@momjian.us 2158 : 433187 : case PGASYNC_READY:
1991 alvherre@alvh.no-ip. 2159 : 433187 : res = pqPrepareAsyncResult(conn);
2160 : :
2161 : : /*
2162 : : * Normally pqPrepareAsyncResult will have left conn->result
2163 : : * empty. Otherwise, "res" must be a not-full PGRES_TUPLES_CHUNK
2164 : : * result, which we want to return to the caller while staying in
2165 : : * PGASYNC_READY state. Then the next call here will return the
2166 : : * empty PGRES_TUPLES_OK result that was restored from
2167 : : * saved_result, after which we can proceed.
2168 : : */
873 tgl@sss.pgh.pa.us 2169 [ + + ]: 433187 : if (conn->result)
2170 : : {
2171 [ - + ]: 13 : Assert(res->resultStatus == PGRES_TUPLES_CHUNK);
2172 : 13 : break;
2173 : : }
2174 : :
2175 : : /* Advance the queue as appropriate */
996 alvherre@alvh.no-ip. 2176 : 433174 : pqCommandQueueAdvance(conn, false,
2177 : 433174 : res->resultStatus == PGRES_PIPELINE_SYNC);
2178 : :
1991 2179 [ + + ]: 433174 : if (conn->pipelineStatus != PQ_PIPELINE_OFF)
2180 : : {
2181 : : /*
2182 : : * We're about to send the results of the current query. Set
2183 : : * us idle now, and ...
2184 : : */
1514 2185 : 2877 : conn->asyncStatus = PGASYNC_PIPELINE_IDLE;
2186 : :
2187 : : /*
2188 : : * ... in cases when we're sending a pipeline-sync result,
2189 : : * move queue processing forwards immediately, so that next
2190 : : * time we're called, we're prepared to return the next result
2191 : : * received from the server. In all other cases, leave the
2192 : : * queue state change for next time, so that a terminating
2193 : : * NULL result is sent.
2194 : : *
2195 : : * (In other words: we don't return a NULL after a pipeline
2196 : : * sync.)
2197 : : */
954 2198 [ + + ]: 2877 : if (res->resultStatus == PGRES_PIPELINE_SYNC)
1991 2199 : 385 : pqPipelineProcessQueue(conn);
2200 : : }
2201 : : else
2202 : : {
2203 : : /* Set the state back to BUSY, allowing parsing to proceed. */
2204 : 430297 : conn->asyncStatus = PGASYNC_BUSY;
2205 : : }
2206 : 433174 : break;
2207 : 2598 : case PGASYNC_READY_MORE:
8481 tgl@sss.pgh.pa.us 2208 : 2598 : res = pqPrepareAsyncResult(conn);
2209 : : /* Set the state back to BUSY, allowing parsing to proceed. */
10340 bruce@momjian.us 2210 : 2598 : conn->asyncStatus = PGASYNC_BUSY;
2211 : 2598 : break;
2212 : 731 : case PGASYNC_COPY_IN:
4579 tgl@sss.pgh.pa.us 2213 : 731 : res = getCopyResult(conn, PGRES_COPY_IN);
10340 bruce@momjian.us 2214 : 731 : break;
2215 : 5532 : case PGASYNC_COPY_OUT:
4579 tgl@sss.pgh.pa.us 2216 : 5532 : res = getCopyResult(conn, PGRES_COPY_OUT);
10340 bruce@momjian.us 2217 : 5532 : break;
5738 rhaas@postgresql.org 2218 : 815 : case PGASYNC_COPY_BOTH:
4579 tgl@sss.pgh.pa.us 2219 : 815 : res = getCopyResult(conn, PGRES_COPY_BOTH);
5738 rhaas@postgresql.org 2220 : 815 : break;
10340 bruce@momjian.us 2221 :UBC 0 : default:
1381 peter@eisentraut.org 2222 : 0 : libpq_append_conn_error(conn, "unexpected asyncStatus: %d", (int) conn->asyncStatus);
1651 tgl@sss.pgh.pa.us 2223 : 0 : pqSaveErrorResult(conn);
2224 : 0 : conn->asyncStatus = PGASYNC_IDLE; /* try to restore valid state */
2225 : 0 : res = pqPrepareAsyncResult(conn);
10340 bruce@momjian.us 2226 : 0 : break;
2227 : : }
2228 : :
2229 : : /* Time to fire PGEVT_RESULTCREATE events, if there are any */
1651 tgl@sss.pgh.pa.us 2230 [ + + - + ]:CBC 972997 : if (res && res->nEvents > 0)
1651 tgl@sss.pgh.pa.us 2231 :UBC 0 : (void) PQfireResultCreateEvents(conn, res);
2232 : :
10340 bruce@momjian.us 2233 :CBC 972997 : return res;
2234 : : }
2235 : :
2236 : : /*
2237 : : * getCopyResult
2238 : : * Helper for PQgetResult: generate result for COPY-in-progress cases
2239 : : */
2240 : : static PGresult *
4579 tgl@sss.pgh.pa.us 2241 : 7078 : getCopyResult(PGconn *conn, ExecStatusType copytype)
2242 : : {
2243 : : /*
2244 : : * If the server connection has been lost, don't pretend everything is
2245 : : * hunky-dory; instead return a PGRES_FATAL_ERROR result, and reset the
2246 : : * asyncStatus to idle (corresponding to what we'd do if we'd detected I/O
2247 : : * error in the earlier steps in PQgetResult). The text returned in the
2248 : : * result is whatever is in conn->errorMessage; we hope that was filled
2249 : : * with something relevant when the lost connection was detected.
2250 : : */
2251 [ - + ]: 7078 : if (conn->status != CONNECTION_OK)
2252 : : {
4579 tgl@sss.pgh.pa.us 2253 :UBC 0 : pqSaveErrorResult(conn);
2254 : 0 : conn->asyncStatus = PGASYNC_IDLE;
2255 : 0 : return pqPrepareAsyncResult(conn);
2256 : : }
2257 : :
2258 : : /* If we have an async result for the COPY, return that */
4579 tgl@sss.pgh.pa.us 2259 [ + + + - ]:CBC 7078 : if (conn->result && conn->result->resultStatus == copytype)
2260 : 6852 : return pqPrepareAsyncResult(conn);
2261 : :
2262 : : /* Otherwise, invent a suitable PGresult */
2263 : 226 : return PQmakeEmptyPGresult(conn, copytype);
2264 : : }
2265 : :
2266 : :
2267 : : /*
2268 : : * PQexec
2269 : : * send a query to the backend and package up the result in a PGresult
2270 : : *
2271 : : * If the query was not even sent, return NULL; conn->errorMessage is set to
2272 : : * a relevant message.
2273 : : * If the query was sent, a new PGresult is returned (which could indicate
2274 : : * either success or failure).
2275 : : * The user is responsible for freeing the PGresult via PQclear()
2276 : : * when done with it.
2277 : : */
2278 : : PGresult *
10340 bruce@momjian.us 2279 : 96628 : PQexec(PGconn *conn, const char *query)
2280 : : {
8468 tgl@sss.pgh.pa.us 2281 [ + + ]: 96628 : if (!PQexecStart(conn))
2282 : 1 : return NULL;
2283 [ - + ]: 96627 : if (!PQsendQuery(conn, query))
8468 tgl@sss.pgh.pa.us 2284 :UBC 0 : return NULL;
8468 tgl@sss.pgh.pa.us 2285 :CBC 96627 : return PQexecFinish(conn);
2286 : : }
2287 : :
2288 : : /*
2289 : : * PQexecParams
2290 : : * Like PQexec, but use extended query protocol so we can pass parameters
2291 : : */
2292 : : PGresult *
2293 : 1081 : PQexecParams(PGconn *conn,
2294 : : const char *command,
2295 : : int nParams,
2296 : : const Oid *paramTypes,
2297 : : const char *const *paramValues,
2298 : : const int *paramLengths,
2299 : : const int *paramFormats,
2300 : : int resultFormat)
2301 : : {
2302 [ - + ]: 1081 : if (!PQexecStart(conn))
8468 tgl@sss.pgh.pa.us 2303 :UBC 0 : return NULL;
8468 tgl@sss.pgh.pa.us 2304 [ - + ]:CBC 1081 : if (!PQsendQueryParams(conn, command,
2305 : : nParams, paramTypes, paramValues, paramLengths,
2306 : : paramFormats, resultFormat))
9718 bruce@momjian.us 2307 :UBC 0 : return NULL;
8468 tgl@sss.pgh.pa.us 2308 :CBC 1081 : return PQexecFinish(conn);
2309 : : }
2310 : :
2311 : : /*
2312 : : * PQprepare
2313 : : * Creates a prepared statement by issuing a Parse message.
2314 : : *
2315 : : * If the query was not even sent, return NULL; conn->errorMessage is set to
2316 : : * a relevant message.
2317 : : * If the query was sent, a new PGresult is returned (which could indicate
2318 : : * either success or failure).
2319 : : * The user is responsible for freeing the PGresult via PQclear()
2320 : : * when done with it.
2321 : : */
2322 : : PGresult *
7983 2323 : 1197 : PQprepare(PGconn *conn,
2324 : : const char *stmtName, const char *query,
2325 : : int nParams, const Oid *paramTypes)
2326 : : {
2327 [ + + ]: 1197 : if (!PQexecStart(conn))
2328 : 12 : return NULL;
2329 [ - + ]: 1185 : if (!PQsendPrepare(conn, stmtName, query, nParams, paramTypes))
7983 tgl@sss.pgh.pa.us 2330 :UBC 0 : return NULL;
7983 tgl@sss.pgh.pa.us 2331 :CBC 1185 : return PQexecFinish(conn);
2332 : : }
2333 : :
2334 : : /*
2335 : : * PQexecPrepared
2336 : : * Like PQexec, but execute a previously prepared statement,
2337 : : * using extended query protocol so we can pass parameters
2338 : : */
2339 : : PGresult *
8415 2340 : 4785 : PQexecPrepared(PGconn *conn,
2341 : : const char *stmtName,
2342 : : int nParams,
2343 : : const char *const *paramValues,
2344 : : const int *paramLengths,
2345 : : const int *paramFormats,
2346 : : int resultFormat)
2347 : : {
2348 [ - + ]: 4785 : if (!PQexecStart(conn))
8415 tgl@sss.pgh.pa.us 2349 :UBC 0 : return NULL;
8415 tgl@sss.pgh.pa.us 2350 [ - + ]:CBC 4785 : if (!PQsendQueryPrepared(conn, stmtName,
2351 : : nParams, paramValues, paramLengths,
2352 : : paramFormats, resultFormat))
8415 tgl@sss.pgh.pa.us 2353 :UBC 0 : return NULL;
8415 tgl@sss.pgh.pa.us 2354 :CBC 4785 : return PQexecFinish(conn);
2355 : : }
2356 : :
2357 : : /*
2358 : : * Common code for PQexec and sibling routines: prepare to send command
2359 : : */
2360 : : static bool
8468 2361 : 103752 : PQexecStart(PGconn *conn)
2362 : : {
2363 : : PGresult *result;
2364 : :
2365 [ - + ]: 103752 : if (!conn)
8468 tgl@sss.pgh.pa.us 2366 :UBC 0 : return false;
2367 : :
2368 : : /*
2369 : : * Since this is the beginning of a query cycle, reset the error state.
2370 : : * However, in pipeline mode with something already queued, the error
2371 : : * buffer belongs to that command and we shouldn't clear it.
2372 : : */
1641 tgl@sss.pgh.pa.us 2373 [ + + ]:CBC 103752 : if (conn->cmd_queue_head == NULL)
2374 : 103737 : pqClearConnErrorState(conn);
2375 : :
1991 alvherre@alvh.no-ip. 2376 [ + + ]: 103752 : if (conn->pipelineStatus != PQ_PIPELINE_OFF)
2377 : : {
1381 peter@eisentraut.org 2378 : 13 : libpq_append_conn_error(conn, "synchronous command execution functions are not allowed in pipeline mode");
1991 alvherre@alvh.no-ip. 2379 : 13 : return false;
2380 : : }
2381 : :
2382 : : /*
2383 : : * Silently discard any prior query result that application didn't eat.
2384 : : * This is probably poor design, but it's here for backward compatibility.
2385 : : */
5138 tgl@sss.pgh.pa.us 2386 [ - + ]: 103739 : while ((result = PQgetResult(conn)) != NULL)
2387 : : {
8415 tgl@sss.pgh.pa.us 2388 :UBC 0 : ExecStatusType resultStatus = result->resultStatus;
2389 : :
2390 : 0 : PQclear(result); /* only need its status */
2391 [ # # ]: 0 : if (resultStatus == PGRES_COPY_IN)
2392 : : {
2393 : : /* get out of a COPY IN state */
2002 heikki.linnakangas@i 2394 [ # # ]: 0 : if (PQputCopyEnd(conn,
2395 : 0 : libpq_gettext("COPY terminated by new PQexec")) < 0)
8461 tgl@sss.pgh.pa.us 2396 : 0 : return false;
2397 : : /* keep waiting to swallow the copy's failure message */
2398 : : }
8415 2399 [ # # ]: 0 : else if (resultStatus == PGRES_COPY_OUT)
2400 : : {
2401 : : /*
2402 : : * Get out of a COPY OUT state: we just switch back to BUSY and
2403 : : * allow the remaining COPY data to be dropped on the floor.
2404 : : */
2002 heikki.linnakangas@i 2405 : 0 : conn->asyncStatus = PGASYNC_BUSY;
2406 : : /* keep waiting to swallow the copy's completion message */
2407 : : }
5738 rhaas@postgresql.org 2408 [ # # ]: 0 : else if (resultStatus == PGRES_COPY_BOTH)
2409 : : {
2410 : : /* We don't allow PQexec during COPY BOTH */
1381 peter@eisentraut.org 2411 : 0 : libpq_append_conn_error(conn, "PQexec not allowed during COPY BOTH");
5618 bruce@momjian.us 2412 : 0 : return false;
2413 : : }
2414 : : /* check for loss of connection, too */
8278 tgl@sss.pgh.pa.us 2415 [ # # ]: 0 : if (conn->status == CONNECTION_BAD)
2416 : 0 : return false;
2417 : : }
2418 : :
2419 : : /* OK to send a command */
8468 tgl@sss.pgh.pa.us 2420 :CBC 103739 : return true;
2421 : : }
2422 : :
2423 : : /*
2424 : : * Common code for PQexec and sibling routines: wait for command result
2425 : : */
2426 : : static PGresult *
2427 : 103739 : PQexecFinish(PGconn *conn)
2428 : : {
2429 : : PGresult *result;
2430 : : PGresult *lastResult;
2431 : :
2432 : : /*
2433 : : * For backwards compatibility, return the last result if there are more
2434 : : * than one. (We used to have logic here to concatenate successive error
2435 : : * messages, but now that happens automatically, since conn->errorMessage
2436 : : * will continue to accumulate errors throughout this loop.)
2437 : : *
2438 : : * We have to stop if we see copy in/out/both, however. We will resume
2439 : : * parsing after application performs the data transfer.
2440 : : *
2441 : : * Also stop if the connection is lost (else we'll loop infinitely).
2442 : : */
10340 bruce@momjian.us 2443 : 103739 : lastResult = NULL;
2444 [ + + ]: 221290 : while ((result = PQgetResult(conn)) != NULL)
2445 : : {
1516 peter@eisentraut.org 2446 : 122223 : PQclear(lastResult);
10340 bruce@momjian.us 2447 : 122223 : lastResult = result;
2448 [ + + ]: 122223 : if (result->resultStatus == PGRES_COPY_IN ||
8278 tgl@sss.pgh.pa.us 2449 [ + + ]: 122176 : result->resultStatus == PGRES_COPY_OUT ||
5738 rhaas@postgresql.org 2450 [ + + ]: 117738 : result->resultStatus == PGRES_COPY_BOTH ||
8278 tgl@sss.pgh.pa.us 2451 [ + - ]: 117551 : conn->status == CONNECTION_BAD)
2452 : : break;
2453 : : }
2454 : :
10340 bruce@momjian.us 2455 : 103739 : return lastResult;
2456 : : }
2457 : :
2458 : : /*
2459 : : * PQdescribePrepared
2460 : : * Obtain information about a previously prepared statement
2461 : : *
2462 : : * If the query was not even sent, return NULL; conn->errorMessage is set to
2463 : : * a relevant message.
2464 : : * If the query was sent, a new PGresult is returned (which could indicate
2465 : : * either success or failure). On success, the PGresult contains status
2466 : : * PGRES_COMMAND_OK, and its parameter and column-heading fields describe
2467 : : * the statement's inputs and outputs respectively.
2468 : : * The user is responsible for freeing the PGresult via PQclear()
2469 : : * when done with it.
2470 : : */
2471 : : PGresult *
7314 tgl@sss.pgh.pa.us 2472 : 58 : PQdescribePrepared(PGconn *conn, const char *stmt)
2473 : : {
2474 [ - + ]: 58 : if (!PQexecStart(conn))
7314 tgl@sss.pgh.pa.us 2475 :UBC 0 : return NULL;
1101 nathan@postgresql.or 2476 [ - + ]:CBC 58 : if (!PQsendTypedCommand(conn, PqMsg_Describe, 'S', stmt))
7314 tgl@sss.pgh.pa.us 2477 :UBC 0 : return NULL;
7314 tgl@sss.pgh.pa.us 2478 :CBC 58 : return PQexecFinish(conn);
2479 : : }
2480 : :
2481 : : /*
2482 : : * PQdescribePortal
2483 : : * Obtain information about a previously created portal
2484 : : *
2485 : : * This is much like PQdescribePrepared, except that no parameter info is
2486 : : * returned. Note that at the moment, libpq doesn't really expose portals
2487 : : * to the client; but this can be used with a portal created by a SQL
2488 : : * DECLARE CURSOR command.
2489 : : */
2490 : : PGresult *
2491 : 1 : PQdescribePortal(PGconn *conn, const char *portal)
2492 : : {
2493 [ - + ]: 1 : if (!PQexecStart(conn))
7314 tgl@sss.pgh.pa.us 2494 :UBC 0 : return NULL;
1101 nathan@postgresql.or 2495 [ - + ]:CBC 1 : if (!PQsendTypedCommand(conn, PqMsg_Describe, 'P', portal))
7314 tgl@sss.pgh.pa.us 2496 :UBC 0 : return NULL;
7314 tgl@sss.pgh.pa.us 2497 :CBC 1 : return PQexecFinish(conn);
2498 : : }
2499 : :
2500 : : /*
2501 : : * PQsendDescribePrepared
2502 : : * Submit a Describe Statement command, but don't wait for it to finish
2503 : : *
2504 : : * Returns: 1 if successfully submitted
2505 : : * 0 if error (conn->errorMessage is set)
2506 : : */
2507 : : int
2508 : 1 : PQsendDescribePrepared(PGconn *conn, const char *stmt)
2509 : : {
1101 nathan@postgresql.or 2510 : 1 : return PQsendTypedCommand(conn, PqMsg_Describe, 'S', stmt);
2511 : : }
2512 : :
2513 : : /*
2514 : : * PQsendDescribePortal
2515 : : * Submit a Describe Portal command, but don't wait for it to finish
2516 : : *
2517 : : * Returns: 1 if successfully submitted
2518 : : * 0 if error (conn->errorMessage is set)
2519 : : */
2520 : : int
7314 tgl@sss.pgh.pa.us 2521 : 1 : PQsendDescribePortal(PGconn *conn, const char *portal)
2522 : : {
1101 nathan@postgresql.or 2523 : 1 : return PQsendTypedCommand(conn, PqMsg_Describe, 'P', portal);
2524 : : }
2525 : :
2526 : : /*
2527 : : * PQclosePrepared
2528 : : * Close a previously prepared statement
2529 : : *
2530 : : * If the query was not even sent, return NULL; conn->errorMessage is set to
2531 : : * a relevant message.
2532 : : * If the query was sent, a new PGresult is returned (which could indicate
2533 : : * either success or failure). On success, the PGresult contains status
2534 : : * PGRES_COMMAND_OK. The user is responsible for freeing the PGresult via
2535 : : * PQclear() when done with it.
2536 : : */
2537 : : PGresult *
1150 michael@paquier.xyz 2538 : 1 : PQclosePrepared(PGconn *conn, const char *stmt)
2539 : : {
2540 [ - + ]: 1 : if (!PQexecStart(conn))
1150 michael@paquier.xyz 2541 :UBC 0 : return NULL;
1101 nathan@postgresql.or 2542 [ - + ]:CBC 1 : if (!PQsendTypedCommand(conn, PqMsg_Close, 'S', stmt))
1150 michael@paquier.xyz 2543 :UBC 0 : return NULL;
1150 michael@paquier.xyz 2544 :CBC 1 : return PQexecFinish(conn);
2545 : : }
2546 : :
2547 : : /*
2548 : : * PQclosePortal
2549 : : * Close a previously created portal
2550 : : *
2551 : : * This is exactly like PQclosePrepared, but for portals. Note that at the
2552 : : * moment, libpq doesn't really expose portals to the client; but this can be
2553 : : * used with a portal created by a SQL DECLARE CURSOR command.
2554 : : */
2555 : : PGresult *
2556 : 1 : PQclosePortal(PGconn *conn, const char *portal)
2557 : : {
2558 [ - + ]: 1 : if (!PQexecStart(conn))
1150 michael@paquier.xyz 2559 :UBC 0 : return NULL;
1101 nathan@postgresql.or 2560 [ - + ]:CBC 1 : if (!PQsendTypedCommand(conn, PqMsg_Close, 'P', portal))
1150 michael@paquier.xyz 2561 :UBC 0 : return NULL;
1150 michael@paquier.xyz 2562 :CBC 1 : return PQexecFinish(conn);
2563 : : }
2564 : :
2565 : : /*
2566 : : * PQsendClosePrepared
2567 : : * Submit a Close Statement command, but don't wait for it to finish
2568 : : *
2569 : : * Returns: 1 if successfully submitted
2570 : : * 0 if error (conn->errorMessage is set)
2571 : : */
2572 : : int
2573 : 26 : PQsendClosePrepared(PGconn *conn, const char *stmt)
2574 : : {
1101 nathan@postgresql.or 2575 : 26 : return PQsendTypedCommand(conn, PqMsg_Close, 'S', stmt);
2576 : : }
2577 : :
2578 : : /*
2579 : : * PQsendClosePortal
2580 : : * Submit a Close Portal command, but don't wait for it to finish
2581 : : *
2582 : : * Returns: 1 if successfully submitted
2583 : : * 0 if error (conn->errorMessage is set)
2584 : : */
2585 : : int
1150 michael@paquier.xyz 2586 : 1 : PQsendClosePortal(PGconn *conn, const char *portal)
2587 : : {
1101 nathan@postgresql.or 2588 : 1 : return PQsendTypedCommand(conn, PqMsg_Close, 'P', portal);
2589 : : }
2590 : :
2591 : : /*
2592 : : * PQsendTypedCommand
2593 : : * Common code to send a Describe or Close command
2594 : : *
2595 : : * Available options for "command" are
2596 : : * PqMsg_Close for Close; or
2597 : : * PqMsg_Describe for Describe.
2598 : : *
2599 : : * Available options for "type" are
2600 : : * 'S' to run a command on a prepared statement; or
2601 : : * 'P' to run a command on a portal.
2602 : : *
2603 : : * Returns 1 on success and 0 on failure.
2604 : : */
2605 : : static int
1150 michael@paquier.xyz 2606 : 90 : PQsendTypedCommand(PGconn *conn, char command, char type, const char *target)
2607 : : {
1991 alvherre@alvh.no-ip. 2608 : 90 : PGcmdQueueEntry *entry = NULL;
2609 : :
2610 : : /* Treat null target as empty string */
1150 michael@paquier.xyz 2611 [ - + ]: 90 : if (!target)
1150 michael@paquier.xyz 2612 :UBC 0 : target = "";
2613 : :
2054 tgl@sss.pgh.pa.us 2614 [ - + ]:CBC 90 : if (!PQsendQueryStart(conn, true))
7314 tgl@sss.pgh.pa.us 2615 :UBC 0 : return 0;
2616 : :
1991 alvherre@alvh.no-ip. 2617 :CBC 90 : entry = pqAllocCmdQueueEntry(conn);
2618 [ - + ]: 90 : if (entry == NULL)
1991 alvherre@alvh.no-ip. 2619 :UBC 0 : return 0; /* error msg already set */
2620 : :
2621 : : /* construct the Close message */
1150 michael@paquier.xyz 2622 [ + - + - ]:CBC 180 : if (pqPutMsgStart(command, conn) < 0 ||
2623 [ + - ]: 180 : pqPutc(type, conn) < 0 ||
2624 [ - + ]: 180 : pqPuts(target, conn) < 0 ||
7314 tgl@sss.pgh.pa.us 2625 : 90 : pqPutMsgEnd(conn) < 0)
7314 tgl@sss.pgh.pa.us 2626 :UBC 0 : goto sendFailed;
2627 : :
2628 : : /* construct the Sync message */
1991 alvherre@alvh.no-ip. 2629 [ + + ]:CBC 90 : if (conn->pipelineStatus == PQ_PIPELINE_OFF)
2630 : : {
1101 nathan@postgresql.or 2631 [ + - - + ]: 148 : if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
1991 alvherre@alvh.no-ip. 2632 : 74 : pqPutMsgEnd(conn) < 0)
1991 alvherre@alvh.no-ip. 2633 :UBC 0 : goto sendFailed;
2634 : : }
2635 : :
2636 : : /* remember if we are doing a Close or a Describe */
1101 nathan@postgresql.or 2637 [ + + ]:CBC 90 : if (command == PqMsg_Close)
2638 : : {
1150 michael@paquier.xyz 2639 : 29 : entry->queryclass = PGQUERY_CLOSE;
2640 : : }
1101 nathan@postgresql.or 2641 [ + - ]: 61 : else if (command == PqMsg_Describe)
2642 : : {
1150 michael@paquier.xyz 2643 : 61 : entry->queryclass = PGQUERY_DESCRIBE;
2644 : : }
2645 : : else
2646 : : {
805 peter@eisentraut.org 2647 :UBC 0 : libpq_append_conn_error(conn, "unrecognized message type \"%c\"", command);
1150 michael@paquier.xyz 2648 : 0 : goto sendFailed;
2649 : : }
2650 : :
2651 : : /*
2652 : : * Give the data a push (in pipeline mode, only if we're past the size
2653 : : * threshold). In nonblock mode, don't complain if we're unable to send
2654 : : * it all; PQgetResult() will do any additional flushing needed.
2655 : : */
1991 alvherre@alvh.no-ip. 2656 [ - + ]:CBC 90 : if (pqPipelineFlush(conn) < 0)
7314 tgl@sss.pgh.pa.us 2657 :UBC 0 : goto sendFailed;
2658 : :
2659 : : /* OK, it's launched! */
1991 alvherre@alvh.no-ip. 2660 :CBC 90 : pqAppendCmdQueueEntry(conn, entry);
2661 : :
7314 tgl@sss.pgh.pa.us 2662 : 90 : return 1;
2663 : :
7314 tgl@sss.pgh.pa.us 2664 :UBC 0 : sendFailed:
1991 alvherre@alvh.no-ip. 2665 : 0 : pqRecycleCmdQueueEntry(conn, entry);
2666 : : /* error message should be set up already */
7314 tgl@sss.pgh.pa.us 2667 : 0 : return 0;
2668 : : }
2669 : :
2670 : : /*
2671 : : * PQnotifies
2672 : : * returns a PGnotify* structure of the latest async notification
2673 : : * that has not yet been handled
2674 : : *
2675 : : * returns NULL, if there is currently
2676 : : * no unhandled async notification from the backend
2677 : : *
2678 : : * the CALLER is responsible for FREE'ing the structure returned
2679 : : *
2680 : : * Note that this function does not read any new data from the socket;
2681 : : * so usually, caller should call PQconsumeInput() first.
2682 : : */
2683 : : PGnotify *
10340 bruce@momjian.us 2684 :CBC 271313 : PQnotifies(PGconn *conn)
2685 : : {
2686 : : PGnotify *event;
2687 : :
2688 [ - + ]: 271313 : if (!conn)
10340 bruce@momjian.us 2689 :UBC 0 : return NULL;
2690 : :
2691 : : /* Parse any available data to see if we can extract NOTIFY messages. */
10340 bruce@momjian.us 2692 :CBC 271313 : parseInput(conn);
2693 : :
7985 tgl@sss.pgh.pa.us 2694 : 271313 : event = conn->notifyHead;
2695 [ + + ]: 271313 : if (event)
2696 : : {
2697 : 53 : conn->notifyHead = event->next;
2698 [ + + ]: 53 : if (!conn->notifyHead)
2699 : 24 : conn->notifyTail = NULL;
2700 : 53 : event->next = NULL; /* don't let app see the internal state */
2701 : : }
10340 bruce@momjian.us 2702 : 271313 : return event;
2703 : : }
2704 : :
2705 : : /*
2706 : : * PQputCopyData - send some data to the backend during COPY IN or COPY BOTH
2707 : : *
2708 : : * Returns 1 if successful, 0 if data could not be sent (only possible
2709 : : * in nonblock mode), or -1 if an error occurs.
2710 : : */
2711 : : int
8468 tgl@sss.pgh.pa.us 2712 : 356928 : PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
2713 : : {
2714 [ - + ]: 356928 : if (!conn)
8468 tgl@sss.pgh.pa.us 2715 :UBC 0 : return -1;
5738 rhaas@postgresql.org 2716 [ + + ]:CBC 356928 : if (conn->asyncStatus != PGASYNC_COPY_IN &&
2717 [ + + ]: 156069 : conn->asyncStatus != PGASYNC_COPY_BOTH)
2718 : : {
1381 peter@eisentraut.org 2719 : 1 : libpq_append_conn_error(conn, "no COPY in progress");
8468 tgl@sss.pgh.pa.us 2720 : 1 : return -1;
2721 : : }
2722 : :
2723 : : /*
2724 : : * Process any NOTICE or NOTIFY messages that might be pending in the
2725 : : * input buffer. Since the server might generate many notices during the
2726 : : * COPY, we want to clean those out reasonably promptly to prevent
2727 : : * indefinite expansion of the input buffer. (Note: the actual read of
2728 : : * input data into the input buffer happens down inside pqSendSome, but
2729 : : * it's not authorized to get rid of the data again.)
2730 : : */
8348 2731 : 356927 : parseInput(conn);
2732 : :
8468 2733 [ + - ]: 356927 : if (nbytes > 0)
2734 : : {
2735 : : /*
2736 : : * Try to flush any previously sent data in preference to growing the
2737 : : * output buffer. If we can't enlarge the buffer enough to hold the
2738 : : * data, return 0 in the nonblock case, else hard error. (For
2739 : : * simplicity, always assume 5 bytes of overhead.)
2740 : : */
2741 [ + + ]: 356927 : if ((conn->outBufSize - conn->outCount - 5) < nbytes)
2742 : : {
2743 [ - + ]: 25 : if (pqFlush(conn) < 0)
8468 tgl@sss.pgh.pa.us 2744 :UBC 0 : return -1;
6664 tgl@sss.pgh.pa.us 2745 [ - + ]:CBC 25 : if (pqCheckOutBufferSpace(conn->outCount + 5 + (size_t) nbytes,
2746 : : conn))
8468 tgl@sss.pgh.pa.us 2747 [ # # ]:UBC 0 : return pqIsnonblocking(conn) ? 0 : -1;
2748 : : }
2749 : : /* Send the data (too simple to delegate to fe-protocol files) */
1101 nathan@postgresql.or 2750 [ + - + - ]:CBC 713854 : if (pqPutMsgStart(PqMsg_CopyData, conn) < 0 ||
2002 heikki.linnakangas@i 2751 [ - + ]: 713854 : pqPutnchar(buffer, nbytes, conn) < 0 ||
2752 : 356927 : pqPutMsgEnd(conn) < 0)
2002 heikki.linnakangas@i 2753 :UBC 0 : return -1;
2754 : : }
8468 tgl@sss.pgh.pa.us 2755 :CBC 356927 : return 1;
2756 : : }
2757 : :
2758 : : /*
2759 : : * PQputCopyEnd - send EOF indication to the backend during COPY IN
2760 : : *
2761 : : * After calling this, use PQgetResult() to check command completion status.
2762 : : *
2763 : : * Returns 1 if successful, or -1 if an error occurs.
2764 : : */
2765 : : int
2766 : 1141 : PQputCopyEnd(PGconn *conn, const char *errormsg)
2767 : : {
2768 [ - + ]: 1141 : if (!conn)
8468 tgl@sss.pgh.pa.us 2769 :UBC 0 : return -1;
5005 heikki.linnakangas@i 2770 [ + + ]:CBC 1141 : if (conn->asyncStatus != PGASYNC_COPY_IN &&
2771 [ + + ]: 420 : conn->asyncStatus != PGASYNC_COPY_BOTH)
2772 : : {
1381 peter@eisentraut.org 2773 : 47 : libpq_append_conn_error(conn, "no COPY in progress");
8468 tgl@sss.pgh.pa.us 2774 : 47 : return -1;
2775 : : }
2776 : :
2777 : : /*
2778 : : * Send the COPY END indicator. This is simple enough that we don't
2779 : : * bother delegating it to the fe-protocol files.
2780 : : */
2002 heikki.linnakangas@i 2781 [ - + ]: 1094 : if (errormsg)
2782 : : {
2783 : : /* Send COPY FAIL */
1101 nathan@postgresql.or 2784 [ # # # # ]:UBC 0 : if (pqPutMsgStart(PqMsg_CopyFail, conn) < 0 ||
2002 heikki.linnakangas@i 2785 [ # # ]: 0 : pqPuts(errormsg, conn) < 0 ||
2786 : 0 : pqPutMsgEnd(conn) < 0)
2787 : 0 : return -1;
2788 : : }
2789 : : else
2790 : : {
2791 : : /* Send COPY DONE */
1101 nathan@postgresql.or 2792 [ + - - + ]:CBC 2188 : if (pqPutMsgStart(PqMsg_CopyDone, conn) < 0 ||
2002 heikki.linnakangas@i 2793 : 1094 : pqPutMsgEnd(conn) < 0)
2002 heikki.linnakangas@i 2794 :UBC 0 : return -1;
2795 : : }
2796 : :
2797 : : /*
2798 : : * If we sent the COPY command in extended-query mode, we must issue a
2799 : : * Sync as well.
2800 : : */
1991 alvherre@alvh.no-ip. 2801 [ + - ]:CBC 1094 : if (conn->cmd_queue_head &&
2802 [ - + ]: 1094 : conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE)
2803 : : {
1101 nathan@postgresql.or 2804 [ # # # # ]:UBC 0 : if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
2002 heikki.linnakangas@i 2805 : 0 : pqPutMsgEnd(conn) < 0)
8468 tgl@sss.pgh.pa.us 2806 : 0 : return -1;
2807 : : }
2808 : :
2809 : : /* Return to active duty */
5005 heikki.linnakangas@i 2810 [ + + ]:CBC 1094 : if (conn->asyncStatus == PGASYNC_COPY_BOTH)
2811 : 373 : conn->asyncStatus = PGASYNC_COPY_OUT;
2812 : : else
2813 : 721 : conn->asyncStatus = PGASYNC_BUSY;
2814 : :
2815 : : /* Try to flush data */
8468 tgl@sss.pgh.pa.us 2816 [ - + ]: 1094 : if (pqFlush(conn) < 0)
8468 tgl@sss.pgh.pa.us 2817 :UBC 0 : return -1;
2818 : :
8468 tgl@sss.pgh.pa.us 2819 :CBC 1094 : return 1;
2820 : : }
2821 : :
2822 : : /*
2823 : : * PQgetCopyData - read a row of data from the backend during COPY OUT
2824 : : * or COPY BOTH
2825 : : *
2826 : : * If successful, sets *buffer to point to a malloc'd row of data, and
2827 : : * returns row length (always > 0) as result.
2828 : : * Returns 0 if no row available yet (only possible if async is true),
2829 : : * -1 if end of copy (consult PQgetResult), or -2 if error (consult
2830 : : * PQerrorMessage).
2831 : : */
2832 : : int
2833 : 2958287 : PQgetCopyData(PGconn *conn, char **buffer, int async)
2834 : : {
2835 : 2958287 : *buffer = NULL; /* for all failure cases */
2836 [ - + ]: 2958287 : if (!conn)
8468 tgl@sss.pgh.pa.us 2837 :UBC 0 : return -2;
5738 rhaas@postgresql.org 2838 [ + + ]:CBC 2958287 : if (conn->asyncStatus != PGASYNC_COPY_OUT &&
2839 [ - + ]: 696108 : conn->asyncStatus != PGASYNC_COPY_BOTH)
2840 : : {
1381 peter@eisentraut.org 2841 :UBC 0 : libpq_append_conn_error(conn, "no COPY in progress");
8468 tgl@sss.pgh.pa.us 2842 : 0 : return -2;
2843 : : }
2002 heikki.linnakangas@i 2844 :CBC 2958287 : return pqGetCopyData3(conn, buffer, async);
2845 : : }
2846 : :
2847 : : /*
2848 : : * PQgetline - gets a newline-terminated string from the backend.
2849 : : *
2850 : : * Chiefly here so that applications can use "COPY <rel> to stdout"
2851 : : * and read the output string. Returns a null-terminated string in `buffer`.
2852 : : *
2853 : : * XXX this routine is now deprecated, because it can't handle binary data.
2854 : : * If called during a COPY BINARY we return EOF.
2855 : : *
2856 : : * PQgetline reads up to `length`-1 characters (like fgets(3)) but strips
2857 : : * the terminating \n (like gets(3)).
2858 : : *
2859 : : * CAUTION: the caller is responsible for detecting the end-of-copy signal
2860 : : * (a line containing just "\.") when using this routine.
2861 : : *
2862 : : * RETURNS:
2863 : : * EOF if error (eg, invalid arguments are given)
2864 : : * 0 if EOL is reached (i.e., \n has been read)
2865 : : * (this is required for backward-compatibility -- this
2866 : : * routine used to always return EOF or 0, assuming that
2867 : : * the line ended within `length` bytes.)
2868 : : * 1 in other cases (i.e., the buffer was filled before \n is reached)
2869 : : */
2870 : : int
1437 pg@bowt.ie 2871 :UBC 0 : PQgetline(PGconn *conn, char *buffer, int length)
2872 : : {
2873 [ # # # # ]: 0 : if (!buffer || length <= 0)
8481 tgl@sss.pgh.pa.us 2874 : 0 : return EOF;
1437 pg@bowt.ie 2875 : 0 : *buffer = '\0';
2876 : : /* length must be at least 3 to hold the \. terminator! */
2877 [ # # ]: 0 : if (length < 3)
10340 bruce@momjian.us 2878 : 0 : return EOF;
2879 : :
8481 tgl@sss.pgh.pa.us 2880 [ # # ]: 0 : if (!conn)
10340 bruce@momjian.us 2881 : 0 : return EOF;
2882 : :
1437 pg@bowt.ie 2883 : 0 : return pqGetline3(conn, buffer, length);
2884 : : }
2885 : :
2886 : : /*
2887 : : * PQgetlineAsync - gets a COPY data row without blocking.
2888 : : *
2889 : : * This routine is for applications that want to do "COPY <rel> to stdout"
2890 : : * asynchronously, that is without blocking. Having issued the COPY command
2891 : : * and gotten a PGRES_COPY_OUT response, the app should call PQconsumeInput
2892 : : * and this routine until the end-of-data signal is detected. Unlike
2893 : : * PQgetline, this routine takes responsibility for detecting end-of-data.
2894 : : *
2895 : : * On each call, PQgetlineAsync will return data if a complete data row
2896 : : * is available in libpq's input buffer. Otherwise, no data is returned
2897 : : * until the rest of the row arrives.
2898 : : *
2899 : : * If -1 is returned, the end-of-data signal has been recognized (and removed
2900 : : * from libpq's input buffer). The caller *must* next call PQendcopy and
2901 : : * then return to normal processing.
2902 : : *
2903 : : * RETURNS:
2904 : : * -1 if the end-of-copy-data marker has been recognized
2905 : : * 0 if no data is available
2906 : : * >0 the number of bytes returned.
2907 : : *
2908 : : * The data returned will not extend beyond a data-row boundary. If possible
2909 : : * a whole row will be returned at one time. But if the buffer offered by
2910 : : * the caller is too small to hold a row sent by the backend, then a partial
2911 : : * data row will be returned. In text mode this can be detected by testing
2912 : : * whether the last returned byte is '\n' or not.
2913 : : *
2914 : : * The returned data is *not* null-terminated.
2915 : : */
2916 : :
2917 : : int
10220 bruce@momjian.us 2918 : 0 : PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
2919 : : {
8481 tgl@sss.pgh.pa.us 2920 [ # # ]: 0 : if (!conn)
8528 2921 : 0 : return -1;
2922 : :
2002 heikki.linnakangas@i 2923 : 0 : return pqGetlineAsync3(conn, buffer, bufsize);
2924 : : }
2925 : :
2926 : : /*
2927 : : * PQputline -- sends a string to the backend during COPY IN.
2928 : : * Returns 0 if OK, EOF if not.
2929 : : *
2930 : : * This is deprecated primarily because the return convention doesn't allow
2931 : : * caller to tell the difference between a hard error and a nonblock-mode
2932 : : * send failure.
2933 : : */
2934 : : int
1437 pg@bowt.ie 2935 :CBC 200028 : PQputline(PGconn *conn, const char *string)
2936 : : {
2937 : 200028 : return PQputnbytes(conn, string, strlen(string));
2938 : : }
2939 : :
2940 : : /*
2941 : : * PQputnbytes -- like PQputline, but buffer need not be null-terminated.
2942 : : * Returns 0 if OK, EOF if not.
2943 : : */
2944 : : int
10237 scrappy@hub.org 2945 : 200028 : PQputnbytes(PGconn *conn, const char *buffer, int nbytes)
2946 : : {
8468 tgl@sss.pgh.pa.us 2947 [ + - ]: 200028 : if (PQputCopyData(conn, buffer, nbytes) > 0)
2948 : 200028 : return 0;
2949 : : else
10220 bruce@momjian.us 2950 :UBC 0 : return EOF;
2951 : : }
2952 : :
2953 : : /*
2954 : : * PQendcopy
2955 : : * After completing the data transfer portion of a copy in/out,
2956 : : * the application must call this routine to finish the command protocol.
2957 : : *
2958 : : * This is deprecated; it's cleaner to use PQgetResult to get the transfer
2959 : : * status.
2960 : : *
2961 : : * RETURNS:
2962 : : * 0 on success
2963 : : * 1 on failure
2964 : : */
2965 : : int
10340 bruce@momjian.us 2966 :CBC 206 : PQendcopy(PGconn *conn)
2967 : : {
2968 [ - + ]: 206 : if (!conn)
10340 bruce@momjian.us 2969 :UBC 0 : return 0;
2970 : :
2002 heikki.linnakangas@i 2971 :CBC 206 : return pqEndcopy3(conn);
2972 : : }
2973 : :
2974 : :
2975 : : /* ----------------
2976 : : * PQfn - Send a function call to the POSTGRES backend.
2977 : : *
2978 : : * conn : backend connection
2979 : : * fnid : OID of function to be called
2980 : : * result_buf : pointer to result buffer
2981 : : * result_len : actual length of result is returned here
2982 : : * result_is_int : If the result is an integer, this must be 1,
2983 : : * otherwise this should be 0
2984 : : * args : pointer to an array of function arguments
2985 : : * (each has length, if integer, and value/pointer)
2986 : : * nargs : # of arguments in args array.
2987 : : *
2988 : : * RETURNS
2989 : : * This function was unsafe and is no longer supported, so it now always
2990 : : * sets *result_len to 0 and returns a PGresult with status set to
2991 : : * PGRES_FATAL_ERROR. As before, NULL is returned instead when conn is
2992 : : * NULL or when the connection state doesn't permit a query cycle.
2993 : : * ----------------
2994 : : */
2995 : :
2996 : : PGresult *
10580 bruce@momjian.us 2997 :LBC (878) : PQfn(PGconn *conn,
2998 : : int fnid,
2999 : : int *result_buf,
3000 : : int *result_len,
3001 : : int result_is_int,
3002 : : const PQArgBlock *args,
3003 : : int nargs)
3004 : : {
13 nathan@postgresql.or 3005 :UNC 0 : *result_len = 0;
3006 : :
3007 [ # # ]: 0 : if (!conn)
3008 : 0 : return NULL;
3009 : :
3010 : : /*
3011 : : * Since this is the beginning of a query cycle, reset the error state.
3012 : : * However, in pipeline mode with something already queued, the error
3013 : : * buffer belongs to that command and we shouldn't clear it.
3014 : : */
3015 [ # # ]: 0 : if (conn->cmd_queue_head == NULL)
3016 : 0 : pqClearConnErrorState(conn);
3017 : :
3018 : : /*
3019 : : * The following state checks may look pointless for a function that can
3020 : : * no longer succeed, but they must stay ahead of the pqSaveErrorResult()
3021 : : * call below, which discards any result that is still being assembled.
3022 : : */
3023 [ # # ]: 0 : if (conn->pipelineStatus != PQ_PIPELINE_OFF)
3024 : : {
3025 : 0 : libpq_append_conn_error(conn, "%s not allowed in pipeline mode", "PQfn");
3026 : 0 : return NULL;
3027 : : }
3028 : :
3029 [ # # # # ]: 0 : if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE ||
3030 [ # # # # ]: 0 : pgHavePendingResult(conn))
3031 : : {
3032 : 0 : libpq_append_conn_error(conn, "connection in wrong state");
3033 : 0 : return NULL;
3034 : : }
3035 : :
3036 : 0 : libpq_append_conn_error(conn,
3037 : : "PQfn() is no longer supported; use a prepared "
3038 : : "statement or PQexecParams() with binary "
3039 : : "parameters and results instead");
3040 : 0 : pqSaveErrorResult(conn);
3041 : 0 : return pqPrepareAsyncResult(conn);
3042 : : }
3043 : :
3044 : : /*
3045 : : * PQnfn
3046 : : * Private version of the fast-path interface with verification that
3047 : : * returned data fits in result_buf when result_is_int == 0. Setting
3048 : : * buf_size to -1 disables this verification. This is currently only
3049 : : * used by the frontend LO interface and will hopefully be removed down
3050 : : * the road.
3051 : : */
3052 : : PGresult *
108 nathan@postgresql.or 3053 :CBC 1343 : PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size, int *result_len,
3054 : : int result_is_int, const PQArgBlock *args, int nargs)
3055 : : {
4190 tgl@sss.pgh.pa.us 3056 : 1343 : *result_len = 0;
3057 : :
10581 bruce@momjian.us 3058 [ - + ]: 1343 : if (!conn)
10581 bruce@momjian.us 3059 :UBC 0 : return NULL;
3060 : :
3061 : : /*
3062 : : * Since this is the beginning of a query cycle, reset the error state.
3063 : : * However, in pipeline mode with something already queued, the error
3064 : : * buffer belongs to that command and we shouldn't clear it.
3065 : : */
1641 tgl@sss.pgh.pa.us 3066 [ + - ]:CBC 1343 : if (conn->cmd_queue_head == NULL)
3067 : 1343 : pqClearConnErrorState(conn);
3068 : :
1991 alvherre@alvh.no-ip. 3069 [ - + ]: 1343 : if (conn->pipelineStatus != PQ_PIPELINE_OFF)
3070 : : {
1381 peter@eisentraut.org 3071 :UBC 0 : libpq_append_conn_error(conn, "%s not allowed in pipeline mode", "PQfn");
1991 alvherre@alvh.no-ip. 3072 : 0 : return NULL;
3073 : : }
3074 : :
4516 bruce@momjian.us 3075 [ + - + - ]:CBC 1343 : if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE ||
1589 tgl@sss.pgh.pa.us 3076 [ + - - + ]: 1343 : pgHavePendingResult(conn))
3077 : : {
1381 peter@eisentraut.org 3078 :UBC 0 : libpq_append_conn_error(conn, "connection in wrong state");
10340 bruce@momjian.us 3079 : 0 : return NULL;
3080 : : }
3081 : :
2002 heikki.linnakangas@i 3082 :CBC 1343 : return pqFunctionCall3(conn, fnid,
3083 : : result_buf, buf_size, result_len,
3084 : : result_is_int,
3085 : : args, nargs);
3086 : : }
3087 : :
3088 : : /* ====== Pipeline mode support ======== */
3089 : :
3090 : : /*
3091 : : * PQenterPipelineMode
3092 : : * Put an idle connection in pipeline mode.
3093 : : *
3094 : : * Returns 1 on success. On failure, errorMessage is set and 0 is returned.
3095 : : *
3096 : : * Commands submitted after this can be pipelined on the connection;
3097 : : * there's no requirement to wait for one to finish before the next is
3098 : : * dispatched.
3099 : : *
3100 : : * Queuing of a new query or syncing during COPY is not allowed.
3101 : : *
3102 : : * A set of commands is terminated by a PQpipelineSync. Multiple sync
3103 : : * points can be established while in pipeline mode. Pipeline mode can
3104 : : * be exited by calling PQexitPipelineMode() once all results are processed.
3105 : : *
3106 : : * This doesn't actually send anything on the wire, it just puts libpq
3107 : : * into a state where it can pipeline work.
3108 : : */
3109 : : int
1991 alvherre@alvh.no-ip. 3110 : 298 : PQenterPipelineMode(PGconn *conn)
3111 : : {
3112 [ - + ]: 298 : if (!conn)
1991 alvherre@alvh.no-ip. 3113 :UBC 0 : return 0;
3114 : :
3115 : : /* succeed with no action if already in pipeline mode */
1991 alvherre@alvh.no-ip. 3116 [ + + ]:CBC 298 : if (conn->pipelineStatus != PQ_PIPELINE_OFF)
3117 : 5 : return 1;
3118 : :
3119 [ - + ]: 293 : if (conn->asyncStatus != PGASYNC_IDLE)
3120 : : {
1381 peter@eisentraut.org 3121 :UBC 0 : libpq_append_conn_error(conn, "cannot enter pipeline mode, connection not idle");
1991 alvherre@alvh.no-ip. 3122 : 0 : return 0;
3123 : : }
3124 : :
1991 alvherre@alvh.no-ip. 3125 :CBC 293 : conn->pipelineStatus = PQ_PIPELINE_ON;
3126 : :
3127 : 293 : return 1;
3128 : : }
3129 : :
3130 : : /*
3131 : : * PQexitPipelineMode
3132 : : * End pipeline mode and return to normal command mode.
3133 : : *
3134 : : * Returns 1 in success (pipeline mode successfully ended, or not in pipeline
3135 : : * mode).
3136 : : *
3137 : : * Returns 0 if in pipeline mode and cannot be ended yet. Error message will
3138 : : * be set.
3139 : : */
3140 : : int
3141 : 284 : PQexitPipelineMode(PGconn *conn)
3142 : : {
3143 [ - + ]: 284 : if (!conn)
1991 alvherre@alvh.no-ip. 3144 :UBC 0 : return 0;
3145 : :
1514 alvherre@alvh.no-ip. 3146 [ + + ]:CBC 284 : if (conn->pipelineStatus == PQ_PIPELINE_OFF &&
3147 [ - + ]: 1 : (conn->asyncStatus == PGASYNC_IDLE ||
1514 alvherre@alvh.no-ip. 3148 [ # # ]:UBC 0 : conn->asyncStatus == PGASYNC_PIPELINE_IDLE) &&
1514 alvherre@alvh.no-ip. 3149 [ + - ]:CBC 1 : conn->cmd_queue_head == NULL)
1991 3150 : 1 : return 1;
3151 : :
3152 [ - + + - : 283 : switch (conn->asyncStatus)
- ]
3153 : : {
1991 alvherre@alvh.no-ip. 3154 :UBC 0 : case PGASYNC_READY:
3155 : : case PGASYNC_READY_MORE:
3156 : : /* there are some uncollected results */
1381 peter@eisentraut.org 3157 : 0 : libpq_append_conn_error(conn, "cannot exit pipeline mode with uncollected results");
1991 alvherre@alvh.no-ip. 3158 : 0 : return 0;
3159 : :
1991 alvherre@alvh.no-ip. 3160 :CBC 5 : case PGASYNC_BUSY:
1381 peter@eisentraut.org 3161 : 5 : libpq_append_conn_error(conn, "cannot exit pipeline mode while busy");
1991 alvherre@alvh.no-ip. 3162 : 5 : return 0;
3163 : :
1514 3164 : 278 : case PGASYNC_IDLE:
3165 : : case PGASYNC_PIPELINE_IDLE:
3166 : : /* OK */
1991 3167 : 278 : break;
3168 : :
1514 alvherre@alvh.no-ip. 3169 :UBC 0 : case PGASYNC_COPY_IN:
3170 : : case PGASYNC_COPY_OUT:
3171 : : case PGASYNC_COPY_BOTH:
1381 peter@eisentraut.org 3172 : 0 : libpq_append_conn_error(conn, "cannot exit pipeline mode while in COPY");
3173 : : }
3174 : :
3175 : : /* still work to process */
1991 alvherre@alvh.no-ip. 3176 [ - + ]:CBC 278 : if (conn->cmd_queue_head != NULL)
3177 : : {
1381 peter@eisentraut.org 3178 :UBC 0 : libpq_append_conn_error(conn, "cannot exit pipeline mode with uncollected results");
1991 alvherre@alvh.no-ip. 3179 : 0 : return 0;
3180 : : }
3181 : :
1991 alvherre@alvh.no-ip. 3182 :CBC 278 : conn->pipelineStatus = PQ_PIPELINE_OFF;
3183 : 278 : conn->asyncStatus = PGASYNC_IDLE;
3184 : :
3185 : : /* Flush any pending data in out buffer */
3186 [ - + ]: 278 : if (pqFlush(conn) < 0)
1991 alvherre@alvh.no-ip. 3187 :UBC 0 : return 0; /* error message is setup already */
1991 alvherre@alvh.no-ip. 3188 :CBC 278 : return 1;
3189 : : }
3190 : :
3191 : : /*
3192 : : * pqCommandQueueAdvance
3193 : : * Remove one query from the command queue, if appropriate.
3194 : : *
3195 : : * If we have received all results corresponding to the head element
3196 : : * in the command queue, remove it.
3197 : : *
3198 : : * In simple query protocol we must not advance the command queue until the
3199 : : * ReadyForQuery message has been received. This is because in simple mode a
3200 : : * command can have multiple queries, and we must process result for all of
3201 : : * them before moving on to the next command.
3202 : : *
3203 : : * Another consideration is synchronization during error processing in
3204 : : * extended query protocol: we refuse to advance the queue past a SYNC queue
3205 : : * element, unless the result we've received is also a SYNC. In particular
3206 : : * this protects us from advancing when an error is received at an
3207 : : * inappropriate moment.
3208 : : */
3209 : : void
996 3210 : 856788 : pqCommandQueueAdvance(PGconn *conn, bool isReadyForQuery, bool gotSync)
3211 : : {
3212 : : PGcmdQueueEntry *prevquery;
3213 : :
1991 3214 [ + + ]: 856788 : if (conn->cmd_queue_head == NULL)
3215 : 27002 : return;
3216 : :
3217 : : /*
3218 : : * If processing a query of simple query protocol, we only advance the
3219 : : * queue when we receive the ReadyForQuery message for it.
3220 : : */
996 3221 [ + + + + ]: 829786 : if (conn->cmd_queue_head->queryclass == PGQUERY_SIMPLE && !isReadyForQuery)
3222 : 418771 : return;
3223 : :
3224 : : /*
3225 : : * If we're waiting for a SYNC, don't advance the queue until we get one.
3226 : : */
3227 [ + + + + ]: 411015 : if (conn->cmd_queue_head->queryclass == PGQUERY_SYNC && !gotSync)
3228 : 32 : return;
3229 : :
3230 : : /* delink element from queue */
1991 3231 : 410983 : prevquery = conn->cmd_queue_head;
3232 : 410983 : conn->cmd_queue_head = conn->cmd_queue_head->next;
3233 : :
3234 : : /* If the queue is now empty, reset the tail too */
1514 3235 [ + + ]: 410983 : if (conn->cmd_queue_head == NULL)
3236 : 408478 : conn->cmd_queue_tail = NULL;
3237 : :
3238 : : /* and make the queue element recyclable */
1991 3239 : 410983 : prevquery->next = NULL;
3240 : 410983 : pqRecycleCmdQueueEntry(conn, prevquery);
3241 : : }
3242 : :
3243 : : /*
3244 : : * pqPipelineProcessQueue: subroutine for PQgetResult
3245 : : * In pipeline mode, start processing the results of the next query in the queue.
3246 : : */
3247 : : static void
3248 : 2889 : pqPipelineProcessQueue(PGconn *conn)
3249 : : {
3250 [ - + + - ]: 2889 : switch (conn->asyncStatus)
3251 : : {
1991 alvherre@alvh.no-ip. 3252 :UBC 0 : case PGASYNC_COPY_IN:
3253 : : case PGASYNC_COPY_OUT:
3254 : : case PGASYNC_COPY_BOTH:
3255 : : case PGASYNC_READY:
3256 : : case PGASYNC_READY_MORE:
3257 : : case PGASYNC_BUSY:
3258 : : /* client still has to process current query or results */
3259 : 0 : return;
3260 : :
1991 alvherre@alvh.no-ip. 3261 :CBC 13 : case PGASYNC_IDLE:
3262 : :
3263 : : /*
3264 : : * If we're in IDLE mode and there's some command in the queue,
3265 : : * get us into PIPELINE_IDLE mode and process normally. Otherwise
3266 : : * there's nothing for us to do.
3267 : : */
1514 3268 [ + - ]: 13 : if (conn->cmd_queue_head != NULL)
3269 : : {
3270 : 13 : conn->asyncStatus = PGASYNC_PIPELINE_IDLE;
3271 : 13 : break;
3272 : : }
1514 alvherre@alvh.no-ip. 3273 :UBC 0 : return;
3274 : :
1514 alvherre@alvh.no-ip. 3275 :CBC 2876 : case PGASYNC_PIPELINE_IDLE:
3276 [ - + ]: 2876 : Assert(conn->pipelineStatus != PQ_PIPELINE_OFF);
3277 : : /* next query please */
1991 3278 : 2876 : break;
3279 : : }
3280 : :
3281 : : /*
3282 : : * Reset partial-result mode. (Client has to set it up for each query, if
3283 : : * desired.)
3284 : : */
873 tgl@sss.pgh.pa.us 3285 : 2889 : conn->partialResMode = false;
1413 alvherre@alvh.no-ip. 3286 : 2889 : conn->singleRowMode = false;
873 tgl@sss.pgh.pa.us 3287 : 2889 : conn->maxChunkSize = 0;
3288 : :
3289 : : /*
3290 : : * If there are no further commands to process in the queue, get us in
3291 : : * "real idle" mode now.
3292 : : */
1514 alvherre@alvh.no-ip. 3293 [ + + ]: 2889 : if (conn->cmd_queue_head == NULL)
3294 : : {
3295 : 339 : conn->asyncStatus = PGASYNC_IDLE;
1991 3296 : 339 : return;
3297 : : }
3298 : :
3299 : : /*
3300 : : * Reset the error state. This and the next couple of steps correspond to
3301 : : * what PQsendQueryStart didn't do for this query.
3302 : : */
1641 tgl@sss.pgh.pa.us 3303 : 2550 : pqClearConnErrorState(conn);
3304 : :
3305 : : /* Initialize async result-accumulation state */
1991 alvherre@alvh.no-ip. 3306 : 2550 : pqClearAsyncResult(conn);
3307 : :
3308 [ + + ]: 2550 : if (conn->pipelineStatus == PQ_PIPELINE_ABORTED &&
3309 [ + + ]: 377 : conn->cmd_queue_head->queryclass != PGQUERY_SYNC)
3310 : : {
3311 : : /*
3312 : : * In an aborted pipeline we don't get anything from the server for
3313 : : * each result; we're just discarding commands from the queue until we
3314 : : * get to the next sync from the server.
3315 : : *
3316 : : * The PGRES_PIPELINE_ABORTED results tell the client that its queries
3317 : : * got aborted.
3318 : : */
3319 : 280 : conn->result = PQmakeEmptyPGresult(conn, PGRES_PIPELINE_ABORTED);
3320 [ - + ]: 280 : if (!conn->result)
3321 : : {
1381 peter@eisentraut.org 3322 :UBC 0 : libpq_append_conn_error(conn, "out of memory");
1991 alvherre@alvh.no-ip. 3323 : 0 : pqSaveErrorResult(conn);
3324 : 0 : return;
3325 : : }
1991 alvherre@alvh.no-ip. 3326 :CBC 280 : conn->asyncStatus = PGASYNC_READY;
3327 : : }
3328 : : else
3329 : : {
3330 : : /* allow parsing to continue */
3331 : 2270 : conn->asyncStatus = PGASYNC_BUSY;
3332 : : }
3333 : : }
3334 : :
3335 : : /*
3336 : : * PQpipelineSync
3337 : : * Send a Sync message as part of a pipeline, and flush to server
3338 : : */
3339 : : int
954 michael@paquier.xyz 3340 : 296 : PQpipelineSync(PGconn *conn)
3341 : : {
3342 : 296 : return pqPipelineSyncInternal(conn, true);
3343 : : }
3344 : :
3345 : : /*
3346 : : * PQsendPipelineSync
3347 : : * Send a Sync message as part of a pipeline, without flushing to server
3348 : : */
3349 : : int
3350 : 101 : PQsendPipelineSync(PGconn *conn)
3351 : : {
3352 : 101 : return pqPipelineSyncInternal(conn, false);
3353 : : }
3354 : :
3355 : : /*
3356 : : * Workhorse function for PQpipelineSync and PQsendPipelineSync.
3357 : : *
3358 : : * immediate_flush controls if the flush happens immediately after sending the
3359 : : * Sync message or not.
3360 : : */
3361 : : static int
3362 : 397 : pqPipelineSyncInternal(PGconn *conn, bool immediate_flush)
3363 : : {
3364 : : PGcmdQueueEntry *entry;
3365 : :
1991 alvherre@alvh.no-ip. 3366 [ - + ]: 397 : if (!conn)
1991 alvherre@alvh.no-ip. 3367 :UBC 0 : return 0;
3368 : :
1991 alvherre@alvh.no-ip. 3369 [ + + ]:CBC 397 : if (conn->pipelineStatus == PQ_PIPELINE_OFF)
3370 : : {
1381 peter@eisentraut.org 3371 : 4 : libpq_append_conn_error(conn, "cannot send pipeline when not in pipeline mode");
1991 alvherre@alvh.no-ip. 3372 : 4 : return 0;
3373 : : }
3374 : :
3375 [ - + - ]: 393 : switch (conn->asyncStatus)
3376 : : {
1991 alvherre@alvh.no-ip. 3377 :UBC 0 : case PGASYNC_COPY_IN:
3378 : : case PGASYNC_COPY_OUT:
3379 : : case PGASYNC_COPY_BOTH:
3380 : : /* should be unreachable */
3381 : 0 : appendPQExpBufferStr(&conn->errorMessage,
3382 : : "internal error: cannot send pipeline while in COPY\n");
3383 : 0 : return 0;
1991 alvherre@alvh.no-ip. 3384 :CBC 393 : case PGASYNC_READY:
3385 : : case PGASYNC_READY_MORE:
3386 : : case PGASYNC_BUSY:
3387 : : case PGASYNC_IDLE:
3388 : : case PGASYNC_PIPELINE_IDLE:
3389 : : /* OK to send sync */
3390 : 393 : break;
3391 : : }
3392 : :
3393 : 393 : entry = pqAllocCmdQueueEntry(conn);
3394 [ - + ]: 393 : if (entry == NULL)
1991 alvherre@alvh.no-ip. 3395 :UBC 0 : return 0; /* error msg already set */
3396 : :
1991 alvherre@alvh.no-ip. 3397 :CBC 393 : entry->queryclass = PGQUERY_SYNC;
3398 : 393 : entry->query = NULL;
3399 : :
3400 : : /* construct the Sync message */
1101 nathan@postgresql.or 3401 [ + - - + ]: 786 : if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
1991 alvherre@alvh.no-ip. 3402 : 393 : pqPutMsgEnd(conn) < 0)
1991 alvherre@alvh.no-ip. 3403 :UBC 0 : goto sendFailed;
3404 : :
3405 : : /*
3406 : : * Give the data a push. In nonblock mode, don't complain if we're unable
3407 : : * to send it all; PQgetResult() will do any additional flushing needed.
3408 : : * If immediate_flush is disabled, the data is pushed if we are past the
3409 : : * size threshold.
3410 : : */
954 michael@paquier.xyz 3411 [ + + ]:CBC 393 : if (immediate_flush)
3412 : : {
3413 [ - + ]: 292 : if (pqFlush(conn) < 0)
954 michael@paquier.xyz 3414 :UBC 0 : goto sendFailed;
3415 : : }
3416 : : else
3417 : : {
954 michael@paquier.xyz 3418 [ - + ]:CBC 101 : if (pqPipelineFlush(conn) < 0)
954 michael@paquier.xyz 3419 :UBC 0 : goto sendFailed;
3420 : : }
3421 : :
3422 : : /* OK, it's launched! */
1875 alvherre@alvh.no-ip. 3423 :CBC 393 : pqAppendCmdQueueEntry(conn, entry);
3424 : :
1991 3425 : 393 : return 1;
3426 : :
1991 alvherre@alvh.no-ip. 3427 :UBC 0 : sendFailed:
3428 : 0 : pqRecycleCmdQueueEntry(conn, entry);
3429 : : /* error message should be set up already */
3430 : 0 : return 0;
3431 : : }
3432 : :
3433 : : /*
3434 : : * PQsendFlushRequest
3435 : : * Send request for server to flush its buffer. Useful in pipeline
3436 : : * mode when a sync point is not desired.
3437 : : */
3438 : : int
1885 alvherre@alvh.no-ip. 3439 :CBC 52 : PQsendFlushRequest(PGconn *conn)
3440 : : {
3441 [ - + ]: 52 : if (!conn)
1885 alvherre@alvh.no-ip. 3442 :UBC 0 : return 0;
3443 : :
3444 : : /* Don't try to send if we know there's no live connection. */
1885 alvherre@alvh.no-ip. 3445 [ - + ]:CBC 52 : if (conn->status != CONNECTION_OK)
3446 : : {
1381 peter@eisentraut.org 3447 :UBC 0 : libpq_append_conn_error(conn, "no connection to the server");
1885 alvherre@alvh.no-ip. 3448 : 0 : return 0;
3449 : : }
3450 : :
3451 : : /* Can't send while already busy, either, unless enqueuing for later */
1885 alvherre@alvh.no-ip. 3452 [ + - ]:CBC 52 : if (conn->asyncStatus != PGASYNC_IDLE &&
3453 [ - + ]: 52 : conn->pipelineStatus == PQ_PIPELINE_OFF)
3454 : : {
1381 peter@eisentraut.org 3455 :UBC 0 : libpq_append_conn_error(conn, "another command is already in progress");
1875 alvherre@alvh.no-ip. 3456 : 0 : return 0;
3457 : : }
3458 : :
1101 nathan@postgresql.or 3459 [ + - - + ]:CBC 104 : if (pqPutMsgStart(PqMsg_Flush, conn) < 0 ||
1885 alvherre@alvh.no-ip. 3460 : 52 : pqPutMsgEnd(conn) < 0)
3461 : : {
1885 alvherre@alvh.no-ip. 3462 :UBC 0 : return 0;
3463 : : }
3464 : :
3465 : : /*
3466 : : * Give the data a push (in pipeline mode, only if we're past the size
3467 : : * threshold). In nonblock mode, don't complain if we're unable to send
3468 : : * it all; PQgetResult() will do any additional flushing needed.
3469 : : */
1023 alvherre@alvh.no-ip. 3470 [ - + ]:CBC 52 : if (pqPipelineFlush(conn) < 0)
1023 alvherre@alvh.no-ip. 3471 :UBC 0 : return 0;
3472 : :
1885 alvherre@alvh.no-ip. 3473 :CBC 52 : return 1;
3474 : : }
3475 : :
3476 : : /* ====== accessor funcs for PGresult ======== */
3477 : :
3478 : : ExecStatusType
9786 bruce@momjian.us 3479 : 1666894 : PQresultStatus(const PGresult *res)
3480 : : {
10581 3481 [ + + ]: 1666894 : if (!res)
8468 tgl@sss.pgh.pa.us 3482 : 193 : return PGRES_FATAL_ERROR;
10581 bruce@momjian.us 3483 : 1666701 : return res->resultStatus;
3484 : : }
3485 : :
3486 : : char *
10063 tgl@sss.pgh.pa.us 3487 : 22 : PQresStatus(ExecStatusType status)
3488 : : {
1991 alvherre@alvh.no-ip. 3489 [ - + ]: 22 : if ((unsigned int) status >= lengthof(pgresStatus))
9174 peter_e@gmx.net 3490 :UBC 0 : return libpq_gettext("invalid ExecStatusType code");
10063 tgl@sss.pgh.pa.us 3491 :CBC 22 : return pgresStatus[status];
3492 : : }
3493 : :
3494 : : char *
9786 bruce@momjian.us 3495 : 48460 : PQresultErrorMessage(const PGresult *res)
3496 : : {
10192 tgl@sss.pgh.pa.us 3497 [ + - + + ]: 48460 : if (!res || !res->errMsg)
3498 : 1 : return "";
3499 : 48459 : return res->errMsg;
3500 : : }
3501 : :
3502 : : char *
3798 3503 : 3 : PQresultVerboseErrorMessage(const PGresult *res,
3504 : : PGVerbosity verbosity,
3505 : : PGContextVisibility show_context)
3506 : : {
3507 : : PQExpBufferData workBuf;
3508 : :
3509 : : /*
3510 : : * Because the caller is expected to free the result string, we must
3511 : : * strdup any constant result. We use plain strdup and document that
3512 : : * callers should expect NULL if out-of-memory.
3513 : : */
3514 [ + - ]: 3 : if (!res ||
3515 [ - + ]: 3 : (res->resultStatus != PGRES_FATAL_ERROR &&
3798 tgl@sss.pgh.pa.us 3516 [ # # ]:UBC 0 : res->resultStatus != PGRES_NONFATAL_ERROR))
3517 : 0 : return strdup(libpq_gettext("PGresult is not an error result\n"));
3518 : :
3798 tgl@sss.pgh.pa.us 3519 :CBC 3 : initPQExpBuffer(&workBuf);
3520 : :
3521 : 3 : pqBuildErrorMessage3(&workBuf, res, verbosity, show_context);
3522 : :
3523 : : /* If insufficient memory to format the message, fail cleanly */
3524 [ - + ]: 3 : if (PQExpBufferDataBroken(workBuf))
3525 : : {
3798 tgl@sss.pgh.pa.us 3526 :UBC 0 : termPQExpBuffer(&workBuf);
3527 : 0 : return strdup(libpq_gettext("out of memory\n"));
3528 : : }
3529 : :
3798 tgl@sss.pgh.pa.us 3530 :CBC 3 : return workBuf.data;
3531 : : }
3532 : :
3533 : : char *
8468 3534 : 433387 : PQresultErrorField(const PGresult *res, int fieldcode)
3535 : : {
3536 : : PGMessageField *pfield;
3537 : :
3538 [ + + ]: 433387 : if (!res)
3539 : 28 : return NULL;
3540 [ + + ]: 3254818 : for (pfield = res->errFields; pfield != NULL; pfield = pfield->next)
3541 : : {
3542 [ + + ]: 3005142 : if (pfield->code == fieldcode)
3543 : 183683 : return pfield->contents;
3544 : : }
3545 : 249676 : return NULL;
3546 : : }
3547 : :
3548 : : int
9786 bruce@momjian.us 3549 : 337094 : PQntuples(const PGresult *res)
3550 : : {
10581 3551 [ + + ]: 337094 : if (!res)
10340 3552 : 1995 : return 0;
10581 3553 : 335099 : return res->ntups;
3554 : : }
3555 : :
3556 : : int
9786 3557 : 208258 : PQnfields(const PGresult *res)
3558 : : {
10581 3559 [ - + ]: 208258 : if (!res)
10340 bruce@momjian.us 3560 :UBC 0 : return 0;
10581 bruce@momjian.us 3561 :CBC 208258 : return res->numAttributes;
3562 : : }
3563 : :
3564 : : int
9786 3565 : 641 : PQbinaryTuples(const PGresult *res)
3566 : : {
10220 3567 [ - + ]: 641 : if (!res)
10220 bruce@momjian.us 3568 :UBC 0 : return 0;
10220 bruce@momjian.us 3569 :CBC 641 : return res->binary;
3570 : : }
3571 : :
3572 : : /*
3573 : : * Helper routines to range-check field numbers and tuple numbers.
3574 : : * Return true if OK, false if not
3575 : : */
3576 : :
3577 : : static int
9174 peter_e@gmx.net 3578 : 2892087 : check_field_number(const PGresult *res, int field_num)
3579 : : {
10581 bruce@momjian.us 3580 [ - + ]: 2892087 : if (!res)
3298 peter_e@gmx.net 3581 :UBC 0 : return false; /* no way to display error message... */
10245 bruce@momjian.us 3582 [ + - - + ]:CBC 2892087 : if (field_num < 0 || field_num >= res->numAttributes)
3583 : : {
8466 tgl@sss.pgh.pa.us 3584 :UBC 0 : pqInternalNotice(&res->noticeHooks,
3585 : : "column number %d is out of range 0..%d",
3586 : 0 : field_num, res->numAttributes - 1);
3298 peter_e@gmx.net 3587 : 0 : return false;
3588 : : }
3298 peter_e@gmx.net 3589 :CBC 2892087 : return true;
3590 : : }
3591 : :
3592 : : static int
9174 3593 : 22473923 : check_tuple_field_number(const PGresult *res,
3594 : : int tup_num, int field_num)
3595 : : {
10245 bruce@momjian.us 3596 [ - + ]: 22473923 : if (!res)
3298 peter_e@gmx.net 3597 :UBC 0 : return false; /* no way to display error message... */
10245 bruce@momjian.us 3598 [ + - - + ]:CBC 22473923 : if (tup_num < 0 || tup_num >= res->ntups)
3599 : : {
8466 tgl@sss.pgh.pa.us 3600 :UBC 0 : pqInternalNotice(&res->noticeHooks,
3601 : : "row number %d is out of range 0..%d",
3602 : 0 : tup_num, res->ntups - 1);
3298 peter_e@gmx.net 3603 : 0 : return false;
3604 : : }
10340 bruce@momjian.us 3605 [ + - - + ]:CBC 22473923 : if (field_num < 0 || field_num >= res->numAttributes)
3606 : : {
8466 tgl@sss.pgh.pa.us 3607 :UBC 0 : pqInternalNotice(&res->noticeHooks,
3608 : : "column number %d is out of range 0..%d",
3609 : 0 : field_num, res->numAttributes - 1);
3298 peter_e@gmx.net 3610 : 0 : return false;
3611 : : }
3298 peter_e@gmx.net 3612 :CBC 22473923 : return true;
3613 : : }
3614 : :
3615 : : static int
7314 tgl@sss.pgh.pa.us 3616 :UBC 0 : check_param_number(const PGresult *res, int param_num)
3617 : : {
3618 [ # # ]: 0 : if (!res)
3298 peter_e@gmx.net 3619 : 0 : return false; /* no way to display error message... */
7314 tgl@sss.pgh.pa.us 3620 [ # # # # ]: 0 : if (param_num < 0 || param_num >= res->numParameters)
3621 : : {
3622 : 0 : pqInternalNotice(&res->noticeHooks,
3623 : : "parameter number %d is out of range 0..%d",
3624 : 0 : param_num, res->numParameters - 1);
3298 peter_e@gmx.net 3625 : 0 : return false;
3626 : : }
3627 : :
3628 : 0 : return true;
3629 : : }
3630 : :
3631 : : /*
3632 : : * returns NULL if the field_num is invalid
3633 : : */
3634 : : char *
9786 bruce@momjian.us 3635 :CBC 190495 : PQfname(const PGresult *res, int field_num)
3636 : : {
9174 peter_e@gmx.net 3637 [ - + ]: 190495 : if (!check_field_number(res, field_num))
10245 bruce@momjian.us 3638 :UBC 0 : return NULL;
10581 bruce@momjian.us 3639 [ + - ]:CBC 190495 : if (res->attDescs)
3640 : 190495 : return res->attDescs[field_num].name;
3641 : : else
10581 bruce@momjian.us 3642 :UBC 0 : return NULL;
3643 : : }
3644 : :
3645 : : /*
3646 : : * PQfnumber: find column number given column name
3647 : : *
3648 : : * The column name is parsed as if it were in a SQL statement, including
3649 : : * case-folding and double-quote processing. But note a possible gotcha:
3650 : : * downcasing in the frontend might follow different locale rules than
3651 : : * downcasing in the backend...
3652 : : *
3653 : : * Returns -1 if no match. In the present backend it is also possible
3654 : : * to have multiple matches, in which case the first one is found.
3655 : : */
3656 : : int
9786 bruce@momjian.us 3657 :CBC 250280 : PQfnumber(const PGresult *res, const char *field_name)
3658 : : {
3659 : : char *field_case;
3660 : : bool in_quotes;
4562 sfrost@snowman.net 3661 : 250280 : bool all_lower = true;
3662 : : const char *iptr;
3663 : : char *optr;
3664 : : int i;
3665 : :
10581 bruce@momjian.us 3666 [ + + ]: 250280 : if (!res)
3667 : 16864 : return -1;
3668 : :
3669 : : /*
3670 : : * Note: it is correct to reject a zero-length input string; the proper
3671 : : * input to match a zero-length field name would be "".
3672 : : */
3673 [ + - ]: 233416 : if (field_name == NULL ||
3674 [ + - ]: 233416 : field_name[0] == '\0' ||
3675 [ - + ]: 233416 : res->attDescs == NULL)
10581 bruce@momjian.us 3676 :UBC 0 : return -1;
3677 : :
3678 : : /*
3679 : : * Check if we can avoid the strdup() and related work because the
3680 : : * passed-in string wouldn't be changed before we do the check anyway.
3681 : : */
4562 sfrost@snowman.net 3682 [ + + ]:CBC 2621598 : for (iptr = field_name; *iptr; iptr++)
3683 : : {
3684 : 2388182 : char c = *iptr;
3685 : :
3686 [ + - - + ]: 2388182 : if (c == '"' || c != pg_tolower((unsigned char) c))
3687 : : {
4562 sfrost@snowman.net 3688 :UBC 0 : all_lower = false;
3689 : 0 : break;
3690 : : }
3691 : : }
3692 : :
4562 sfrost@snowman.net 3693 [ + - ]:CBC 233416 : if (all_lower)
3694 [ + - ]: 1828898 : for (i = 0; i < res->numAttributes; i++)
3695 [ + + ]: 1828898 : if (strcmp(field_name, res->attDescs[i].name) == 0)
3696 : 233416 : return i;
3697 : :
3698 : : /* Fall through to the normal check if that didn't work out. */
3699 : :
3700 : : /*
3701 : : * Note: this code will not reject partially quoted strings, eg
3702 : : * foo"BAR"foo will become fooBARfoo when it probably ought to be an error
3703 : : * condition.
3704 : : */
10517 bruce@momjian.us 3705 :UBC 0 : field_case = strdup(field_name);
8363 tgl@sss.pgh.pa.us 3706 [ # # ]: 0 : if (field_case == NULL)
3707 : 0 : return -1; /* grotty */
3708 : :
3709 : 0 : in_quotes = false;
3710 : 0 : optr = field_case;
3711 [ # # ]: 0 : for (iptr = field_case; *iptr; iptr++)
3712 : : {
8033 bruce@momjian.us 3713 : 0 : char c = *iptr;
3714 : :
8363 tgl@sss.pgh.pa.us 3715 [ # # ]: 0 : if (in_quotes)
3716 : : {
3717 [ # # ]: 0 : if (c == '"')
3718 : : {
3719 [ # # ]: 0 : if (iptr[1] == '"')
3720 : : {
3721 : : /* doubled quotes become a single quote */
3722 : 0 : *optr++ = '"';
3723 : 0 : iptr++;
3724 : : }
3725 : : else
3726 : 0 : in_quotes = false;
3727 : : }
3728 : : else
3729 : 0 : *optr++ = c;
3730 : : }
3731 [ # # ]: 0 : else if (c == '"')
3732 : 0 : in_quotes = true;
3733 : : else
3734 : : {
8147 3735 : 0 : c = pg_tolower((unsigned char) c);
8363 3736 : 0 : *optr++ = c;
3737 : : }
3738 : : }
3739 : 0 : *optr = '\0';
3740 : :
10581 bruce@momjian.us 3741 [ # # ]: 0 : for (i = 0; i < res->numAttributes; i++)
3742 : : {
10067 3743 [ # # ]: 0 : if (strcmp(field_case, res->attDescs[i].name) == 0)
3744 : : {
10517 3745 : 0 : free(field_case);
10581 3746 : 0 : return i;
3747 : : }
3748 : : }
10517 3749 : 0 : free(field_case);
10581 3750 : 0 : return -1;
3751 : : }
3752 : :
3753 : : Oid
8468 tgl@sss.pgh.pa.us 3754 : 0 : PQftable(const PGresult *res, int field_num)
3755 : : {
3756 [ # # ]: 0 : if (!check_field_number(res, field_num))
3757 : 0 : return InvalidOid;
3758 [ # # ]: 0 : if (res->attDescs)
3759 : 0 : return res->attDescs[field_num].tableid;
3760 : : else
3761 : 0 : return InvalidOid;
3762 : : }
3763 : :
3764 : : int
3765 : 0 : PQftablecol(const PGresult *res, int field_num)
3766 : : {
3767 [ # # ]: 0 : if (!check_field_number(res, field_num))
3768 : 0 : return 0;
3769 [ # # ]: 0 : if (res->attDescs)
3770 : 0 : return res->attDescs[field_num].columnid;
3771 : : else
3772 : 0 : return 0;
3773 : : }
3774 : :
3775 : : int
8468 tgl@sss.pgh.pa.us 3776 :CBC 4655 : PQfformat(const PGresult *res, int field_num)
3777 : : {
3778 [ - + ]: 4655 : if (!check_field_number(res, field_num))
8468 tgl@sss.pgh.pa.us 3779 :UBC 0 : return 0;
8468 tgl@sss.pgh.pa.us 3780 [ + - ]:CBC 4655 : if (res->attDescs)
3781 : 4655 : return res->attDescs[field_num].format;
3782 : : else
8468 tgl@sss.pgh.pa.us 3783 :UBC 0 : return 0;
3784 : : }
3785 : :
3786 : : Oid
9786 bruce@momjian.us 3787 :CBC 2696687 : PQftype(const PGresult *res, int field_num)
3788 : : {
9174 peter_e@gmx.net 3789 [ - + ]: 2696687 : if (!check_field_number(res, field_num))
10581 bruce@momjian.us 3790 :UBC 0 : return InvalidOid;
10581 bruce@momjian.us 3791 [ + - ]:CBC 2696687 : if (res->attDescs)
10272 3792 : 2696687 : return res->attDescs[field_num].typid;
3793 : : else
10581 bruce@momjian.us 3794 :UBC 0 : return InvalidOid;
3795 : : }
3796 : :
3797 : : int
9786 bruce@momjian.us 3798 :CBC 80 : PQfsize(const PGresult *res, int field_num)
3799 : : {
9174 peter_e@gmx.net 3800 [ - + ]: 80 : if (!check_field_number(res, field_num))
10340 bruce@momjian.us 3801 :UBC 0 : return 0;
10581 bruce@momjian.us 3802 [ + - ]:CBC 80 : if (res->attDescs)
10272 3803 : 80 : return res->attDescs[field_num].typlen;
3804 : : else
10581 bruce@momjian.us 3805 :UBC 0 : return 0;
3806 : : }
3807 : :
3808 : : int
9786 bruce@momjian.us 3809 :CBC 170 : PQfmod(const PGresult *res, int field_num)
3810 : : {
9174 peter_e@gmx.net 3811 [ - + ]: 170 : if (!check_field_number(res, field_num))
10340 bruce@momjian.us 3812 :UBC 0 : return 0;
10340 bruce@momjian.us 3813 [ + - ]:CBC 170 : if (res->attDescs)
10272 3814 : 170 : return res->attDescs[field_num].atttypmod;
3815 : : else
10340 bruce@momjian.us 3816 :UBC 0 : return 0;
3817 : : }
3818 : :
3819 : : char *
9698 peter_e@gmx.net 3820 :CBC 449874 : PQcmdStatus(PGresult *res)
3821 : : {
10581 bruce@momjian.us 3822 [ - + ]: 449874 : if (!res)
10581 bruce@momjian.us 3823 :UBC 0 : return NULL;
10581 bruce@momjian.us 3824 :CBC 449874 : return res->cmdStatus;
3825 : : }
3826 : :
3827 : : /*
3828 : : * PQoidStatus -
3829 : : * if the last command was an INSERT, return the oid string
3830 : : * if not, return ""
3831 : : */
3832 : : char *
9786 bruce@momjian.us 3833 :UBC 0 : PQoidStatus(const PGresult *res)
3834 : : {
3835 : : /*
3836 : : * This must be enough to hold the result. Don't laugh, this is better
3837 : : * than what this function used to do.
3838 : : */
3839 : : static char buf[24];
3840 : :
3841 : : size_t len;
3842 : :
4562 sfrost@snowman.net 3843 [ # # # # ]: 0 : if (!res || strncmp(res->cmdStatus, "INSERT ", 7) != 0)
10237 scrappy@hub.org 3844 : 0 : return "";
3845 : :
9786 bruce@momjian.us 3846 : 0 : len = strspn(res->cmdStatus + 7, "0123456789");
4233 tgl@sss.pgh.pa.us 3847 [ # # ]: 0 : if (len > sizeof(buf) - 1)
3848 : 0 : len = sizeof(buf) - 1;
3849 : 0 : memcpy(buf, res->cmdStatus + 7, len);
9333 3850 : 0 : buf[len] = '\0';
3851 : :
9786 bruce@momjian.us 3852 : 0 : return buf;
3853 : : }
3854 : :
3855 : : /*
3856 : : * PQoidValue -
3857 : : * a perhaps preferable form of the above which just returns
3858 : : * an Oid type
3859 : : */
3860 : : Oid
9786 bruce@momjian.us 3861 :CBC 129508 : PQoidValue(const PGresult *res)
3862 : : {
9633 3863 : 129508 : char *endptr = NULL;
3864 : : unsigned long result;
3865 : :
7621 3866 [ + - ]: 129508 : if (!res ||
3867 [ + + ]: 129508 : strncmp(res->cmdStatus, "INSERT ", 7) != 0 ||
3868 [ + - ]: 21987 : res->cmdStatus[7] < '0' ||
3869 [ - + ]: 21987 : res->cmdStatus[7] > '9')
9633 3870 : 107521 : return InvalidOid;
3871 : :
3872 : 21987 : result = strtoul(res->cmdStatus + 7, &endptr, 10);
3873 : :
7674 3874 [ + - - + : 21987 : if (!endptr || (*endptr != ' ' && *endptr != '\0'))
- - ]
9633 bruce@momjian.us 3875 :UBC 0 : return InvalidOid;
3876 : : else
9633 bruce@momjian.us 3877 :CBC 21987 : return (Oid) result;
3878 : : }
3879 : :
3880 : :
3881 : : /*
3882 : : * PQcmdTuples -
3883 : : * If the last command was INSERT/UPDATE/DELETE/MERGE/MOVE/FETCH/COPY,
3884 : : * return a string containing the number of inserted/affected tuples.
3885 : : * If not, return "".
3886 : : *
3887 : : * XXX: this should probably return an int
3888 : : */
3889 : : char *
9698 peter_e@gmx.net 3890 : 225471 : PQcmdTuples(PGresult *res)
3891 : : {
3892 : : char *p,
3893 : : *c;
3894 : :
10581 bruce@momjian.us 3895 [ + + ]: 225471 : if (!res)
10245 3896 : 447 : return "";
3897 : :
8590 3898 [ + + ]: 225024 : if (strncmp(res->cmdStatus, "INSERT ", 7) == 0)
3899 : : {
7482 tgl@sss.pgh.pa.us 3900 : 22722 : p = res->cmdStatus + 7;
3901 : : /* INSERT: skip oid and space */
3902 [ + - + + ]: 45444 : while (*p && *p != ' ')
8590 bruce@momjian.us 3903 : 22722 : p++;
7482 tgl@sss.pgh.pa.us 3904 [ - + ]: 22722 : if (*p == 0)
3354 tgl@sss.pgh.pa.us 3905 :UBC 0 : goto interpret_error; /* no space? */
7482 tgl@sss.pgh.pa.us 3906 :CBC 22722 : p++;
3907 : : }
6036 bruce@momjian.us 3908 [ + + ]: 202302 : else if (strncmp(res->cmdStatus, "SELECT ", 7) == 0 ||
3909 [ + + ]: 118583 : strncmp(res->cmdStatus, "DELETE ", 7) == 0 ||
8590 3910 [ + + ]: 116494 : strncmp(res->cmdStatus, "UPDATE ", 7) == 0)
7482 tgl@sss.pgh.pa.us 3911 : 89451 : p = res->cmdStatus + 7;
1613 alvherre@alvh.no-ip. 3912 [ + + ]: 112851 : else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0 ||
3913 [ + + ]: 111880 : strncmp(res->cmdStatus, "MERGE ", 6) == 0)
7482 tgl@sss.pgh.pa.us 3914 : 1640 : p = res->cmdStatus + 6;
3915 [ + + ]: 111211 : else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0 ||
3916 [ + + ]: 111174 : strncmp(res->cmdStatus, "COPY ", 5) == 0)
8590 bruce@momjian.us 3917 : 761 : p = res->cmdStatus + 5;
3918 : : else
3919 : 110450 : return "";
3920 : :
3921 : : /* check that we have an integer (at least one digit, nothing else) */
7482 tgl@sss.pgh.pa.us 3922 [ + + ]: 241722 : for (c = p; *c; c++)
3923 : : {
3924 [ - + ]: 127148 : if (!isdigit((unsigned char) *c))
7482 tgl@sss.pgh.pa.us 3925 :UBC 0 : goto interpret_error;
3926 : : }
7482 tgl@sss.pgh.pa.us 3927 [ - + ]:CBC 114574 : if (c == p)
7482 tgl@sss.pgh.pa.us 3928 :UBC 0 : goto interpret_error;
3929 : :
8590 bruce@momjian.us 3930 :CBC 114574 : return p;
3931 : :
7482 tgl@sss.pgh.pa.us 3932 :UBC 0 : interpret_error:
3933 : 0 : pqInternalNotice(&res->noticeHooks,
3934 : : "could not interpret result from server: %s",
3935 : 0 : res->cmdStatus);
3936 : 0 : return "";
3937 : : }
3938 : :
3939 : : /*
3940 : : * PQgetvalue:
3941 : : * return the value of field 'field_num' of row 'tup_num'
3942 : : */
3943 : : char *
9786 bruce@momjian.us 3944 :CBC 18897134 : PQgetvalue(const PGresult *res, int tup_num, int field_num)
3945 : : {
9174 peter_e@gmx.net 3946 [ - + ]: 18897134 : if (!check_tuple_field_number(res, tup_num, field_num))
10581 bruce@momjian.us 3947 :UBC 0 : return NULL;
10581 bruce@momjian.us 3948 :CBC 18897134 : return res->tuples[tup_num][field_num].value;
3949 : : }
3950 : :
3951 : : /*
3952 : : * PQgetlength:
3953 : : * returns the actual length of a field value in bytes.
3954 : : */
3955 : : int
9786 3956 : 21105 : PQgetlength(const PGresult *res, int tup_num, int field_num)
3957 : : {
9174 peter_e@gmx.net 3958 [ - + ]: 21105 : if (!check_tuple_field_number(res, tup_num, field_num))
10340 bruce@momjian.us 3959 :UBC 0 : return 0;
10581 bruce@momjian.us 3960 [ + + ]:CBC 21105 : if (res->tuples[tup_num][field_num].len != NULL_LEN)
3961 : 20925 : return res->tuples[tup_num][field_num].len;
3962 : : else
3963 : 180 : return 0;
3964 : : }
3965 : :
3966 : : /*
3967 : : * PQgetisnull:
3968 : : * returns the null status of a field value.
3969 : : */
3970 : : int
9786 3971 : 3555684 : PQgetisnull(const PGresult *res, int tup_num, int field_num)
3972 : : {
9174 peter_e@gmx.net 3973 [ - + ]: 3555684 : if (!check_tuple_field_number(res, tup_num, field_num))
10340 bruce@momjian.us 3974 :UBC 0 : return 1; /* pretend it is null */
10581 bruce@momjian.us 3975 [ + + ]:CBC 3555684 : if (res->tuples[tup_num][field_num].len == NULL_LEN)
3976 : 583212 : return 1;
3977 : : else
3978 : 2972472 : return 0;
3979 : : }
3980 : :
3981 : : /*
3982 : : * PQnparams:
3983 : : * returns the number of input parameters of a prepared statement.
3984 : : */
3985 : : int
7314 tgl@sss.pgh.pa.us 3986 :UBC 0 : PQnparams(const PGresult *res)
3987 : : {
3988 [ # # ]: 0 : if (!res)
3989 : 0 : return 0;
3990 : 0 : return res->numParameters;
3991 : : }
3992 : :
3993 : : /*
3994 : : * PQparamtype:
3995 : : * returns type Oid of the specified statement parameter.
3996 : : */
3997 : : Oid
3998 : 0 : PQparamtype(const PGresult *res, int param_num)
3999 : : {
4000 [ # # ]: 0 : if (!check_param_number(res, param_num))
4001 : 0 : return InvalidOid;
4002 [ # # ]: 0 : if (res->paramDescs)
4003 : 0 : return res->paramDescs[param_num].typid;
4004 : : else
4005 : 0 : return InvalidOid;
4006 : : }
4007 : :
4008 : :
4009 : : /*
4010 : : * PQsetnonblocking:
4011 : : * sets the PGconn's database connection non-blocking if the arg is true
4012 : : * or makes it blocking if the arg is false, this will not protect
4013 : : * you from PQexec(), you'll only be safe when using the non-blocking API.
4014 : : * Needs to be called only on a connected database connection.
4015 : : */
4016 : : int
9718 bruce@momjian.us 4017 :CBC 5 : PQsetnonblocking(PGconn *conn, int arg)
4018 : : {
4019 : : bool barg;
4020 : :
8468 tgl@sss.pgh.pa.us 4021 [ + - - + ]: 5 : if (!conn || conn->status == CONNECTION_BAD)
8468 tgl@sss.pgh.pa.us 4022 :UBC 0 : return -1;
4023 : :
3298 peter_e@gmx.net 4024 :CBC 5 : barg = (arg ? true : false);
4025 : :
4026 : : /* early out if the socket is already in the state requested */
8415 tgl@sss.pgh.pa.us 4027 [ - + ]: 5 : if (barg == conn->nonblocking)
7533 neilc@samurai.com 4028 :UBC 0 : return 0;
4029 : :
4030 : : /*
4031 : : * to guarantee constancy for flushing/query/result-polling behavior we
4032 : : * need to flush the send queue at this point in order to guarantee proper
4033 : : * behavior. this is ok because either they are making a transition _from_
4034 : : * or _to_ blocking mode, either way we can block them.
4035 : : *
4036 : : * Clear error state in case pqFlush adds to it, unless we're actively
4037 : : * pipelining, in which case it seems best not to.
4038 : : */
1641 tgl@sss.pgh.pa.us 4039 [ + + ]:CBC 5 : if (conn->cmd_queue_head == NULL)
4040 : 4 : pqClearConnErrorState(conn);
4041 : :
4042 : : /* if we are going from blocking to non-blocking flush here */
9712 bruce@momjian.us 4043 [ - + ]: 5 : if (pqFlush(conn))
7533 neilc@samurai.com 4044 :UBC 0 : return -1;
4045 : :
8415 tgl@sss.pgh.pa.us 4046 :CBC 5 : conn->nonblocking = barg;
4047 : :
7533 neilc@samurai.com 4048 : 5 : return 0;
4049 : : }
4050 : :
4051 : : /*
4052 : : * return the blocking status of the database connection
4053 : : * true == nonblocking, false == blocking
4054 : : */
4055 : : int
9718 bruce@momjian.us 4056 : 2 : PQisnonblocking(const PGconn *conn)
4057 : : {
1473 tgl@sss.pgh.pa.us 4058 [ + - - + ]: 2 : if (!conn || conn->status == CONNECTION_BAD)
1473 tgl@sss.pgh.pa.us 4059 :UBC 0 : return false;
7533 neilc@samurai.com 4060 :CBC 2 : return pqIsnonblocking(conn);
4061 : : }
4062 : :
4063 : : /* libpq is thread-safe? */
4064 : : int
7401 bruce@momjian.us 4065 :UBC 0 : PQisthreadsafe(void)
4066 : : {
4067 : 0 : return true;
4068 : : }
4069 : :
4070 : :
4071 : : /* try to force data out, really only useful for non-blocking users */
4072 : : int
9718 bruce@momjian.us 4073 :CBC 174185 : PQflush(PGconn *conn)
4074 : : {
1473 tgl@sss.pgh.pa.us 4075 [ + - - + ]: 174185 : if (!conn || conn->status == CONNECTION_BAD)
1473 tgl@sss.pgh.pa.us 4076 :UBC 0 : return -1;
7790 bruce@momjian.us 4077 :CBC 174185 : return pqFlush(conn);
4078 : : }
4079 : :
4080 : : /*
4081 : : * pqPipelineFlush
4082 : : *
4083 : : * In pipeline mode, data will be flushed only when the out buffer reaches the
4084 : : * threshold value. In non-pipeline mode, it behaves as stock pqFlush.
4085 : : *
4086 : : * Returns 0 on success.
4087 : : */
4088 : : static int
1991 alvherre@alvh.no-ip. 4089 : 14129 : pqPipelineFlush(PGconn *conn)
4090 : : {
4091 [ + + ]: 14129 : if ((conn->pipelineStatus != PQ_PIPELINE_ON) ||
4092 [ - + ]: 2546 : (conn->outCount >= OUTBUFFER_THRESHOLD))
4093 : 11583 : return pqFlush(conn);
4094 : 2546 : return 0;
4095 : : }
4096 : :
4097 : :
4098 : : /*
4099 : : * PQfreemem - safely frees memory allocated
4100 : : *
4101 : : * Needed mostly by Win32, unless multithreaded DLL (/MD in VC6)
4102 : : * Used for freeing memory from PQescapeBytea()/PQunescapeBytea()
4103 : : */
4104 : : void
8424 bruce@momjian.us 4105 : 2698820 : PQfreemem(void *ptr)
4106 : : {
8512 tgl@sss.pgh.pa.us 4107 : 2698820 : free(ptr);
4108 : 2698820 : }
4109 : :
4110 : : /*
4111 : : * PQfreeNotify - free's the memory associated with a PGnotify
4112 : : *
4113 : : * This function is here only for binary backward compatibility.
4114 : : * New code should use PQfreemem(). A macro will automatically map
4115 : : * calls to PQfreemem. It should be removed in the future. bjm 2003-03-24
4116 : : */
4117 : :
4118 : : #undef PQfreeNotify
4119 : : void PQfreeNotify(PGnotify *notify);
4120 : :
4121 : : void
8556 bruce@momjian.us 4122 :UBC 0 : PQfreeNotify(PGnotify *notify)
4123 : : {
4124 : 0 : PQfreemem(notify);
4125 : 0 : }
4126 : :
4127 : :
4128 : : /*
4129 : : * Escaping arbitrary strings to get valid SQL literal strings.
4130 : : *
4131 : : * Replaces "'" with "''", and if not std_strings, replaces "\" with "\\".
4132 : : *
4133 : : * length is the length of the source string. (Note: if a terminating NUL
4134 : : * is encountered sooner, PQescapeString stops short of "length"; the behavior
4135 : : * is thus rather like strncpy.)
4136 : : *
4137 : : * For safety the buffer at "to" must be at least 2*length + 1 bytes long.
4138 : : * A terminating NUL character is added to the output string, whether the
4139 : : * input is NUL-terminated or not.
4140 : : *
4141 : : * Returns the actual length of the output (not counting the terminating NUL).
4142 : : */
4143 : : static size_t
7403 tgl@sss.pgh.pa.us 4144 :CBC 6527 : PQescapeStringInternal(PGconn *conn,
4145 : : char *to, const char *from, size_t length,
4146 : : int *error,
4147 : : int encoding, bool std_strings)
4148 : : {
8512 4149 : 6527 : const char *source = from;
4150 : 6527 : char *target = to;
563 andres@anarazel.de 4151 : 6527 : size_t remaining = strnlen(from, length);
558 tgl@sss.pgh.pa.us 4152 : 6527 : bool already_complained = false;
4153 : :
7403 4154 [ + + ]: 6527 : if (error)
4155 : 64 : *error = 0;
4156 : :
563 andres@anarazel.de 4157 [ + + ]: 114075 : while (remaining > 0)
4158 : : {
7267 bruce@momjian.us 4159 : 107548 : char c = *source;
4160 : : int charlen;
4161 : : int i;
4162 : :
4163 : : /* Fast path for plain ASCII */
7403 tgl@sss.pgh.pa.us 4164 [ + + ]: 107548 : if (!IS_HIGHBIT_SET(c))
4165 : : {
4166 : : /* Apply quoting if needed */
7396 4167 [ + + + + : 106672 : if (SQL_STR_DOUBLE(c, !std_strings))
- + ]
7403 4168 : 46 : *target++ = c;
4169 : : /* Copy the character */
4170 : 106672 : *target++ = c;
4171 : 106672 : source++;
4172 : 106672 : remaining--;
4173 : 106672 : continue;
4174 : : }
4175 : :
4176 : : /* Slow path for possible multibyte characters */
479 noah@leadboat.com 4177 : 876 : charlen = pg_encoding_mblen_or_incomplete(encoding,
4178 : : source, remaining);
4179 : :
558 tgl@sss.pgh.pa.us 4180 [ + + + + ]: 1698 : if (remaining < charlen ||
4181 : 822 : pg_encoding_verifymbchar(encoding, source, charlen) == -1)
4182 : : {
4183 : : /*
4184 : : * Multibyte character is invalid. It's important to verify that
4185 : : * as invalid multibyte characters could e.g. be used to "skip"
4186 : : * over quote characters, e.g. when parsing
4187 : : * character-by-character.
4188 : : *
4189 : : * Report an error if possible, and replace the character's first
4190 : : * byte with an invalid sequence. The invalid sequence ensures
4191 : : * that the escaped string will trigger an error on the
4192 : : * server-side, even if we can't directly report an error here.
4193 : : *
4194 : : * This isn't *that* crucial when we can report an error to the
4195 : : * caller; but if we can't or the caller ignores it, the caller
4196 : : * will use this string unmodified and it needs to be safe for
4197 : : * parsing.
4198 : : *
4199 : : * We know there's enough space for the invalid sequence because
4200 : : * the "to" buffer needs to be at least 2 * length + 1 long, and
4201 : : * at worst we're replacing a single input byte with two invalid
4202 : : * bytes.
4203 : : *
4204 : : * It would be a bit faster to verify the whole string the first
4205 : : * time we encounter a set highbit, but this way we can replace
4206 : : * just the invalid data, which probably makes it easier for users
4207 : : * to find the invalidly encoded portion of a larger string.
4208 : : */
7403 4209 [ + + ]: 80 : if (error)
4210 : 40 : *error = 1;
558 4211 [ + + + - ]: 80 : if (conn && !already_complained)
4212 : : {
4213 [ + + ]: 40 : if (remaining < charlen)
4214 : 27 : libpq_append_conn_error(conn, "incomplete multibyte character");
4215 : : else
4216 : 13 : libpq_append_conn_error(conn, "invalid multibyte character");
4217 : : /* Issue a complaint only once per string */
4218 : 40 : already_complained = true;
4219 : : }
4220 : :
563 andres@anarazel.de 4221 : 80 : pg_encoding_set_invalid(encoding, target);
4222 : 80 : target += 2;
4223 : :
4224 : : /*
4225 : : * Handle the following bytes as if this byte didn't exist. That's
4226 : : * safer in case the subsequent bytes contain important characters
4227 : : * for the caller (e.g. '>' in html).
4228 : : */
558 tgl@sss.pgh.pa.us 4229 : 80 : source++;
4230 : 80 : remaining--;
4231 : : }
4232 : : else
4233 : : {
4234 : : /* Copy the character */
563 andres@anarazel.de 4235 [ + + ]: 1618 : for (i = 0; i < charlen; i++)
4236 : : {
4237 : 822 : *target++ = *source++;
4238 : 822 : remaining--;
4239 : : }
4240 : : }
4241 : : }
4242 : :
4243 : : /* Write the terminating NUL character. */
8512 tgl@sss.pgh.pa.us 4244 : 6527 : *target = '\0';
4245 : :
4246 : 6527 : return target - to;
4247 : : }
4248 : :
4249 : : size_t
7403 4250 : 6463 : PQescapeStringConn(PGconn *conn,
4251 : : char *to, const char *from, size_t length,
4252 : : int *error)
4253 : : {
4254 [ - + ]: 6463 : if (!conn)
4255 : : {
4256 : : /* force empty-string result */
7403 tgl@sss.pgh.pa.us 4257 :UBC 0 : *to = '\0';
4258 [ # # ]: 0 : if (error)
4259 : 0 : *error = 1;
4260 : 0 : return 0;
4261 : : }
4262 : :
1641 tgl@sss.pgh.pa.us 4263 [ + - ]:CBC 6463 : if (conn->cmd_queue_head == NULL)
4264 : 6463 : pqClearConnErrorState(conn);
4265 : :
7403 4266 : 6463 : return PQescapeStringInternal(conn, to, from, length, error,
4267 : : conn->client_encoding,
4268 : 6463 : conn->std_strings);
4269 : : }
4270 : :
4271 : : size_t
4272 : 64 : PQescapeString(char *to, const char *from, size_t length)
4273 : : {
4274 : 64 : return PQescapeStringInternal(NULL, to, from, length, NULL,
4275 : : static_client_encoding,
4276 : : static_std_strings);
4277 : : }
4278 : :
4279 : :
4280 : : /*
4281 : : * Escape arbitrary strings. If as_ident is true, we escape the result
4282 : : * as an identifier; if false, as a literal. The result is returned in
4283 : : * a newly allocated buffer. If we fail due to an encoding violation or out
4284 : : * of memory condition, we return NULL, storing an error message into conn.
4285 : : */
4286 : : static char *
6062 rhaas@postgresql.org 4287 : 1113 : PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
4288 : : {
4289 : : const char *s;
4290 : : char *result;
4291 : : char *rp;
290 jchampion@postgresql 4292 : 1113 : size_t num_quotes = 0; /* single or double, depending on as_ident */
4293 : 1113 : size_t num_backslashes = 0;
559 andres@anarazel.de 4294 : 1113 : size_t input_len = strnlen(str, len);
4295 : : size_t result_size;
6026 bruce@momjian.us 4296 [ + + ]: 1113 : char quote_char = as_ident ? '"' : '\'';
563 andres@anarazel.de 4297 : 1113 : bool validated_mb = false;
4298 : :
4299 : : /* We must have a connection, else fail immediately. */
6062 rhaas@postgresql.org 4300 [ - + ]: 1113 : if (!conn)
6062 rhaas@postgresql.org 4301 :UBC 0 : return NULL;
4302 : :
1641 tgl@sss.pgh.pa.us 4303 [ + - ]:CBC 1113 : if (conn->cmd_queue_head == NULL)
4304 : 1113 : pqClearConnErrorState(conn);
4305 : :
4306 : : /*
4307 : : * Scan the string for characters that must be escaped and for invalidly
4308 : : * encoded data.
4309 : : */
563 andres@anarazel.de 4310 : 1113 : s = str;
4311 [ + + ]: 577272 : for (size_t remaining = input_len; remaining > 0; remaining--, s++)
4312 : : {
6062 rhaas@postgresql.org 4313 [ + + ]: 576240 : if (*s == quote_char)
4314 : 97 : ++num_quotes;
4315 [ + + ]: 576143 : else if (*s == '\\')
4316 : 154 : ++num_backslashes;
4317 [ + + ]: 575989 : else if (IS_HIGHBIT_SET(*s))
4318 : : {
4319 : : int charlen;
4320 : :
4321 : : /* Slow path for possible multibyte characters */
479 noah@leadboat.com 4322 : 109 : charlen = pg_encoding_mblen_or_incomplete(conn->client_encoding,
4323 : : s, remaining);
4324 : :
563 andres@anarazel.de 4325 [ + + ]: 109 : if (charlen > remaining)
4326 : : {
4327 : : /* Multibyte character overruns allowable length. */
1381 peter@eisentraut.org 4328 : 55 : libpq_append_conn_error(conn, "incomplete multibyte character");
6062 rhaas@postgresql.org 4329 : 55 : return NULL;
4330 : : }
4331 : :
4332 : : /*
4333 : : * If we haven't already, check that multibyte characters are
4334 : : * valid. It's important to verify that as invalid multi-byte
4335 : : * characters could e.g. be used to "skip" over quote characters,
4336 : : * e.g. when parsing character-by-character.
4337 : : *
4338 : : * We check validity once, for the whole remainder of the string,
4339 : : * when we first encounter any multi-byte character. Some
4340 : : * encodings have optimized implementations for longer strings.
4341 : : */
563 andres@anarazel.de 4342 [ + - ]: 54 : if (!validated_mb)
4343 : : {
4344 [ + + ]: 54 : if (pg_encoding_verifymbstr(conn->client_encoding, s, remaining)
4345 : : != remaining)
4346 : : {
4347 : 26 : libpq_append_conn_error(conn, "invalid multibyte character");
4348 : 26 : return NULL;
4349 : : }
4350 : 28 : validated_mb = true;
4351 : : }
4352 : :
4353 : : /* Adjust s, bearing in mind that for loop will increment it. */
6062 rhaas@postgresql.org 4354 : 28 : s += charlen - 1;
563 andres@anarazel.de 4355 : 28 : remaining -= charlen - 1;
4356 : : }
4357 : : }
4358 : :
4359 : : /*
4360 : : * Allocate output buffer. Protect against overflow, in case the caller
4361 : : * has allocated a large fraction of the available size_t.
4362 : : */
276 jchampion@postgresql 4363 [ + - - + ]: 2064 : if (pg_add_size_overflow(input_len, num_quotes, &result_size) ||
4364 : 1032 : pg_add_size_overflow(result_size, 3, &result_size)) /* two quotes plus a NUL */
290 jchampion@postgresql 4365 :UBC 0 : goto overflow;
4366 : :
6062 rhaas@postgresql.org 4367 [ + + + + ]:CBC 1032 : if (!as_ident && num_backslashes > 0)
4368 : : {
276 jchampion@postgresql 4369 [ + - - + ]: 60 : if (pg_add_size_overflow(result_size, num_backslashes, &result_size) ||
4370 : 30 : pg_add_size_overflow(result_size, 2, &result_size)) /* for " E" prefix */
290 jchampion@postgresql 4371 :UBC 0 : goto overflow;
4372 : : }
4373 : :
6062 rhaas@postgresql.org 4374 :CBC 1032 : result = rp = (char *) malloc(result_size);
4375 [ - + ]: 1032 : if (rp == NULL)
4376 : : {
1381 peter@eisentraut.org 4377 :UBC 0 : libpq_append_conn_error(conn, "out of memory");
6062 rhaas@postgresql.org 4378 : 0 : return NULL;
4379 : : }
4380 : :
4381 : : /*
4382 : : * If we are escaping a literal that contains backslashes, we use the
4383 : : * escape string syntax so that the result is correct under either value
4384 : : * of standard_conforming_strings. We also emit a leading space in this
4385 : : * case, to guard against the possibility that the result might be
4386 : : * interpolated immediately following an identifier.
4387 : : */
6062 rhaas@postgresql.org 4388 [ + + + + ]:CBC 1032 : if (!as_ident && num_backslashes > 0)
4389 : : {
4390 : 30 : *rp++ = ' ';
4391 : 30 : *rp++ = 'E';
4392 : : }
4393 : :
4394 : : /* Opening quote. */
4395 : 1032 : *rp++ = quote_char;
4396 : :
4397 : : /*
4398 : : * Use fast path if possible.
4399 : : *
4400 : : * We've already verified that the input string is well-formed in the
4401 : : * current encoding. If it contains no quotes and, in the case of
4402 : : * literal-escaping, no backslashes, then we can just copy it directly to
4403 : : * the output buffer, adding the necessary quotes.
4404 : : *
4405 : : * If not, we must rescan the input and process each character
4406 : : * individually.
4407 : : */
4408 [ + + + + : 1032 : if (num_quotes == 0 && (num_backslashes == 0 || as_ident))
+ + ]
4409 : : {
4410 : 977 : memcpy(rp, str, input_len);
4411 : 977 : rp += input_len;
4412 : : }
4413 : : else
4414 : : {
563 andres@anarazel.de 4415 : 55 : s = str;
4416 [ + + ]: 3572 : for (size_t remaining = input_len; remaining > 0; remaining--, s++)
4417 : : {
6062 rhaas@postgresql.org 4418 [ + + + + : 3517 : if (*s == quote_char || (!as_ident && *s == '\\'))
+ + ]
4419 : : {
4420 : 231 : *rp++ = *s;
4421 : 231 : *rp++ = *s;
4422 : : }
4423 [ + + ]: 3286 : else if (!IS_HIGHBIT_SET(*s))
4424 : 3275 : *rp++ = *s;
4425 : : else
4426 : : {
6026 bruce@momjian.us 4427 : 11 : int i = pg_encoding_mblen(conn->client_encoding, s);
4428 : :
4429 : : while (1)
4430 : : {
6062 rhaas@postgresql.org 4431 : 21 : *rp++ = *s;
4432 [ + + ]: 21 : if (--i == 0)
4433 : 11 : break;
563 andres@anarazel.de 4434 : 10 : remaining--;
6026 bruce@momjian.us 4435 : 10 : ++s; /* for loop will provide the final increment */
4436 : : }
4437 : : }
4438 : : }
4439 : : }
4440 : :
4441 : : /* Closing quote and terminating NUL. */
6062 rhaas@postgresql.org 4442 : 1032 : *rp++ = quote_char;
4443 : 1032 : *rp = '\0';
4444 : :
4445 : 1032 : return result;
4446 : :
290 jchampion@postgresql 4447 :UBC 0 : overflow:
4448 : 0 : libpq_append_conn_error(conn,
4449 : : "escaped string size exceeds the maximum allowed (%zu)",
4450 : : SIZE_MAX);
4451 : 0 : return NULL;
4452 : : }
4453 : :
4454 : : char *
6062 rhaas@postgresql.org 4455 :CBC 929 : PQescapeLiteral(PGconn *conn, const char *str, size_t len)
4456 : : {
4457 : 929 : return PQescapeInternal(conn, str, len, false);
4458 : : }
4459 : :
4460 : : char *
4461 : 184 : PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
4462 : : {
4463 : 184 : return PQescapeInternal(conn, str, len, true);
4464 : : }
4465 : :
4466 : : /* HEX encoding support for bytea */
4467 : : static const char hextbl[] = "0123456789abcdef";
4468 : :
4469 : : static const int8 hexlookup[128] = {
4470 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4471 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4472 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4473 : : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4474 : : -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4475 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4476 : : -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4477 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4478 : : };
4479 : :
4480 : : static inline char
6232 tgl@sss.pgh.pa.us 4481 :UBC 0 : get_hex(char c)
4482 : : {
4483 : 0 : int res = -1;
4484 : :
4485 [ # # # # ]: 0 : if (c > 0 && c < 127)
4486 : 0 : res = hexlookup[(unsigned char) c];
4487 : :
4488 : 0 : return (char) res;
4489 : : }
4490 : :
4491 : :
4492 : : /*
4493 : : * PQescapeBytea - converts from binary string to the
4494 : : * minimal encoding necessary to include the string in an SQL
4495 : : * INSERT statement with a bytea type column as the target.
4496 : : *
4497 : : * We can use either hex or escape (traditional) encoding.
4498 : : * In escape mode, the following transformations are applied:
4499 : : * '\0' == ASCII 0 == \000
4500 : : * '\'' == ASCII 39 == ''
4501 : : * '\\' == ASCII 92 == \\
4502 : : * anything < 0x20, or > 0x7e ---> \ooo
4503 : : * (where ooo is an octal expression)
4504 : : *
4505 : : * If not std_strings, all backslashes sent to the output are doubled.
4506 : : */
4507 : : static unsigned char *
7403 4508 : 0 : PQescapeByteaInternal(PGconn *conn,
4509 : : const unsigned char *from, size_t from_length,
4510 : : size_t *to_length, bool std_strings, bool use_hex)
4511 : : {
4512 : : const unsigned char *vp;
4513 : : unsigned char *rp;
4514 : : unsigned char *result;
4515 : : size_t i;
4516 : : size_t len;
290 jchampion@postgresql 4517 [ # # ]: 0 : const size_t bslash_len = (std_strings ? 1 : 2);
4518 : :
4519 : : /*
4520 : : * Calculate the escaped length, watching for overflow as we do with
4521 : : * PQescapeInternal(). The following code relies on a small constant
4522 : : * bslash_len so that small additions and multiplications don't need their
4523 : : * own overflow checks.
4524 : : *
4525 : : * Start with the empty string, which has 1 char ('\0').
4526 : : */
8512 tgl@sss.pgh.pa.us 4527 : 0 : len = 1;
4528 : :
6232 4529 [ # # ]: 0 : if (use_hex)
4530 : : {
4531 : : /* We prepend "\x" and double each input character. */
276 jchampion@postgresql 4532 [ # # # # ]: 0 : if (pg_add_size_overflow(len, bslash_len + 1, &len) ||
4533 [ # # ]: 0 : pg_add_size_overflow(len, from_length, &len) ||
4534 : 0 : pg_add_size_overflow(len, from_length, &len))
290 4535 : 0 : goto overflow;
4536 : : }
4537 : : else
4538 : : {
6232 tgl@sss.pgh.pa.us 4539 : 0 : vp = from;
4540 [ # # ]: 0 : for (i = from_length; i > 0; i--, vp++)
4541 : : {
4542 [ # # # # ]: 0 : if (*vp < 0x20 || *vp > 0x7e)
4543 : : {
276 jchampion@postgresql 4544 [ # # ]: 0 : if (pg_add_size_overflow(len, bslash_len + 3, &len)) /* octal "\ooo" */
290 4545 : 0 : goto overflow;
4546 : : }
6232 tgl@sss.pgh.pa.us 4547 [ # # ]: 0 : else if (*vp == '\'')
4548 : : {
276 jchampion@postgresql 4549 [ # # ]: 0 : if (pg_add_size_overflow(len, 2, &len)) /* double each quote */
290 4550 : 0 : goto overflow;
4551 : : }
6232 tgl@sss.pgh.pa.us 4552 [ # # ]: 0 : else if (*vp == '\\')
4553 : : {
276 jchampion@postgresql 4554 [ # # ]: 0 : if (pg_add_size_overflow(len, bslash_len * 2, &len)) /* double each backslash */
290 4555 : 0 : goto overflow;
4556 : : }
4557 : : else
4558 : : {
276 4559 [ # # ]: 0 : if (pg_add_size_overflow(len, 1, &len))
290 4560 : 0 : goto overflow;
4561 : : }
4562 : : }
4563 : : }
4564 : :
7403 tgl@sss.pgh.pa.us 4565 : 0 : *to_length = len;
8512 4566 : 0 : rp = result = (unsigned char *) malloc(len);
4567 [ # # ]: 0 : if (rp == NULL)
4568 : : {
7403 4569 [ # # ]: 0 : if (conn)
1381 peter@eisentraut.org 4570 : 0 : libpq_append_conn_error(conn, "out of memory");
8512 tgl@sss.pgh.pa.us 4571 : 0 : return NULL;
4572 : : }
4573 : :
6232 4574 [ # # ]: 0 : if (use_hex)
4575 : : {
4576 [ # # ]: 0 : if (!std_strings)
4577 : 0 : *rp++ = '\\';
4578 : 0 : *rp++ = '\\';
4579 : 0 : *rp++ = 'x';
4580 : : }
4581 : :
7403 4582 : 0 : vp = from;
4583 [ # # ]: 0 : for (i = from_length; i > 0; i--, vp++)
4584 : : {
6232 4585 : 0 : unsigned char c = *vp;
4586 : :
4587 [ # # ]: 0 : if (use_hex)
4588 : : {
4589 : 0 : *rp++ = hextbl[(c >> 4) & 0xF];
4590 : 0 : *rp++ = hextbl[c & 0xF];
4591 : : }
4592 [ # # # # ]: 0 : else if (c < 0x20 || c > 0x7e)
4593 : : {
7403 4594 [ # # ]: 0 : if (!std_strings)
4595 : 0 : *rp++ = '\\';
6560 4596 : 0 : *rp++ = '\\';
6232 4597 : 0 : *rp++ = (c >> 6) + '0';
4598 : 0 : *rp++ = ((c >> 3) & 07) + '0';
4599 : 0 : *rp++ = (c & 07) + '0';
4600 : : }
4601 [ # # ]: 0 : else if (c == '\'')
4602 : : {
7403 4603 : 0 : *rp++ = '\'';
4604 : 0 : *rp++ = '\'';
4605 : : }
6232 4606 [ # # ]: 0 : else if (c == '\\')
4607 : : {
7403 4608 [ # # ]: 0 : if (!std_strings)
4609 : : {
4610 : 0 : *rp++ = '\\';
4611 : 0 : *rp++ = '\\';
4612 : : }
4613 : 0 : *rp++ = '\\';
4614 : 0 : *rp++ = '\\';
4615 : : }
4616 : : else
6232 4617 : 0 : *rp++ = c;
4618 : : }
8512 4619 : 0 : *rp = '\0';
4620 : :
4621 : 0 : return result;
4622 : :
290 jchampion@postgresql 4623 : 0 : overflow:
4624 [ # # ]: 0 : if (conn)
4625 : 0 : libpq_append_conn_error(conn,
4626 : : "escaped bytea size exceeds the maximum allowed (%zu)",
4627 : : SIZE_MAX);
4628 : 0 : return NULL;
4629 : : }
4630 : :
4631 : : unsigned char *
7403 tgl@sss.pgh.pa.us 4632 : 0 : PQescapeByteaConn(PGconn *conn,
4633 : : const unsigned char *from, size_t from_length,
4634 : : size_t *to_length)
4635 : : {
4636 [ # # ]: 0 : if (!conn)
4637 : 0 : return NULL;
4638 : :
1641 4639 [ # # ]: 0 : if (conn->cmd_queue_head == NULL)
4640 : 0 : pqClearConnErrorState(conn);
4641 : :
7403 4642 : 0 : return PQescapeByteaInternal(conn, from, from_length, to_length,
6232 4643 : 0 : conn->std_strings,
6035 4644 : 0 : (conn->sversion >= 90000));
4645 : : }
4646 : :
4647 : : unsigned char *
7403 4648 : 0 : PQescapeBytea(const unsigned char *from, size_t from_length, size_t *to_length)
4649 : : {
4650 : 0 : return PQescapeByteaInternal(NULL, from, from_length, to_length,
4651 : : static_std_strings,
4652 : : false /* can't use hex */ );
4653 : : }
4654 : :
4655 : :
4656 : : #define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3')
4657 : : #define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7')
4658 : : #define OCTVAL(CH) ((CH) - '0')
4659 : :
4660 : : /*
4661 : : * PQunescapeBytea - converts the null terminated string representation
4662 : : * of a bytea, strtext, into binary, filling a buffer. It returns a
4663 : : * pointer to the buffer (or NULL on error), and the size of the
4664 : : * buffer in retbuflen. The pointer may subsequently be used as an
4665 : : * argument to the function PQfreemem.
4666 : : *
4667 : : * The following transformations are made:
4668 : : * \\ == ASCII 92 == \
4669 : : * \ooo == a byte whose value = ooo (ooo is an octal number)
4670 : : * \x == x (x is any character not matched by the above transformations)
4671 : : */
4672 : : unsigned char *
8512 4673 : 0 : PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
4674 : : {
4675 : : size_t strtextlen,
4676 : : buflen;
4677 : : unsigned char *buffer,
4678 : : *tmpbuf;
4679 : : size_t i,
4680 : : j;
4681 : :
8424 bruce@momjian.us 4682 [ # # ]: 0 : if (strtext == NULL)
8512 tgl@sss.pgh.pa.us 4683 : 0 : return NULL;
4684 : :
7642 4685 : 0 : strtextlen = strlen((const char *) strtext);
4686 : :
6232 4687 [ # # # # ]: 0 : if (strtext[0] == '\\' && strtext[1] == 'x')
4688 : 0 : {
4689 : : const unsigned char *s;
4690 : : unsigned char *p;
4691 : :
6026 bruce@momjian.us 4692 : 0 : buflen = (strtextlen - 2) / 2;
4693 : : /* Avoid unportable malloc(0) */
6232 tgl@sss.pgh.pa.us 4694 [ # # ]: 0 : buffer = (unsigned char *) malloc(buflen > 0 ? buflen : 1);
4695 [ # # ]: 0 : if (buffer == NULL)
4696 : 0 : return NULL;
4697 : :
4698 : 0 : s = strtext + 2;
4699 : 0 : p = buffer;
4700 [ # # ]: 0 : while (*s)
4701 : : {
4702 : : char v1,
4703 : : v2;
4704 : :
4705 : : /*
4706 : : * Bad input is silently ignored. Note that this includes
4707 : : * whitespace between hex pairs, which is allowed by byteain.
4708 : : */
4709 : 0 : v1 = get_hex(*s++);
4710 [ # # # # ]: 0 : if (!*s || v1 == (char) -1)
4711 : 0 : continue;
4712 : 0 : v2 = get_hex(*s++);
4713 [ # # ]: 0 : if (v2 != (char) -1)
4714 : 0 : *p++ = (v1 << 4) | v2;
4715 : : }
4716 : :
4717 : 0 : buflen = p - buffer;
4718 : : }
4719 : : else
4720 : : {
4721 : : /*
4722 : : * Length of input is max length of output, but add one to avoid
4723 : : * unportable malloc(0) if input is zero-length.
4724 : : */
6026 bruce@momjian.us 4725 : 0 : buffer = (unsigned char *) malloc(strtextlen + 1);
4726 [ # # ]: 0 : if (buffer == NULL)
4727 : 0 : return NULL;
4728 : :
4729 [ # # ]: 0 : for (i = j = 0; i < strtextlen;)
4730 : : {
4731 [ # # ]: 0 : switch (strtext[i])
4732 : : {
4733 : 0 : case '\\':
4734 : 0 : i++;
4735 [ # # ]: 0 : if (strtext[i] == '\\')
4736 : 0 : buffer[j++] = strtext[i++];
4737 : : else
4738 : : {
4739 [ # # # # ]: 0 : if ((ISFIRSTOCTDIGIT(strtext[i])) &&
4740 [ # # # # ]: 0 : (ISOCTDIGIT(strtext[i + 1])) &&
4741 [ # # # # ]: 0 : (ISOCTDIGIT(strtext[i + 2])))
4742 : : {
4743 : : int byte;
4744 : :
4745 : 0 : byte = OCTVAL(strtext[i++]);
5618 4746 : 0 : byte = (byte << 3) + OCTVAL(strtext[i++]);
4747 : 0 : byte = (byte << 3) + OCTVAL(strtext[i++]);
6026 4748 : 0 : buffer[j++] = byte;
4749 : : }
4750 : : }
4751 : :
4752 : : /*
4753 : : * Note: if we see '\' followed by something that isn't a
4754 : : * recognized escape sequence, we loop around having done
4755 : : * nothing except advance i. Therefore the something will
4756 : : * be emitted as ordinary data on the next cycle. Corner
4757 : : * case: '\' at end of string will just be discarded.
4758 : : */
4759 : 0 : break;
4760 : :
4761 : 0 : default:
4762 : 0 : buffer[j++] = strtext[i++];
4763 : 0 : break;
4764 : : }
4765 : : }
4766 : 0 : buflen = j; /* buflen is the length of the dequoted data */
4767 : : }
4768 : :
4769 : : /* Shrink the buffer to be no larger than necessary */
4770 : : /* +1 avoids unportable behavior when buflen==0 */
8336 tgl@sss.pgh.pa.us 4771 : 0 : tmpbuf = realloc(buffer, buflen + 1);
4772 : :
4773 : : /* It would only be a very brain-dead realloc that could fail, but... */
8477 bruce@momjian.us 4774 [ # # ]: 0 : if (!tmpbuf)
4775 : : {
4776 : 0 : free(buffer);
8365 tgl@sss.pgh.pa.us 4777 : 0 : return NULL;
4778 : : }
4779 : :
8512 4780 : 0 : *retbuflen = buflen;
8477 bruce@momjian.us 4781 : 0 : return tmpbuf;
4782 : : }
|