Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/ruleutils.c300
-rw-r--r--src/backend/utils/cache/relcache.c171
2 files changed, 246 insertions, 225 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 59f3586d13f..bcaa0f0d68c 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* out of it's tuple
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.26 1999/10/02 01:07:51 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.27 1999/10/03 23:55:31 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -39,25 +39,28 @@
#include <fcntl.h>
#include "postgres.h"
+
#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
-#include "utils/lsyscache.h"
#include "catalog/pg_index.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
/* ----------
* Local data types
* ----------
*/
-typedef struct QryHier
+typedef struct
{
- struct QryHier *parent;
- Query *query;
-} QryHier;
+ StringInfo buf; /* output buffer to append to */
+ List *rangetables; /* List of List of RangeTblEntry */
+ bool varprefix; /* TRUE to print prefixes on Vars */
+} deparse_context;
typedef struct {
Index rt_index;
@@ -69,7 +72,7 @@ typedef struct {
* Global data
* ----------
*/
-static char *rulename;
+static char *rulename = NULL;
static void *plan_getrule = NULL;
static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";
static void *plan_getview = NULL;
@@ -81,16 +84,6 @@ static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";
/* ----------
- * Global functions
- * ----------
- */
-text *pg_get_ruledef(NameData *rname);
-text *pg_get_viewdef(NameData *rname);
-text *pg_get_indexdef(Oid indexrelid);
-NameData *pg_get_userbyid(int4 uid);
-
-
-/* ----------
* Local functions
*
* Most of these functions used to use fixed-size buffers to build their
@@ -100,21 +93,17 @@ NameData *pg_get_userbyid(int4 uid);
*/
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
-static void get_query_def(StringInfo buf, Query *query, QryHier *parentqh);
-static void get_select_query_def(StringInfo buf, Query *query, QryHier *qh);
-static void get_insert_query_def(StringInfo buf, Query *query, QryHier *qh);
-static void get_update_query_def(StringInfo buf, Query *query, QryHier *qh);
-static void get_delete_query_def(StringInfo buf, Query *query, QryHier *qh);
-static RangeTblEntry *get_rte_for_var(Var *var, QryHier *qh);
-static void get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
- Node *node, bool varprefix);
-static void get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
- Expr *expr, bool varprefix);
-static void get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
- TargetEntry *tle, bool varprefix);
-static void get_const_expr(StringInfo buf, Const *constval);
-static void get_sublink_expr(StringInfo buf, QryHier *qh, int rt_index,
- Node *node, bool varprefix);
+static void get_query_def(Query *query, StringInfo buf, List *parentrtables);
+static void get_select_query_def(Query *query, deparse_context *context);
+static void get_insert_query_def(Query *query, deparse_context *context);
+static void get_update_query_def(Query *query, deparse_context *context);
+static void get_delete_query_def(Query *query, deparse_context *context);
+static RangeTblEntry *get_rte_for_var(Var *var, deparse_context *context);
+static void get_rule_expr(Node *node, deparse_context *context);
+static void get_func_expr(Expr *expr, deparse_context *context);
+static void get_tle_expr(TargetEntry *tle, deparse_context *context);
+static void get_const_expr(Const *constval, deparse_context *context);
+static void get_sublink_expr(Node *node, deparse_context *context);
static char *get_relation_name(Oid relid);
static char *get_attribute_name(Oid relid, int2 attnum);
static bool check_if_rte_used(Node *node, Index rt_index, int levelsup);
@@ -554,7 +543,7 @@ pg_get_indexdef(Oid indexrelid)
* ----------
*/
NameData *
-pg_get_userbyid(int4 uid)
+pg_get_userbyid(int32 uid)
{
HeapTuple usertup;
Form_pg_shadow user_rec;
@@ -584,6 +573,43 @@ pg_get_userbyid(int4 uid)
return result;
}
+/* ----------
+ * deparse_expression - General utility for deparsing expressions
+ *
+ * expr is the node tree to be deparsed. It must be a transformed expression
+ * tree (ie, not the raw output of gram.y).
+ *
+ * rangetables is a List of Lists of RangeTblEntry nodes: first sublist is for
+ * varlevelsup = 0, next for varlevelsup = 1, etc. In each sublist the first
+ * item is for varno = 1, next varno = 2, etc. (Each sublist has the same
+ * format as the rtable list of a parsetree or query.)
+ *
+ * forceprefix is TRUE to force all Vars to be prefixed with their table names.
+ * Otherwise, a prefix is printed only if there's more than one table involved
+ * (and someday the code might try to print one only if there's ambiguity).
+ *
+ * The result is a palloc'd string.
+ * ----------
+ */
+char *
+deparse_expression(Node *expr, List *rangetables, bool forceprefix)
+{
+ StringInfoData buf;
+ deparse_context context;
+
+ initStringInfo(&buf);
+ context.buf = &buf;
+ context.rangetables = rangetables;
+ context.varprefix = (forceprefix ||
+ length(rangetables) != 1 ||
+ length((List *) lfirst(rangetables)) != 1);
+
+ rulename = ""; /* in case of errors */
+
+ get_rule_expr(expr, &context);
+
+ return buf.data;
+}
/* ----------
* make_ruledef - reconstruct the CREATE RULE command
@@ -672,15 +698,18 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
{
Node *qual;
Query *query;
- QryHier qh;
+ deparse_context context;
+
+ appendStringInfo(buf, " WHERE ");
qual = stringToNode(ev_qual);
query = (Query *) lfirst(actions);
- qh.parent = NULL;
- qh.query = query;
- appendStringInfo(buf, " WHERE ");
- get_rule_expr(buf, &qh, 0, qual, TRUE);
+ context.buf = buf;
+ context.rangetables = lcons(query->rtable, NIL);
+ context.varprefix = (length(query->rtable) != 1);
+
+ get_rule_expr(qual, &context);
}
appendStringInfo(buf, " DO ");
@@ -699,7 +728,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
foreach(action, actions)
{
query = (Query *) lfirst(action);
- get_query_def(buf, query, NULL);
+ get_query_def(query, buf, NIL);
appendStringInfo(buf, "; ");
}
appendStringInfo(buf, ");");
@@ -715,7 +744,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
Query *query;
query = (Query *) lfirst(actions);
- get_query_def(buf, query, NULL);
+ get_query_def(query, buf, NIL);
appendStringInfo(buf, ";");
}
}
@@ -779,7 +808,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
return;
}
- get_query_def(buf, query, NULL);
+ get_query_def(query, buf, NIL);
appendStringInfo(buf, ";");
}
@@ -791,29 +820,31 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
* ----------
*/
static void
-get_query_def(StringInfo buf, Query *query, QryHier *parentqh)
+get_query_def(Query *query, StringInfo buf, List *parentrtables)
{
- QryHier qh;
+ deparse_context context;
- qh.parent = parentqh;
- qh.query = query;
+ context.buf = buf;
+ context.rangetables = lcons(query->rtable, parentrtables);
+ context.varprefix = (parentrtables != NIL ||
+ length(query->rtable) != 1);
switch (query->commandType)
{
case CMD_SELECT:
- get_select_query_def(buf, query, &qh);
+ get_select_query_def(query, &context);
break;
case CMD_UPDATE:
- get_update_query_def(buf, query, &qh);
+ get_update_query_def(query, &context);
break;
case CMD_INSERT:
- get_insert_query_def(buf, query, &qh);
+ get_insert_query_def(query, &context);
break;
case CMD_DELETE:
- get_delete_query_def(buf, query, &qh);
+ get_delete_query_def(query, &context);
break;
case CMD_NOTHING:
@@ -833,8 +864,9 @@ get_query_def(StringInfo buf, Query *query, QryHier *parentqh)
* ----------
*/
static void
-get_select_query_def(StringInfo buf, Query *query, QryHier *qh)
+get_select_query_def(Query *query, deparse_context *context)
{
+ StringInfo buf = context->buf;
char *sep;
TargetEntry *tle;
RangeTblEntry *rte;
@@ -904,7 +936,7 @@ get_select_query_def(StringInfo buf, Query *query, QryHier *qh)
appendStringInfo(buf, sep);
sep = ", ";
- get_tle_expr(buf, qh, 0, tle, (rt_numused > 1));
+ get_tle_expr(tle, context);
/* Check if we must say AS ... */
if (! IsA(tle->expr, Var))
@@ -914,7 +946,7 @@ get_select_query_def(StringInfo buf, Query *query, QryHier *qh)
Var *var = (Var *) (tle->expr);
char *attname;
- rte = get_rte_for_var(var, qh);
+ rte = get_rte_for_var(var, context);
attname = get_attribute_name(rte->relid, var->varattno);
if (strcmp(attname, tle->resdom->resname))
tell_as = TRUE;
@@ -957,7 +989,7 @@ get_select_query_def(StringInfo buf, Query *query, QryHier *qh)
if (query->qual != NULL)
{
appendStringInfo(buf, " WHERE ");
- get_rule_expr(buf, qh, 0, query->qual, (rt_numused > 1));
+ get_rule_expr(query->qual, context);
}
/* Add the GROUP BY CLAUSE */
@@ -973,7 +1005,7 @@ get_select_query_def(StringInfo buf, Query *query, QryHier *qh)
groupexpr = get_sortgroupclause_expr(grp,
query->targetList);
appendStringInfo(buf, sep);
- get_rule_expr(buf, qh, 0, groupexpr, (rt_numused > 1));
+ get_rule_expr(groupexpr, context);
sep = ", ";
}
}
@@ -985,8 +1017,9 @@ get_select_query_def(StringInfo buf, Query *query, QryHier *qh)
* ----------
*/
static void
-get_insert_query_def(StringInfo buf, Query *query, QryHier *qh)
+get_insert_query_def(Query *query, deparse_context *context)
{
+ StringInfo buf = context->buf;
char *sep;
TargetEntry *tle;
RangeTblEntry *rte;
@@ -1064,12 +1097,12 @@ get_insert_query_def(StringInfo buf, Query *query, QryHier *qh)
appendStringInfo(buf, sep);
sep = ", ";
- get_tle_expr(buf, qh, 0, tle, (rt_numused > 1));
+ get_tle_expr(tle, context);
}
appendStringInfo(buf, ")");
}
else
- get_select_query_def(buf, query, qh);
+ get_select_query_def(query, context);
}
@@ -1078,8 +1111,9 @@ get_insert_query_def(StringInfo buf, Query *query, QryHier *qh)
* ----------
*/
static void
-get_update_query_def(StringInfo buf, Query *query, QryHier *qh)
+get_update_query_def(Query *query, deparse_context *context)
{
+ StringInfo buf = context->buf;
char *sep;
TargetEntry *tle;
RangeTblEntry *rte;
@@ -1101,14 +1135,14 @@ get_update_query_def(StringInfo buf, Query *query, QryHier *qh)
appendStringInfo(buf, sep);
sep = ", ";
appendStringInfo(buf, "\"%s\" = ", tle->resdom->resname);
- get_tle_expr(buf, qh, query->resultRelation, tle, TRUE);
+ get_tle_expr(tle, context);
}
/* Finally add a WHERE clause if given */
if (query->qual != NULL)
{
appendStringInfo(buf, " WHERE ");
- get_rule_expr(buf, qh, query->resultRelation, query->qual, TRUE);
+ get_rule_expr(query->qual, context);
}
}
@@ -1118,8 +1152,9 @@ get_update_query_def(StringInfo buf, Query *query, QryHier *qh)
* ----------
*/
static void
-get_delete_query_def(StringInfo buf, Query *query, QryHier *qh)
+get_delete_query_def(Query *query, deparse_context *context)
{
+ StringInfo buf = context->buf;
RangeTblEntry *rte;
/* ----------
@@ -1133,7 +1168,7 @@ get_delete_query_def(StringInfo buf, Query *query, QryHier *qh)
if (query->qual != NULL)
{
appendStringInfo(buf, " WHERE ");
- get_rule_expr(buf, qh, 0, query->qual, FALSE);
+ get_rule_expr(query->qual, context);
}
}
@@ -1141,14 +1176,15 @@ get_delete_query_def(StringInfo buf, Query *query, QryHier *qh)
* Find the RTE referenced by a (possibly nonlocal) Var.
*/
static RangeTblEntry *
-get_rte_for_var(Var *var, QryHier *qh)
+get_rte_for_var(Var *var, deparse_context *context)
{
+ List *rtlist = context->rangetables;
int sup = var->varlevelsup;
while (sup-- > 0)
- qh = qh->parent;
+ rtlist = lnext(rtlist);
- return (RangeTblEntry *) nth(var->varno - 1, qh->query->rtable);
+ return (RangeTblEntry *) nth(var->varno - 1, (List *) lfirst(rtlist));
}
@@ -1157,9 +1193,10 @@ get_rte_for_var(Var *var, QryHier *qh)
* ----------
*/
static void
-get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
- Node *node, bool varprefix)
+get_rule_expr(Node *node, deparse_context *context)
{
+ StringInfo buf = context->buf;
+
if (node == NULL)
return;
@@ -1175,20 +1212,23 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
switch (nodeTag(node))
{
case T_Const:
- get_const_expr(buf, (Const *) node);
+ get_const_expr((Const *) node, context);
break;
case T_Var:
{
Var *var = (Var *) node;
- RangeTblEntry *rte = get_rte_for_var(var, qh);
+ RangeTblEntry *rte = get_rte_for_var(var, context);
- if (!strcmp(rte->refname, "*NEW*"))
- appendStringInfo(buf, "new.");
- else if (!strcmp(rte->refname, "*CURRENT*"))
- appendStringInfo(buf, "old.");
- else
- appendStringInfo(buf, "\"%s\".", rte->refname);
+ if (context->varprefix)
+ {
+ if (!strcmp(rte->refname, "*NEW*"))
+ appendStringInfo(buf, "new.");
+ else if (!strcmp(rte->refname, "*CURRENT*"))
+ appendStringInfo(buf, "old.");
+ else
+ appendStringInfo(buf, "\"%s\".", rte->refname);
+ }
appendStringInfo(buf, "\"%s\"",
get_attribute_name(rte->relid,
var->varattno));
@@ -1211,14 +1251,10 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
if (length(args) == 2)
{
/* binary operator */
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
+ get_rule_expr((Node *) lfirst(args), context);
appendStringInfo(buf, " %s ",
get_opname(((Oper *) expr->oper)->opno));
- get_rule_expr(buf, qh, rt_index,
- (Node *) lsecond(args),
- varprefix);
+ get_rule_expr((Node *) lsecond(args), context);
}
else
{
@@ -1237,14 +1273,12 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
case 'l':
appendStringInfo(buf, "%s ",
get_opname(opno));
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
+ get_rule_expr((Node *) lfirst(args),
+ context);
break;
case 'r':
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
+ get_rule_expr((Node *) lfirst(args),
+ context);
appendStringInfo(buf, " %s",
get_opname(opno));
break;
@@ -1257,49 +1291,34 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
case OR_EXPR:
appendStringInfo(buf, "(");
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
- /* It's not clear that we can ever see N-argument
- * OR/AND clauses here, but might as well cope...
- */
+ get_rule_expr((Node *) lfirst(args), context);
while ((args = lnext(args)) != NIL)
{
appendStringInfo(buf, " OR ");
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
+ get_rule_expr((Node *) lfirst(args), context);
}
appendStringInfo(buf, ")");
break;
case AND_EXPR:
appendStringInfo(buf, "(");
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
+ get_rule_expr((Node *) lfirst(args), context);
while ((args = lnext(args)) != NIL)
{
appendStringInfo(buf, " AND ");
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
+ get_rule_expr((Node *) lfirst(args), context);
}
appendStringInfo(buf, ")");
break;
case NOT_EXPR:
appendStringInfo(buf, "(NOT ");
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(args),
- varprefix);
+ get_rule_expr((Node *) lfirst(args), context);
appendStringInfo(buf, ")");
break;
case FUNC_EXPR:
- get_func_expr(buf, qh, rt_index,
- (Expr *) node,
- varprefix);
+ get_func_expr((Expr *) node, context);
break;
default:
@@ -1314,15 +1333,13 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
Aggref *aggref = (Aggref *) node;
appendStringInfo(buf, "\"%s\"(", aggref->aggname);
- get_rule_expr(buf, qh, rt_index,
- (Node *) (aggref->target), varprefix);
+ get_rule_expr(aggref->target, context);
appendStringInfo(buf, ")");
}
break;
case T_Iter:
- get_rule_expr(buf, qh, rt_index,
- ((Iter *) node)->iterexpr, varprefix);
+ get_rule_expr(((Iter *) node)->iterexpr, context);
break;
case T_ArrayRef:
@@ -1331,23 +1348,18 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
List *lowlist;
List *uplist;
- get_rule_expr(buf, qh, rt_index,
- aref->refexpr, varprefix);
+ get_rule_expr(aref->refexpr, context);
lowlist = aref->reflowerindexpr;
foreach(uplist, aref->refupperindexpr)
{
appendStringInfo(buf, "[");
if (lowlist)
{
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(lowlist),
- varprefix);
+ get_rule_expr((Node *) lfirst(lowlist), context);
appendStringInfo(buf, ":");
lowlist = lnext(lowlist);
}
- get_rule_expr(buf, qh, rt_index,
- (Node *) lfirst(uplist),
- varprefix);
+ get_rule_expr((Node *) lfirst(uplist), context);
appendStringInfo(buf, "]");
}
/* XXX need to do anything with refassgnexpr? */
@@ -1365,21 +1377,18 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
CaseWhen *when = (CaseWhen *) lfirst(temp);
appendStringInfo(buf, " WHEN ");
- get_rule_expr(buf, qh, rt_index,
- when->expr, varprefix);
+ get_rule_expr(when->expr, context);
appendStringInfo(buf, " THEN ");
- get_rule_expr(buf, qh, rt_index,
- when->result, varprefix);
+ get_rule_expr(when->result, context);
}
appendStringInfo(buf, " ELSE ");
- get_rule_expr(buf, qh, rt_index,
- caseexpr->defresult, varprefix);
+ get_rule_expr(caseexpr->defresult, context);
appendStringInfo(buf, " END");
}
break;
case T_SubLink:
- get_sublink_expr(buf, qh, rt_index, node, varprefix);
+ get_sublink_expr(node, context);
break;
default:
@@ -1396,9 +1405,9 @@ get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
* ----------
*/
static void
-get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
- Expr *expr, bool varprefix)
+get_func_expr(Expr *expr, deparse_context *context)
{
+ StringInfo buf = context->buf;
HeapTuple proctup;
Form_pg_proc procStruct;
List *l;
@@ -1411,7 +1420,8 @@ get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
* ----------
*/
proctup = SearchSysCacheTuple(PROOID,
- ObjectIdGetDatum(func->funcid), 0, 0, 0);
+ ObjectIdGetDatum(func->funcid),
+ 0, 0, 0);
if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup for proc %u failed", func->funcid);
@@ -1426,14 +1436,14 @@ get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
if (!strcmp(proname, "nullvalue"))
{
appendStringInfo(buf, "(");
- get_rule_expr(buf, qh, rt_index, lfirst(expr->args), varprefix);
+ get_rule_expr((Node *) lfirst(expr->args), context);
appendStringInfo(buf, " ISNULL)");
return;
}
if (!strcmp(proname, "nonnullvalue"))
{
appendStringInfo(buf, "(");
- get_rule_expr(buf, qh, rt_index, lfirst(expr->args), varprefix);
+ get_rule_expr((Node *) lfirst(expr->args), context);
appendStringInfo(buf, " NOTNULL)");
return;
}
@@ -1449,7 +1459,7 @@ get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
{
appendStringInfo(buf, sep);
sep = ", ";
- get_rule_expr(buf, qh, rt_index, lfirst(l), varprefix);
+ get_rule_expr((Node *) lfirst(l), context);
}
appendStringInfo(buf, ")");
}
@@ -1466,8 +1476,7 @@ get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
* ----------
*/
static void
-get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
- TargetEntry *tle, bool varprefix)
+get_tle_expr(TargetEntry *tle, deparse_context *context)
{
Expr *expr = (Expr *) (tle->expr);
Func *func;
@@ -1485,7 +1494,7 @@ get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
! IsA(expr, Expr) ||
expr->opType != FUNC_EXPR)
{
- get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
+ get_rule_expr(tle->expr, context);
return;
}
@@ -1511,7 +1520,7 @@ get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
procStruct->prorettype != procStruct->proargtypes[0] ||
procStruct->proargtypes[1] != INT4OID)
{
- get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
+ get_rule_expr(tle->expr, context);
return;
}
@@ -1529,7 +1538,7 @@ get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
if (strncmp(procStruct->proname.data, typeStruct->typname.data,
NAMEDATALEN) != 0)
{
- get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
+ get_rule_expr(tle->expr, context);
return;
}
@@ -1542,7 +1551,7 @@ get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
if (! IsA(second_arg, Const) ||
DatumGetInt32(second_arg->constvalue) != tle->resdom->restypmod)
{
- get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
+ get_rule_expr(tle->expr, context);
return;
}
@@ -1550,7 +1559,7 @@ get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
* Whow - got it. Now get rid of the padding function
* ----------
*/
- get_rule_expr(buf, qh, rt_index, lfirst(expr->args), varprefix);
+ get_rule_expr((Node *) lfirst(expr->args), context);
}
@@ -1561,8 +1570,9 @@ get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
* ----------
*/
static void
-get_const_expr(StringInfo buf, Const *constval)
+get_const_expr(Const *constval, deparse_context *context)
{
+ StringInfo buf = context->buf;
HeapTuple typetup;
Form_pg_type typeStruct;
FmgrInfo finfo_output;
@@ -1624,9 +1634,9 @@ get_const_expr(StringInfo buf, Const *constval)
* ----------
*/
static void
-get_sublink_expr(StringInfo buf, QryHier *qh, int rt_index,
- Node *node, bool varprefix)
+get_sublink_expr(Node *node, deparse_context *context)
{
+ StringInfo buf = context->buf;
SubLink *sublink = (SubLink *) node;
Query *query = (Query *) (sublink->subselect);
Oper *oper;
@@ -1645,7 +1655,7 @@ get_sublink_expr(StringInfo buf, QryHier *qh, int rt_index,
{
appendStringInfo(buf, sep);
sep = ", ";
- get_rule_expr(buf, qh, rt_index, lfirst(l), varprefix);
+ get_rule_expr((Node *) lfirst(l), context);
}
if (length(sublink->lefthand) > 1)
@@ -1682,7 +1692,7 @@ get_sublink_expr(StringInfo buf, QryHier *qh, int rt_index,
}
appendStringInfo(buf, "(");
- get_query_def(buf, query, qh);
+ get_query_def(query, buf, context->rangetables);
appendStringInfo(buf, "))");
}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index afba41db108..fab04036d2e 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.73 1999/09/18 19:07:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.74 1999/10/03 23:55:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,7 @@
* RelationIdGetRelation - get a reldesc by relation id
* RelationNameGetRelation - get a reldesc by relation name
* RelationClose - close an open relation
- * RelationFlushRelation - flush relation information
+ * RelationRebuildRelation - rebuild relation information
*
* NOTES
* This file is in the process of being cleaned up
@@ -59,8 +59,9 @@
#include "utils/temprel.h"
+static void RelationClearRelation(Relation relation, bool rebuildIt);
static void RelationFlushRelation(Relation *relationPtr,
- bool onlyFlushReferenceCountZero);
+ bool onlyFlushReferenceCountZero);
static Relation RelationNameCacheGetRelation(char *relationName);
static void RelationCacheAbortWalker(Relation *relationPtr,
int dummy);
@@ -247,34 +248,6 @@ static List *newlyCreatedRelns = NULL;
*/
-#if NOT_USED /* XXX This doesn't seem to be used
- * anywhere */
-/* --------------------------------
- * BuildDescInfoError returns a string appropriate to
- * the buildinfo passed to it
- * --------------------------------
- */
-static char *
-BuildDescInfoError(RelationBuildDescInfo buildinfo)
-{
- static char errBuf[64];
-
- MemSet(errBuf, 0, (int) sizeof(errBuf));
- switch (buildinfo.infotype)
- {
- case INFO_RELID:
- sprintf(errBuf, "(relation id %u)", buildinfo.i.info_id);
- break;
- case INFO_RELNAME:
- sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name);
- break;
- }
-
- return errBuf;
-}
-
-#endif
-
/* --------------------------------
* ScanPgRelation
*
@@ -403,7 +376,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
*
* If 'relation' is NULL, allocate a new RelationData object.
* If not, reuse the given object (that path is taken only when
- * we have to rebuild a relcache entry during RelationFlushRelation).
+ * we have to rebuild a relcache entry during RelationClearRelation).
* ----------------
*/
static Relation
@@ -578,11 +551,14 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
if (attp->atthasdef)
{
if (attrdef == NULL)
+ {
attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
sizeof(AttrDefault));
+ MemSet(attrdef, 0,
+ relation->rd_rel->relnatts * sizeof(AttrDefault));
+ }
attrdef[ndef].adnum = i;
attrdef[ndef].adbin = NULL;
- attrdef[ndef].adsrc = NULL;
ndef++;
}
}
@@ -1231,7 +1207,9 @@ RelationNameGetRelation(char *relationName)
*/
/* --------------------------------
- * RelationClose - close an open relation
+ * RelationClose - close an open relation
+ *
+ * Actually, we just decrement the refcount.
* --------------------------------
*/
void
@@ -1242,17 +1220,18 @@ RelationClose(Relation relation)
}
/* --------------------------------
- * RelationFlushRelation
+ * RelationClearRelation
*
- * Actually blows away a relation cache entry... RelationFree doesn't do
- * anything anymore.
+ * Physically blow away a relation cache entry, or reset it and rebuild
+ * it from scratch (that is, from catalog entries). The latter path is
+ * usually used when we are notified of a change to an open relation
+ * (one with refcount > 0). However, this routine just does whichever
+ * it's told to do; callers must determine which they want.
* --------------------------------
*/
static void
-RelationFlushRelation(Relation *relationPtr,
- bool onlyFlushReferenceCountZero)
+RelationClearRelation(Relation relation, bool rebuildIt)
{
- Relation relation = *relationPtr;
MemoryContext oldcxt;
/*
@@ -1261,19 +1240,18 @@ RelationFlushRelation(Relation *relationPtr,
* if the relation is not deleted, the next smgr access should
* reopen the files automatically. This ensures that the low-level
* file access state is updated after, say, a vacuum truncation.
+ *
* NOTE: this call is a no-op if the relation's smgr file is already
* closed or unlinked.
*/
smgrclose(DEFAULT_SMGR, relation);
- if (relation->rd_isnailed || relation->rd_myxactonly)
- {
- /* Do not flush relation cache entry if it is a nailed-in system
- * relation or it is marked transaction-local.
- * (To delete a local relation, caller must clear rd_myxactonly!)
- */
+ /*
+ * Never, never ever blow away a nailed-in system relation,
+ * because we'd be unable to recover.
+ */
+ if (relation->rd_isnailed)
return;
- }
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
@@ -1293,19 +1271,21 @@ RelationFlushRelation(Relation *relationPtr,
FreeTriggerDesc(relation);
pfree(RelationGetForm(relation));
- /* If we're really done with the relcache entry, blow it away.
+ /*
+ * If we're really done with the relcache entry, blow it away.
* But if someone is still using it, reconstruct the whole deal
* without moving the physical RelationData record (so that the
- * someone's pointer is still valid). Preserve ref count, too.
+ * someone's pointer is still valid). Must preserve ref count
+ * and myxactonly flag, too.
*/
- if (!onlyFlushReferenceCountZero ||
- RelationHasReferenceCountZero(relation))
+ if (! rebuildIt)
{
pfree(relation);
}
else
{
uint16 old_refcnt = relation->rd_refcnt;
+ bool old_myxactonly = relation->rd_myxactonly;
RelationBuildDescInfo buildinfo;
buildinfo.infotype = INFO_RELID;
@@ -1315,19 +1295,53 @@ RelationFlushRelation(Relation *relationPtr,
{
/* Should only get here if relation was deleted */
pfree(relation);
- elog(ERROR, "RelationFlushRelation: relation %u deleted while still in use",
+ elog(ERROR, "RelationClearRelation: relation %u deleted while still in use",
buildinfo.i.info_id);
}
RelationSetReferenceCount(relation, old_refcnt);
+ relation->rd_myxactonly = old_myxactonly;
}
MemoryContextSwitchTo(oldcxt);
}
/* --------------------------------
- * RelationForgetRelation -
- * RelationFlushRelation + if the relation is myxactonly then
- * get rid of the relation descriptor from the newly created
+ * RelationFlushRelation
+ *
+ * Rebuild the relation if it is open (refcount > 0), else blow it away.
+ * Setting onlyFlushReferenceCountZero to FALSE overrides refcount check.
+ * This is currently only used to process SI invalidation notifications.
+ * The peculiar calling convention (pointer to pointer to relation)
+ * is needed so that we can use this routine as a hash table walker.
+ * --------------------------------
+ */
+static void
+RelationFlushRelation(Relation *relationPtr,
+ bool onlyFlushReferenceCountZero)
+{
+ Relation relation = *relationPtr;
+
+ /*
+ * Do nothing to transaction-local relations, since they cannot be
+ * subjects of SI notifications from other backends.
+ */
+ if (relation->rd_myxactonly)
+ return;
+
+ /*
+ * Zap it. Rebuild if it has nonzero ref count and we did not get
+ * the override flag.
+ */
+ RelationClearRelation(relation,
+ (onlyFlushReferenceCountZero &&
+ ! RelationHasReferenceCountZero(relation)));
+}
+
+/* --------------------------------
+ * RelationForgetRelation -
+ *
+ * RelationClearRelation + if the relation is myxactonly then
+ * remove the relation descriptor from the newly created
* relation list.
* --------------------------------
*/
@@ -1368,13 +1382,25 @@ RelationForgetRelation(Oid rid)
MemoryContextSwitchTo(oldcxt);
}
- relation->rd_myxactonly = false; /* so it can be flushed */
-
- RelationFlushRelation(&relation, false);
+ /* Unconditionally destroy the relcache entry */
+ RelationClearRelation(relation, false);
}
}
/* --------------------------------
+ * RelationRebuildRelation -
+ *
+ * Force a relcache entry to be rebuilt from catalog entries.
+ * This is needed, eg, after modifying an attribute of the rel.
+ * --------------------------------
+ */
+void
+RelationRebuildRelation(Relation relation)
+{
+ RelationClearRelation(relation, true);
+}
+
+/* --------------------------------
* RelationIdInvalidateRelationCacheByRelationId
* --------------------------------
*/
@@ -1573,6 +1599,11 @@ RelationPurgeLocalRelation(bool xactCommitted)
Assert(reln != NULL && reln->rd_myxactonly);
+ reln->rd_myxactonly = false; /* mark it not on list anymore */
+
+ newlyCreatedRelns = lnext(newlyCreatedRelns);
+ pfree(l);
+
if (!xactCommitted)
{
@@ -1592,13 +1623,8 @@ RelationPurgeLocalRelation(bool xactCommitted)
smgrunlink(DEFAULT_SMGR, reln);
}
- reln->rd_myxactonly = false; /* so it can be flushed */
-
if (!IsBootstrapProcessingMode())
- RelationFlushRelation(&reln, false);
-
- newlyCreatedRelns = lnext(newlyCreatedRelns);
- pfree(l);
+ RelationClearRelation(reln, false);
}
MemoryContextSwitchTo(oldcxt);
@@ -1717,7 +1743,7 @@ AttrDefaultFetch(Relation relation)
{
if (adform->adnum != attrdef[i].adnum)
continue;
- if (attrdef[i].adsrc != NULL)
+ if (attrdef[i].adbin != NULL)
elog(ERROR, "AttrDefaultFetch: second record found for attr %s in rel %s",
relation->rd_att->attrs[adform->adnum - 1]->attname.data,
relation->rd_rel->relname.data);
@@ -1730,14 +1756,6 @@ AttrDefaultFetch(Relation relation)
relation->rd_att->attrs[adform->adnum - 1]->attname.data,
relation->rd_rel->relname.data);
attrdef[i].adbin = textout(val);
- val = (struct varlena *) fastgetattr(&tuple,
- Anum_pg_attrdef_adsrc,
- adrel->rd_att, &isnull);
- if (isnull)
- elog(ERROR, "AttrDefaultFetch: adsrc IS NULL for attr %s in rel %s",
- relation->rd_att->attrs[adform->adnum - 1]->attname.data,
- relation->rd_rel->relname.data);
- attrdef[i].adsrc = textout(val);
break;
}
ReleaseBuffer(buffer);
@@ -1816,13 +1834,6 @@ RelCheckFetch(Relation relation)
elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
relation->rd_rel->relname.data);
check[found].ccbin = textout(val);
- val = (struct varlena *) fastgetattr(&tuple,
- Anum_pg_relcheck_rcsrc,
- rcrel->rd_att, &isnull);
- if (isnull)
- elog(ERROR, "RelCheckFetch: rcsrc IS NULL for rel %s",
- relation->rd_rel->relname.data);
- check[found].ccsrc = textout(val);
found++;
ReleaseBuffer(buffer);
}