1999-11-23 21:07:06 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* tidpath.c
|
|
|
|
* Routines to determine which tids are usable for scanning a
|
|
|
|
* given relation, and create TidPaths accordingly.
|
|
|
|
*
|
2004-12-31 23:04:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1999-11-23 21:07:06 +01:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2005-06-06 00:32:58 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.23 2005/06/05 22:32:55 tgl Exp $
|
1999-11-23 21:07:06 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2002-09-05 02:43:07 +02:00
|
|
|
#include <math.h>
|
|
|
|
|
1999-11-23 21:07:06 +01:00
|
|
|
#include "catalog/pg_operator.h"
|
|
|
|
#include "optimizer/clauses.h"
|
|
|
|
#include "optimizer/cost.h"
|
|
|
|
#include "optimizer/pathnode.h"
|
|
|
|
#include "optimizer/paths.h"
|
|
|
|
#include "parser/parse_coerce.h"
|
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
|
2005-06-06 00:32:58 +02:00
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
static List *TidqualFromRestrictinfo(Relids relids, List *restrictinfo);
|
2000-04-12 19:17:23 +02:00
|
|
|
static bool isEvaluable(int varno, Node *node);
|
2003-08-08 23:42:59 +02:00
|
|
|
static Node *TidequalClause(int varno, OpExpr *node);
|
2000-04-12 19:17:23 +02:00
|
|
|
static List *TidqualFromExpr(int varno, Expr *expr);
|
1999-11-23 21:07:06 +01:00
|
|
|
|
2005-06-06 00:32:58 +02:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
static bool
|
2000-04-12 19:17:23 +02:00
|
|
|
isEvaluable(int varno, Node *node)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
2002-12-12 16:49:42 +01:00
|
|
|
FuncExpr *expr;
|
1999-11-23 21:07:06 +01:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
if (IsA(node, Const))
|
|
|
|
return true;
|
|
|
|
if (IsA(node, Param))
|
|
|
|
return true;
|
1999-11-23 21:07:06 +01:00
|
|
|
if (IsA(node, Var))
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
Var *var = (Var *) node;
|
1999-11-23 21:07:06 +01:00
|
|
|
|
|
|
|
if (var->varno == varno)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
if (!is_funcclause(node))
|
|
|
|
return false;
|
2002-12-12 16:49:42 +01:00
|
|
|
expr = (FuncExpr *) node;
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, expr->args)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
if (!isEvaluable(varno, lfirst(l)))
|
1999-11-23 21:07:06 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The 2nd parameter should be an opclause
|
|
|
|
* Extract the right node if the opclause is CTID= ....
|
2000-04-12 19:17:23 +02:00
|
|
|
* or the left node if the opclause is ....=CTID
|
1999-11-23 21:07:06 +01:00
|
|
|
*/
|
2002-12-12 16:49:42 +01:00
|
|
|
static Node *
|
2003-08-08 23:42:59 +02:00
|
|
|
TidequalClause(int varno, OpExpr *node)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
Node *rnode = NULL,
|
2000-04-12 19:17:23 +02:00
|
|
|
*arg1,
|
|
|
|
*arg2,
|
|
|
|
*arg;
|
|
|
|
Var *var;
|
|
|
|
Const *aconst;
|
|
|
|
Param *param;
|
2002-12-12 16:49:42 +01:00
|
|
|
FuncExpr *expr;
|
1999-11-23 21:07:06 +01:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
if (node->opno != TIDEqualOperator)
|
2000-04-12 19:17:23 +02:00
|
|
|
return rnode;
|
2004-05-31 01:40:41 +02:00
|
|
|
if (list_length(node->args) != 2)
|
2000-04-12 19:17:23 +02:00
|
|
|
return rnode;
|
2004-05-26 06:41:50 +02:00
|
|
|
arg1 = linitial(node->args);
|
1999-11-23 21:07:06 +01:00
|
|
|
arg2 = lsecond(node->args);
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
arg = NULL;
|
1999-11-23 21:07:06 +01:00
|
|
|
if (IsA(arg1, Var))
|
|
|
|
{
|
|
|
|
var = (Var *) arg1;
|
|
|
|
if (var->varno == varno &&
|
2000-04-12 19:17:23 +02:00
|
|
|
var->varattno == SelfItemPointerAttributeNumber &&
|
|
|
|
var->vartype == TIDOID)
|
1999-11-23 21:07:06 +01:00
|
|
|
arg = arg2;
|
|
|
|
else if (var->varnoold == varno &&
|
2000-04-12 19:17:23 +02:00
|
|
|
var->varoattno == SelfItemPointerAttributeNumber &&
|
|
|
|
var->vartype == TIDOID)
|
1999-11-23 21:07:06 +01:00
|
|
|
arg = arg2;
|
|
|
|
}
|
|
|
|
if ((!arg) && IsA(arg2, Var))
|
|
|
|
{
|
|
|
|
var = (Var *) arg2;
|
|
|
|
if (var->varno == varno &&
|
2000-04-12 19:17:23 +02:00
|
|
|
var->varattno == SelfItemPointerAttributeNumber &&
|
|
|
|
var->vartype == TIDOID)
|
1999-11-23 21:07:06 +01:00
|
|
|
arg = arg1;
|
|
|
|
}
|
|
|
|
if (!arg)
|
|
|
|
return rnode;
|
|
|
|
switch (nodeTag(arg))
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
case T_Const:
|
1999-11-23 21:07:06 +01:00
|
|
|
aconst = (Const *) arg;
|
|
|
|
if (aconst->consttype != TIDOID)
|
|
|
|
return rnode;
|
|
|
|
if (aconst->constbyval)
|
|
|
|
return rnode;
|
|
|
|
rnode = arg;
|
|
|
|
break;
|
2000-04-12 19:17:23 +02:00
|
|
|
case T_Param:
|
1999-11-23 21:07:06 +01:00
|
|
|
param = (Param *) arg;
|
|
|
|
if (param->paramtype != TIDOID)
|
|
|
|
return rnode;
|
|
|
|
rnode = arg;
|
|
|
|
break;
|
2000-04-12 19:17:23 +02:00
|
|
|
case T_Var:
|
1999-11-23 21:07:06 +01:00
|
|
|
var = (Var *) arg;
|
|
|
|
if (var->varno == varno ||
|
2000-04-12 19:17:23 +02:00
|
|
|
var->vartype != TIDOID)
|
1999-11-23 21:07:06 +01:00
|
|
|
return rnode;
|
|
|
|
rnode = arg;
|
|
|
|
break;
|
2002-12-12 16:49:42 +01:00
|
|
|
case T_FuncExpr:
|
|
|
|
expr = (FuncExpr *) arg;
|
|
|
|
if (expr->funcresulttype != TIDOID)
|
2000-04-12 19:17:23 +02:00
|
|
|
return rnode;
|
|
|
|
if (isEvaluable(varno, (Node *) expr))
|
1999-11-23 21:07:06 +01:00
|
|
|
rnode = arg;
|
|
|
|
break;
|
2000-04-12 19:17:23 +02:00
|
|
|
default:
|
1999-11-23 21:07:06 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return rnode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extract the list of CTID values from a specified expr node.
|
|
|
|
* When the expr node is an or_clause,we try to extract CTID
|
|
|
|
* values from all member nodes. However we would discard them
|
|
|
|
* all if we couldn't extract CTID values from a member node.
|
|
|
|
* When the expr node is an and_clause,we return the list of
|
|
|
|
* CTID values if we could extract the CTID values from a member
|
|
|
|
* node.
|
2000-04-12 19:17:23 +02:00
|
|
|
*/
|
2002-12-12 16:49:42 +01:00
|
|
|
static List *
|
2000-04-12 19:17:23 +02:00
|
|
|
TidqualFromExpr(int varno, Expr *expr)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
List *rlst = NIL,
|
|
|
|
*frtn;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
2000-04-12 19:17:23 +02:00
|
|
|
Node *node = (Node *) expr,
|
|
|
|
*rnode;
|
1999-11-23 21:07:06 +01:00
|
|
|
|
|
|
|
if (is_opclause(node))
|
|
|
|
{
|
2002-12-12 16:49:42 +01:00
|
|
|
rnode = TidequalClause(varno, (OpExpr *) expr);
|
1999-11-23 21:07:06 +01:00
|
|
|
if (rnode)
|
|
|
|
rlst = lcons(rnode, rlst);
|
|
|
|
}
|
|
|
|
else if (and_clause(node))
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, ((BoolExpr *) expr)->args)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
node = (Node *) lfirst(l);
|
2000-04-12 19:17:23 +02:00
|
|
|
rlst = TidqualFromExpr(varno, (Expr *) node);
|
1999-11-23 21:07:06 +01:00
|
|
|
if (rlst)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (or_clause(node))
|
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, ((BoolExpr *) expr)->args)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
node = (Node *) lfirst(l);
|
2002-12-12 16:49:42 +01:00
|
|
|
frtn = TidqualFromExpr(varno, (Expr *) node);
|
|
|
|
if (frtn)
|
2004-05-31 01:40:41 +02:00
|
|
|
rlst = list_concat(rlst, frtn);
|
1999-11-23 21:07:06 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rlst)
|
2004-05-31 01:40:41 +02:00
|
|
|
list_free(rlst);
|
1999-11-23 21:07:06 +01:00
|
|
|
rlst = NIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rlst;
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
1999-11-23 21:07:06 +01:00
|
|
|
|
2000-02-07 05:41:04 +01:00
|
|
|
static List *
|
2003-02-08 21:20:55 +01:00
|
|
|
TidqualFromRestrictinfo(Relids relids, List *restrictinfo)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
|
|
|
List *rlst = NIL;
|
2000-04-12 19:17:23 +02:00
|
|
|
int varno;
|
|
|
|
Node *node;
|
|
|
|
Expr *expr;
|
1999-11-23 21:07:06 +01:00
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
if (bms_membership(relids) != BMS_SINGLETON)
|
2000-02-07 05:41:04 +01:00
|
|
|
return NIL;
|
2003-02-08 21:20:55 +01:00
|
|
|
varno = bms_singleton_member(relids);
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, restrictinfo)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
node = (Node *) lfirst(l);
|
2000-04-12 19:17:23 +02:00
|
|
|
if (!IsA(node, RestrictInfo))
|
|
|
|
continue;
|
|
|
|
expr = ((RestrictInfo *) node)->clause;
|
1999-11-23 21:07:06 +01:00
|
|
|
rlst = TidqualFromExpr(varno, expr);
|
|
|
|
if (rlst)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return rlst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create_tidscan_paths
|
2000-02-15 21:49:31 +01:00
|
|
|
* Creates paths corresponding to tid direct scans of the given rel.
|
|
|
|
* Candidate paths are added to the rel's pathlist (using add_path).
|
1999-11-23 21:07:06 +01:00
|
|
|
*/
|
2000-02-15 21:49:31 +01:00
|
|
|
void
|
2005-06-06 00:32:58 +02:00
|
|
|
create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
|
1999-11-23 21:07:06 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
List *tideval = TidqualFromRestrictinfo(rel->relids,
|
|
|
|
rel->baserestrictinfo);
|
|
|
|
|
1999-11-23 21:07:06 +01:00
|
|
|
if (tideval)
|
2001-06-05 07:26:05 +02:00
|
|
|
add_path(rel, (Path *) create_tidscan_path(root, rel, tideval));
|
1999-11-23 21:07:06 +01:00
|
|
|
}
|