LCOV - code coverage report
Current view: top level - contrib/intarray - _int_bool.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 94.5 % 289 273
Test Date: 2026-03-03 14:15:12 Functions: 91.7 % 24 22
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * contrib/intarray/_int_bool.c
       3              :  */
       4              : #include "postgres.h"
       5              : 
       6              : #include "_int.h"
       7              : #include "miscadmin.h"
       8              : 
       9            2 : PG_FUNCTION_INFO_V1(bqarr_in);
      10            2 : PG_FUNCTION_INFO_V1(bqarr_out);
      11            2 : PG_FUNCTION_INFO_V1(boolop);
      12            1 : PG_FUNCTION_INFO_V1(rboolop);
      13            1 : PG_FUNCTION_INFO_V1(querytree);
      14              : 
      15              : 
      16              : /* parser's states */
      17              : #define WAITOPERAND 1
      18              : #define WAITENDOPERAND  2
      19              : #define WAITOPERATOR    3
      20              : 
      21              : /*
      22              :  * node of query tree, also used
      23              :  * for storing polish notation in parser
      24              :  */
      25              : typedef struct NODE
      26              : {
      27              :     int32       type;
      28              :     int32       val;
      29              :     struct NODE *next;
      30              : } NODE;
      31              : 
      32              : typedef struct
      33              : {
      34              :     char       *buf;
      35              :     int32       state;
      36              :     int32       count;
      37              :     struct Node *escontext;
      38              :     /* reverse polish notation in list (for temporary usage) */
      39              :     NODE       *str;
      40              :     /* number in str */
      41              :     int32       num;
      42              : } WORKSTATE;
      43              : 
      44              : /*
      45              :  * get token from query string
      46              :  */
      47              : static int32
      48          613 : gettoken(WORKSTATE *state, int32 *val)
      49              : {
      50              :     char        nnn[16];
      51              :     int         innn;
      52              : 
      53          613 :     *val = 0;                   /* default result */
      54              : 
      55          613 :     innn = 0;
      56              :     while (1)
      57              :     {
      58         1056 :         if (innn >= sizeof(nnn))
      59            0 :             return ERR;         /* buffer overrun => syntax error */
      60         1056 :         switch (state->state)
      61              :         {
      62          367 :             case WAITOPERAND:
      63          367 :                 innn = 0;
      64          367 :                 if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
      65          141 :                     *(state->buf) == '-')
      66              :                 {
      67          226 :                     state->state = WAITENDOPERAND;
      68          226 :                     nnn[innn++] = *(state->buf);
      69              :                 }
      70          141 :                 else if (*(state->buf) == '!')
      71              :                 {
      72           55 :                     (state->buf)++;
      73           55 :                     *val = (int32) '!';
      74           55 :                     return OPR;
      75              :                 }
      76           86 :                 else if (*(state->buf) == '(')
      77              :                 {
      78           52 :                     state->count++;
      79           52 :                     (state->buf)++;
      80           52 :                     return OPEN;
      81              :                 }
      82           34 :                 else if (*(state->buf) != ' ')
      83            2 :                     return ERR;
      84          258 :                 break;
      85          380 :             case WAITENDOPERAND:
      86          380 :                 if (*(state->buf) >= '0' && *(state->buf) <= '9')
      87              :                 {
      88          154 :                     nnn[innn++] = *(state->buf);
      89              :                 }
      90              :                 else
      91              :                 {
      92              :                     long        lval;
      93              : 
      94          226 :                     nnn[innn] = '\0';
      95          226 :                     errno = 0;
      96          226 :                     lval = strtol(nnn, NULL, 0);
      97          226 :                     *val = (int32) lval;
      98          226 :                     if (errno != 0 || (long) *val != lval)
      99            0 :                         return ERR;
     100          226 :                     state->state = WAITOPERATOR;
     101           90 :                     return (state->count && *(state->buf) == '\0')
     102          316 :                         ? ERR : VAL;
     103              :                 }
     104          154 :                 break;
     105          309 :             case WAITOPERATOR:
     106          309 :                 if (*(state->buf) == '&' || *(state->buf) == '|')
     107              :                 {
     108          136 :                     state->state = WAITOPERAND;
     109          136 :                     *val = (int32) *(state->buf);
     110          136 :                     (state->buf)++;
     111          136 :                     return OPR;
     112              :                 }
     113          173 :                 else if (*(state->buf) == ')')
     114              :                 {
     115           52 :                     (state->buf)++;
     116           52 :                     state->count--;
     117           52 :                     return (state->count < 0) ? ERR : CLOSE;
     118              :                 }
     119          121 :                 else if (*(state->buf) == '\0')
     120           88 :                     return (state->count) ? ERR : END;
     121           33 :                 else if (*(state->buf) != ' ')
     122            2 :                     return ERR;
     123           31 :                 break;
     124            0 :             default:
     125            0 :                 return ERR;
     126              :                 break;
     127              :         }
     128          443 :         (state->buf)++;
     129              :     }
     130              : }
     131              : 
     132              : /*
     133              :  * push new one in polish notation reverse view
     134              :  */
     135              : static void
     136          417 : pushquery(WORKSTATE *state, int32 type, int32 val)
     137              : {
     138          417 :     NODE       *tmp = palloc_object(NODE);
     139              : 
     140          417 :     tmp->type = type;
     141          417 :     tmp->val = val;
     142          417 :     tmp->next = state->str;
     143          417 :     state->str = tmp;
     144          417 :     state->num++;
     145          417 : }
     146              : 
     147              : #define STACKDEPTH  16
     148              : 
     149              : /*
     150              :  * make polish notation of query
     151              :  */
     152              : static int32
     153          144 : makepol(WORKSTATE *state)
     154              : {
     155              :     int32       val,
     156              :                 type;
     157              :     int32       stack[STACKDEPTH];
     158          144 :     int32       lenstack = 0;
     159              : 
     160              :     /* since this function recurses, it could be driven to stack overflow */
     161          144 :     check_stack_depth();
     162              : 
     163          613 :     while ((type = gettoken(state, &val)) != END)
     164              :     {
     165          525 :         switch (type)
     166              :         {
     167          226 :             case VAL:
     168          226 :                 pushquery(state, type, val);
     169          330 :                 while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
     170           97 :                                     stack[lenstack - 1] == (int32) '!'))
     171              :                 {
     172          104 :                     lenstack--;
     173          104 :                     pushquery(state, OPR, stack[lenstack]);
     174              :                 }
     175          226 :                 break;
     176          191 :             case OPR:
     177          191 :                 if (lenstack && val == (int32) '|')
     178            3 :                     pushquery(state, OPR, val);
     179              :                 else
     180              :                 {
     181          188 :                     if (lenstack == STACKDEPTH)
     182            0 :                         ereturn(state->escontext, ERR,
     183              :                                 (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
     184              :                                  errmsg("statement too complex")));
     185          188 :                     stack[lenstack] = val;
     186          188 :                     lenstack++;
     187              :                 }
     188          191 :                 break;
     189           52 :             case OPEN:
     190           52 :                 if (makepol(state) == ERR)
     191            0 :                     return ERR;
     192           82 :                 while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
     193           19 :                                     stack[lenstack - 1] == (int32) '!'))
     194              :                 {
     195           30 :                     lenstack--;
     196           30 :                     pushquery(state, OPR, stack[lenstack]);
     197              :                 }
     198           52 :                 break;
     199           52 :             case CLOSE:
     200           73 :                 while (lenstack)
     201              :                 {
     202           21 :                     lenstack--;
     203           21 :                     pushquery(state, OPR, stack[lenstack]);
     204              :                 };
     205           52 :                 return END;
     206              :                 break;
     207            4 :             case ERR:
     208              :             default:
     209            4 :                 ereturn(state->escontext, ERR,
     210              :                         (errcode(ERRCODE_SYNTAX_ERROR),
     211              :                          errmsg("syntax error")));
     212              :         }
     213              :     }
     214              : 
     215          121 :     while (lenstack)
     216              :     {
     217           33 :         lenstack--;
     218           33 :         pushquery(state, OPR, stack[lenstack]);
     219              :     };
     220           88 :     return END;
     221              : }
     222              : 
     223              : typedef struct
     224              : {
     225              :     int32      *arrb;
     226              :     int32      *arre;
     227              : } CHKVAL;
     228              : 
     229              : /*
     230              :  * is there value 'val' in (sorted) array or not ?
     231              :  */
     232              : static bool
     233       315326 : checkcondition_arr(void *checkval, ITEM *item, void *options)
     234              : {
     235       315326 :     int32      *StopLow = ((CHKVAL *) checkval)->arrb;
     236       315326 :     int32      *StopHigh = ((CHKVAL *) checkval)->arre;
     237              :     int32      *StopMiddle;
     238              : 
     239              :     /* Loop invariant: StopLow <= val < StopHigh */
     240              : 
     241      1132222 :     while (StopLow < StopHigh)
     242              :     {
     243       829733 :         StopMiddle = StopLow + (StopHigh - StopLow) / 2;
     244       829733 :         if (*StopMiddle == item->val)
     245        12837 :             return true;
     246       816896 :         else if (*StopMiddle < item->val)
     247       239982 :             StopLow = StopMiddle + 1;
     248              :         else
     249       576914 :             StopHigh = StopMiddle;
     250              :     }
     251       302489 :     return false;
     252              : }
     253              : 
     254              : static bool
     255        44258 : checkcondition_bit(void *checkval, ITEM *item, void *siglen)
     256              : {
     257        44258 :     return GETBIT(checkval, HASHVAL(item->val, (int) (intptr_t) siglen));
     258              : }
     259              : 
     260              : /*
     261              :  * evaluate boolean expression, using chkcond() to test the primitive cases
     262              :  */
     263              : static bool
     264       885611 : execute(ITEM *curitem, void *checkval, void *options, bool calcnot,
     265              :         bool (*chkcond) (void *checkval, ITEM *item, void *options))
     266              : {
     267              :     /* since this function recurses, it could be driven to stack overflow */
     268       885611 :     check_stack_depth();
     269              : 
     270       885611 :     if (curitem->type == VAL)
     271       388625 :         return (*chkcond) (checkval, curitem, options);
     272       496986 :     else if (curitem->val == (int32) '!')
     273              :     {
     274              :         return calcnot ?
     275       153749 :             ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true)
     276       362749 :             : true;
     277              :     }
     278       287986 :     else if (curitem->val == (int32) '&')
     279              :     {
     280       154390 :         if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
     281        85980 :             return execute(curitem - 1, checkval, options, calcnot, chkcond);
     282              :         else
     283        68410 :             return false;
     284              :     }
     285              :     else
     286              :     {                           /* |-operator */
     287       133596 :         if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
     288         6563 :             return true;
     289              :         else
     290       127033 :             return execute(curitem - 1, checkval, options, calcnot, chkcond);
     291              :     }
     292              : }
     293              : 
     294              : /*
     295              :  * signconsistent & execconsistent called by *_consistent
     296              :  */
     297              : bool
     298        50679 : signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot)
     299              : {
     300       101358 :     return execute(GETQUERY(query) + query->size - 1,
     301        50679 :                    sign, (void *) (intptr_t) siglen, calcnot,
     302              :                    checkcondition_bit);
     303              : }
     304              : 
     305              : /* Array must be sorted! */
     306              : bool
     307        83267 : execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
     308              : {
     309              :     CHKVAL      chkval;
     310              : 
     311        83267 :     CHECKARRVALID(array);
     312        83267 :     chkval.arrb = ARRPTR(array);
     313        83267 :     chkval.arre = chkval.arrb + ARRNELEMS(array);
     314        83267 :     return execute(GETQUERY(query) + query->size - 1,
     315              :                    &chkval, NULL, calcnot,
     316              :                    checkcondition_arr);
     317              : }
     318              : 
     319              : typedef struct
     320              : {
     321              :     ITEM       *first;
     322              :     bool       *mapped_check;
     323              : } GinChkVal;
     324              : 
     325              : static bool
     326        29041 : checkcondition_gin(void *checkval, ITEM *item, void *options)
     327              : {
     328        29041 :     GinChkVal  *gcv = (GinChkVal *) checkval;
     329              : 
     330        29041 :     return gcv->mapped_check[item - gcv->first];
     331              : }
     332              : 
     333              : bool
     334        14919 : gin_bool_consistent(QUERYTYPE *query, bool *check)
     335              : {
     336              :     GinChkVal   gcv;
     337        14919 :     ITEM       *items = GETQUERY(query);
     338              :     int         i,
     339        14919 :                 j = 0;
     340              : 
     341        14919 :     if (query->size <= 0)
     342            0 :         return false;
     343              : 
     344              :     /*
     345              :      * Set up data for checkcondition_gin.  This must agree with the query
     346              :      * extraction code in ginint4_queryextract.
     347              :      */
     348        14919 :     gcv.first = items;
     349        14919 :     gcv.mapped_check = palloc_array(bool, query->size);
     350        82333 :     for (i = 0; i < query->size; i++)
     351              :     {
     352        67414 :         if (items[i].type == VAL)
     353        31016 :             gcv.mapped_check[i] = check[j++];
     354              :     }
     355              : 
     356        14919 :     return execute(GETQUERY(query) + query->size - 1,
     357              :                    &gcv, NULL, true,
     358              :                    checkcondition_gin);
     359              : }
     360              : 
     361              : static bool
     362           46 : contains_required_value(ITEM *curitem)
     363              : {
     364              :     /* since this function recurses, it could be driven to stack overflow */
     365           46 :     check_stack_depth();
     366              : 
     367           46 :     if (curitem->type == VAL)
     368           18 :         return true;
     369           28 :     else if (curitem->val == (int32) '!')
     370              :     {
     371              :         /*
     372              :          * Assume anything under a NOT is non-required.  For some cases with
     373              :          * nested NOTs, we could prove there's a required value, but it seems
     374              :          * unlikely to be worth the trouble.
     375              :          */
     376            8 :         return false;
     377              :     }
     378           20 :     else if (curitem->val == (int32) '&')
     379              :     {
     380              :         /* If either side has a required value, we're good */
     381           12 :         if (contains_required_value(curitem + curitem->left))
     382            8 :             return true;
     383              :         else
     384            4 :             return contains_required_value(curitem - 1);
     385              :     }
     386              :     else
     387              :     {                           /* |-operator */
     388              :         /* Both sides must have required values */
     389            8 :         if (contains_required_value(curitem + curitem->left))
     390            8 :             return contains_required_value(curitem - 1);
     391              :         else
     392            0 :             return false;
     393              :     }
     394              : }
     395              : 
     396              : bool
     397           14 : query_has_required_values(QUERYTYPE *query)
     398              : {
     399           14 :     if (query->size <= 0)
     400            0 :         return false;
     401           14 :     return contains_required_value(GETQUERY(query) + query->size - 1);
     402              : }
     403              : 
     404              : /*
     405              :  * boolean operations
     406              :  */
     407              : Datum
     408            0 : rboolop(PG_FUNCTION_ARGS)
     409              : {
     410              :     /* just reverse the operands */
     411            0 :     return DirectFunctionCall2(boolop,
     412              :                                PG_GETARG_DATUM(1),
     413              :                                PG_GETARG_DATUM(0));
     414              : }
     415              : 
     416              : Datum
     417        81998 : boolop(PG_FUNCTION_ARGS)
     418              : {
     419        81998 :     ArrayType  *val = PG_GETARG_ARRAYTYPE_P_COPY(0);
     420        81998 :     QUERYTYPE  *query = PG_GETARG_QUERYTYPE_P(1);
     421              :     CHKVAL      chkval;
     422              :     bool        result;
     423              : 
     424        81998 :     CHECKARRVALID(val);
     425        81998 :     PREPAREARR(val);
     426        81998 :     chkval.arrb = ARRPTR(val);
     427        81998 :     chkval.arre = chkval.arrb + ARRNELEMS(val);
     428        81998 :     result = execute(GETQUERY(query) + query->size - 1,
     429              :                      &chkval, NULL, true,
     430              :                      checkcondition_arr);
     431        81998 :     pfree(val);
     432              : 
     433        81998 :     PG_FREE_IF_COPY(query, 1);
     434        81998 :     PG_RETURN_BOOL(result);
     435              : }
     436              : 
     437              : static void
     438          415 : findoprnd(ITEM *ptr, int32 *pos)
     439              : {
     440              :     /* since this function recurses, it could be driven to stack overflow. */
     441          415 :     check_stack_depth();
     442              : 
     443              : #ifdef BS_DEBUG
     444              :     elog(DEBUG3, (ptr[*pos].type == OPR) ?
     445              :          "%d  %c" : "%d  %d", *pos, ptr[*pos].val);
     446              : #endif
     447          415 :     if (ptr[*pos].type == VAL)
     448              :     {
     449          224 :         ptr[*pos].left = 0;
     450          224 :         (*pos)--;
     451              :     }
     452          191 :     else if (ptr[*pos].val == (int32) '!')
     453              :     {
     454           55 :         ptr[*pos].left = -1;
     455           55 :         (*pos)--;
     456           55 :         findoprnd(ptr, pos);
     457              :     }
     458              :     else
     459              :     {
     460          136 :         ITEM       *curitem = &ptr[*pos];
     461          136 :         int32       tmp = *pos;
     462              : 
     463          136 :         (*pos)--;
     464          136 :         findoprnd(ptr, pos);
     465          136 :         curitem->left = *pos - tmp;
     466          136 :         findoprnd(ptr, pos);
     467              :     }
     468          415 : }
     469              : 
     470              : 
     471              : /*
     472              :  * input
     473              :  */
     474              : Datum
     475           92 : bqarr_in(PG_FUNCTION_ARGS)
     476              : {
     477           92 :     char       *buf = (char *) PG_GETARG_POINTER(0);
     478              :     WORKSTATE   state;
     479              :     int32       i;
     480              :     QUERYTYPE  *query;
     481              :     int32       commonlen;
     482              :     ITEM       *ptr;
     483              :     NODE       *tmp;
     484           92 :     int32       pos = 0;
     485           92 :     struct Node *escontext = fcinfo->context;
     486              : 
     487              : #ifdef BS_DEBUG
     488              :     StringInfoData pbuf;
     489              : #endif
     490              : 
     491           92 :     state.buf = buf;
     492           92 :     state.state = WAITOPERAND;
     493           92 :     state.count = 0;
     494           92 :     state.num = 0;
     495           92 :     state.str = NULL;
     496           92 :     state.escontext = escontext;
     497              : 
     498              :     /* make polish notation (postfix, but in reverse order) */
     499           92 :     if (makepol(&state) == ERR)
     500            4 :         PG_RETURN_NULL();
     501           88 :     if (!state.num)
     502            0 :         ereturn(escontext, (Datum) 0,
     503              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     504              :                  errmsg("empty query")));
     505              : 
     506           88 :     if (state.num > QUERYTYPEMAXITEMS)
     507            0 :         ereturn(escontext, (Datum) 0,
     508              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     509              :                  errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
     510              :                         state.num, (int) QUERYTYPEMAXITEMS)));
     511           88 :     commonlen = COMPUTESIZE(state.num);
     512              : 
     513           88 :     query = (QUERYTYPE *) palloc(commonlen);
     514           88 :     SET_VARSIZE(query, commonlen);
     515           88 :     query->size = state.num;
     516           88 :     ptr = GETQUERY(query);
     517              : 
     518          503 :     for (i = state.num - 1; i >= 0; i--)
     519              :     {
     520          415 :         ptr[i].type = state.str->type;
     521          415 :         ptr[i].val = state.str->val;
     522          415 :         tmp = state.str->next;
     523          415 :         pfree(state.str);
     524          415 :         state.str = tmp;
     525              :     }
     526              : 
     527           88 :     pos = query->size - 1;
     528           88 :     findoprnd(ptr, &pos);
     529              : #ifdef BS_DEBUG
     530              :     initStringInfo(&pbuf);
     531              :     for (i = 0; i < query->size; i++)
     532              :     {
     533              :         if (ptr[i].type == OPR)
     534              :             appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
     535              :         else
     536              :             appendStringInfo(&pbuf, "%d ", ptr[i].val);
     537              :     }
     538              :     elog(DEBUG3, "POR: %s", pbuf.data);
     539              :     pfree(pbuf.data);
     540              : #endif
     541              : 
     542           88 :     PG_RETURN_POINTER(query);
     543              : }
     544              : 
     545              : 
     546              : /*
     547              :  * out function
     548              :  */
     549              : typedef struct
     550              : {
     551              :     ITEM       *curpol;
     552              :     char       *buf;
     553              :     char       *cur;
     554              :     int32       buflen;
     555              : } INFIX;
     556              : 
     557              : #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
     558              :     int32 len = inf->cur - inf->buf; \
     559              :     inf->buflen *= 2; \
     560              :     inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
     561              :     inf->cur = inf->buf + len; \
     562              : }
     563              : 
     564              : static void
     565          180 : infix(INFIX *in, bool first)
     566              : {
     567              :     /* since this function recurses, it could be driven to stack overflow. */
     568          180 :     check_stack_depth();
     569              : 
     570          180 :     if (in->curpol->type == VAL)
     571              :     {
     572           95 :         RESIZEBUF(in, 11);
     573           95 :         sprintf(in->cur, "%d", in->curpol->val);
     574           95 :         in->cur = strchr(in->cur, '\0');
     575           95 :         in->curpol--;
     576              :     }
     577           85 :     else if (in->curpol->val == (int32) '!')
     578              :     {
     579           27 :         bool        isopr = false;
     580              : 
     581           27 :         RESIZEBUF(in, 1);
     582           27 :         *(in->cur) = '!';
     583           27 :         in->cur++;
     584           27 :         *(in->cur) = '\0';
     585           27 :         in->curpol--;
     586           27 :         if (in->curpol->type == OPR)
     587              :         {
     588            6 :             isopr = true;
     589            6 :             RESIZEBUF(in, 2);
     590            6 :             sprintf(in->cur, "( ");
     591            6 :             in->cur = strchr(in->cur, '\0');
     592              :         }
     593           27 :         infix(in, isopr);
     594           27 :         if (isopr)
     595              :         {
     596            6 :             RESIZEBUF(in, 2);
     597            6 :             sprintf(in->cur, " )");
     598            6 :             in->cur = strchr(in->cur, '\0');
     599              :         }
     600              :     }
     601              :     else
     602              :     {
     603           58 :         int32       op = in->curpol->val;
     604              :         INFIX       nrm;
     605              : 
     606           58 :         in->curpol--;
     607           58 :         if (op == (int32) '|' && !first)
     608              :         {
     609           10 :             RESIZEBUF(in, 2);
     610           10 :             sprintf(in->cur, "( ");
     611           10 :             in->cur = strchr(in->cur, '\0');
     612              :         }
     613              : 
     614           58 :         nrm.curpol = in->curpol;
     615           58 :         nrm.buflen = 16;
     616           58 :         nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
     617              : 
     618              :         /* get right operand */
     619           58 :         infix(&nrm, false);
     620              : 
     621              :         /* get & print left operand */
     622           58 :         in->curpol = nrm.curpol;
     623           58 :         infix(in, false);
     624              : 
     625              :         /* print operator & right operand */
     626           62 :         RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
     627           58 :         sprintf(in->cur, " %c %s", op, nrm.buf);
     628           58 :         in->cur = strchr(in->cur, '\0');
     629           58 :         pfree(nrm.buf);
     630              : 
     631           58 :         if (op == (int32) '|' && !first)
     632              :         {
     633           10 :             RESIZEBUF(in, 2);
     634           10 :             sprintf(in->cur, " )");
     635           10 :             in->cur = strchr(in->cur, '\0');
     636              :         }
     637              :     }
     638          180 : }
     639              : 
     640              : 
     641              : Datum
     642           37 : bqarr_out(PG_FUNCTION_ARGS)
     643              : {
     644           37 :     QUERYTYPE  *query = PG_GETARG_QUERYTYPE_P(0);
     645              :     INFIX       nrm;
     646              : 
     647           37 :     if (query->size == 0)
     648            0 :         ereport(ERROR,
     649              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     650              :                  errmsg("empty query")));
     651              : 
     652           37 :     nrm.curpol = GETQUERY(query) + query->size - 1;
     653           37 :     nrm.buflen = 32;
     654           37 :     nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
     655           37 :     *(nrm.cur) = '\0';
     656           37 :     infix(&nrm, true);
     657              : 
     658           37 :     PG_FREE_IF_COPY(query, 0);
     659           37 :     PG_RETURN_POINTER(nrm.buf);
     660              : }
     661              : 
     662              : 
     663              : /* Useless old "debugging" function for a fundamentally wrong algorithm */
     664              : Datum
     665            0 : querytree(PG_FUNCTION_ARGS)
     666              : {
     667            0 :     elog(ERROR, "querytree is no longer implemented");
     668              :     PG_RETURN_NULL();
     669              : }
        

Generated by: LCOV version 2.0-1