Datum spg_text_inner_consistent(PG_FUNCTION_ARGS) { spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0); spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1); StrategyNumber strategy = in->strategy; text *inText; int inSize; int i; text *reconstrText = NULL; int maxReconstrLen = 0; text *prefixText = NULL; int prefixSize = 0; /* * If it's a collation-aware operator, but the collation is C, we can * treat it as non-collation-aware. */ if (strategy > 10 && lc_collate_is_c(PG_GET_COLLATION())) strategy -= 10; inText = DatumGetTextPP(in->query); inSize = VARSIZE_ANY_EXHDR(inText); /* * Reconstruct values represented at this tuple, including parent data, * prefix of this tuple if any, and the node label if any. in->level * should be the length of the previously reconstructed value, and the * number of bytes added here is prefixSize or prefixSize + 1. * * Note: we assume that in->reconstructedValue isn't toasted and doesn't * have a short varlena header. This is okay because it must have been * created by a previous invocation of this routine, and we always emit * long-format reconstructed values. */ Assert(in->level == 0 ? DatumGetPointer(in->reconstructedValue) == NULL : VARSIZE_ANY_EXHDR(DatumGetPointer(in->reconstructedValue)) == in->level); maxReconstrLen = in->level + 1; if (in->hasPrefix) { prefixText = DatumGetTextPP(in->prefixDatum); prefixSize = VARSIZE_ANY_EXHDR(prefixText); maxReconstrLen += prefixSize; } reconstrText = palloc(VARHDRSZ + maxReconstrLen); SET_VARSIZE(reconstrText, VARHDRSZ + maxReconstrLen); if (in->level) memcpy(VARDATA(reconstrText), VARDATA(DatumGetPointer(in->reconstructedValue)), in->level); if (prefixSize) memcpy(((char *) VARDATA(reconstrText)) + in->level, VARDATA_ANY(prefixText), prefixSize); /* last byte of reconstrText will be filled in below */ /* * Scan the child nodes. For each one, complete the reconstructed value * and see if it's consistent with the query. If so, emit an entry into * the output arrays. */ out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes); out->levelAdds = (int *) palloc(sizeof(int) * in->nNodes); out->reconstructedValues = (Datum *) palloc(sizeof(Datum) * in->nNodes); out->nNodes = 0; for (i = 0; i < in->nNodes; i++) { uint8 nodeChar = DatumGetUInt8(in->nodeLabels[i]); int thisLen; int r; bool res = false; /* If nodeChar is zero, don't include it in data */ if (nodeChar == '\0') thisLen = maxReconstrLen - 1; else { ((char *) VARDATA(reconstrText))[maxReconstrLen - 1] = nodeChar; thisLen = maxReconstrLen; } r = memcmp(VARDATA(reconstrText), VARDATA_ANY(inText), Min(inSize, thisLen)); switch (strategy) { case BTLessStrategyNumber: case BTLessEqualStrategyNumber: if (r <= 0) res = true; break; case BTEqualStrategyNumber: if (r == 0 && inSize >= thisLen) res = true; break; case BTGreaterEqualStrategyNumber: case BTGreaterStrategyNumber: if (r >= 0) res = true; break; case BTLessStrategyNumber + 10: case BTLessEqualStrategyNumber + 10: case BTGreaterEqualStrategyNumber + 10: case BTGreaterStrategyNumber + 10: /* * with non-C collation we need to traverse whole tree :-( */ res = true; break; default: elog(ERROR, "unrecognized strategy number: %d", in->strategy); break; } if (res) { out->nodeNumbers[out->nNodes] = i; out->levelAdds[out->nNodes] = thisLen - in->level; SET_VARSIZE(reconstrText, VARHDRSZ + thisLen); out->reconstructedValues[out->nNodes] = datumCopy(PointerGetDatum(reconstrText), false, -1); out->nNodes++; } } PG_RETURN_VOID(); }
Datum spg_text_inner_consistent(PG_FUNCTION_ARGS) { spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0); spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1); bool collate_is_c = lc_collate_is_c(PG_GET_COLLATION()); text *reconstrText = NULL; int maxReconstrLen = 0; text *prefixText = NULL; int prefixSize = 0; int i; /* * Reconstruct values represented at this tuple, including parent data, * prefix of this tuple if any, and the node label if it's non-dummy. * in->level should be the length of the previously reconstructed value, * and the number of bytes added here is prefixSize or prefixSize + 1. * * Note: we assume that in->reconstructedValue isn't toasted and doesn't * have a short varlena header. This is okay because it must have been * created by a previous invocation of this routine, and we always emit * long-format reconstructed values. */ Assert(in->level == 0 ? DatumGetPointer(in->reconstructedValue) == NULL : VARSIZE_ANY_EXHDR(DatumGetPointer(in->reconstructedValue)) == in->level); maxReconstrLen = in->level + 1; if (in->hasPrefix) { prefixText = DatumGetTextPP(in->prefixDatum); prefixSize = VARSIZE_ANY_EXHDR(prefixText); maxReconstrLen += prefixSize; } reconstrText = palloc(VARHDRSZ + maxReconstrLen); SET_VARSIZE(reconstrText, VARHDRSZ + maxReconstrLen); if (in->level) memcpy(VARDATA(reconstrText), VARDATA(DatumGetPointer(in->reconstructedValue)), in->level); if (prefixSize) memcpy(((char *) VARDATA(reconstrText)) + in->level, VARDATA_ANY(prefixText), prefixSize); /* last byte of reconstrText will be filled in below */ /* * Scan the child nodes. For each one, complete the reconstructed value * and see if it's consistent with the query. If so, emit an entry into * the output arrays. */ out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes); out->levelAdds = (int *) palloc(sizeof(int) * in->nNodes); out->reconstructedValues = (Datum *) palloc(sizeof(Datum) * in->nNodes); out->nNodes = 0; for (i = 0; i < in->nNodes; i++) { int16 nodeChar = DatumGetInt16(in->nodeLabels[i]); int thisLen; bool res = true; int j; /* If nodeChar is a dummy value, don't include it in data */ if (nodeChar <= 0) thisLen = maxReconstrLen - 1; else { ((unsigned char *) VARDATA(reconstrText))[maxReconstrLen - 1] = nodeChar; thisLen = maxReconstrLen; } for (j = 0; j < in->nkeys; j++) { StrategyNumber strategy = in->scankeys[j].sk_strategy; text *inText; int inSize; int r; /* * If it's a collation-aware operator, but the collation is C, we * can treat it as non-collation-aware. With non-C collation we * need to traverse whole tree :-( so there's no point in making * any check here. (Note also that our reconstructed value may * well end with a partial multibyte character, so that applying * any encoding-sensitive test to it would be risky anyhow.) */ if (strategy > 10) { if (collate_is_c) strategy -= 10; else continue; } inText = DatumGetTextPP(in->scankeys[j].sk_argument); inSize = VARSIZE_ANY_EXHDR(inText); r = memcmp(VARDATA(reconstrText), VARDATA_ANY(inText), Min(inSize, thisLen)); switch (strategy) { case BTLessStrategyNumber: case BTLessEqualStrategyNumber: if (r > 0) res = false; break; case BTEqualStrategyNumber: if (r != 0 || inSize < thisLen) res = false; break; case BTGreaterEqualStrategyNumber: case BTGreaterStrategyNumber: if (r < 0) res = false; break; default: elog(ERROR, "unrecognized strategy number: %d", in->scankeys[j].sk_strategy); break; } if (!res) break; /* no need to consider remaining conditions */ } if (res) { out->nodeNumbers[out->nNodes] = i; out->levelAdds[out->nNodes] = thisLen - in->level; SET_VARSIZE(reconstrText, VARHDRSZ + thisLen); out->reconstructedValues[out->nNodes] = datumCopy(PointerGetDatum(reconstrText), false, -1); out->nNodes++; } } PG_RETURN_VOID(); }