Header And Logo

PostgreSQL
| The world's most advanced open source database.

tsquery_util.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * tsquery_util.c
00004  *    Utilities for tsquery datatype
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  *
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/utils/adt/tsquery_util.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 
00015 #include "postgres.h"
00016 
00017 #include "tsearch/ts_utils.h"
00018 #include "miscadmin.h"
00019 
00020 QTNode *
00021 QT2QTN(QueryItem *in, char *operand)
00022 {
00023     QTNode     *node = (QTNode *) palloc0(sizeof(QTNode));
00024 
00025     /* since this function recurses, it could be driven to stack overflow. */
00026     check_stack_depth();
00027 
00028     node->valnode = in;
00029 
00030     if (in->type == QI_OPR)
00031     {
00032         node->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
00033         node->child[0] = QT2QTN(in + 1, operand);
00034         node->sign = node->child[0]->sign;
00035         if (in->qoperator.oper == OP_NOT)
00036             node->nchild = 1;
00037         else
00038         {
00039             node->nchild = 2;
00040             node->child[1] = QT2QTN(in + in->qoperator.left, operand);
00041             node->sign |= node->child[1]->sign;
00042         }
00043     }
00044     else if (operand)
00045     {
00046         node->word = operand + in->qoperand.distance;
00047         node->sign = ((uint32) 1) << (((unsigned int) in->qoperand.valcrc) % 32);
00048     }
00049 
00050     return node;
00051 }
00052 
00053 void
00054 QTNFree(QTNode *in)
00055 {
00056     if (!in)
00057         return;
00058 
00059     /* since this function recurses, it could be driven to stack overflow. */
00060     check_stack_depth();
00061 
00062     if (in->valnode->type == QI_VAL && in->word && (in->flags & QTN_WORDFREE) != 0)
00063         pfree(in->word);
00064 
00065     if (in->child)
00066     {
00067         if (in->valnode)
00068         {
00069             if (in->valnode->type == QI_OPR && in->nchild > 0)
00070             {
00071                 int         i;
00072 
00073                 for (i = 0; i < in->nchild; i++)
00074                     QTNFree(in->child[i]);
00075             }
00076             if (in->flags & QTN_NEEDFREE)
00077                 pfree(in->valnode);
00078         }
00079         pfree(in->child);
00080     }
00081 
00082     pfree(in);
00083 }
00084 
00085 int
00086 QTNodeCompare(QTNode *an, QTNode *bn)
00087 {
00088     /* since this function recurses, it could be driven to stack overflow. */
00089     check_stack_depth();
00090 
00091     if (an->valnode->type != bn->valnode->type)
00092         return (an->valnode->type > bn->valnode->type) ? -1 : 1;
00093 
00094     if (an->valnode->type == QI_OPR)
00095     {
00096         QueryOperator *ao = &an->valnode->qoperator;
00097         QueryOperator *bo = &bn->valnode->qoperator;
00098 
00099         if (ao->oper != bo->oper)
00100             return (ao->oper > bo->oper) ? -1 : 1;
00101 
00102         if (an->nchild != bn->nchild)
00103             return (an->nchild > bn->nchild) ? -1 : 1;
00104 
00105         {
00106             int         i,
00107                         res;
00108 
00109             for (i = 0; i < an->nchild; i++)
00110                 if ((res = QTNodeCompare(an->child[i], bn->child[i])) != 0)
00111                     return res;
00112         }
00113         return 0;
00114     }
00115     else if (an->valnode->type == QI_VAL)
00116     {
00117         QueryOperand *ao = &an->valnode->qoperand;
00118         QueryOperand *bo = &bn->valnode->qoperand;
00119 
00120         if (ao->valcrc != bo->valcrc)
00121         {
00122             return (ao->valcrc > bo->valcrc) ? -1 : 1;
00123         }
00124 
00125         return tsCompareString(an->word, ao->length, bn->word, bo->length, false);
00126     }
00127     else
00128     {
00129         elog(ERROR, "unrecognized QueryItem type: %d", an->valnode->type);
00130         return 0;               /* keep compiler quiet */
00131     }
00132 }
00133 
00134 static int
00135 cmpQTN(const void *a, const void *b)
00136 {
00137     return QTNodeCompare(*(QTNode *const *) a, *(QTNode *const *) b);
00138 }
00139 
00140 void
00141 QTNSort(QTNode *in)
00142 {
00143     int         i;
00144 
00145     /* since this function recurses, it could be driven to stack overflow. */
00146     check_stack_depth();
00147 
00148     if (in->valnode->type != QI_OPR)
00149         return;
00150 
00151     for (i = 0; i < in->nchild; i++)
00152         QTNSort(in->child[i]);
00153     if (in->nchild > 1)
00154         qsort((void *) in->child, in->nchild, sizeof(QTNode *), cmpQTN);
00155 }
00156 
00157 bool
00158 QTNEq(QTNode *a, QTNode *b)
00159 {
00160     uint32      sign = a->sign & b->sign;
00161 
00162     if (!(sign == a->sign && sign == b->sign))
00163         return 0;
00164 
00165     return (QTNodeCompare(a, b) == 0) ? true : false;
00166 }
00167 
00168 /*
00169  * Remove unnecessary intermediate nodes. For example:
00170  *
00171  *  OR          OR
00172  * a  OR    -> a b c
00173  *   b  c
00174  */
00175 void
00176 QTNTernary(QTNode *in)
00177 {
00178     int         i;
00179 
00180     /* since this function recurses, it could be driven to stack overflow. */
00181     check_stack_depth();
00182 
00183     if (in->valnode->type != QI_OPR)
00184         return;
00185 
00186     for (i = 0; i < in->nchild; i++)
00187         QTNTernary(in->child[i]);
00188 
00189     for (i = 0; i < in->nchild; i++)
00190     {
00191         QTNode     *cc = in->child[i];
00192 
00193         if (cc->valnode->type == QI_OPR && in->valnode->qoperator.oper == cc->valnode->qoperator.oper)
00194         {
00195             int         oldnchild = in->nchild;
00196 
00197             in->nchild += cc->nchild - 1;
00198             in->child = (QTNode **) repalloc(in->child, in->nchild * sizeof(QTNode *));
00199 
00200             if (i + 1 != oldnchild)
00201                 memmove(in->child + i + cc->nchild, in->child + i + 1,
00202                         (oldnchild - i - 1) * sizeof(QTNode *));
00203 
00204             memcpy(in->child + i, cc->child, cc->nchild * sizeof(QTNode *));
00205             i += cc->nchild - 1;
00206 
00207             if (cc->flags & QTN_NEEDFREE)
00208                 pfree(cc->valnode);
00209             pfree(cc);
00210         }
00211     }
00212 }
00213 
00214 /*
00215  * Convert a tree to binary tree by inserting intermediate nodes.
00216  * (Opposite of QTNTernary)
00217  */
00218 void
00219 QTNBinary(QTNode *in)
00220 {
00221     int         i;
00222 
00223     /* since this function recurses, it could be driven to stack overflow. */
00224     check_stack_depth();
00225 
00226     if (in->valnode->type != QI_OPR)
00227         return;
00228 
00229     for (i = 0; i < in->nchild; i++)
00230         QTNBinary(in->child[i]);
00231 
00232     if (in->nchild <= 2)
00233         return;
00234 
00235     while (in->nchild > 2)
00236     {
00237         QTNode     *nn = (QTNode *) palloc0(sizeof(QTNode));
00238 
00239         nn->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
00240         nn->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
00241 
00242         nn->nchild = 2;
00243         nn->flags = QTN_NEEDFREE;
00244 
00245         nn->child[0] = in->child[0];
00246         nn->child[1] = in->child[1];
00247         nn->sign = nn->child[0]->sign | nn->child[1]->sign;
00248 
00249         nn->valnode->type = in->valnode->type;
00250         nn->valnode->qoperator.oper = in->valnode->qoperator.oper;
00251 
00252         in->child[0] = nn;
00253         in->child[1] = in->child[in->nchild - 1];
00254         in->nchild--;
00255     }
00256 }
00257 
00258 /*
00259  * Count the total length of operand string in tree, including '\0'-
00260  * terminators.
00261  */
00262 static void
00263 cntsize(QTNode *in, int *sumlen, int *nnode)
00264 {
00265     /* since this function recurses, it could be driven to stack overflow. */
00266     check_stack_depth();
00267 
00268     *nnode += 1;
00269     if (in->valnode->type == QI_OPR)
00270     {
00271         int         i;
00272 
00273         for (i = 0; i < in->nchild; i++)
00274             cntsize(in->child[i], sumlen, nnode);
00275     }
00276     else
00277     {
00278         *sumlen += in->valnode->qoperand.length + 1;
00279     }
00280 }
00281 
00282 typedef struct
00283 {
00284     QueryItem  *curitem;
00285     char       *operand;
00286     char       *curoperand;
00287 } QTN2QTState;
00288 
00289 static void
00290 fillQT(QTN2QTState *state, QTNode *in)
00291 {
00292     /* since this function recurses, it could be driven to stack overflow. */
00293     check_stack_depth();
00294 
00295     if (in->valnode->type == QI_VAL)
00296     {
00297         memcpy(state->curitem, in->valnode, sizeof(QueryOperand));
00298 
00299         memcpy(state->curoperand, in->word, in->valnode->qoperand.length);
00300         state->curitem->qoperand.distance = state->curoperand - state->operand;
00301         state->curoperand[in->valnode->qoperand.length] = '\0';
00302         state->curoperand += in->valnode->qoperand.length + 1;
00303         state->curitem++;
00304     }
00305     else
00306     {
00307         QueryItem  *curitem = state->curitem;
00308 
00309         Assert(in->valnode->type == QI_OPR);
00310 
00311         memcpy(state->curitem, in->valnode, sizeof(QueryOperator));
00312 
00313         Assert(in->nchild <= 2);
00314         state->curitem++;
00315 
00316         fillQT(state, in->child[0]);
00317 
00318         if (in->nchild == 2)
00319         {
00320             curitem->qoperator.left = state->curitem - curitem;
00321             fillQT(state, in->child[1]);
00322         }
00323     }
00324 }
00325 
00326 TSQuery
00327 QTN2QT(QTNode *in)
00328 {
00329     TSQuery     out;
00330     int         len;
00331     int         sumlen = 0,
00332                 nnode = 0;
00333     QTN2QTState state;
00334 
00335     cntsize(in, &sumlen, &nnode);
00336     len = COMPUTESIZE(nnode, sumlen);
00337 
00338     out = (TSQuery) palloc0(len);
00339     SET_VARSIZE(out, len);
00340     out->size = nnode;
00341 
00342     state.curitem = GETQUERY(out);
00343     state.operand = state.curoperand = GETOPERAND(out);
00344 
00345     fillQT(&state, in);
00346     return out;
00347 }
00348 
00349 QTNode *
00350 QTNCopy(QTNode *in)
00351 {
00352     QTNode     *out;
00353 
00354     /* since this function recurses, it could be driven to stack overflow. */
00355     check_stack_depth();
00356 
00357     out = (QTNode *) palloc(sizeof(QTNode));
00358 
00359     *out = *in;
00360     out->valnode = (QueryItem *) palloc(sizeof(QueryItem));
00361     *(out->valnode) = *(in->valnode);
00362     out->flags |= QTN_NEEDFREE;
00363 
00364     if (in->valnode->type == QI_VAL)
00365     {
00366         out->word = palloc(in->valnode->qoperand.length + 1);
00367         memcpy(out->word, in->word, in->valnode->qoperand.length);
00368         out->word[in->valnode->qoperand.length] = '\0';
00369         out->flags |= QTN_WORDFREE;
00370     }
00371     else
00372     {
00373         int         i;
00374 
00375         out->child = (QTNode **) palloc(sizeof(QTNode *) * in->nchild);
00376 
00377         for (i = 0; i < in->nchild; i++)
00378             out->child[i] = QTNCopy(in->child[i]);
00379     }
00380 
00381     return out;
00382 }
00383 
00384 void
00385 QTNClearFlags(QTNode *in, uint32 flags)
00386 {
00387     /* since this function recurses, it could be driven to stack overflow. */
00388     check_stack_depth();
00389 
00390     in->flags &= ~flags;
00391 
00392     if (in->valnode->type != QI_VAL)
00393     {
00394         int         i;
00395 
00396         for (i = 0; i < in->nchild; i++)
00397             QTNClearFlags(in->child[i], flags);
00398     }
00399 }