LCOV - code coverage report
Current view: top level - contrib/intarray - _int_bool.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 93.2 % 293 273
Test Date: 2026-05-28 09:16:21 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       131685 : gettoken(WORKSTATE *state, int32 *val)
      49              : {
      50              :     char        nnn[16];
      51              :     int         innn;
      52              : 
      53       131685 :     *val = 0;                   /* default result */
      54              : 
      55       131685 :     innn = 0;
      56              :     while (1)
      57              :     {
      58       164897 :         if (innn >= sizeof(nnn))
      59            0 :             return ERR;         /* buffer overrun => syntax error */
      60       164897 :         switch (state->state)
      61              :         {
      62        65903 :             case WAITOPERAND:
      63        65903 :                 innn = 0;
      64        65903 :                 if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
      65        32908 :                     *(state->buf) == '-')
      66              :                 {
      67        32995 :                     state->state = WAITENDOPERAND;
      68        32995 :                     nnn[innn++] = *(state->buf);
      69              :                 }
      70        32908 :                 else if (*(state->buf) == '!')
      71              :                 {
      72           55 :                     (state->buf)++;
      73           55 :                     *val = (int32) '!';
      74           55 :                     return OPR;
      75              :                 }
      76        32853 :                 else if (*(state->buf) == '(')
      77              :                 {
      78        32819 :                     state->count++;
      79        32819 :                     (state->buf)++;
      80        32819 :                     return OPEN;
      81              :                 }
      82           34 :                 else if (*(state->buf) != ' ')
      83            2 :                     return ERR;
      84        33027 :                 break;
      85        33149 :             case WAITENDOPERAND:
      86        33149 :                 if (*(state->buf) >= '0' && *(state->buf) <= '9')
      87              :                 {
      88          154 :                     nnn[innn++] = *(state->buf);
      89              :                 }
      90              :                 else
      91              :                 {
      92              :                     long        lval;
      93              : 
      94        32995 :                     nnn[innn] = '\0';
      95        32995 :                     errno = 0;
      96        32995 :                     lval = strtol(nnn, NULL, 0);
      97        32995 :                     *val = (int32) lval;
      98        32995 :                     if (errno != 0 || (long) *val != lval)
      99            0 :                         return ERR;
     100        32995 :                     state->state = WAITOPERATOR;
     101        32858 :                     return (state->count && *(state->buf) == '\0')
     102        65853 :                         ? ERR : VAL;
     103              :                 }
     104          154 :                 break;
     105        65845 :             case WAITOPERATOR:
     106        65845 :                 if (*(state->buf) == '&' || *(state->buf) == '|')
     107              :                 {
     108        32904 :                     state->state = WAITOPERAND;
     109        32904 :                     *val = (int32) *(state->buf);
     110        32904 :                     (state->buf)++;
     111        32904 :                     return OPR;
     112              :                 }
     113        32941 :                 else if (*(state->buf) == ')')
     114              :                 {
     115        32819 :                     (state->buf)++;
     116        32819 :                     state->count--;
     117        32819 :                     return (state->count < 0) ? ERR : CLOSE;
     118              :                 }
     119          122 :                 else if (*(state->buf) == '\0')
     120           89 :                     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        33212 :         (state->buf)++;
     129              :     }
     130              : }
     131              : 
     132              : /*
     133              :  * push new one in polish notation reverse view
     134              :  */
     135              : static void
     136        65954 : pushquery(WORKSTATE *state, int32 type, int32 val)
     137              : {
     138        65954 :     NODE       *tmp = palloc_object(NODE);
     139              : 
     140        65954 :     tmp->type = type;
     141        65954 :     tmp->val = val;
     142        65954 :     tmp->next = state->str;
     143        65954 :     state->str = tmp;
     144        65954 :     state->num++;
     145        65954 : }
     146              : 
     147              : #define STACKDEPTH  16
     148              : 
     149              : /*
     150              :  * make polish notation of query
     151              :  */
     152              : static int32
     153        32912 : makepol(WORKSTATE *state)
     154              : {
     155              :     int32       val,
     156              :                 type;
     157              :     int32       stack[STACKDEPTH];
     158        32912 :     int32       lenstack = 0;
     159              : 
     160              :     /* since this function recurses, it could be driven to stack overflow */
     161        32912 :     check_stack_depth();
     162              : 
     163       131685 :     while ((type = gettoken(state, &val)) != END)
     164              :     {
     165       131596 :         switch (type)
     166              :         {
     167        32995 :             case VAL:
     168        32995 :                 pushquery(state, type, val);
     169        49483 :                 while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
     170           97 :                                     stack[lenstack - 1] == (int32) '!'))
     171              :                 {
     172        16488 :                     lenstack--;
     173        16488 :                     pushquery(state, OPR, stack[lenstack]);
     174              :                 }
     175        32995 :                 break;
     176        32959 :             case OPR:
     177        32959 :                 if (lenstack && val == (int32) '|')
     178            3 :                     pushquery(state, OPR, val);
     179              :                 else
     180              :                 {
     181        32956 :                     if (lenstack == STACKDEPTH)
     182            0 :                         ereturn(state->escontext, ERR,
     183              :                                 (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
     184              :                                  errmsg("statement too complex")));
     185        32956 :                     stack[lenstack] = val;
     186        32956 :                     lenstack++;
     187              :                 }
     188        32959 :                 break;
     189        32819 :             case OPEN:
     190        32819 :                 if (makepol(state) == ERR)
     191            0 :                     return ERR;
     192        49232 :                 while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
     193           20 :                                     stack[lenstack - 1] == (int32) '!'))
     194              :                 {
     195        16413 :                     lenstack--;
     196        16413 :                     pushquery(state, OPR, stack[lenstack]);
     197              :                 }
     198        32819 :                 break;
     199        32819 :             case CLOSE:
     200        32840 :                 while (lenstack)
     201              :                 {
     202           21 :                     lenstack--;
     203           21 :                     pushquery(state, OPR, stack[lenstack]);
     204              :                 };
     205        32819 :                 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          123 :     while (lenstack)
     216              :     {
     217           34 :         lenstack--;
     218           34 :         pushquery(state, OPR, stack[lenstack]);
     219              :     };
     220           89 :     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       319904 : checkcondition_arr(void *checkval, ITEM *item, void *options)
     234              : {
     235       319904 :     int32      *StopLow = ((CHKVAL *) checkval)->arrb;
     236       319904 :     int32      *StopHigh = ((CHKVAL *) checkval)->arre;
     237              :     int32      *StopMiddle;
     238              : 
     239              :     /* Loop invariant: StopLow <= val < StopHigh */
     240              : 
     241      1147304 :     while (StopLow < StopHigh)
     242              :     {
     243       840077 :         StopMiddle = StopLow + (StopHigh - StopLow) / 2;
     244       840077 :         if (*StopMiddle == item->val)
     245        12677 :             return true;
     246       827400 :         else if (*StopMiddle < item->val)
     247       243169 :             StopLow = StopMiddle + 1;
     248              :         else
     249       584231 :             StopHigh = StopMiddle;
     250              :     }
     251       307227 :     return false;
     252              : }
     253              : 
     254              : static bool
     255        44169 : checkcondition_bit(void *checkval, ITEM *item, void *siglen)
     256              : {
     257        44169 :     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       894946 : 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       894946 :     check_stack_depth();
     269              : 
     270       894946 :     if (curitem->type == VAL)
     271       393114 :         return (*chkcond) (checkval, curitem, options);
     272       501832 :     else if (curitem->val == (int32) '!')
     273              :     {
     274              :         return calcnot ?
     275       153833 :             ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true)
     276       362582 :             : true;
     277              :     }
     278       293083 :     else if (curitem->val == (int32) '&')
     279              :     {
     280       157751 :         if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
     281        85963 :             return execute(curitem - 1, checkval, options, calcnot, chkcond);
     282              :         else
     283        71788 :             return false;
     284              :     }
     285              :     else
     286              :     {                           /* |-operator */
     287       135332 :         if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
     288         6794 :             return true;
     289              :         else
     290       128538 :             return execute(curitem - 1, checkval, options, calcnot, chkcond);
     291              :     }
     292              : }
     293              : 
     294              : /*
     295              :  * signconsistent & execconsistent called by *_consistent
     296              :  */
     297              : bool
     298        50696 : signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot)
     299              : {
     300       101392 :     return execute(GETQUERY(query) + query->size - 1,
     301        50696 :                    sign, (void *) (intptr_t) siglen, calcnot,
     302              :                    checkcondition_bit);
     303              : }
     304              : 
     305              : /* Array must be sorted! */
     306              : bool
     307        85916 : execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
     308              : {
     309              :     CHKVAL      chkval;
     310              : 
     311        85916 :     CHECKARRVALID(array);
     312        85916 :     chkval.arrb = ARRPTR(array);
     313        85916 :     chkval.arre = chkval.arrb + ARRNELEMS(array);
     314        85916 :     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              : /*
     438              :  * Recursively fill the "left" fields of an ITEM array that represents
     439              :  * a valid postfix tree.
     440              :  *
     441              :  *  state: only needed for error reporting
     442              :  *  ptr: starting element of array
     443              :  *  pos: in/out argument, the array index this call is responsible to fill
     444              :  *
     445              :  * At exit, *pos has been decremented to point before the sub-tree whose
     446              :  * top is the entry-time value of *pos.
     447              :  *
     448              :  * Returns true if okay, false if error (the only possible error is
     449              :  * overflow of a "left" field).
     450              :  */
     451              : static bool
     452        65951 : findoprnd(WORKSTATE *state, ITEM *ptr, int32 *pos)
     453              : {
     454              :     int32       mypos;
     455              : 
     456              :     /* since this function recurses, it could be driven to stack overflow. */
     457        65951 :     check_stack_depth();
     458              : 
     459              :     /* get the position this call is supposed to update */
     460        65951 :     mypos = *pos;
     461              :     Assert(mypos >= 0);
     462              : 
     463              :     /* in all cases, we should decrement *pos to advance over this item */
     464        65951 :     (*pos)--;
     465              : 
     466              : #ifdef BS_DEBUG
     467              :     elog(DEBUG3, (ptr[mypos].type == OPR) ?
     468              :          "%d  %c" : "%d  %d", mypos, ptr[mypos].val);
     469              : #endif
     470              : 
     471        65951 :     if (ptr[mypos].type == VAL)
     472              :     {
     473              :         /* base case: a VAL has no operand, so just set its left to zero */
     474        32992 :         ptr[mypos].left = 0;
     475              :     }
     476        32959 :     else if (ptr[mypos].val == (int32) '!')
     477              :     {
     478              :         /* unary operator, likewise easy: operand is just before it */
     479           55 :         ptr[mypos].left = -1;
     480              :         /* recurse to scan operand */
     481           55 :         if (!findoprnd(state, ptr, pos))
     482            0 :             return false;
     483              :     }
     484              :     else
     485              :     {
     486              :         /* binary operator */
     487              :         int32       delta;
     488              : 
     489              :         /* recurse to scan right operand */
     490        32904 :         if (!findoprnd(state, ptr, pos))
     491            0 :             return false;
     492              :         /* we must fill left with offset to left operand's top */
     493              :         /* abs(delta) < QUERYTYPEMAXITEMS, so it can't overflow ... */
     494        32904 :         delta = *pos - mypos;
     495              :         /* ... but it might be too large to fit in the 16-bit left field */
     496              :         Assert(delta < 0);
     497        32904 :         if (unlikely(delta < PG_INT16_MIN))
     498            1 :             ereturn(state->escontext, false,
     499              :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     500              :                      errmsg("query_int expression is too complex")));
     501        32903 :         ptr[mypos].left = (int16) delta;
     502              :         /* recurse to scan left operand */
     503        32903 :         if (!findoprnd(state, ptr, pos))
     504            0 :             return false;
     505              :     }
     506              : 
     507        65950 :     return true;
     508              : }
     509              : 
     510              : 
     511              : /*
     512              :  * input
     513              :  */
     514              : Datum
     515           93 : bqarr_in(PG_FUNCTION_ARGS)
     516              : {
     517           93 :     char       *buf = (char *) PG_GETARG_POINTER(0);
     518              :     WORKSTATE   state;
     519              :     int32       i;
     520              :     QUERYTYPE  *query;
     521              :     int32       commonlen;
     522              :     ITEM       *ptr;
     523              :     NODE       *tmp;
     524           93 :     int32       pos = 0;
     525           93 :     struct Node *escontext = fcinfo->context;
     526              : 
     527              : #ifdef BS_DEBUG
     528              :     StringInfoData pbuf;
     529              : #endif
     530              : 
     531           93 :     state.buf = buf;
     532           93 :     state.state = WAITOPERAND;
     533           93 :     state.count = 0;
     534           93 :     state.num = 0;
     535           93 :     state.str = NULL;
     536           93 :     state.escontext = escontext;
     537              : 
     538              :     /* make polish notation (postfix, but in reverse order) */
     539           93 :     if (makepol(&state) == ERR)
     540            4 :         PG_RETURN_NULL();
     541           89 :     if (!state.num)
     542            0 :         ereturn(escontext, (Datum) 0,
     543              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     544              :                  errmsg("empty query")));
     545              : 
     546           89 :     if (state.num > QUERYTYPEMAXITEMS)
     547            0 :         ereturn(escontext, (Datum) 0,
     548              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     549              :                  errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
     550              :                         state.num, (int) QUERYTYPEMAXITEMS)));
     551           89 :     commonlen = COMPUTESIZE(state.num);
     552              : 
     553           89 :     query = (QUERYTYPE *) palloc(commonlen);
     554           89 :     SET_VARSIZE(query, commonlen);
     555           89 :     query->size = state.num;
     556           89 :     ptr = GETQUERY(query);
     557              : 
     558              :     /* fill the query array from the data makepol constructed */
     559        66041 :     for (i = state.num - 1; i >= 0; i--)
     560              :     {
     561        65952 :         ptr[i].type = state.str->type;
     562        65952 :         ptr[i].val = state.str->val;
     563        65952 :         tmp = state.str->next;
     564        65952 :         pfree(state.str);
     565        65952 :         state.str = tmp;
     566              :     }
     567              : 
     568              :     /* now fill the "left" fields */
     569           89 :     pos = query->size - 1;
     570           89 :     if (!findoprnd(&state, ptr, &pos))
     571            0 :         PG_RETURN_NULL();
     572              :     /* if successful, findoprnd should have scanned the whole array */
     573              :     Assert(pos == -1);
     574              : 
     575              : #ifdef BS_DEBUG
     576              :     initStringInfo(&pbuf);
     577              :     for (i = 0; i < query->size; i++)
     578              :     {
     579              :         if (ptr[i].type == OPR)
     580              :             appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
     581              :         else
     582              :             appendStringInfo(&pbuf, "%d ", ptr[i].val);
     583              :     }
     584              :     elog(DEBUG3, "POR: %s", pbuf.data);
     585              :     pfree(pbuf.data);
     586              : #endif
     587              : 
     588           88 :     PG_RETURN_POINTER(query);
     589              : }
     590              : 
     591              : 
     592              : /*
     593              :  * out function
     594              :  */
     595              : typedef struct
     596              : {
     597              :     ITEM       *curpol;
     598              :     char       *buf;
     599              :     char       *cur;
     600              :     int32       buflen;
     601              : } INFIX;
     602              : 
     603              : #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
     604              :     int32 len = inf->cur - inf->buf; \
     605              :     inf->buflen *= 2; \
     606              :     inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
     607              :     inf->cur = inf->buf + len; \
     608              : }
     609              : 
     610              : static void
     611          180 : infix(INFIX *in, bool first)
     612              : {
     613              :     /* since this function recurses, it could be driven to stack overflow. */
     614          180 :     check_stack_depth();
     615              : 
     616          180 :     if (in->curpol->type == VAL)
     617              :     {
     618           95 :         RESIZEBUF(in, 11);
     619           95 :         sprintf(in->cur, "%d", in->curpol->val);
     620           95 :         in->cur = strchr(in->cur, '\0');
     621           95 :         in->curpol--;
     622              :     }
     623           85 :     else if (in->curpol->val == (int32) '!')
     624              :     {
     625           27 :         bool        isopr = false;
     626              : 
     627           27 :         RESIZEBUF(in, 1);
     628           27 :         *(in->cur) = '!';
     629           27 :         in->cur++;
     630           27 :         *(in->cur) = '\0';
     631           27 :         in->curpol--;
     632           27 :         if (in->curpol->type == OPR)
     633              :         {
     634            6 :             isopr = true;
     635            6 :             RESIZEBUF(in, 2);
     636            6 :             sprintf(in->cur, "( ");
     637            6 :             in->cur = strchr(in->cur, '\0');
     638              :         }
     639           27 :         infix(in, isopr);
     640           27 :         if (isopr)
     641              :         {
     642            6 :             RESIZEBUF(in, 2);
     643            6 :             sprintf(in->cur, " )");
     644            6 :             in->cur = strchr(in->cur, '\0');
     645              :         }
     646              :     }
     647              :     else
     648              :     {
     649           58 :         int32       op = in->curpol->val;
     650              :         INFIX       nrm;
     651              : 
     652           58 :         in->curpol--;
     653           58 :         if (op == (int32) '|' && !first)
     654              :         {
     655           10 :             RESIZEBUF(in, 2);
     656           10 :             sprintf(in->cur, "( ");
     657           10 :             in->cur = strchr(in->cur, '\0');
     658              :         }
     659              : 
     660           58 :         nrm.curpol = in->curpol;
     661           58 :         nrm.buflen = 16;
     662           58 :         nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
     663              : 
     664              :         /* get right operand */
     665           58 :         infix(&nrm, false);
     666              : 
     667              :         /* get & print left operand */
     668           58 :         in->curpol = nrm.curpol;
     669           58 :         infix(in, false);
     670              : 
     671              :         /* print operator & right operand */
     672           62 :         RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
     673           58 :         sprintf(in->cur, " %c %s", op, nrm.buf);
     674           58 :         in->cur = strchr(in->cur, '\0');
     675           58 :         pfree(nrm.buf);
     676              : 
     677           58 :         if (op == (int32) '|' && !first)
     678              :         {
     679           10 :             RESIZEBUF(in, 2);
     680           10 :             sprintf(in->cur, " )");
     681           10 :             in->cur = strchr(in->cur, '\0');
     682              :         }
     683              :     }
     684          180 : }
     685              : 
     686              : 
     687              : Datum
     688           37 : bqarr_out(PG_FUNCTION_ARGS)
     689              : {
     690           37 :     QUERYTYPE  *query = PG_GETARG_QUERYTYPE_P(0);
     691              :     INFIX       nrm;
     692              : 
     693           37 :     if (query->size == 0)
     694            0 :         ereport(ERROR,
     695              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     696              :                  errmsg("empty query")));
     697              : 
     698           37 :     nrm.curpol = GETQUERY(query) + query->size - 1;
     699           37 :     nrm.buflen = 32;
     700           37 :     nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
     701           37 :     *(nrm.cur) = '\0';
     702           37 :     infix(&nrm, true);
     703              : 
     704           37 :     PG_FREE_IF_COPY(query, 0);
     705           37 :     PG_RETURN_POINTER(nrm.buf);
     706              : }
     707              : 
     708              : 
     709              : /* Useless old "debugging" function for a fundamentally wrong algorithm */
     710              : Datum
     711            0 : querytree(PG_FUNCTION_ARGS)
     712              : {
     713            0 :     elog(ERROR, "querytree is no longer implemented");
     714              :     PG_RETURN_NULL();
     715              : }
        

Generated by: LCOV version 2.0-1