mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Cross-data-type comparisons are now indexable by btrees, pursuant to my
pghackers proposal of 8-Nov. All the existing cross-type comparison operators (int2/int4/int8 and float4/float8) have appropriate support. The original proposal of storing the right-hand-side datatype as part of the primary key for pg_amop and pg_amproc got modified a bit in the event; it is easier to store zero as the 'default' case and only store a nonzero when the operator is actually cross-type. Along the way, remove the long-since-defunct bigbox_ops operator class.
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.147 2003/08/04 02:40:00 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.148 2003/11/12 21:15:52 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1072,7 +1072,7 @@ pred_test_recurse_pred(Expr *predicate, Node *clause)
|
||||
*
|
||||
* If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you
|
||||
* want to determine whether "ATTR target_op CONST2" must also be true, then
|
||||
* you can use "CONST1 test_op CONST2" as a test. If this test returns true,
|
||||
* you can use "CONST2 test_op CONST1" as a test. If this test returns true,
|
||||
* then the target expression must be true; if the test returns false, then
|
||||
* the target expression may be false.
|
||||
*
|
||||
@ -1082,11 +1082,11 @@ pred_test_recurse_pred(Expr *predicate, Node *clause)
|
||||
|
||||
static const StrategyNumber
|
||||
BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
|
||||
{2, 2, 0, 0, 0},
|
||||
{1, 2, 0, 0, 0},
|
||||
{1, 2, 3, 4, 5},
|
||||
{0, 0, 0, 4, 5},
|
||||
{0, 0, 0, 4, 4}
|
||||
{4, 4, 0, 0, 0},
|
||||
{5, 4, 0, 0, 0},
|
||||
{5, 4, 3, 2, 1},
|
||||
{0, 0, 0, 2, 1},
|
||||
{0, 0, 0, 2, 2}
|
||||
};
|
||||
|
||||
|
||||
@ -1118,12 +1118,13 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
*clause_const;
|
||||
Oid pred_op,
|
||||
clause_op,
|
||||
test_op;
|
||||
Oid opclass_id = InvalidOid;
|
||||
test_op = InvalidOid;
|
||||
Oid opclass_id;
|
||||
bool found = false;
|
||||
StrategyNumber pred_strategy = 0,
|
||||
clause_strategy = 0,
|
||||
StrategyNumber pred_strategy,
|
||||
clause_strategy,
|
||||
test_strategy;
|
||||
Oid clause_subtype;
|
||||
Expr *test_expr;
|
||||
ExprState *test_exprstate;
|
||||
Datum test_result;
|
||||
@ -1140,7 +1141,9 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
/*
|
||||
* Can't do anything more unless they are both binary opclauses with a
|
||||
* Var on the left and a Const on the right. (XXX someday try to
|
||||
* commute Const/Var cases?)
|
||||
* commute Const/Var cases?) Note we don't have to think about binary
|
||||
* relabeling of the Const node, since that would have been folded right
|
||||
* into the Const.
|
||||
*/
|
||||
if (!is_opclause(predicate))
|
||||
return false;
|
||||
@ -1173,14 +1176,20 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
clause_op = ((OpExpr *) clause)->opno;
|
||||
|
||||
/*
|
||||
* 1. Find "btree" strategy numbers for the pred_op and clause_op.
|
||||
* Try to find a btree opclass containing the needed operators.
|
||||
*
|
||||
* We must find a btree opclass that contains both operators, else the
|
||||
* implication can't be determined. If there are multiple such
|
||||
* opclasses, assume we can use any one to determine the logical
|
||||
* relationship of the two operators and the correct corresponding
|
||||
* test operator. This should work for any logically consistent
|
||||
* opclasses.
|
||||
* implication can't be determined. Also, the pred_op has to be of
|
||||
* default subtype (implying left and right input datatypes are the same);
|
||||
* otherwise it's unsafe to put the pred_const on the left side of the
|
||||
* test. Also, the opclass must contain a suitable test operator
|
||||
* matching the clause_const's type (which we take to mean that it has
|
||||
* the same subtype as the original clause_operator).
|
||||
*
|
||||
* If there are multiple matching opclasses, assume we can use any one to
|
||||
* determine the logical relationship of the two operators and the correct
|
||||
* corresponding test operator. This should work for any logically
|
||||
* consistent opclasses.
|
||||
*/
|
||||
catlist = SearchSysCacheList(AMOPOPID, 1,
|
||||
ObjectIdGetDatum(pred_op),
|
||||
@ -1192,7 +1201,13 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
|
||||
HeapTuple clause_tuple;
|
||||
|
||||
if (!opclass_is_btree(pred_form->amopclaid))
|
||||
opclass_id = pred_form->amopclaid;
|
||||
|
||||
/* must be btree */
|
||||
if (!opclass_is_btree(opclass_id))
|
||||
continue;
|
||||
/* predicate operator must be default within this opclass */
|
||||
if (pred_form->amopsubtype != InvalidOid)
|
||||
continue;
|
||||
|
||||
/* Get the predicate operator's btree strategy number */
|
||||
@ -1200,12 +1215,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
Assert(pred_strategy >= 1 && pred_strategy <= 5);
|
||||
|
||||
/*
|
||||
* Remember which operator class this strategy number came from
|
||||
*/
|
||||
opclass_id = pred_form->amopclaid;
|
||||
|
||||
/*
|
||||
* From the same opclass, find a strategy num for the clause_op,
|
||||
* From the same opclass, find a strategy number for the clause_op,
|
||||
* if possible
|
||||
*/
|
||||
clause_tuple = SearchSysCache(AMOPOPID,
|
||||
@ -1216,13 +1226,35 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
{
|
||||
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
|
||||
|
||||
/* Get the restriction clause operator's strategy number */
|
||||
/* Get the restriction clause operator's strategy/subtype */
|
||||
clause_strategy = (StrategyNumber) clause_form->amopstrategy;
|
||||
Assert(clause_strategy >= 1 && clause_strategy <= 5);
|
||||
clause_subtype = clause_form->amopsubtype;
|
||||
|
||||
/* done with clause_tuple */
|
||||
ReleaseSysCache(clause_tuple);
|
||||
found = true;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Look up the "test" strategy number in the implication table
|
||||
*/
|
||||
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
|
||||
if (test_strategy == 0)
|
||||
{
|
||||
/* Can't determine implication using this interpretation */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if opclass has an operator for the test strategy and the
|
||||
* clause datatype.
|
||||
*/
|
||||
test_op = get_opclass_member(opclass_id, clause_subtype,
|
||||
test_strategy);
|
||||
if (OidIsValid(test_op))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1235,25 +1267,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. Look up the "test" strategy number in the implication table
|
||||
*/
|
||||
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
|
||||
if (test_strategy == 0)
|
||||
return false; /* the implication cannot be determined */
|
||||
|
||||
/*
|
||||
* 3. From the same opclass, find the operator for the test strategy
|
||||
*/
|
||||
test_op = get_opclass_member(opclass_id, test_strategy);
|
||||
if (!OidIsValid(test_op))
|
||||
{
|
||||
/* This should not fail, else pg_amop entry is missing */
|
||||
elog(ERROR, "missing pg_amop entry for opclass %u strategy %d",
|
||||
opclass_id, test_strategy);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. Evaluate the test. For this we need an EState.
|
||||
* Evaluate the test. For this we need an EState.
|
||||
*/
|
||||
estate = CreateExecutorState();
|
||||
|
||||
@ -1264,8 +1278,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
test_expr = make_opclause(test_op,
|
||||
BOOLOID,
|
||||
false,
|
||||
(Expr *) clause_const,
|
||||
(Expr *) pred_const);
|
||||
(Expr *) pred_const,
|
||||
(Expr *) clause_const);
|
||||
|
||||
/* Prepare it for execution */
|
||||
test_exprstate = ExecPrepareExpr(test_expr, estate);
|
||||
@ -1907,7 +1921,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
* (The latter is not depended on by any part of the planner, so far as I can
|
||||
* tell; but some parts of the executor do assume that the indxqual list
|
||||
* ultimately delivered to the executor is so ordered. One such place is
|
||||
* _bt_orderkeys() in the btree support. Perhaps that ought to be fixed
|
||||
* _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed
|
||||
* someday --- tgl 7/00)
|
||||
*/
|
||||
List *
|
||||
@ -2103,7 +2117,8 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
*/
|
||||
if (pstatus == Pattern_Prefix_Exact)
|
||||
{
|
||||
oproid = get_opclass_member(opclass, BTEqualStrategyNumber);
|
||||
oproid = get_opclass_member(opclass, InvalidOid,
|
||||
BTEqualStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no = operator for opclass %u", opclass);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
@ -2117,7 +2132,8 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
*
|
||||
* We can always say "x >= prefix".
|
||||
*/
|
||||
oproid = get_opclass_member(opclass, BTGreaterEqualStrategyNumber);
|
||||
oproid = get_opclass_member(opclass, InvalidOid,
|
||||
BTGreaterEqualStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no >= operator for opclass %u", opclass);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
@ -2132,7 +2148,8 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
greaterstr = make_greater_string(prefix_const);
|
||||
if (greaterstr)
|
||||
{
|
||||
oproid = get_opclass_member(opclass, BTLessStrategyNumber);
|
||||
oproid = get_opclass_member(opclass, InvalidOid,
|
||||
BTLessStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no < operator for opclass %u", opclass);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
@ -2189,13 +2206,15 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
|
||||
*/
|
||||
if (is_eq)
|
||||
{
|
||||
opr1oid = get_opclass_member(opclass, BTGreaterEqualStrategyNumber);
|
||||
opr1oid = get_opclass_member(opclass, InvalidOid,
|
||||
BTGreaterEqualStrategyNumber);
|
||||
if (opr1oid == InvalidOid)
|
||||
elog(ERROR, "no >= operator for opclass %u", opclass);
|
||||
}
|
||||
else
|
||||
{
|
||||
opr1oid = get_opclass_member(opclass, BTGreaterStrategyNumber);
|
||||
opr1oid = get_opclass_member(opclass, InvalidOid,
|
||||
BTGreaterStrategyNumber);
|
||||
if (opr1oid == InvalidOid)
|
||||
elog(ERROR, "no > operator for opclass %u", opclass);
|
||||
}
|
||||
@ -2210,7 +2229,8 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
|
||||
|
||||
/* create clause "key <= network_scan_last( rightop )" */
|
||||
|
||||
opr2oid = get_opclass_member(opclass, BTLessEqualStrategyNumber);
|
||||
opr2oid = get_opclass_member(opclass, InvalidOid,
|
||||
BTLessEqualStrategyNumber);
|
||||
if (opr2oid == InvalidOid)
|
||||
elog(ERROR, "no <= operator for opclass %u", opclass);
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.158 2003/11/09 21:30:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.159 2003/11/12 21:15:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -63,13 +63,15 @@ static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path,
|
||||
static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
List **fixed_indexquals,
|
||||
List **recheck_indexquals,
|
||||
List **indxstrategy);
|
||||
List **indxstrategy,
|
||||
List **indxsubtype);
|
||||
static void fix_indxqual_sublist(List *indexqual,
|
||||
Relids baserelids, int baserelid,
|
||||
IndexOptInfo *index,
|
||||
List **fixed_quals,
|
||||
List **recheck_quals,
|
||||
List **strategy);
|
||||
List **strategy,
|
||||
List **subtype);
|
||||
static Node *fix_indxqual_operand(Node *node, int baserelid,
|
||||
IndexOptInfo *index,
|
||||
Oid *opclass);
|
||||
@ -79,8 +81,8 @@ static void copy_path_costsize(Plan *dest, Path *src);
|
||||
static void copy_plan_costsize(Plan *dest, Plan *src);
|
||||
static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
|
||||
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
|
||||
List *indxid, List *indxqual,
|
||||
List *indxqualorig, List *indxstrategy,
|
||||
List *indxid, List *indxqual, List *indxqualorig,
|
||||
List *indxstrategy, List *indxsubtype,
|
||||
ScanDirection indexscandir);
|
||||
static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
|
||||
List *tideval);
|
||||
@ -704,6 +706,7 @@ create_indexscan_plan(Query *root,
|
||||
List *fixed_indxqual;
|
||||
List *recheck_indxqual;
|
||||
List *indxstrategy;
|
||||
List *indxsubtype;
|
||||
FastList indexids;
|
||||
List *ixinfo;
|
||||
IndexScan *scan_plan;
|
||||
@ -771,7 +774,7 @@ create_indexscan_plan(Query *root,
|
||||
*/
|
||||
fix_indxqual_references(indxqual, best_path,
|
||||
&fixed_indxqual, &recheck_indxqual,
|
||||
&indxstrategy);
|
||||
&indxstrategy, &indxsubtype);
|
||||
|
||||
/*
|
||||
* If there were any "lossy" operators, need to add back the
|
||||
@ -804,6 +807,7 @@ create_indexscan_plan(Query *root,
|
||||
fixed_indxqual,
|
||||
indxqual,
|
||||
indxstrategy,
|
||||
indxsubtype,
|
||||
best_path->indexscandir);
|
||||
|
||||
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
|
||||
@ -1151,8 +1155,8 @@ create_hashjoin_plan(Query *root,
|
||||
* must add (the original form of) the indexqual clause to the "qpquals"
|
||||
* of the indexscan node, where the operator will be re-evaluated to
|
||||
* ensure it passes.
|
||||
* * We must construct a list of operator strategy numbers corresponding
|
||||
* to the top-level operators of each index clause.
|
||||
* * We must construct lists of operator strategy numbers and subtypes for
|
||||
* the top-level operators of each index clause.
|
||||
*
|
||||
* Both the input list and the output lists have the form of lists of sublists
|
||||
* of qual clauses --- the top-level list has one entry for each indexscan
|
||||
@ -1167,11 +1171,12 @@ create_hashjoin_plan(Query *root,
|
||||
* need rechecking.
|
||||
*
|
||||
* indxstrategy receives a list of integer sublists of strategy numbers.
|
||||
* indxsubtype receives a list of OID sublists of strategy subtypes.
|
||||
*/
|
||||
static void
|
||||
fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
List **fixed_indexquals, List **recheck_indexquals,
|
||||
List **indxstrategy)
|
||||
List **indxstrategy, List **indxsubtype)
|
||||
{
|
||||
FastList fixed_quals;
|
||||
FastList recheck_quals;
|
||||
@ -1183,6 +1188,7 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
FastListInit(&fixed_quals);
|
||||
FastListInit(&recheck_quals);
|
||||
*indxstrategy = NIL;
|
||||
*indxsubtype = NIL;
|
||||
foreach(i, indexquals)
|
||||
{
|
||||
List *indexqual = lfirst(i);
|
||||
@ -1190,13 +1196,16 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
List *fixed_qual;
|
||||
List *recheck_qual;
|
||||
List *strategy;
|
||||
List *subtype;
|
||||
|
||||
fix_indxqual_sublist(indexqual, baserelids, baserelid, index,
|
||||
&fixed_qual, &recheck_qual, &strategy);
|
||||
&fixed_qual, &recheck_qual,
|
||||
&strategy, &subtype);
|
||||
FastAppend(&fixed_quals, fixed_qual);
|
||||
if (recheck_qual != NIL)
|
||||
FastAppend(&recheck_quals, recheck_qual);
|
||||
*indxstrategy = lappend(*indxstrategy, strategy);
|
||||
*indxsubtype = lappend(*indxsubtype, subtype);
|
||||
|
||||
ixinfo = lnext(ixinfo);
|
||||
}
|
||||
@ -1211,12 +1220,15 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
* For each qual clause, commute if needed to put the indexkey operand on the
|
||||
* left, and then fix its varattno. (We do not need to change the other side
|
||||
* of the clause.) Also change the operator if necessary, check for
|
||||
* lossy index behavior, and determine the operator's strategy number.
|
||||
* lossy index behavior, and determine the operator's strategy number and
|
||||
* subtype number.
|
||||
*
|
||||
* Returns three lists: the list of fixed indexquals, the list (usually
|
||||
* empty) of original clauses that must be rechecked as qpquals because
|
||||
* the index is lossy for this operator type, and the integer list of
|
||||
* strategy numbers.
|
||||
* Returns four lists:
|
||||
* the list of fixed indexquals
|
||||
* the list (usually empty) of original clauses that must be rechecked
|
||||
* as qpquals because the index is lossy for this operator type
|
||||
* the integer list of strategy numbers
|
||||
* the OID list of strategy subtypes
|
||||
*/
|
||||
static void
|
||||
fix_indxqual_sublist(List *indexqual,
|
||||
@ -1224,7 +1236,8 @@ fix_indxqual_sublist(List *indexqual,
|
||||
IndexOptInfo *index,
|
||||
List **fixed_quals,
|
||||
List **recheck_quals,
|
||||
List **strategy)
|
||||
List **strategy,
|
||||
List **subtype)
|
||||
{
|
||||
FastList fixed_qual;
|
||||
FastList recheck_qual;
|
||||
@ -1233,6 +1246,7 @@ fix_indxqual_sublist(List *indexqual,
|
||||
FastListInit(&fixed_qual);
|
||||
FastListInit(&recheck_qual);
|
||||
*strategy = NIL;
|
||||
*subtype = NIL;
|
||||
foreach(i, indexqual)
|
||||
{
|
||||
OpExpr *clause = (OpExpr *) lfirst(i);
|
||||
@ -1240,6 +1254,7 @@ fix_indxqual_sublist(List *indexqual,
|
||||
Relids leftvarnos;
|
||||
Oid opclass;
|
||||
int stratno;
|
||||
Oid stratsubtype;
|
||||
bool recheck;
|
||||
|
||||
if (!IsA(clause, OpExpr) ||
|
||||
@ -1278,13 +1293,14 @@ fix_indxqual_sublist(List *indexqual,
|
||||
|
||||
/*
|
||||
* Look up the operator in the operator class to get its strategy
|
||||
* number and the recheck indicator. This also double-checks that
|
||||
* numbers and the recheck indicator. This also double-checks that
|
||||
* we found an operator matching the index.
|
||||
*/
|
||||
get_op_opclass_properties(newclause->opno, opclass,
|
||||
&stratno, &recheck);
|
||||
&stratno, &stratsubtype, &recheck);
|
||||
|
||||
*strategy = lappendi(*strategy, stratno);
|
||||
*subtype = lappendo(*subtype, stratsubtype);
|
||||
|
||||
/*
|
||||
* If index is lossy for this operator, add (a copy of) original form
|
||||
@ -1540,6 +1556,7 @@ make_indexscan(List *qptlist,
|
||||
List *indxqual,
|
||||
List *indxqualorig,
|
||||
List *indxstrategy,
|
||||
List *indxsubtype,
|
||||
ScanDirection indexscandir)
|
||||
{
|
||||
IndexScan *node = makeNode(IndexScan);
|
||||
@ -1555,6 +1572,7 @@ make_indexscan(List *qptlist,
|
||||
node->indxqual = indxqual;
|
||||
node->indxqualorig = indxqualorig;
|
||||
node->indxstrategy = indxstrategy;
|
||||
node->indxsubtype = indxsubtype;
|
||||
node->indxorderdir = indexscandir;
|
||||
|
||||
return node;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.88 2003/11/09 21:30:37 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.89 2003/11/12 21:15:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -23,7 +23,6 @@
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_inherits.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/plancat.h"
|
||||
@ -329,10 +328,10 @@ find_inheritance_children(Oid inhparent)
|
||||
if (!has_subclass(inhparent))
|
||||
return NIL;
|
||||
|
||||
ScanKeyEntryInitialize(&key[0], 0,
|
||||
Anum_pg_inherits_inhparent,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(inhparent), OIDOID);
|
||||
ScanKeyInit(&key[0],
|
||||
Anum_pg_inherits_inhparent,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(inhparent));
|
||||
relation = heap_openr(InheritsRelationName, AccessShareLock);
|
||||
scan = heap_beginscan(relation, SnapshotNow, 1, key);
|
||||
while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
||||
|
Reference in New Issue
Block a user