@@ -63,7 +63,7 @@ static bool _bt_check_compare(IndexScanDesc scan, ScanDirection dir,
6363 bool advancenonrequired , bool forcenonrequired ,
6464 bool * continuescan , int * ikey );
6565static bool _bt_rowcompare_cmpresult (ScanKey subkey , int cmpresult );
66- static bool _bt_check_rowcompare (ScanKey skey ,
66+ static bool _bt_check_rowcompare (ScanKey header ,
6767 IndexTuple tuple , int tupnatts , TupleDesc tupdesc ,
6868 ScanDirection dir , bool forcenonrequired , bool * continuescan );
6969static void _bt_checkkeys_look_ahead (IndexScanDesc scan , BTReadPageState * pstate ,
@@ -3008,6 +3008,8 @@ _bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult)
30083008{
30093009 bool satisfied ;
30103010
3011+ Assert (subkey -> sk_flags & SK_ROW_MEMBER );
3012+
30113013 switch (subkey -> sk_strategy )
30123014 {
30133015 case BTLessStrategyNumber :
@@ -3039,19 +3041,64 @@ _bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult)
30393041 * it's not possible for any future tuples in the current scan direction
30403042 * to pass the qual.
30413043 *
3042- * This is a subroutine for _bt_checkkeys/_bt_check_compare.
3044+ * This is a subroutine for _bt_checkkeys/_bt_check_compare. Caller passes us
3045+ * a row compare header key taken from so->keyData[].
3046+ *
3047+ * Row value comparisons can be described in terms of logical expansions that
3048+ * use only scalar operators. Consider the following example row comparison:
3049+ *
3050+ * "(a, b, c) > (7, 'bar', 62)"
3051+ *
3052+ * This can be evaluated as:
3053+ *
3054+ * "(a = 7 AND b = 'bar' AND c > 62) OR (a = 7 AND b > 'bar') OR (a > 7)".
3055+ *
3056+ * Notice that this condition is satisfied by _all_ rows that satisfy "a > 7",
3057+ * and by a subset of all rows that satisfy "a >= 7" (possibly all such rows).
3058+ * It _can't_ be satisfied by other rows (where "a < 7" or where "a IS NULL").
3059+ * A row comparison header key can therefore often be treated as if it was a
3060+ * simple scalar inequality on the row compare's most significant column.
3061+ * (For example, _bt_advance_array_keys and most preprocessing routines treat
3062+ * row compares like any other same-strategy inequality on the same column.)
3063+ *
3064+ * Things get more complicated for our row compare given a row where "a = 7".
3065+ * Note that a row compare isn't necessarily satisfied by _every_ tuple that
3066+ * appears between the first and last satisfied tuple returned by the scan,
3067+ * due to the way that its lower-order subkeys are only conditionally applied.
3068+ * A forwards scan that uses our example qual might initially return a tuple
3069+ * "(a, b, c) = (7, 'zebra', 54)". But it won't subsequently return a tuple
3070+ * "(a, b, c) = (7, NULL, 1)" located to the right of the first matching tuple
3071+ * (assume that "b" was declared NULLS LAST here). The scan will only return
3072+ * additional matches upon reaching tuples where "a > 7". If you rereview our
3073+ * example row comparison's logical expansion, you'll understand why this is.
3074+ * (Here we assume that all subkeys could be marked required, guaranteeing
3075+ * that row comparison order matches index order. This is the common case.)
3076+ *
3077+ * Note that a row comparison header key behaves _exactly_ the same as a
3078+ * similar scalar inequality key on the row's most significant column once the
3079+ * scan reaches the point where it no longer needs to evaluate lower-order
3080+ * subkeys (or before the point where it starts needing to evaluate them).
3081+ * For example, once a forwards scan that uses our example qual reaches the
3082+ * first tuple "a > 7", we'll behave in just the same way as our caller would
3083+ * behave with a similar scalar inequality "a > 7" for the remainder of the
3084+ * scan (assuming that the scan never changes direction/never goes backwards).
3085+ * We'll even set continuescan=false according to exactly the same rules as
3086+ * the ones our caller applies with simple scalar inequalities, including the
3087+ * rules it applies when NULL tuple values don't satisfy an inequality qual.
30433088 */
30443089static bool
3045- _bt_check_rowcompare (ScanKey skey , IndexTuple tuple , int tupnatts ,
3090+ _bt_check_rowcompare (ScanKey header , IndexTuple tuple , int tupnatts ,
30463091 TupleDesc tupdesc , ScanDirection dir ,
30473092 bool forcenonrequired , bool * continuescan )
30483093{
3049- ScanKey subkey = (ScanKey ) DatumGetPointer (skey -> sk_argument );
3094+ ScanKey subkey = (ScanKey ) DatumGetPointer (header -> sk_argument );
30503095 int32 cmpresult = 0 ;
30513096 bool result ;
30523097
30533098 /* First subkey should be same as the header says */
3054- Assert (subkey -> sk_attno == skey -> sk_attno );
3099+ Assert (header -> sk_flags & SK_ROW_HEADER );
3100+ Assert (subkey -> sk_attno == header -> sk_attno );
3101+ Assert (subkey -> sk_strategy == header -> sk_strategy );
30553102
30563103 /* Loop over columns of the row condition */
30573104 for (;;)
@@ -3071,7 +3118,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts,
30713118 * columns are required for the scan direction, we can stop the
30723119 * scan, because there can't be another tuple that will succeed.
30733120 */
3074- Assert (subkey != (ScanKey ) DatumGetPointer (skey -> sk_argument ));
3121+ Assert (subkey != (ScanKey ) DatumGetPointer (header -> sk_argument ));
30753122 subkey -- ;
30763123 if (forcenonrequired )
30773124 {
@@ -3142,7 +3189,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts,
31423189 * can only happen with an "a" NULL some time after the scan
31433190 * completely stops needing to use its "b" and "c" members.)
31443191 */
3145- if (subkey == (ScanKey ) DatumGetPointer (skey -> sk_argument ))
3192+ if (subkey == (ScanKey ) DatumGetPointer (header -> sk_argument ))
31463193 reqflags |= SK_BT_REQFWD ; /* safe, first row member */
31473194
31483195 if ((subkey -> sk_flags & reqflags ) &&
@@ -3180,7 +3227,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts,
31803227 * happen with an "a" NULL some time after the scan completely
31813228 * stops needing to use its "b" and "c" members.)
31823229 */
3183- if (subkey == (ScanKey ) DatumGetPointer (skey -> sk_argument ))
3230+ if (subkey == (ScanKey ) DatumGetPointer (header -> sk_argument ))
31843231 reqflags |= SK_BT_REQBKWD ; /* safe, first row member */
31853232
31863233 if ((subkey -> sk_flags & reqflags ) &&
0 commit comments