/* * Returns whether trg2 contains all trigrams in trg1. * This relies on the trigram arrays being sorted. */ bool trgm_contained_by(TRGM *trg1, TRGM *trg2) { trgm *ptr1, *ptr2; int len1, len2; ptr1 = GETARR(trg1); ptr2 = GETARR(trg2); len1 = ARRNELEM(trg1); len2 = ARRNELEM(trg2); while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2) { int res = CMPTRGM(ptr1, ptr2); if (res < 0) return false; else if (res > 0) ptr2++; else { ptr1++; ptr2++; } } if (ptr1 - GETARR(trg1) < len1) return false; else return true; }
Datum show_trgm(PG_FUNCTION_ARGS) { text *in = PG_GETARG_TEXT_P(0); TRGM *trg; Datum *d; ArrayType *a; trgm *ptr; int i; trg = generate_trgm(VARDATA(in), VARSIZE(in) - VARHDRSZ); d = (Datum *) palloc(sizeof(Datum) * (1 + ARRNELEM(trg))); for (i = 0, ptr = GETARR(trg); i < ARRNELEM(trg); i++, ptr++) { text *item = (text *) palloc(VARHDRSZ + Max(12, pg_database_encoding_max_length() * 3)); if (pg_database_encoding_max_length() > 1 && !ISPRINTABLETRGM(ptr)) { snprintf(VARDATA(item), 12, "0x%06x", trgm2int(ptr)); SET_VARSIZE(item, VARHDRSZ + strlen(VARDATA(item))); } else { SET_VARSIZE(item, VARHDRSZ + 3); CPTRGM(VARDATA(item), ptr); } d[i] = PointerGetDatum(item); } a = construct_array( d, ARRNELEM(trg), TEXTOID, -1, false, 'i' ); for (i = 0; i < ARRNELEM(trg); i++) pfree(DatumGetPointer(d[i])); pfree(d); pfree(trg); PG_FREE_IF_COPY(in, 0); PG_RETURN_POINTER(a); }
Datum gin_extract_value_trgm(PG_FUNCTION_ARGS) { text *val = (text *) PG_GETARG_TEXT_P(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); Datum *entries = NULL; TRGM *trg; int32 trglen; *nentries = 0; trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ); trglen = ARRNELEM(trg); if (trglen > 0) { trgm *ptr; int32 i; *nentries = trglen; entries = (Datum *) palloc(sizeof(Datum) * trglen); ptr = GETARR(trg); for (i = 0; i < trglen; i++) { int32 item = trgm2int(ptr); entries[i] = Int32GetDatum(item); ptr++; } } PG_RETURN_POINTER(entries); }
Datum gin_extract_trgm(PG_FUNCTION_ARGS) { text *val = (text *) PG_GETARG_TEXT_P(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); Datum *entries = NULL; TRGM *trg; int4 trglen; *nentries = 0; trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ); trglen = ARRNELEM(trg); if (trglen > 0) { trgm *ptr; int4 i = 0, item; *nentries = (int32) trglen; entries = (Datum *) palloc(sizeof(Datum) * trglen); ptr = GETARR(trg); while (ptr - GETARR(trg) < ARRNELEM(trg)) { item = trgm2int(ptr); entries[i++] = Int32GetDatum(item); ptr++; } if (PG_NARGS() > 4) { /* * Function called from query extracting */ Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4); *extra_data = (Pointer *) palloc0(sizeof(Pointer) * (*nentries)); *(int32 *) (*extra_data) = trglen; } } PG_RETURN_POINTER(entries); }
float4 cnt_sml(TRGM *trg1, TRGM *trg2) { trgm *ptr1, *ptr2; int count = 0; int len1, len2; ptr1 = GETARR(trg1); ptr2 = GETARR(trg2); len1 = ARRNELEM(trg1); len2 = ARRNELEM(trg2); /* explicit test is needed to avoid 0/0 division when both lengths are 0 */ if (len1 <= 0 || len2 <= 0) return (float4) 0.0; while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2) { int res = CMPTRGM(ptr1, ptr2); if (res < 0) ptr1++; else if (res > 0) ptr2++; else { ptr1++; ptr2++; count++; } } #ifdef DIVUNION return ((float4) count) / ((float4) (len1 + len2 - count)); #else return ((float4) count) / ((float4) ((len1 > len2) ? len1 : len2)); #endif }
float4 cnt_sml(TRGM *trg1, TRGM *trg2, bool inexact) { trgm *ptr1, *ptr2; int count = 0; int len1, len2; ptr1 = GETARR(trg1); ptr2 = GETARR(trg2); len1 = ARRNELEM(trg1); len2 = ARRNELEM(trg2); /* explicit test is needed to avoid 0/0 division when both lengths are 0 */ if (len1 <= 0 || len2 <= 0) return (float4) 0.0; while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2) { int res = CMPTRGM(ptr1, ptr2); if (res < 0) ptr1++; else if (res > 0) ptr2++; else { ptr1++; ptr2++; count++; } } /* * If inexact then len2 is equal to count, because we don't know actual * length of second string in inexact search and we can assume that count * is a lower bound of len2. */ return CALCSML(count, len1, inexact ? count : len2); }
static void makesign(BITVECP sign, SignTSVector *a) { int32 k, len = ARRNELEM(a); int32 *ptr = GETARR(a); MemSet((void *) sign, 0, sizeof(BITVEC)); for (k = 0; k < len; k++) HASH(sign, ptr[k]); }
static void makesign(BITVECP sign, GISTTYPE * a) { int4 k, len = ARRNELEM(a); int4 *ptr = GETARR(a); MemSet((void *) sign, 0, sizeof(BITVEC)); for (k = 0; k < len; k++) HASH(sign, ptr[k]); }
float4 cnt_sml(TRGM *trg1, TRGM *trg2) { trgm *ptr1, *ptr2; int count = 0; int len1, len2; ptr1 = GETARR(trg1); ptr2 = GETARR(trg2); len1 = ARRNELEM(trg1); len2 = ARRNELEM(trg2); while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2) { int res = CMPTRGM(ptr1, ptr2); if (res < 0) ptr1++; else if (res > 0) ptr2++; else { ptr1++; ptr2++; count++; } } #ifdef DIVUNION return ((((float4) count) / ((float4) (len1 + len2 - count)))); #else return (((float) count) / ((float) ((len1 > len2) ? len1 : len2))); #endif }
/* * Return a palloc'd boolean array showing, for each trigram in "query", * whether it is present in the trigram array "key". * This relies on the "key" array being sorted, but "query" need not be. */ bool * trgm_presence_map(TRGM *query, TRGM *key) { bool *result; trgm *ptrq = GETARR(query), *ptrk = GETARR(key); int lenq = ARRNELEM(query), lenk = ARRNELEM(key), i; result = (bool *) palloc0(lenq * sizeof(bool)); /* for each query trigram, do a binary search in the key array */ for (i = 0; i < lenq; i++) { int lo = 0; int hi = lenk; while (lo < hi) { int mid = (lo + hi) / 2; int res = CMPTRGM(ptrq, ptrk + mid); if (res < 0) hi = mid; else if (res > 0) lo = mid + 1; else { result[i] = true; break; } } ptrq++; } return result; }
static void makesign(BITVECP sign, TRGM *a) { int32 k, len = ARRNELEM(a); trgm *ptr = GETARR(a); int32 tmp = 0; MemSet((void *) sign, 0, sizeof(BITVEC)); SETBIT(sign, SIGLENBIT); /* set last unused bit */ for (k = 0; k < len; k++) { CPTRGM(((char *) &tmp), ptr + k); HASH(sign, tmp); } }
Datum gtsvectorout(PG_FUNCTION_ARGS) { SignTSVector *key = (SignTSVector *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_POINTER(0))); char *outbuf; if (outbuf_maxlen == 0) outbuf_maxlen = 2 * EXTRALEN + Max(strlen(SINGOUTSTR), strlen(ARROUTSTR)) + 1; outbuf = palloc(outbuf_maxlen); if (ISARRKEY(key)) sprintf(outbuf, ARROUTSTR, (int) ARRNELEM(key)); else { int cnttrue = (ISALLTRUE(key)) ? SIGLENBIT : sizebitvec(GETSIGN(key)); sprintf(outbuf, SINGOUTSTR, cnttrue, (int) SIGLENBIT - cnttrue); } PG_FREE_IF_COPY(key, 0); PG_RETURN_POINTER(outbuf); }
Datum gin_extract_query_trgm(PG_FUNCTION_ARGS) { text *val = (text *) PG_GETARG_TEXT_P(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); StrategyNumber strategy = PG_GETARG_UINT16(2); /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */ Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4); /* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */ int32 *searchMode = (int32 *) PG_GETARG_POINTER(6); Datum *entries = NULL; TRGM *trg; int32 trglen; trgm *ptr; TrgmPackedGraph *graph; int32 i; switch (strategy) { case SimilarityStrategyNumber: trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ); break; case ILikeStrategyNumber: #ifndef IGNORECASE elog(ERROR, "cannot handle ~~* with case-sensitive trigrams"); #endif /* FALL THRU */ case LikeStrategyNumber: /* * For wildcard search we extract all the trigrams that every * potentially-matching string must include. */ trg = generate_wildcard_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ); break; case RegExpICaseStrategyNumber: #ifndef IGNORECASE elog(ERROR, "cannot handle ~* with case-sensitive trigrams"); #endif /* FALL THRU */ case RegExpStrategyNumber: trg = createTrgmNFA(val, PG_GET_COLLATION(), &graph, CurrentMemoryContext); if (trg && ARRNELEM(trg) > 0) { /* * Successful regex processing: store NFA-like graph as * extra_data. GIN API requires an array of nentries * Pointers, but we just put the same value in each element. */ trglen = ARRNELEM(trg); *extra_data = (Pointer *) palloc(sizeof(Pointer) * trglen); for (i = 0; i < trglen; i++) (*extra_data)[i] = (Pointer) graph; } else { /* No result: have to do full index scan. */ *nentries = 0; *searchMode = GIN_SEARCH_MODE_ALL; PG_RETURN_POINTER(entries); } break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); trg = NULL; /* keep compiler quiet */ break; } trglen = ARRNELEM(trg); *nentries = trglen; if (trglen > 0) { entries = (Datum *) palloc(sizeof(Datum) * trglen); ptr = GETARR(trg); for (i = 0; i < trglen; i++) { int32 item = trgm2int(ptr); entries[i] = Int32GetDatum(item); ptr++; } } /* * If no trigram was extracted then we have to scan all the index. */ if (trglen == 0) *searchMode = GIN_SEARCH_MODE_ALL; PG_RETURN_POINTER(entries); }
Datum gin_extract_query_trgm(PG_FUNCTION_ARGS) { text *val = (text *) PG_GETARG_TEXT_P(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); StrategyNumber strategy = PG_GETARG_UINT16(2); /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */ /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ /* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */ int32 *searchMode = (int32 *) PG_GETARG_POINTER(6); Datum *entries = NULL; TRGM *trg; int32 trglen; trgm *ptr; int32 i; switch (strategy) { case SimilarityStrategyNumber: trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ); break; case ILikeStrategyNumber: #ifndef IGNORECASE elog(ERROR, "cannot handle ~~* with case-sensitive trigrams"); #endif /* FALL THRU */ case LikeStrategyNumber: /* * For wildcard search we extract all the trigrams that every * potentially-matching string must include. */ trg = generate_wildcard_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ); break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); trg = NULL; /* keep compiler quiet */ break; } trglen = ARRNELEM(trg); *nentries = trglen; if (trglen > 0) { entries = (Datum *) palloc(sizeof(Datum) * trglen); ptr = GETARR(trg); for (i = 0; i < trglen; i++) { int32 item = trgm2int(ptr); entries[i] = Int32GetDatum(item); ptr++; } } /* * If no trigram was extracted then we have to scan all the index. */ if (trglen == 0) *searchMode = GIN_SEARCH_MODE_ALL; PG_RETURN_POINTER(entries); }