*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.18 2000/01/26 05:56:21 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.19 2000/08/13 02:50:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* ----------------
*/
case T_NestLoop:
- result = ExecNestLoop((NestLoop *) node, parent);
+ result = ExecNestLoop((NestLoop *) node);
break;
case T_MergeJoin:
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.52 2000/07/12 02:37:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.53 2000/08/13 02:50:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
TupleTableSlot *
ExecIndexScan(IndexScan *node)
{
+ IndexScanState *indexstate = node->indxstate;
+
+ /* ----------------
+ * If we have runtime keys and they've not already been set up,
+ * do it now.
+ * ----------------
+ */
+ if (indexstate->iss_RuntimeKeyInfo && !indexstate->iss_RuntimeKeysReady)
+ ExecReScan((Plan *) node, NULL, NULL);
+
/* ----------------
* use IndexNext as access method
* ----------------
scanKeys = indexstate->iss_ScanKeys;
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
numScanKeys = indexstate->iss_NumScanKeys;
- indexstate->iss_IndexPtr = -1;
if (ScanDirectionIsBackward(node->indxorderdir))
indexstate->iss_IndexPtr = numIndices;
+ else
+ indexstate->iss_IndexPtr = -1;
if (econtext)
{
skey = scanKeys[i];
index_rescan(scan, direction, skey);
}
+
+ if (runtimeKeyInfo)
+ indexstate->iss_RuntimeKeysReady = true;
}
/* ----------------------------------------------------------------
Relation currentRelation;
HeapScanDesc currentScanDesc;
ScanDirection direction;
- List *execParam = NIL;
/* ----------------
* assign execution state to node
indexstate->iss_NumScanKeys = NULL;
indexstate->iss_RuntimeKeyInfo = NULL;
indexstate->iss_RuntimeContext = NULL;
+ indexstate->iss_RuntimeKeysReady = false;
indexstate->iss_RelationDescs = NULL;
indexstate->iss_ScanDescs = NULL;
*/
leftop = (Node *) get_leftop(clause);
+ if (leftop && IsA(leftop, RelabelType))
+ leftop = ((RelabelType *) leftop)->arg;
+
Assert(leftop != NULL);
if (IsA(leftop, Var) && var_is_rel((Var *) leftop))
/* treat Param as runtime key */
have_runtime_keys = true;
run_keys[j] = LEFT_OP;
- execParam = lappendi(execParam, ((Param *) leftop)->paramid);
}
else
{
*/
rightop = (Node *) get_rightop(clause);
+ if (rightop && IsA(rightop, RelabelType))
+ rightop = ((RelabelType *) rightop)->arg;
+
Assert(rightop != NULL);
if (IsA(rightop, Var) && var_is_rel((Var *) rightop))
/* treat Param as runtime key */
have_runtime_keys = true;
run_keys[j] = RIGHT_OP;
- execParam = lappendi(execParam, ((Param *) rightop)->paramid);
}
else
{
indexstate->iss_RelationDescs = relationDescs;
indexstate->iss_ScanDescs = scanDescs;
- /*
- * if there are some PARAM_EXEC in scankeys then force index rescan on
- * first scan.
- */
- ((Plan *) node)->chgParam = execParam;
-
/* ----------------
* all done.
* ----------------
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.18 2000/07/17 03:04:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.19 2000/08/13 02:50:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecNestLoop(NestLoop *node, Plan *parent)
+ExecNestLoop(NestLoop *node)
{
NestLoopState *nlstate;
Plan *innerPlan;
* outer tuple (e.g. in index scans), that's why we pass our
* expr context.
*/
- ExecReScan(innerPlan, econtext, parent);
+ ExecReScan(innerPlan, econtext, (Plan *) node);
ENL1_printf("getting new inner tuple");
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.38 2000/06/08 22:37:09 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.39 2000/08/13 02:50:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Selectivity s2;
/*
- * See if it looks like a restriction clause with a Const or Param
+ * See if it looks like a restriction clause with a pseudoconstant
* on one side. (Anything more complicated than that might not
* behave in the simple way we are expecting.)
*
other = (flag & SEL_RIGHT) ? get_rightop((Expr *) clause) :
get_leftop((Expr *) clause);
- if (IsA(other, Const) || IsA(other, Param))
+ if (is_pseudo_constant_clause((Node *) other))
{
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
RegProcedure oprrest = get_oprrest(opno);
*/
s1 = 1.0;
}
+ else if (IsA(clause, RelabelType))
+ {
+ /* Not sure this case is needed, but it can't hurt */
+ s1 = clause_selectivity(root,
+ ((RelabelType *) clause)->arg,
+ varRelid);
+ }
return s1;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.92 2000/08/08 15:41:30 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.93 2000/08/13 02:50:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* a key of an index.
*
* To match, the clause:
-
+ *
* (1a) for a restriction clause: must be in the form (indexkey op const)
* or (const op indexkey), or
* (1b) for a join clause: must be in the form (indexkey op others)
/*
* Not considering joins, so check for clauses of the form:
* (indexkey operator constant) or (constant operator indexkey).
- * We will accept a Param as being constant.
+ * Anything that is a "pseudo constant" expression will do.
*/
- if ((IsA(rightop, Const) ||IsA(rightop, Param)) &&
- match_index_to_operand(indexkey, leftop, rel, index))
+ if (match_index_to_operand(indexkey, leftop, rel, index) &&
+ is_pseudo_constant_clause((Node *) rightop))
{
if (is_indexable_operator(clause, opclass, index->relam, true))
return true;
return true;
return false;
}
- if ((IsA(leftop, Const) ||IsA(leftop, Param)) &&
- match_index_to_operand(indexkey, rightop, rel, index))
+ if (match_index_to_operand(indexkey, rightop, rel, index) &&
+ is_pseudo_constant_clause((Node *) leftop))
{
if (is_indexable_operator(clause, opclass, index->relam, false))
return true;
/*
* Check for an indexqual that could be handled by a nestloop
* join. We need the index key to be compared against an
- * expression that uses none of the indexed relation's vars.
+ * expression that uses none of the indexed relation's vars
+ * and contains no non-cachable functions.
*/
if (match_index_to_operand(indexkey, leftop, rel, index))
{
List *othervarnos = pull_varnos((Node *) rightop);
bool isIndexable;
- isIndexable = !intMember(lfirsti(rel->relids), othervarnos);
+ isIndexable =
+ !intMember(lfirsti(rel->relids), othervarnos) &&
+ !contain_noncachable_functions((Node *) rightop) &&
+ is_indexable_operator(clause, opclass, index->relam, true);
freeList(othervarnos);
- if (isIndexable &&
- is_indexable_operator(clause, opclass, index->relam, true))
- return true;
+ return isIndexable;
}
else if (match_index_to_operand(indexkey, rightop, rel, index))
{
List *othervarnos = pull_varnos((Node *) leftop);
bool isIndexable;
- isIndexable = !intMember(lfirsti(rel->relids), othervarnos);
+ isIndexable =
+ !intMember(lfirsti(rel->relids), othervarnos) &&
+ !contain_noncachable_functions((Node *) leftop) &&
+ is_indexable_operator(clause, opclass, index->relam, false);
freeList(othervarnos);
- if (isIndexable &&
- is_indexable_operator(clause, opclass, index->relam, false))
- return true;
+ return isIndexable;
}
}
* recognizing binary-compatible datatypes. For example, if we have
* an expression like "oid = 123", the operator will be oideqint4,
* which we need to replace with oideq in order to recognize it as
- * matching an oid_ops index on the oid field.
+ * matching an oid_ops index on the oid field. A variant case is where
+ * the expression is like "oid::int4 = 123", where the given operator
+ * will be int4eq and again we need to intuit that we want to use oideq.
*
* Returns the OID of the matching operator, or InvalidOid if no match.
* Note that the returned OID will be different from the one in the given
{
Oid expr_op = ((Oper *) clause->oper)->opno;
Oid commuted_op;
+ Operator oldop,
+ newop;
+ Form_pg_operator oldopform;
+ char *opname;
Oid ltype,
- rtype;
+ rtype,
+ indexkeytype;
/* Get the commuted operator if necessary */
if (indexkey_on_left)
/*
* Maybe the index uses a binary-compatible operator set.
+ *
+ * Get the nominal input types of the given operator and the actual
+ * type (before binary-compatible relabeling) of the index key.
*/
- ltype = exprType((Node *) get_leftop(clause));
- rtype = exprType((Node *) get_rightop(clause));
+ oldop = get_operator_tuple(expr_op);
+ if (! HeapTupleIsValid(oldop))
+ return InvalidOid; /* probably can't happen */
+ oldopform = (Form_pg_operator) GETSTRUCT(oldop);
+ opname = NameStr(oldopform->oprname);
+ ltype = oldopform->oprleft;
+ rtype = oldopform->oprright;
+
+ if (indexkey_on_left)
+ {
+ Node *leftop = (Node *) get_leftop(clause);
+
+ if (leftop && IsA(leftop, RelabelType))
+ leftop = ((RelabelType *) leftop)->arg;
+ indexkeytype = exprType(leftop);
+ }
+ else
+ {
+ Node *rightop = (Node *) get_rightop(clause);
+
+ if (rightop && IsA(rightop, RelabelType))
+ rightop = ((RelabelType *) rightop)->arg;
+ indexkeytype = exprType(rightop);
+ }
/*
- * make sure we have two different binary-compatible types...
+ * Make sure we have different but binary-compatible types.
*/
- if (ltype != rtype && IS_BINARY_COMPATIBLE(ltype, rtype))
- {
- char *opname = get_opname(expr_op);
- Operator newop;
+ if (ltype == indexkeytype && rtype == indexkeytype)
+ return InvalidOid; /* no chance for a different operator */
+ if (ltype != indexkeytype && !IS_BINARY_COMPATIBLE(ltype, indexkeytype))
+ return InvalidOid;
+ if (rtype != indexkeytype && !IS_BINARY_COMPATIBLE(rtype, indexkeytype))
+ return InvalidOid;
- if (opname == NULL)
- return InvalidOid; /* probably shouldn't happen */
+ /*
+ * OK, look for operator of the same name with the indexkey's data type.
+ * (In theory this might find a non-semantically-comparable operator,
+ * but in practice that seems pretty unlikely for binary-compatible types.)
+ */
+ newop = oper(opname, indexkeytype, indexkeytype, TRUE);
- /* Use the datatype of the index key */
- if (indexkey_on_left)
- newop = oper(opname, ltype, ltype, TRUE);
- else
- newop = oper(opname, rtype, rtype, TRUE);
+ if (HeapTupleIsValid(newop))
+ {
+ Oid new_expr_op = oprid(newop);
- if (HeapTupleIsValid(newop))
+ if (new_expr_op != expr_op)
{
- Oid new_expr_op = oprid(newop);
-
- if (new_expr_op != expr_op)
- {
- /*
- * OK, we found a binary-compatible operator of the same
- * name; now does it match the index?
- */
- if (indexkey_on_left)
- commuted_op = new_expr_op;
- else
- commuted_op = get_commutator(new_expr_op);
- if (commuted_op == InvalidOid)
- return InvalidOid;
-
- if (op_class(commuted_op, opclass, relam))
- return new_expr_op;
- }
+ /*
+ * OK, we found a binary-compatible operator of the same
+ * name; now does it match the index?
+ */
+ if (indexkey_on_left)
+ commuted_op = new_expr_op;
+ else
+ commuted_op = get_commutator(new_expr_op);
+ if (commuted_op == InvalidOid)
+ return InvalidOid;
+
+ if (op_class(commuted_op, opclass, relam))
+ return new_expr_op;
}
}
RelOptInfo *rel,
IndexOptInfo *index)
{
+ /*
+ * Ignore any RelabelType node above the indexkey. This is needed to
+ * be able to apply indexscanning in binary-compatible-operator cases.
+ * Note: we can assume there is at most one RelabelType node;
+ * eval_const_expressions() will have simplified if more than one.
+ */
+ if (operand && IsA(operand, RelabelType))
+ operand = (Var *) ((RelabelType *) operand)->arg;
+
if (index->indproc == InvalidOid)
{
/*
- * Normal index.
+ * Simple index.
*/
- if (IsA(operand, Var) &&
+ if (operand && IsA(operand, Var) &&
lfirsti(rel->relids) == operand->varno &&
indexkey == operand->varattno)
return true;
}
/*
- * functional index check
+ * Functional index.
*/
return function_index_operand((Expr *) operand, rel, index);
}
if (function->funcid != index->indproc)
return false;
- /*
+ /*----------
* Check that the arguments correspond to the same arguments used to
- * create the functional index. To do this we must check that 1.
- * refer to the right relation. 2. the args have the right attr.
- * numbers in the right order.
+ * create the functional index. To do this we must check that
+ * 1. they refer to the right relation.
+ * 2. the args have the right attr. numbers in the right order.
+ * We must ignore RelabelType nodes above the argument Vars in order
+ * to recognize binary-compatible-function cases correctly.
+ *----------
*/
i = 0;
foreach(arg, funcargs)
{
Var *var = (Var *) lfirst(arg);
- if (!IsA(var, Var))
+ if (var && IsA(var, RelabelType))
+ var = (Var *) ((RelabelType *) var)->arg;
+ if (var == NULL || !IsA(var, Var))
return false;
if (indexKeys[i] == 0)
return false;
* additional indexscanable qualifications.
*
* The given clause is already known to be a binary opclause having
- * the form (indexkey OP const/param) or (const/param OP indexkey),
+ * the form (indexkey OP pseudoconst) or (pseudoconst OP indexkey),
* but the OP proved not to be one of the index's opclass operators.
* Return 'true' if we can do something with it anyway.
*/
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.94 2000/07/12 02:37:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.95 2000/08/13 02:50:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
Oid *opclass)
{
+ /*
+ * Remove any binary-compatible relabeling of the indexkey
+ */
+ if (IsA(node, RelabelType))
+ node = ((RelabelType *) node)->arg;
+
/*
* We represent index keys by Var nodes having the varno of the base
* table but varattno equal to the index's attribute number (index
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.48 2000/08/08 15:41:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.49 2000/08/13 02:50:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* There is only one relation participating in 'clause', so
- * 'clause' must be a restriction clause for that relation.
+ * 'clause' is a restriction clause for that relation.
*/
RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
*/
check_mergejoinable(restrictinfo);
}
- else
+ else if (relids != NIL)
{
/*
- * 'clause' is a join clause, since there is more than one atom in
+ * 'clause' is a join clause, since there is more than one rel in
* the relid list. Set additional RestrictInfo fields for
* joining.
*
/*
* Add clause to the join lists of all the relevant relations.
- * (If, perchance, 'clause' contains NO vars, then nothing will
- * happen...)
*/
add_join_info_to_rels(root, restrictinfo, relids);
*/
add_vars_to_targetlist(root, vars);
}
+ else
+ {
+ /*
+ * 'clause' references no rels, and therefore we have no place to
+ * attach it. This means query_planner() screwed up --- it should
+ * treat variable-less clauses separately.
+ */
+ elog(ERROR, "add_restrict_and_join_to_rel: can't cope with variable-free clause");
+ }
/*
* If the clause has a mergejoinable operator, then the two sides
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.57 2000/07/27 04:51:04 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.58 2000/08/13 02:50:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
List *qual,
double tuple_fraction)
{
- List *constant_qual = NIL;
+ List *noncachable_qual;
+ List *constant_qual;
List *var_only_tlist;
Plan *subplan;
* have been optimized away by eval_const_expressions(). What we're
* mostly interested in here is quals that depend only on outer-level
* vars, although if the qual reduces to "WHERE FALSE" this path will
- * also be taken.
+ * also be taken. We also need a special case for quals that contain
+ * noncachable functions but no vars, such as "WHERE random() < 0.5".
+ * These cannot be treated as normal restriction or join quals, but
+ * they're not constants either. Instead, attach them to the qpqual
+ * of the top-level plan, so that they get evaluated once per potential
+ * output tuple.
*/
- qual = pull_constant_clauses(qual, &constant_qual);
+ qual = pull_constant_clauses(qual, &noncachable_qual, &constant_qual);
/*
* Create a target list that consists solely of (resdom var) target
*/
subplan = subplanner(root, var_only_tlist, qual, tuple_fraction);
+ /*
+ * Handle the noncachable quals.
+ */
+ if (noncachable_qual)
+ subplan->qual = nconc(subplan->qual, noncachable_qual);
+
/*
* Build a result node to control the plan if we have constant quals.
*/
* for processing a single level of attributes.
*
* flat_tlist is the flattened target list
- * qual is the qualification to be satisfied
+ * qual is the qualification to be satisfied (restrict and join quals only)
* tuple_fraction is the fraction of tuples we expect will be retrieved
*
* See query_planner() comments about the interpretation of tuple_fraction.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.70 2000/08/08 15:41:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.71 2000/08/13 02:50:10 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
static bool pull_subplans_walker(Node *node, List **listptr);
static bool check_subplans_for_ungrouped_vars_walker(Node *node,
Query *context);
+static bool contain_noncachable_functions_walker(Node *node, void *context);
static int is_single_func(Node *node);
static Node *eval_const_expressions_mutator(Node *node, void *context);
static Expr *simplify_op_or_func(Expr *expr, List *args);
/*****************************************************************************
- * *
- * General clause-manipulating routines *
- * *
+ * Check clauses for noncachable functions
*****************************************************************************/
-
/*
- * pull_constant_clauses
- * Scans through a list of qualifications and find those that
- * contain no variables (of the current query level).
+ * contain_noncachable_functions
+ * Recursively search for noncachable functions within a clause.
*
- * Returns a list of the constant clauses in constantQual and the remaining
- * quals as the return value.
+ * Returns true if any noncachable function (or operator implemented by a
+ * noncachable function) is found. This test is needed so that we don't
+ * mistakenly think that something like "WHERE random() < 0.5" can be treated
+ * as a constant qualification.
*
+ * XXX we do not examine sublinks/subplans to see if they contain uses of
+ * noncachable functions. It's not real clear if that is correct or not...
+ */
+bool
+contain_noncachable_functions(Node *clause)
+{
+ return contain_noncachable_functions_walker(clause, NULL);
+}
+
+static bool
+contain_noncachable_functions_walker(Node *node, void *context)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, Expr))
+ {
+ Expr *expr = (Expr *) node;
+
+ switch (expr->opType)
+ {
+ case OP_EXPR:
+ if (! op_iscachable(((Oper *) expr->oper)->opno))
+ return true;
+ break;
+ case FUNC_EXPR:
+ if (! func_iscachable(((Func *) expr->oper)->funcid))
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+ return expression_tree_walker(node, contain_noncachable_functions_walker,
+ context);
+}
+
+
+/*****************************************************************************
+ * Check for "pseudo-constant" clauses
+ *****************************************************************************/
+
+/*
+ * is_pseudo_constant_clause
+ * Detect whether a clause is "constant", ie, it contains no variables
+ * of the current query level and no uses of noncachable functions.
+ * Such a clause is not necessarily a true constant: it can still contain
+ * Params and outer-level Vars. However, its value will be constant over
+ * any one scan of the current query, so it can be used as an indexscan
+ * key or (if a top-level qual) can be pushed up to become a gating qual.
+ */
+bool
+is_pseudo_constant_clause(Node *clause)
+{
+ /*
+ * We could implement this check in one recursive scan. But since the
+ * check for noncachable functions is both moderately expensive and
+ * unlikely to fail, it seems better to look for Vars first and only
+ * check for noncachable functions if we find no Vars.
+ */
+ if (!contain_var_clause(clause) &&
+ !contain_noncachable_functions(clause))
+ return true;
+ return false;
+}
+
+/*----------
+ * pull_constant_clauses
+ * Scan through a list of qualifications and separate "constant" quals
+ * from those that are not.
+ *
+ * The input qual list is divided into three parts:
+ * * The function's return value is a list of all those quals that contain
+ * variable(s) of the current query level. (These quals will become
+ * restrict and join quals.)
+ * * *noncachableQual receives a list of quals that have no Vars, yet
+ * cannot be treated as constants because they contain noncachable
+ * function calls. (Example: WHERE random() < 0.5)
+ * * *constantQual receives a list of the remaining quals, which can be
+ * treated as constants for any one scan of the current query level.
+ * (They are really only pseudo-constant, since they may contain
+ * Params or outer-level Vars.)
+ *----------
*/
List *
-pull_constant_clauses(List *quals, List **constantQual)
+pull_constant_clauses(List *quals,
+ List **noncachableQual,
+ List **constantQual)
{
List *q;
+ List *normqual = NIL;
+ List *noncachequal = NIL;
List *constqual = NIL;
- List *restqual = NIL;
foreach(q, quals)
{
- if (!contain_var_clause(lfirst(q)))
- constqual = lcons(lfirst(q), constqual);
+ Node *qual = (Node *) lfirst(q);
+
+ if (contain_var_clause(qual))
+ normqual = lappend(normqual, qual);
+ else if (contain_noncachable_functions(qual))
+ noncachequal = lappend(noncachequal, qual);
else
- restqual = lcons(lfirst(q), restqual);
+ constqual = lappend(constqual, qual);
}
+
+ *noncachableQual = noncachequal;
*constantQual = constqual;
- return restqual;
+ return normqual;
}
+/*****************************************************************************
+ * *
+ * General clause-manipulating routines *
+ * *
+ *****************************************************************************/
+
/*
* clause_relids_vars
* Retrieves distinct relids and vars appearing within a clause.
if (!right)
goto default_results;
+ /* Ignore any binary-compatible relabeling */
+
+ if (IsA(left, RelabelType))
+ left = (Var *) ((RelabelType *) left)->arg;
+ if (IsA(right, RelabelType))
+ right = (Var *) ((RelabelType *) right)->arg;
+
/* First look for the var or func */
if (IsA(left, Var) &&
{
int funcvarno;
+ /* Ignore any binary-compatible relabeling */
+ if (IsA(left, RelabelType))
+ left = (Var *) ((RelabelType *) left)->arg;
+ if (IsA(right, RelabelType))
+ right = (Var *) ((RelabelType *) right)->arg;
+
if (IsA(left, Var))
{
*relid1 = left->varno;
/*
* If we can simplify the input to a constant, then we don't need
* the RelabelType node anymore: just change the type field of the
- * Const node. Otherwise, copy the RelabelType node.
+ * Const node. Otherwise, must copy the RelabelType node.
*/
RelabelType *relabel = (RelabelType *) node;
Node *arg;
arg = eval_const_expressions_mutator(relabel->arg, context);
+
+ /*
+ * If we find stacked RelabelTypes (eg, from foo :: int :: oid)
+ * we can discard all but the top one.
+ */
+ while (arg && IsA(arg, RelabelType))
+ arg = ((RelabelType *) arg)->arg;
+
if (arg && IsA(arg, Const))
{
Const *con = (Const *) arg;
funcid = func->funcid;
result_typeid = func->functype;
}
- /* Someday lsyscache.c might provide a function for this */
+ /*
+ * we could use func_iscachable() here, but we need several fields
+ * out of the func tuple, so might as well just look it up once.
+ */
func_tuple = SearchSysCacheTuple(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.44 2000/07/23 03:50:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.45 2000/08/13 02:50:16 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
/*
* op_class
*
- * Return t iff operator 'opid' is in operator class 'opclass' for
+ * Return t iff operator 'opno' is in operator class 'opclass' for
* access method 'amopid'.
*/
bool
-op_class(Oid opid, Oid opclass, Oid amopid)
+op_class(Oid opno, Oid opclass, Oid amopid)
{
if (HeapTupleIsValid(SearchSysCacheTuple(AMOPOPID,
ObjectIdGetDatum(opclass),
- ObjectIdGetDatum(opid),
+ ObjectIdGetDatum(opno),
ObjectIdGetDatum(amopid),
0)))
return true;
return optup->oprcode;
}
else
- return (RegProcedure) NULL;
+ return (RegProcedure) InvalidOid;
}
/*
return InvalidOid;
}
+/*
+ * op_iscachable
+ *
+ * Get the proiscachable flag for the operator's underlying function.
+ */
+bool
+op_iscachable(Oid opno)
+{
+ RegProcedure funcid = get_opcode(opno);
+
+ if (funcid == (RegProcedure) InvalidOid)
+ elog(ERROR, "Operator OID %u does not exist", opno);
+
+ return func_iscachable((Oid) funcid);
+}
+
HeapTuple
get_operator_tuple(Oid opno)
{
- HeapTuple optup;
-
- if ((optup = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0)))
- return optup;
- else
- return (HeapTuple) NULL;
+ return SearchSysCacheTuple(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
}
/*
return optup->oprrest;
}
else
- return (RegProcedure) NULL;
+ return (RegProcedure) InvalidOid;
}
/*
return optup->oprjoin;
}
else
- return (RegProcedure) NULL;
+ return (RegProcedure) InvalidOid;
}
/* ---------- FUNCTION CACHE ---------- */
return ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
}
+/*
+ * func_iscachable
+ * Given procedure id, return the function's proiscachable flag.
+ */
+bool
+func_iscachable(Oid funcid)
+{
+ HeapTuple func_tuple;
+
+ func_tuple = SearchSysCacheTuple(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(func_tuple))
+ elog(ERROR, "Function OID %u does not exist", funcid);
+
+ return ((Form_pg_proc) GETSTRUCT(func_tuple))->proiscachable;
+}
+
/* ---------- RELATION CACHE ---------- */
#ifdef NOT_USED
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodeNestloop.h,v 1.12 2000/01/26 05:58:05 momjian Exp $
+ * $Id: nodeNestloop.h,v 1.13 2000/08/13 02:50:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/plannodes.h"
-extern TupleTableSlot *ExecNestLoop(NestLoop *node, Plan *parent);
+extern TupleTableSlot *ExecNestLoop(NestLoop *node);
extern bool ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent);
extern int ExecCountSlotsNestLoop(NestLoop *node);
extern void ExecEndNestLoop(NestLoop *node);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: execnodes.h,v 1.45 2000/08/06 04:26:29 tgl Exp $
+ * $Id: execnodes.h,v 1.46 2000/08/13 02:50:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* NumScanKeys array of no of keys in each Skey struct
* RuntimeKeyInfo array of array of flags for Skeys evaled at runtime
* RuntimeContext expr context for evaling runtime Skeys
+ * RuntimeKeysReady true if runtime Skeys have been computed
* RelationDescs ptr to array of relation descriptors
* ScanDescs ptr to array of scan descriptors
* ----------------
int *iss_NumScanKeys;
int **iss_RuntimeKeyInfo;
ExprContext *iss_RuntimeContext;
+ bool iss_RuntimeKeysReady;
RelationPtr iss_RelationDescs;
IndexScanDescPtr iss_ScanDescs;
HeapTupleData iss_htup;
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: clauses.h,v 1.37 2000/05/30 04:24:57 tgl Exp $
+ * $Id: clauses.h,v 1.38 2000/08/13 02:50:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern List *pull_subplans(Node *clause);
extern void check_subplans_for_ungrouped_vars(Node *clause, Query *query);
-extern List *pull_constant_clauses(List *quals, List **constantQual);
+extern bool contain_noncachable_functions(Node *clause);
+
+extern bool is_pseudo_constant_clause(Node *clause);
+
+extern List *pull_constant_clauses(List *quals,
+ List **noncachableQual,
+ List **constantQual);
extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
extern int NumRelids(Node *clause);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: lsyscache.h,v 1.24 2000/06/08 22:37:58 momjian Exp $
+ * $Id: lsyscache.h,v 1.25 2000/08/13 02:50:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/htup.h"
-extern bool op_class(Oid opid, Oid opclass, Oid amopid);
+extern bool op_class(Oid opno, Oid opclass, Oid amopid);
extern char *get_attname(Oid relid, AttrNumber attnum);
extern AttrNumber get_attnum(Oid relid, char *attname);
extern Oid get_atttype(Oid relid, AttrNumber attnum);
extern int32 get_atttypmod(Oid relid, AttrNumber attnum);
extern double get_attdisbursion(Oid relid, AttrNumber attnum,
double min_estimate);
-extern RegProcedure get_opcode(Oid opid);
-extern char *get_opname(Oid opid);
-extern bool op_mergejoinable(Oid opid, Oid ltype, Oid rtype,
+extern RegProcedure get_opcode(Oid opno);
+extern char *get_opname(Oid opno);
+extern bool op_mergejoinable(Oid opno, Oid ltype, Oid rtype,
Oid *leftOp, Oid *rightOp);
-extern Oid op_hashjoinable(Oid opid, Oid ltype, Oid rtype);
-extern Oid get_commutator(Oid opid);
+extern Oid op_hashjoinable(Oid opno, Oid ltype, Oid rtype);
+extern bool op_iscachable(Oid opno);
extern HeapTuple get_operator_tuple(Oid opno);
-extern Oid get_negator(Oid opid);
-extern RegProcedure get_oprrest(Oid opid);
-extern RegProcedure get_oprjoin(Oid opid);
+extern Oid get_commutator(Oid opno);
+extern Oid get_negator(Oid opno);
+extern RegProcedure get_oprrest(Oid opno);
+extern RegProcedure get_oprjoin(Oid opno);
extern Oid get_func_rettype(Oid funcid);
+extern bool func_iscachable(Oid funcid);
extern char *get_rel_name(Oid relid);
-extern struct varlena *get_relstub(Oid relid, int no, bool *islast);
-extern Oid get_ruleid(char *rulename);
-extern Oid get_eventrelid(Oid ruleid);
extern int16 get_typlen(Oid typid);
extern bool get_typbyval(Oid typid);
extern Datum get_typdefault(Oid typid);
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.26 2000/08/03 16:34:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.27 2000/08/13 02:50:35 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
#include "executor/spi.h"
#include "executor/spi_priv.h"
#include "fmgr.h"
+#include "parser/parse_expr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
case T_Const:
return TRUE;
+ case T_RelabelType:
+ return exec_simple_check_node(((RelabelType *) node)->arg);
+
default:
return FALSE;
}
* ----------
*/
expr->plan_simple_expr = tle->expr;
-
- switch (nodeTag(tle->expr))
- {
- case T_Expr:
- expr->plan_simple_type =
- ((Expr *) (tle->expr))->typeOid;
- break;
-
- case T_Param:
- expr->plan_simple_type =
- ((Param *) (tle->expr))->paramtype;
- break;
-
- case T_Const:
- expr->plan_simple_type = ((Const *) (tle->expr))->consttype;
- break;
-
- default:
- expr->plan_simple_type = InvalidOid;
- }
+ expr->plan_simple_type = exprType(tle->expr);
}