diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
commit | 46651ce6fe013220ed397add242004d764fc0153 (patch) | |
tree | 6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/backend/utils/adt/tsquery_op.c | |
parent | Initial commit. (diff) | |
download | postgresql-14-upstream.tar.xz postgresql-14-upstream.zip |
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/utils/adt/tsquery_op.c')
-rw-r--r-- | src/backend/utils/adt/tsquery_op.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/src/backend/utils/adt/tsquery_op.c b/src/backend/utils/adt/tsquery_op.c new file mode 100644 index 0000000..8211e6c --- /dev/null +++ b/src/backend/utils/adt/tsquery_op.c @@ -0,0 +1,358 @@ +/*------------------------------------------------------------------------- + * + * tsquery_op.c + * Various operations with tsquery + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/utils/adt/tsquery_op.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "lib/qunique.h" +#include "tsearch/ts_utils.h" +#include "utils/builtins.h" + +Datum +tsquery_numnode(PG_FUNCTION_ARGS) +{ + TSQuery query = PG_GETARG_TSQUERY(0); + int nnode = query->size; + + PG_FREE_IF_COPY(query, 0); + PG_RETURN_INT32(nnode); +} + +static QTNode * +join_tsqueries(TSQuery a, TSQuery b, int8 operator, uint16 distance) +{ + QTNode *res = (QTNode *) palloc0(sizeof(QTNode)); + + res->flags |= QTN_NEEDFREE; + + res->valnode = (QueryItem *) palloc0(sizeof(QueryItem)); + res->valnode->type = QI_OPR; + res->valnode->qoperator.oper = operator; + if (operator == OP_PHRASE) + res->valnode->qoperator.distance = distance; + + res->child = (QTNode **) palloc0(sizeof(QTNode *) * 2); + res->child[0] = QT2QTN(GETQUERY(b), GETOPERAND(b)); + res->child[1] = QT2QTN(GETQUERY(a), GETOPERAND(a)); + res->nchild = 2; + + return res; +} + +Datum +tsquery_and(PG_FUNCTION_ARGS) +{ + TSQuery a = PG_GETARG_TSQUERY_COPY(0); + TSQuery b = PG_GETARG_TSQUERY_COPY(1); + QTNode *res; + TSQuery query; + + if (a->size == 0) + { + PG_FREE_IF_COPY(a, 1); + PG_RETURN_POINTER(b); + } + else if (b->size == 0) + { + PG_FREE_IF_COPY(b, 1); + PG_RETURN_POINTER(a); + } + + res = join_tsqueries(a, b, OP_AND, 0); + + query = QTN2QT(res); + + QTNFree(res); + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + + PG_RETURN_TSQUERY(query); +} + +Datum +tsquery_or(PG_FUNCTION_ARGS) +{ + TSQuery a = PG_GETARG_TSQUERY_COPY(0); + TSQuery b = PG_GETARG_TSQUERY_COPY(1); + QTNode *res; + TSQuery query; + + if (a->size == 0) + { + PG_FREE_IF_COPY(a, 1); + PG_RETURN_POINTER(b); + } + else if (b->size == 0) + { + PG_FREE_IF_COPY(b, 1); + PG_RETURN_POINTER(a); + } + + res = join_tsqueries(a, b, OP_OR, 0); + + query = QTN2QT(res); + + QTNFree(res); + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + + PG_RETURN_TSQUERY(query); +} + +Datum +tsquery_phrase_distance(PG_FUNCTION_ARGS) +{ + TSQuery a = PG_GETARG_TSQUERY_COPY(0); + TSQuery b = PG_GETARG_TSQUERY_COPY(1); + QTNode *res; + TSQuery query; + int32 distance = PG_GETARG_INT32(2); + + if (distance < 0 || distance > MAXENTRYPOS) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("distance in phrase operator must be an integer value between zero and %d inclusive", + MAXENTRYPOS))); + if (a->size == 0) + { + PG_FREE_IF_COPY(a, 1); + PG_RETURN_POINTER(b); + } + else if (b->size == 0) + { + PG_FREE_IF_COPY(b, 1); + PG_RETURN_POINTER(a); + } + + res = join_tsqueries(a, b, OP_PHRASE, (uint16) distance); + + query = QTN2QT(res); + + QTNFree(res); + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + + PG_RETURN_TSQUERY(query); +} + +Datum +tsquery_phrase(PG_FUNCTION_ARGS) +{ + PG_RETURN_POINTER(DirectFunctionCall3(tsquery_phrase_distance, + PG_GETARG_DATUM(0), + PG_GETARG_DATUM(1), + Int32GetDatum(1))); +} + +Datum +tsquery_not(PG_FUNCTION_ARGS) +{ + TSQuery a = PG_GETARG_TSQUERY_COPY(0); + QTNode *res; + TSQuery query; + + if (a->size == 0) + PG_RETURN_POINTER(a); + + res = (QTNode *) palloc0(sizeof(QTNode)); + + res->flags |= QTN_NEEDFREE; + + res->valnode = (QueryItem *) palloc0(sizeof(QueryItem)); + res->valnode->type = QI_OPR; + res->valnode->qoperator.oper = OP_NOT; + + res->child = (QTNode **) palloc0(sizeof(QTNode *)); + res->child[0] = QT2QTN(GETQUERY(a), GETOPERAND(a)); + res->nchild = 1; + + query = QTN2QT(res); + + QTNFree(res); + PG_FREE_IF_COPY(a, 0); + + PG_RETURN_POINTER(query); +} + +static int +CompareTSQ(TSQuery a, TSQuery b) +{ + if (a->size != b->size) + { + return (a->size < b->size) ? -1 : 1; + } + else if (VARSIZE(a) != VARSIZE(b)) + { + return (VARSIZE(a) < VARSIZE(b)) ? -1 : 1; + } + else if (a->size != 0) + { + QTNode *an = QT2QTN(GETQUERY(a), GETOPERAND(a)); + QTNode *bn = QT2QTN(GETQUERY(b), GETOPERAND(b)); + int res = QTNodeCompare(an, bn); + + QTNFree(an); + QTNFree(bn); + + return res; + } + + return 0; +} + +Datum +tsquery_cmp(PG_FUNCTION_ARGS) +{ + TSQuery a = PG_GETARG_TSQUERY_COPY(0); + TSQuery b = PG_GETARG_TSQUERY_COPY(1); + int res = CompareTSQ(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + + PG_RETURN_INT32(res); +} + +#define CMPFUNC( NAME, CONDITION ) \ +Datum \ +NAME(PG_FUNCTION_ARGS) { \ + TSQuery a = PG_GETARG_TSQUERY_COPY(0); \ + TSQuery b = PG_GETARG_TSQUERY_COPY(1); \ + int res = CompareTSQ(a,b); \ + \ + PG_FREE_IF_COPY(a,0); \ + PG_FREE_IF_COPY(b,1); \ + \ + PG_RETURN_BOOL( CONDITION ); \ +} \ +/* keep compiler quiet - no extra ; */ \ +extern int no_such_variable + +CMPFUNC(tsquery_lt, res < 0); +CMPFUNC(tsquery_le, res <= 0); +CMPFUNC(tsquery_eq, res == 0); +CMPFUNC(tsquery_ge, res >= 0); +CMPFUNC(tsquery_gt, res > 0); +CMPFUNC(tsquery_ne, res != 0); + +TSQuerySign +makeTSQuerySign(TSQuery a) +{ + int i; + QueryItem *ptr = GETQUERY(a); + TSQuerySign sign = 0; + + for (i = 0; i < a->size; i++) + { + if (ptr->type == QI_VAL) + sign |= ((TSQuerySign) 1) << (((unsigned int) ptr->qoperand.valcrc) % TSQS_SIGLEN); + ptr++; + } + + return sign; +} + +static char ** +collectTSQueryValues(TSQuery a, int *nvalues_p) +{ + QueryItem *ptr = GETQUERY(a); + char *operand = GETOPERAND(a); + char **values; + int nvalues = 0; + int i; + + values = (char **) palloc(sizeof(char *) * a->size); + + for (i = 0; i < a->size; i++) + { + if (ptr->type == QI_VAL) + { + int len = ptr->qoperand.length; + char *val; + + val = palloc(len + 1); + memcpy(val, operand + ptr->qoperand.distance, len); + val[len] = '\0'; + + values[nvalues++] = val; + } + ptr++; + } + + *nvalues_p = nvalues; + return values; +} + +static int +cmp_string(const void *a, const void *b) +{ + const char *sa = *((char *const *) a); + const char *sb = *((char *const *) b); + + return strcmp(sa, sb); +} + +Datum +tsq_mcontains(PG_FUNCTION_ARGS) +{ + TSQuery query = PG_GETARG_TSQUERY(0); + TSQuery ex = PG_GETARG_TSQUERY(1); + char **query_values; + int query_nvalues; + char **ex_values; + int ex_nvalues; + bool result = true; + + /* Extract the query terms into arrays */ + query_values = collectTSQueryValues(query, &query_nvalues); + ex_values = collectTSQueryValues(ex, &ex_nvalues); + + /* Sort and remove duplicates from both arrays */ + qsort(query_values, query_nvalues, sizeof(char *), cmp_string); + query_nvalues = qunique(query_values, query_nvalues, sizeof(char *), + cmp_string); + qsort(ex_values, ex_nvalues, sizeof(char *), cmp_string); + ex_nvalues = qunique(ex_values, ex_nvalues, sizeof(char *), cmp_string); + + if (ex_nvalues > query_nvalues) + result = false; + else + { + int i; + int j = 0; + + for (i = 0; i < ex_nvalues; i++) + { + for (; j < query_nvalues; j++) + { + if (strcmp(ex_values[i], query_values[j]) == 0) + break; + } + if (j == query_nvalues) + { + result = false; + break; + } + } + } + + PG_RETURN_BOOL(result); +} + +Datum +tsq_mcontained(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall2(tsq_mcontains, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(0))); +} |