📄 nbtutils.c
字号:
* "break" statement below. */ for (i = 0;; cur++, i++) { if (i < numberOfKeys) { /* See comments above: any NULL implies cannot match qual */ if (cur->sk_flags & SK_ISNULL) { so->qual_ok = false; /* * Quit processing so we don't try to invoke comparison * routines on NULLs. */ return; } } /* * If we are at the end of the keys for a particular attr, finish up * processing and emit the cleaned-up keys. */ if (i == numberOfKeys || cur->sk_attno != attno) { int priorNumberOfEqualCols = numberOfEqualCols; /* check input keys are correctly ordered */ if (i < numberOfKeys && cur->sk_attno < attno) elog(ERROR, "btree index keys must be ordered by attribute"); /* * If = has been specified, no other key will be used. In case of * key > 2 && key == 1 and so on we have to set qual_ok to false * before discarding the other keys. */ if (xform[BTEqualStrategyNumber - 1]) { ScanKey eq = xform[BTEqualStrategyNumber - 1]; for (j = BTMaxStrategyNumber; --j >= 0;) { ScanKey chk = xform[j]; if (!chk || j == (BTEqualStrategyNumber - 1)) continue; test = FunctionCall2(&chk->sk_func, eq->sk_argument, chk->sk_argument); if (!DatumGetBool(test)) { so->qual_ok = false; break; } } xform[BTLessStrategyNumber - 1] = NULL; xform[BTLessEqualStrategyNumber - 1] = NULL; xform[BTGreaterEqualStrategyNumber - 1] = NULL; xform[BTGreaterStrategyNumber - 1] = NULL; /* track number of attrs for which we have "=" keys */ numberOfEqualCols++; } else { /* track number of attrs for which we have "=" keys */ if (hasOtherTypeEqual) numberOfEqualCols++; } /* keep only one of <, <= */ if (xform[BTLessStrategyNumber - 1] && xform[BTLessEqualStrategyNumber - 1]) { ScanKey lt = xform[BTLessStrategyNumber - 1]; ScanKey le = xform[BTLessEqualStrategyNumber - 1]; test = FunctionCall2(&le->sk_func, lt->sk_argument, le->sk_argument); if (DatumGetBool(test)) xform[BTLessEqualStrategyNumber - 1] = NULL; else xform[BTLessStrategyNumber - 1] = NULL; } /* keep only one of >, >= */ if (xform[BTGreaterStrategyNumber - 1] && xform[BTGreaterEqualStrategyNumber - 1]) { ScanKey gt = xform[BTGreaterStrategyNumber - 1]; ScanKey ge = xform[BTGreaterEqualStrategyNumber - 1]; test = FunctionCall2(&ge->sk_func, gt->sk_argument, ge->sk_argument); if (DatumGetBool(test)) xform[BTGreaterEqualStrategyNumber - 1] = NULL; else xform[BTGreaterStrategyNumber - 1] = NULL; } /* * Emit the cleaned-up keys into the outkeys[] array. */ for (j = BTMaxStrategyNumber; --j >= 0;) { if (xform[j]) memcpy(&outkeys[new_numberOfKeys++], xform[j], sizeof(ScanKeyData)); } /* * If all attrs before this one had "=", include these keys into * the required-keys count. */ if (priorNumberOfEqualCols == attno - 1) so->numberOfRequiredKeys = new_numberOfKeys; /* * Exit loop here if done. */ if (i == numberOfKeys) break; /* Re-initialize for new attno */ attno = cur->sk_attno; memset(xform, 0, sizeof(xform)); hasOtherTypeEqual = false; } /* check strategy this key's operator corresponds to */ j = cur->sk_strategy - 1; /* if wrong RHS data type, punt */ if (cur->sk_subtype != InvalidOid) { memcpy(&outkeys[new_numberOfKeys++], cur, sizeof(ScanKeyData)); if (j == (BTEqualStrategyNumber - 1)) hasOtherTypeEqual = true; continue; } /* have we seen one of these before? */ if (xform[j]) { /* yup, keep the more restrictive key */ test = FunctionCall2(&cur->sk_func, cur->sk_argument, xform[j]->sk_argument); if (DatumGetBool(test)) xform[j] = cur; else if (j == (BTEqualStrategyNumber - 1)) { /* key == a && key == b, but a != b */ so->qual_ok = false; return; } } else { /* nope, so remember this scankey */ xform[j] = cur; } } so->numberOfKeys = new_numberOfKeys; /* * If unique index and we have equality keys for all columns, set * keys_are_unique flag for higher levels. */ if (relation->rd_index->indisunique && relation->rd_rel->relnatts == numberOfEqualCols) scan->keys_are_unique = true;}/* * Test whether an indextuple satisfies all the scankey conditions. * * If the tuple fails to pass the qual, we also determine whether there's * any need to continue the scan beyond this tuple, and set *continuescan * accordingly. See comments for _bt_preprocess_keys(), above, about how * this is done. */bool_bt_checkkeys(IndexScanDesc scan, IndexTuple tuple, ScanDirection dir, bool *continuescan){ BTScanOpaque so = (BTScanOpaque) scan->opaque; int keysz = so->numberOfKeys; int ikey; TupleDesc tupdesc; ScanKey key; *continuescan = true; /* If no keys, always scan the whole index */ if (keysz == 0) return true; IncrIndexProcessed(); tupdesc = RelationGetDescr(scan->indexRelation); for (key = so->keyData, ikey = 0; ikey < keysz; key++, ikey++) { Datum datum; bool isNull; Datum test; datum = index_getattr(tuple, key->sk_attno, tupdesc, &isNull); /* btree doesn't support 'A is null' clauses, yet */ if (key->sk_flags & SK_ISNULL) { /* we shouldn't get here, really; see _bt_preprocess_keys() */ *continuescan = false; return false; } if (isNull) { /* * Since NULLs are sorted after non-NULLs, we know we have reached * the upper limit of the range of values for this index attr. On * a forward scan, we can stop if this qual is one of the "must * match" subset. On a backward scan, however, we should keep * going. */ if (ikey < so->numberOfRequiredKeys && ScanDirectionIsForward(dir)) *continuescan = false; /* * In any case, this indextuple doesn't match the qual. */ return false; } test = FunctionCall2(&key->sk_func, datum, key->sk_argument); if (!DatumGetBool(test)) { /* * Tuple fails this qual. If it's a required qual, then we may be * able to conclude no further tuples will pass, either. We have * to look at the scan direction and the qual type. * * Note: the only case in which we would keep going after failing * a required qual is if there are partially-redundant quals that * _bt_preprocess_keys() was unable to eliminate. For example, * given "x > 4 AND x > 10" where both are cross-type comparisons * and so not removable, we might start the scan at the x = 4 * boundary point. The "x > 10" condition will fail until we pass * x = 10, but we must not stop the scan on its account. * * Note: because we stop the scan as soon as any required equality * qual fails, it is critical that equality quals be used for the * initial positioning in _bt_first() when they are available. See * comments in _bt_first(). */ if (ikey < so->numberOfRequiredKeys) { switch (key->sk_strategy) { case BTLessStrategyNumber: case BTLessEqualStrategyNumber: if (ScanDirectionIsForward(dir)) *continuescan = false; break; case BTEqualStrategyNumber: *continuescan = false; break; case BTGreaterEqualStrategyNumber: case BTGreaterStrategyNumber: if (ScanDirectionIsBackward(dir)) *continuescan = false; break; default: elog(ERROR, "unrecognized StrategyNumber: %d", key->sk_strategy); } } /* * In any case, this indextuple doesn't match the qual. */ return false; } } /* If we get here, the tuple passes all quals. */ return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -