diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-03-10 18:36:49 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-03-10 18:36:49 -0500 |
commit | 03e56f798e365763486b03a2630fbc3190ccd29a (patch) | |
tree | 6fbcad7968eaad22de3a7dac6c45f2b8a82de099 /src/backend/access/spgist/spgtextproc.c | |
parent | 39d74e346c083aa371ba64c4edb1332c40b56530 (diff) | |
download | postgresql-03e56f798e365763486b03a2630fbc3190ccd29a.tar.gz postgresql-03e56f798e365763486b03a2630fbc3190ccd29a.zip |
Restructure SPGiST opclass interface API to support whole-index scans.
The original API definition was incapable of supporting whole-index scans
because there was no way to invoke leaf-value reconstruction without
checking any qual conditions. Also, it was inefficient for
multiple-qual-condition scans because value reconstruction got done over
again for each qual condition, and because other internal work in the
consistent functions likewise had to be done for each qual. To fix these
issues, pass the whole scankey array to the opclass consistent functions,
instead of only letting them see one item at a time. (Essentially, the
loop over scankey entries is now inside the consistent functions not
outside them. This makes the consistent functions a bit more complicated,
but not unreasonably so.)
In itself this commit does nothing except save a few cycles in
multiple-qual-condition index scans, since we can't support whole-index
scans on SPGiST indexes until nulls are included in the index. However,
I consider this a must-fix for 9.2 because once we release it will get
very much harder to change the opclass API definition.
Diffstat (limited to 'src/backend/access/spgist/spgtextproc.c')
-rw-r--r-- | src/backend/access/spgist/spgtextproc.c | 218 |
1 files changed, 112 insertions, 106 deletions
diff --git a/src/backend/access/spgist/spgtextproc.c b/src/backend/access/spgist/spgtextproc.c index b194fc1b13e..656015ea7e6 100644 --- a/src/backend/access/spgist/spgtextproc.c +++ b/src/backend/access/spgist/spgtextproc.c @@ -362,25 +362,12 @@ 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; + bool collate_is_c = lc_collate_is_c(PG_GET_COLLATION()); 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); + int i; /* * Reconstruct values represented at this tuple, including parent data, @@ -431,8 +418,8 @@ spg_text_inner_consistent(PG_FUNCTION_ARGS) { uint8 nodeChar = DatumGetUInt8(in->nodeLabels[i]); int thisLen; - int r; - bool res = false; + bool res = true; + int j; /* If nodeChar is zero, don't include it in data */ if (nodeChar == '\0') @@ -443,38 +430,57 @@ spg_text_inner_consistent(PG_FUNCTION_ARGS) thisLen = maxReconstrLen; } - r = memcmp(VARDATA(reconstrText), VARDATA_ANY(inText), - Min(inSize, thisLen)); - - switch (strategy) + for (j = 0; j < in->nkeys; j++) { - 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; + 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. + */ + 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) @@ -496,16 +502,13 @@ spg_text_leaf_consistent(PG_FUNCTION_ARGS) { spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0); spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1); - StrategyNumber strategy = in->strategy; - text *query = DatumGetTextPP(in->query); int level = in->level; text *leafValue, *reconstrValue = NULL; char *fullValue; int fullLen; - int queryLen; - int r; bool res; + int j; /* all tests are exact */ out->recheck = false; @@ -518,18 +521,8 @@ spg_text_leaf_consistent(PG_FUNCTION_ARGS) Assert(level == 0 ? reconstrValue == NULL : VARSIZE_ANY_EXHDR(reconstrValue) == level); + /* Reconstruct the full string represented by this leaf tuple */ fullLen = level + VARSIZE_ANY_EXHDR(leafValue); - - queryLen = VARSIZE_ANY_EXHDR(query); - - /* - * For an equality check, we needn't reconstruct fullValue if not same - * length; it can't match - */ - if (strategy == BTEqualStrategyNumber && queryLen != fullLen) - PG_RETURN_BOOL(false); - - /* Else, reconstruct the full string represented by this leaf tuple */ if (VARSIZE_ANY_EXHDR(leafValue) == 0 && level > 0) { fullValue = VARDATA(reconstrValue); @@ -549,54 +542,67 @@ spg_text_leaf_consistent(PG_FUNCTION_ARGS) out->leafValue = PointerGetDatum(fullText); } - /* Run the appropriate type of comparison */ - if (strategy > 10) + /* Perform the required comparison(s) */ + res = true; + for (j = 0; j < in->nkeys; j++) { - /* Collation-aware comparison */ - strategy -= 10; + StrategyNumber strategy = in->scankeys[j].sk_strategy; + text *query = DatumGetTextPP(in->scankeys[j].sk_argument); + int queryLen = VARSIZE_ANY_EXHDR(query); + int r; - /* If asserts are enabled, verify encoding of reconstructed string */ - Assert(pg_verifymbstr(fullValue, fullLen, false)); + if (strategy > 10) + { + /* Collation-aware comparison */ + strategy -= 10; - r = varstr_cmp(fullValue, Min(queryLen, fullLen), - VARDATA_ANY(query), Min(queryLen, fullLen), - PG_GET_COLLATION()); - } - else - { - /* Non-collation-aware comparison */ - r = memcmp(fullValue, VARDATA_ANY(query), Min(queryLen, fullLen)); - } + /* If asserts enabled, verify encoding of reconstructed string */ + Assert(pg_verifymbstr(fullValue, fullLen, false)); - if (r == 0) - { - if (queryLen > fullLen) - r = -1; - else if (queryLen < fullLen) - r = 1; - } + r = varstr_cmp(fullValue, Min(queryLen, fullLen), + VARDATA_ANY(query), Min(queryLen, fullLen), + PG_GET_COLLATION()); + } + else + { + /* Non-collation-aware comparison */ + r = memcmp(fullValue, VARDATA_ANY(query), Min(queryLen, fullLen)); + } - switch (strategy) - { - case BTLessStrategyNumber: - res = (r < 0); - break; - case BTLessEqualStrategyNumber: - res = (r <= 0); - break; - case BTEqualStrategyNumber: - res = (r == 0); - break; - case BTGreaterEqualStrategyNumber: - res = (r >= 0); - break; - case BTGreaterStrategyNumber: - res = (r > 0); - break; - default: - elog(ERROR, "unrecognized strategy number: %d", in->strategy); - res = false; - break; + if (r == 0) + { + if (queryLen > fullLen) + r = -1; + else if (queryLen < fullLen) + r = 1; + } + + switch (strategy) + { + case BTLessStrategyNumber: + res = (r < 0); + break; + case BTLessEqualStrategyNumber: + res = (r <= 0); + break; + case BTEqualStrategyNumber: + res = (r == 0); + break; + case BTGreaterEqualStrategyNumber: + res = (r >= 0); + break; + case BTGreaterStrategyNumber: + res = (r > 0); + break; + default: + elog(ERROR, "unrecognized strategy number: %d", + in->scankeys[j].sk_strategy); + res = false; + break; + } + + if (!res) + break; /* no need to consider remaining conditions */ } PG_RETURN_BOOL(res); |