LCOV - differential code coverage report
Current view: top level - src/interfaces/libpq - pqexpbuffer.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 77.2 % 114 88 3 19 4 4 53 31 18 54
Current Date: 2023-04-08 17:13:01 Functions: 92.3 % 13 12 1 12 1 12
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 77.2 % 114 88 3 19 4 4 53 31 18 54
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 46.2 % 26 12 1 12 1 12

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * pqexpbuffer.c
                                  4                 :  *
                                  5                 :  * PQExpBuffer provides an indefinitely-extensible string data type.
                                  6                 :  * It can be used to buffer either ordinary C strings (null-terminated text)
                                  7                 :  * or arbitrary binary data.  All storage is allocated with malloc().
                                  8                 :  *
                                  9                 :  * This module is essentially the same as the backend's StringInfo data type,
                                 10                 :  * but it is intended for use in frontend libpq and client applications.
                                 11                 :  * Thus, it does not rely on palloc() nor elog(), nor psprintf.c which
                                 12                 :  * will exit() on error.
                                 13                 :  *
                                 14                 :  * It does rely on vsnprintf(); if configure finds that libc doesn't provide
                                 15                 :  * a usable vsnprintf(), then a copy of our own implementation of it will
                                 16                 :  * be linked into libpq.
                                 17                 :  *
                                 18                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 19                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 20                 :  *
                                 21                 :  * src/interfaces/libpq/pqexpbuffer.c
                                 22                 :  *
                                 23                 :  *-------------------------------------------------------------------------
                                 24                 :  */
                                 25                 : 
                                 26                 : #include "postgres_fe.h"
                                 27                 : 
                                 28                 : #include <limits.h>
                                 29                 : 
                                 30                 : #include "pqexpbuffer.h"
                                 31                 : 
                                 32                 : #ifdef WIN32
                                 33                 : #include "win32.h"
                                 34                 : #endif
                                 35                 : 
                                 36                 : 
                                 37                 : /* All "broken" PQExpBuffers point to this string. */
                                 38                 : static const char oom_buffer[1] = "";
                                 39                 : 
                                 40                 : /* Need a char * for unconstify() compatibility */
                                 41                 : static const char *oom_buffer_ptr = oom_buffer;
                                 42                 : 
                                 43                 : 
                                 44                 : /*
                                 45                 :  * markPQExpBufferBroken
                                 46                 :  *
                                 47                 :  * Put a PQExpBuffer in "broken" state if it isn't already.
 5247 tgl                        48 EUB             :  */
                                 49                 : static void
 5247 tgl                        50 UBC           0 : markPQExpBufferBroken(PQExpBuffer str)
 5247 tgl                        51 EUB             : {
 5247 tgl                        52 UIC           0 :     if (str->data != oom_buffer)
                                 53               0 :         free(str->data);
                                 54                 : 
                                 55                 :     /*
                                 56                 :      * Casting away const here is a bit ugly, but it seems preferable to not
                                 57                 :      * marking oom_buffer const.  We want to do that to encourage the compiler
                                 58                 :      * to put oom_buffer in read-only storage, so that anyone who tries to
 5050 bruce                      59 EUB             :      * scribble on a broken PQExpBuffer will get a failure.
 5247 tgl                        60                 :      */
 1531 peter                      61 UBC           0 :     str->data = unconstify(char *, oom_buffer_ptr);
 5247 tgl                        62               0 :     str->len = 0;
 5247 tgl                        63 UIC           0 :     str->maxlen = 0;
                                 64               0 : }
                                 65                 : 
                                 66                 : /*
                                 67                 :  * createPQExpBuffer
                                 68                 :  *
                                 69                 :  * Create an empty 'PQExpBufferData' & return a pointer to it.
 8622 tgl                        70 ECB             :  */
                                 71                 : PQExpBuffer
 8622 tgl                        72 GIC      288432 : createPQExpBuffer(void)
                                 73                 : {
 8397 bruce                      74 ECB             :     PQExpBuffer res;
 8622 tgl                        75                 : 
 8622 tgl                        76 CBC      288432 :     res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
 8622 tgl                        77 GIC      288432 :     if (res != NULL)
 8622 tgl                        78 CBC      288432 :         initPQExpBuffer(res);
                                 79                 : 
 8622 tgl                        80 GIC      288432 :     return res;
                                 81                 : }
                                 82                 : 
                                 83                 : /*
                                 84                 :  * initPQExpBuffer
                                 85                 :  *
                                 86                 :  * Initialize a PQExpBufferData struct (with previously undefined contents)
                                 87                 :  * to describe an empty string.
 8622 tgl                        88 ECB             :  */
                                 89                 : void
 8622 tgl                        90 CBC      571531 : initPQExpBuffer(PQExpBuffer str)
 8622 tgl                        91 ECB             : {
 8622 tgl                        92 GIC      571531 :     str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
 8622 tgl                        93 GBC      571531 :     if (str->data == NULL)
 8622 tgl                        94 EUB             :     {
 1418 tgl                        95 UBC           0 :         str->data = unconstify(char *, oom_buffer_ptr); /* see comment above */
 8622 tgl                        96 UIC           0 :         str->maxlen = 0;
                                 97               0 :         str->len = 0;
                                 98                 :     }
 8622 tgl                        99 ECB             :     else
                                100                 :     {
 8622 tgl                       101 CBC      571531 :         str->maxlen = INITIAL_EXPBUFFER_SIZE;
 8622 tgl                       102 GIC      571531 :         str->len = 0;
 8622 tgl                       103 CBC      571531 :         str->data[0] = '\0';
                                104                 :     }
 8622 tgl                       105 GIC      571531 : }
                                106                 : 
                                107                 : /*
                                108                 :  * destroyPQExpBuffer(str);
                                109                 :  *
                                110                 :  *      free()s both the data buffer and the PQExpBufferData.
                                111                 :  *      This is the inverse of createPQExpBuffer().
 8622 tgl                       112 ECB             :  */
                                113                 : void
 8622 tgl                       114 CBC      277228 : destroyPQExpBuffer(PQExpBuffer str)
                                115                 : {
                                116          277228 :     if (str)
 8622 tgl                       117 ECB             :     {
 8622 tgl                       118 GIC      277113 :         termPQExpBuffer(str);
 8622 tgl                       119 CBC      277113 :         free(str);
                                120                 :     }
 8622 tgl                       121 GIC      277228 : }
                                122                 : 
                                123                 : /*
                                124                 :  * termPQExpBuffer(str)
                                125                 :  *      free()s the data buffer but not the PQExpBufferData itself.
                                126                 :  *      This is the inverse of initPQExpBuffer().
 8622 tgl                       127 ECB             :  */
                                128                 : void
 8622 tgl                       129 CBC      508544 : termPQExpBuffer(PQExpBuffer str)
 8622 tgl                       130 ECB             : {
 5247 tgl                       131 GIC      508544 :     if (str->data != oom_buffer)
 8622 tgl                       132 CBC      508544 :         free(str->data);
 8115 tgl                       133 ECB             :     /* just for luck, make the buffer validly empty. */
 1418 tgl                       134 CBC      508544 :     str->data = unconstify(char *, oom_buffer_ptr); /* see comment above */
 8115                           135          508544 :     str->maxlen = 0;
 8115 tgl                       136 GIC      508544 :     str->len = 0;
 8622                           137          508544 : }
                                138                 : 
                                139                 : /*
                                140                 :  * resetPQExpBuffer
                                141                 :  *      Reset a PQExpBuffer to empty
                                142                 :  *
                                143                 :  * Note: if possible, a "broken" PQExpBuffer is returned to normal.
 8622 tgl                       144 ECB             :  */
                                145                 : void
 8622 tgl                       146 CBC     2415258 : resetPQExpBuffer(PQExpBuffer str)
                                147                 : {
                                148         2415258 :     if (str)
                                149                 :     {
 5247                           150         2414498 :         if (str->data != oom_buffer)
 5247 tgl                       151 ECB             :         {
 5247 tgl                       152 GIC     2414498 :             str->len = 0;
 8622                           153         2414498 :             str->data[0] = '\0';
                                154                 :         }
                                155                 :         else
 5247 tgl                       156 EUB             :         {
                                157                 :             /* try to reinitialize to valid state */
 5247 tgl                       158 UIC           0 :             initPQExpBuffer(str);
 5247 tgl                       159 ECB             :         }
                                160                 :     }
 8622 tgl                       161 GIC     2415258 : }
                                162                 : 
                                163                 : /*
                                164                 :  * enlargePQExpBuffer
                                165                 :  * Make sure there is enough space for 'needed' more bytes in the buffer
                                166                 :  * ('needed' does not include the terminating null).
                                167                 :  *
                                168                 :  * Returns 1 if OK, 0 if failed to enlarge buffer.  (In the latter case
                                169                 :  * the buffer is left in "broken" state.)
 8622 tgl                       170 ECB             :  */
                                171                 : int
 8462 peter_e                   172 GIC     6033140 : enlargePQExpBuffer(PQExpBuffer str, size_t needed)
                                173                 : {
                                174                 :     size_t      newlen;
 8622 tgl                       175 ECB             :     char       *newdata;
 8622 tgl                       176 EUB             : 
 5247 tgl                       177 GIC     6033140 :     if (PQExpBufferBroken(str))
 5247 tgl                       178 UIC           0 :         return 0;               /* already failed */
                                179                 : 
                                180                 :     /*
                                181                 :      * Guard against ridiculous "needed" values, which can occur if we're fed
                                182                 :      * bogus data.  Without this, we can get an overflow or infinite loop in
 6385 bruce                     183 ECB             :      * the following.
                                184                 :      */
 6904 tgl                       185 GBC     6033140 :     if (needed >= ((size_t) INT_MAX - str->len))
 5247 tgl                       186 EUB             :     {
 5247 tgl                       187 UIC           0 :         markPQExpBufferBroken(str);
 6904                           188               0 :         return 0;
 5247 tgl                       189 ECB             :     }
                                190                 : 
 8622 tgl                       191 GIC     6033140 :     needed += str->len + 1;      /* total space required now */
                                192                 : 
 6904 tgl                       193 ECB             :     /* Because of the above test, we now have needed <= INT_MAX */
                                194                 : 
 8622 tgl                       195 GIC     6033140 :     if (needed <= str->maxlen)
                                196         6014982 :         return 1;               /* got enough space already */
                                197                 : 
                                198                 :     /*
                                199                 :      * We don't want to allocate just a little more space with each append;
                                200                 :      * for efficiency, double the buffer size each time it overflows.
 6385 bruce                     201 ECB             :      * Actually, we might need to more than double it if 'needed' is big...
 8622 tgl                       202                 :      */
 8115 tgl                       203 CBC       18158 :     newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
 8622 tgl                       204 GIC       20425 :     while (needed > newlen)
                                205            2267 :         newlen = 2 * newlen;
                                206                 : 
                                207                 :     /*
                                208                 :      * Clamp to INT_MAX in case we went past it.  Note we are assuming here
                                209                 :      * that INT_MAX <= UINT_MAX/2, else the above loop could overflow.  We
 6385 bruce                     210 ECB             :      * will still have newlen >= needed.
 6904 tgl                       211 EUB             :      */
 6904 tgl                       212 GIC       18158 :     if (newlen > (size_t) INT_MAX)
 6904 tgl                       213 LBC           0 :         newlen = (size_t) INT_MAX;
 6904 tgl                       214 ECB             : 
 8622 tgl                       215 GIC       18158 :     newdata = (char *) realloc(str->data, newlen);
 8622 tgl                       216 CBC       18158 :     if (newdata != NULL)
 8622 tgl                       217 ECB             :     {
 8622 tgl                       218 CBC       18158 :         str->data = newdata;
 8622 tgl                       219 GIC       18158 :         str->maxlen = newlen;
                                220           18158 :         return 1;
 8622 tgl                       221 EUB             :     }
 5247                           222                 : 
 5247 tgl                       223 UIC           0 :     markPQExpBufferBroken(str);
 8622                           224               0 :     return 0;
                                225                 : }
                                226                 : 
                                227                 : /*
                                228                 :  * printfPQExpBuffer
                                229                 :  * Format text data under the control of fmt (an sprintf-like format string)
                                230                 :  * and insert it into str.  More space is allocated to str if necessary.
                                231                 :  * This is a convenience routine that does the same thing as
                                232                 :  * resetPQExpBuffer() followed by appendPQExpBuffer().
 8622 tgl                       233 ECB             :  */
                                234                 : void
 8622 tgl                       235 CBC      231196 : printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
                                236                 : {
 1656 tgl                       237 GIC      231196 :     int         save_errno = errno;
                                238                 :     va_list     args;
 3453 tgl                       239 ECB             :     bool        done;
                                240                 : 
 8622 tgl                       241 CBC      231196 :     resetPQExpBuffer(str);
 8483 tgl                       242 EUB             : 
 5247 tgl                       243 GIC      231196 :     if (PQExpBufferBroken(str))
 5247 tgl                       244 UIC           0 :         return;                 /* already failed */
                                245                 : 
                                246                 :     /* Loop in case we have to retry after enlarging the buffer. */
 3453 tgl                       247 ECB             :     do
 8483                           248                 :     {
 1656 tgl                       249 CBC      233332 :         errno = save_errno;
 3453                           250          233332 :         va_start(args, fmt);
                                251          233332 :         done = appendPQExpBufferVA(str, fmt, args);
 3453 tgl                       252 GIC      233332 :         va_end(args);
                                253          233332 :     } while (!done);
                                254                 : }
                                255                 : 
                                256                 : /*
                                257                 :  * appendPQExpBuffer
                                258                 :  *
                                259                 :  * Format text data under the control of fmt (an sprintf-like format string)
                                260                 :  * and append it to whatever is already in str.  More space is allocated
                                261                 :  * to str if necessary.  This is sort of like a combination of sprintf and
                                262                 :  * strcat.
 8622 tgl                       263 ECB             :  */
                                264                 : void
 8622 tgl                       265 CBC      325952 : appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
                                266                 : {
 1656 tgl                       267 GIC      325952 :     int         save_errno = errno;
                                268                 :     va_list     args;
 3453 tgl                       269 ECB             :     bool        done;
 8622 tgl                       270 EUB             : 
 5247 tgl                       271 GIC      325952 :     if (PQExpBufferBroken(str))
 5247 tgl                       272 UIC           0 :         return;                 /* already failed */
                                273                 : 
                                274                 :     /* Loop in case we have to retry after enlarging the buffer. */
 3453 tgl                       275 ECB             :     do
                                276                 :     {
 1656 tgl                       277 CBC      335842 :         errno = save_errno;
 3453                           278          335842 :         va_start(args, fmt);
                                279          335842 :         done = appendPQExpBufferVA(str, fmt, args);
 3453 tgl                       280 GIC      335842 :         va_end(args);
                                281          335842 :     } while (!done);
                                282                 : }
                                283                 : 
                                284                 : /*
                                285                 :  * appendPQExpBufferVA
                                286                 :  * Shared guts of printfPQExpBuffer/appendPQExpBuffer.
                                287                 :  * Attempt to format data and append it to str.  Returns true if done
                                288                 :  * (either successful or hard failure), false if need to retry.
                                289                 :  *
                                290                 :  * Caution: callers must be sure to preserve their entry-time errno
                                291                 :  * when looping, in case the fmt contains "%m".
 3453 tgl                       292 ECB             :  */
                                293                 : bool
 3453 tgl                       294 GIC      569624 : appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args)
                                295                 : {
                                296                 :     size_t      avail;
                                297                 :     size_t      needed;
                                298                 :     int         nprinted;
                                299                 : 
                                300                 :     /*
                                301                 :      * Try to format the given string into the available space; but if there's
 3453 tgl                       302 ECB             :      * hardly any space, don't bother trying, just enlarge the buffer first.
                                303                 :      */
 3453 tgl                       304 CBC      569624 :     if (str->maxlen > str->len + 16)
                                305                 :     {
 1697                           306          567697 :         avail = str->maxlen - str->len;
                                307                 : 
 3453 tgl                       308 GIC      567697 :         nprinted = vsnprintf(str->data + str->len, avail, fmt, args);
                                309                 : 
                                310                 :         /*
                                311                 :          * If vsnprintf reports an error, fail (we assume this means there's
 1697 tgl                       312 ECB             :          * something wrong with the format string).
                                313                 :          */
 1697 tgl                       314 GBC      567697 :         if (unlikely(nprinted < 0))
 8483 tgl                       315 EUB             :         {
 3453 tgl                       316 UIC           0 :             markPQExpBufferBroken(str);
                                317               0 :             return true;
 3453 tgl                       318 ECB             :         }
                                319                 : 
 1697 tgl                       320 GIC      567697 :         if ((size_t) nprinted < avail)
 3453 tgl                       321 ECB             :         {
                                322                 :             /* Success.  Note nprinted does not include trailing null. */
 3453 tgl                       323 GIC      557594 :             str->len += nprinted;
                                324          557594 :             return true;
                                325                 :         }
                                326                 : 
                                327                 :         /*
                                328                 :          * We assume a C99-compliant vsnprintf, so believe its estimate of the
                                329                 :          * required space, and add one for the trailing null.  (If it's wrong,
                                330                 :          * the logic will still work, but we may loop multiple times.)
                                331                 :          *
                                332                 :          * Choke if the required space would exceed INT_MAX, since str->maxlen
 1697 tgl                       333 ECB             :          * can't represent more than that.
                                334                 :          */
 1697 tgl                       335 GBC       10103 :         if (unlikely(nprinted > INT_MAX - 1))
 3453 tgl                       336 EUB             :         {
 1697 tgl                       337 UIC           0 :             markPQExpBufferBroken(str);
 1697 tgl                       338 LBC           0 :             return true;
                                339                 :         }
 1697 tgl                       340 GIC       10103 :         needed = nprinted + 1;
                                341                 :     }
                                342                 :     else
                                343                 :     {
                                344                 :         /*
                                345                 :          * We have to guess at how much to enlarge, since we're skipping the
                                346                 :          * formatting work.  Fortunately, because of enlargePQExpBuffer's
                                347                 :          * preference for power-of-2 sizes, this number isn't very sensitive;
                                348                 :          * the net effect is that we'll double the buffer size before trying
 1697 tgl                       349 ECB             :          * to run vsnprintf, which seems sensible.
                                350                 :          */
 3453 tgl                       351 GIC        1927 :         needed = 32;
                                352                 :     }
 3453 tgl                       353 ECB             : 
 3453 tgl                       354 EUB             :     /* Increase the buffer size and try again. */
 3453 tgl                       355 GIC       12030 :     if (!enlargePQExpBuffer(str, needed))
 3453 tgl                       356 LBC           0 :         return true;            /* oops, out of memory */
                                357                 : 
 3453 tgl                       358 GIC       12030 :     return false;
                                359                 : }
                                360                 : 
                                361                 : /*
                                362                 :  * appendPQExpBufferStr
                                363                 :  * Append the given string to a PQExpBuffer, allocating more space
                                364                 :  * if necessary.
 8622 tgl                       365 ECB             :  */
                                366                 : void
 8622 tgl                       367 CBC      862218 : appendPQExpBufferStr(PQExpBuffer str, const char *data)
 8622 tgl                       368 ECB             : {
 8622 tgl                       369 GIC      862218 :     appendBinaryPQExpBuffer(str, data, strlen(data));
                                370          862218 : }
                                371                 : 
                                372                 : /*
                                373                 :  * appendPQExpBufferChar
                                374                 :  * Append a single byte to str.
                                375                 :  * Like appendPQExpBuffer(str, "%c", ch) but much faster.
 8622 tgl                       376 ECB             :  */
                                377                 : void
 8622 tgl                       378 GIC      780211 : appendPQExpBufferChar(PQExpBuffer str, char ch)
 8622 tgl                       379 ECB             : {
 8622 tgl                       380 EUB             :     /* Make more room if needed */
 8397 bruce                     381 GIC      780211 :     if (!enlargePQExpBuffer(str, 1))
 8622 tgl                       382 UIC           0 :         return;
 8622 tgl                       383 ECB             : 
                                384                 :     /* OK, append the character */
 8622 tgl                       385 CBC      780211 :     str->data[str->len] = ch;
 8622 tgl                       386 GIC      780211 :     str->len++;
                                387          780211 :     str->data[str->len] = '\0';
                                388                 : }
                                389                 : 
                                390                 : /*
                                391                 :  * appendBinaryPQExpBuffer
                                392                 :  *
                                393                 :  * Append arbitrary binary data to a PQExpBuffer, allocating more space
                                394                 :  * if necessary.
 8622 tgl                       395 ECB             :  */
                                396                 : void
 8462 peter_e                   397 GIC     5220049 : appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
 8622 tgl                       398 ECB             : {
 8622 tgl                       399 EUB             :     /* Make more room if needed */
 8397 bruce                     400 GIC     5220049 :     if (!enlargePQExpBuffer(str, datalen))
 8622 tgl                       401 UIC           0 :         return;
 8622 tgl                       402 ECB             : 
                                403                 :     /* OK, append the data */
 8622 tgl                       404 GIC     5220049 :     memcpy(str->data + str->len, data, datalen);
                                405         5220049 :     str->len += datalen;
                                406                 : 
                                407                 :     /*
                                408                 :      * Keep a trailing null in place, even though it's probably useless for
 6385 bruce                     409 ECB             :      * binary data...
                                410                 :      */
 8622 tgl                       411 GIC     5220049 :     str->data[str->len] = '\0';
                                412                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a