diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-12-28 01:30:02 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-12-28 01:30:02 +0000 |
commit | 6e07709760a29d8dbfb93b9846c905bd40689082 (patch) | |
tree | 9bf0084587d7e313ba087ce53c24bc748c63a456 /src/backend/utils/cache/lsyscache.c | |
parent | a37422e042a6114ab0e513f50dac4a47fab22313 (diff) |
Implement SQL-compliant treatment of row comparisons for < <= > >= cases
(previously we only did = and <> correctly). Also, allow row comparisons
with any operators that are in btree opclasses, not only those with these
specific names. This gets rid of a whole lot of indefensible assumptions
about the behavior of particular operators based on their names ... though
it's still true that IN and NOT IN expand to "= ANY". The patch adds a
RowCompareExpr expression node type, and makes some changes in the
representation of ANY/ALL/ROWCOMPARE SubLinks so that they can share code
with RowCompareExpr.
I have not yet done anything about making RowCompareExpr an indexable
operator, but will look at that soon.
initdb forced due to changes in stored rules.
Diffstat (limited to 'src/backend/utils/cache/lsyscache.c')
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 144 |
1 files changed, 143 insertions, 1 deletions
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 40dd6806596..d470b28f24f 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.130 2005/11/17 22:14:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.131 2005/12/28 01:30:01 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -183,6 +183,99 @@ get_op_hash_function(Oid opno) return InvalidOid; } +/* + * get_op_btree_interpretation + * Given an operator's OID, find out which btree opclasses it belongs to, + * and what strategy number it has within each one. The results are + * returned as an OID list and a parallel integer list. + * + * In addition to the normal btree operators, we consider a <> operator to be + * a "member" of an opclass if its negator is the opclass' equality operator. + * ROWCOMPARE_NE is returned as the strategy number for this case. + */ +void +get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats) +{ + Oid lefttype, + righttype; + CatCList *catlist; + bool op_negated; + int i; + + *opclasses = NIL; + *opstrats = NIL; + + /* + * Get the nominal left-hand input type of the operator; we will ignore + * opclasses that don't have that as the expected input datatype. This + * is a kluge to avoid being confused by binary-compatible opclasses + * (such as text_ops and varchar_ops, which share the same operators). + */ + op_input_types(opno, &lefttype, &righttype); + Assert(OidIsValid(lefttype)); + + /* + * Find all the pg_amop entries containing the operator. + */ + catlist = SearchSysCacheList(AMOPOPID, 1, + ObjectIdGetDatum(opno), + 0, 0, 0); + /* + * If we can't find any opclass containing the op, perhaps it is a + * <> operator. See if it has a negator that is in an opclass. + */ + op_negated = false; + if (catlist->n_members == 0) + { + Oid op_negator = get_negator(opno); + + if (OidIsValid(op_negator)) + { + op_negated = true; + ReleaseSysCacheList(catlist); + catlist = SearchSysCacheList(AMOPOPID, 1, + ObjectIdGetDatum(op_negator), + 0, 0, 0); + } + } + + /* Now search the opclasses */ + for (i = 0; i < catlist->n_members; i++) + { + HeapTuple op_tuple = &catlist->members[i]->tuple; + Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple); + Oid opclass_id; + StrategyNumber op_strategy; + + opclass_id = op_form->amopclaid; + + /* must be btree */ + if (!opclass_is_btree(opclass_id)) + continue; + + /* must match operator input type exactly */ + if (get_opclass_input_type(opclass_id) != lefttype) + continue; + + /* Get the operator's btree strategy number */ + op_strategy = (StrategyNumber) op_form->amopstrategy; + Assert(op_strategy >= 1 && op_strategy <= 5); + + if (op_negated) + { + /* Only consider negators that are = */ + if (op_strategy != BTEqualStrategyNumber) + continue; + op_strategy = ROWCOMPARE_NE; + } + + *opclasses = lappend_oid(*opclasses, opclass_id); + *opstrats = lappend_int(*opstrats, op_strategy); + } + + ReleaseSysCacheList(catlist); +} + /* ---------- AMPROC CACHES ---------- */ @@ -433,6 +526,55 @@ opclass_is_hash(Oid opclass) return result; } +/* + * opclass_is_default + * + * Returns TRUE iff the specified opclass is the default for its + * index access method and input data type. + */ +bool +opclass_is_default(Oid opclass) +{ + HeapTuple tp; + Form_pg_opclass cla_tup; + bool result; + + tp = SearchSysCache(CLAOID, + ObjectIdGetDatum(opclass), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for opclass %u", opclass); + cla_tup = (Form_pg_opclass) GETSTRUCT(tp); + + result = cla_tup->opcdefault; + ReleaseSysCache(tp); + return result; +} + +/* + * get_opclass_input_type + * + * Returns the OID of the datatype the opclass indexes. + */ +Oid +get_opclass_input_type(Oid opclass) +{ + HeapTuple tp; + Form_pg_opclass cla_tup; + Oid result; + + tp = SearchSysCache(CLAOID, + ObjectIdGetDatum(opclass), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for opclass %u", opclass); + cla_tup = (Form_pg_opclass) GETSTRUCT(tp); + + result = cla_tup->opcintype; + ReleaseSysCache(tp); + return result; +} + /* ---------- OPERATOR CACHE ---------- */ /* |