mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Here's a combination of all the patches I'm currently waiting
for against a just updated CVS tree. It contains Partial new rewrite system that handles subselects, view aggregate columns, insert into select from view, updates with set col = view-value and select rules restriction to view definition. Updates for rule/view backparsing utility functions to handle subselects correct. New system views pg_tables and pg_indexes (where you can see the complete index definition in the latter one). Enabling array references on query parameters. Bugfix for functional index. Little changes to system views pg_rules and pg_views. The rule system isn't a release-stopper any longer. But another stopper is that I don't know if the latest changes to PL/pgSQL (not already in CVS) made it compile on AIX. Still wait for some response from Dave. Jan
This commit is contained in:
parent
9b21a18cee
commit
f93b6974f9
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.27 1998/09/07 05:35:30 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.28 1998/10/02 16:27:43 momjian Exp $
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
* index_open - open an index relation by relationId
|
||||
@ -362,7 +362,7 @@ GetIndexValue(HeapTuple tuple,
|
||||
bool *attNull)
|
||||
{
|
||||
Datum returnVal;
|
||||
bool isNull;
|
||||
bool isNull = FALSE;
|
||||
|
||||
if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid)
|
||||
{
|
||||
@ -375,13 +375,15 @@ GetIndexValue(HeapTuple tuple,
|
||||
attrNums[i],
|
||||
hTupDesc,
|
||||
attNull);
|
||||
if (*attNull)
|
||||
isNull = TRUE;
|
||||
}
|
||||
returnVal = (Datum) fmgr_array_args(FIgetProcOid(fInfo),
|
||||
FIgetnArgs(fInfo),
|
||||
(char **) attData,
|
||||
&isNull);
|
||||
pfree(attData);
|
||||
*attNull = FALSE;
|
||||
*attNull = isNull;
|
||||
}
|
||||
else
|
||||
returnVal = heap_getattr(tuple, attrNums[attOff], hTupDesc, attNull);
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.13 1998/09/01 04:31:30 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.14 1998/10/02 16:27:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -24,7 +24,6 @@
|
||||
#include "utils/builtins.h"
|
||||
#include "catalog/pg_shadow.h"
|
||||
|
||||
static void checkLockPerms(List *locks, Query *parsetree, int rt_index);
|
||||
|
||||
/*
|
||||
* ThisLockWasTriggered
|
||||
@ -170,7 +169,7 @@ matchLocks(CmdType event,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
checkLockPerms(List *locks, Query *parsetree, int rt_index)
|
||||
{
|
||||
Relation ev_rel;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.21 1998/09/01 04:31:32 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.22 1998/10/02 16:27:46 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -199,11 +199,8 @@ DefineQueryRewrite(RuleStmt *stmt)
|
||||
/* ----------
|
||||
* The current rewrite handler is known to work on relation level
|
||||
* rules only. And for SELECT events, it expects one non-nothing
|
||||
* action that is instead. Since we now hand out views and rules
|
||||
* to regular users, we must deny anything else.
|
||||
*
|
||||
* I know that I must write a new rewrite handler from scratch
|
||||
* for 6.5 so we can remove these checks and allow all the rules.
|
||||
* action that is instead and returns exactly a tuple of the
|
||||
* rewritten relation. This restricts SELECT rules to views.
|
||||
*
|
||||
* Jan
|
||||
* ----------
|
||||
@ -217,6 +214,9 @@ DefineQueryRewrite(RuleStmt *stmt)
|
||||
else
|
||||
eslot_string = NULL;
|
||||
|
||||
/*
|
||||
* No rule actions that modify OLD or NEW
|
||||
*/
|
||||
if (action != NIL)
|
||||
foreach(l, action)
|
||||
{
|
||||
@ -233,23 +233,86 @@ DefineQueryRewrite(RuleStmt *stmt)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Rules ON SELECT are restricted to view definitions
|
||||
*/
|
||||
if (event_type == CMD_SELECT)
|
||||
{
|
||||
TargetEntry *tle;
|
||||
Resdom *resdom;
|
||||
Form_pg_attribute attr;
|
||||
char *attname;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* So there cannot be INSTEAD NOTHING, ...
|
||||
*/
|
||||
if (length(action) == 0)
|
||||
{
|
||||
elog(NOTICE, "instead nothing rules on select currently not supported");
|
||||
elog(ERROR, " use views instead");
|
||||
}
|
||||
|
||||
/*
|
||||
* ... there cannot be multiple actions, ...
|
||||
*/
|
||||
if (length(action) > 1)
|
||||
elog(ERROR, "multiple action rules on select currently not supported");
|
||||
/*
|
||||
* ... the one action must be a SELECT, ...
|
||||
*/
|
||||
query = (Query *) lfirst(action);
|
||||
if (!is_instead || query->commandType != CMD_SELECT)
|
||||
elog(ERROR, "only instead-select rules currently supported on select");
|
||||
if (event_qual != NULL)
|
||||
elog(ERROR, "event qualifications not supported for rules on select");
|
||||
|
||||
/*
|
||||
* ... the targetlist of the SELECT action must
|
||||
* exactly match the event relation ...
|
||||
*/
|
||||
event_relation = heap_openr(event_obj->relname);
|
||||
if (event_relation == NULL)
|
||||
elog(ERROR, "virtual relations not supported yet");
|
||||
|
||||
if (event_relation->rd_att->natts != length(query->targetList))
|
||||
elog(ERROR, "select rules target list must match event relations structure");
|
||||
|
||||
for (i = 1; i <= event_relation->rd_att->natts; i++) {
|
||||
tle = (TargetEntry *)nth(i - 1, query->targetList);
|
||||
resdom = tle->resdom;
|
||||
attr = event_relation->rd_att->attrs[i - 1];
|
||||
attname = nameout(&(attr->attname));
|
||||
|
||||
if (strcmp(resdom->resname, attname) != 0)
|
||||
elog(ERROR, "select rules target entry %d has different column name from %s", i, attname);
|
||||
|
||||
if (attr->atttypid != resdom->restype)
|
||||
elog(ERROR, "select rules target entry %d has different type from attribute %s", i, attname);
|
||||
|
||||
if (attr->atttypmod != resdom->restypmod)
|
||||
elog(ERROR, "select rules target entry %d has different size from attribute %s", i, attname);
|
||||
}
|
||||
|
||||
/*
|
||||
* ... and final there must not be another ON SELECT
|
||||
* rule already.
|
||||
*/
|
||||
if (event_relation->rd_rules != NULL) {
|
||||
for (i = 0; i < event_relation->rd_rules->numLocks; i++) {
|
||||
RewriteRule *rule;
|
||||
|
||||
rule = event_relation->rd_rules->rules[i];
|
||||
if (rule->event == CMD_SELECT)
|
||||
elog(ERROR, "%s is already a view", nameout(&(event_relation->rd_rel->relname)));
|
||||
}
|
||||
}
|
||||
|
||||
heap_close(event_relation);
|
||||
}
|
||||
|
||||
/*
|
||||
* This rule is currently allowed - too restricted I know - but women
|
||||
* and children first Jan
|
||||
* This rule is allowed - install it.
|
||||
*/
|
||||
|
||||
event_relation = heap_openr(event_obj->relname);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.18 1998/09/11 16:39:59 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.19 1998/10/02 16:27:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -73,6 +73,23 @@ OffsetVarNodes(Node *node, int offset)
|
||||
OffsetVarNodes((Node *) expr->args, offset);
|
||||
}
|
||||
break;
|
||||
case T_Iter:
|
||||
{
|
||||
Iter *iter = (Iter *) node;
|
||||
|
||||
OffsetVarNodes((Node *) iter->iterexpr, offset);
|
||||
}
|
||||
break;
|
||||
case T_ArrayRef:
|
||||
{
|
||||
ArrayRef *ref = (ArrayRef *) node;
|
||||
|
||||
OffsetVarNodes((Node *) ref->refupperindexpr, offset);
|
||||
OffsetVarNodes((Node *) ref->reflowerindexpr, offset);
|
||||
OffsetVarNodes((Node *) ref->refexpr, offset);
|
||||
OffsetVarNodes((Node *) ref->refassgnexpr, offset);
|
||||
}
|
||||
break;
|
||||
case T_Var:
|
||||
{
|
||||
Var *var = (Var *) node;
|
||||
@ -157,6 +174,23 @@ ChangeVarNodes(Node *node, int old_varno, int new_varno, int sublevels_up)
|
||||
ChangeVarNodes((Node *) expr->args, old_varno, new_varno, sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_Iter:
|
||||
{
|
||||
Iter *iter = (Iter *) node;
|
||||
|
||||
ChangeVarNodes((Node *) iter->iterexpr, old_varno, new_varno, sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_ArrayRef:
|
||||
{
|
||||
ArrayRef *ref = (ArrayRef *) node;
|
||||
|
||||
ChangeVarNodes((Node *) ref->refupperindexpr, old_varno, new_varno, sublevels_up);
|
||||
ChangeVarNodes((Node *) ref->reflowerindexpr, old_varno, new_varno, sublevels_up);
|
||||
ChangeVarNodes((Node *) ref->refexpr, old_varno, new_varno, sublevels_up);
|
||||
ChangeVarNodes((Node *) ref->refassgnexpr, old_varno, new_varno, sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_Var:
|
||||
{
|
||||
Var *var = (Var *) node;
|
||||
@ -353,6 +387,20 @@ ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
|
||||
ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
|
||||
sublevels_up);
|
||||
break;
|
||||
case T_Iter:
|
||||
ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
|
||||
sublevels_up);
|
||||
break;
|
||||
case T_ArrayRef:
|
||||
ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
|
||||
sublevels_up);
|
||||
ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
|
||||
sublevels_up);
|
||||
ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
|
||||
sublevels_up);
|
||||
ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
|
||||
sublevels_up);
|
||||
break;
|
||||
case T_Var:
|
||||
{
|
||||
int this_varno = (int) ((Var *) node)->varno;
|
||||
@ -454,6 +502,38 @@ nodeHandleRIRAttributeRule(Node **nodePtr,
|
||||
sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_Iter:
|
||||
{
|
||||
Iter *iter = (Iter *) node;
|
||||
|
||||
nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
|
||||
targetlist, rt_index, attr_num,
|
||||
modified, badsql,
|
||||
sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_ArrayRef:
|
||||
{
|
||||
ArrayRef *ref = (ArrayRef *) node;
|
||||
|
||||
nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
|
||||
targetlist, rt_index, attr_num,
|
||||
modified, badsql,
|
||||
sublevels_up);
|
||||
nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
|
||||
targetlist, rt_index, attr_num,
|
||||
modified, badsql,
|
||||
sublevels_up);
|
||||
nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
|
||||
targetlist, rt_index, attr_num,
|
||||
modified, badsql,
|
||||
sublevels_up);
|
||||
nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
|
||||
targetlist, rt_index, attr_num,
|
||||
modified, badsql,
|
||||
sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_Var:
|
||||
{
|
||||
int this_varno = ((Var *) node)->varno;
|
||||
@ -598,6 +678,33 @@ nodeHandleViewRule(Node **nodePtr,
|
||||
rt_index, modified, sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_Iter:
|
||||
{
|
||||
Iter *iter = (Iter *) node;
|
||||
|
||||
nodeHandleViewRule((Node **) (&(iter->iterexpr)),
|
||||
rtable, targetlist,
|
||||
rt_index, modified, sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_ArrayRef:
|
||||
{
|
||||
ArrayRef *ref = (ArrayRef *) node;
|
||||
|
||||
nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
|
||||
rtable, targetlist,
|
||||
rt_index, modified, sublevels_up);
|
||||
nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
|
||||
rtable, targetlist,
|
||||
rt_index, modified, sublevels_up);
|
||||
nodeHandleViewRule((Node **) (&(ref->refexpr)),
|
||||
rtable, targetlist,
|
||||
rt_index, modified, sublevels_up);
|
||||
nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
|
||||
rtable, targetlist,
|
||||
rt_index, modified, sublevels_up);
|
||||
}
|
||||
break;
|
||||
case T_Var:
|
||||
{
|
||||
Var *var = (Var *) node;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* out of it's tuple
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.3 1998/09/01 04:32:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.4 1998/10/02 16:27:51 momjian Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -52,9 +52,22 @@
|
||||
#include "utils/lsyscache.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "catalog/pg_shadow.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "fmgr.h"
|
||||
|
||||
|
||||
/* ----------
|
||||
* Local data types
|
||||
* ----------
|
||||
*/
|
||||
typedef struct QryHier {
|
||||
struct QryHier *parent;
|
||||
Query *query;
|
||||
} QryHier;
|
||||
|
||||
|
||||
/* ----------
|
||||
* Global data
|
||||
* ----------
|
||||
@ -64,6 +77,10 @@ static void *plan_getrule = NULL;
|
||||
static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";
|
||||
static void *plan_getview = NULL;
|
||||
static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1 or rulename = $2";
|
||||
static void *plan_getam = NULL;
|
||||
static char *query_getam = "SELECT * FROM pg_am WHERE oid = $1";
|
||||
static void *plan_getopclass = NULL;
|
||||
static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";
|
||||
|
||||
|
||||
/* ----------
|
||||
@ -72,6 +89,8 @@ static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1 or ru
|
||||
*/
|
||||
text *pg_get_ruledef(NameData *rname);
|
||||
text *pg_get_viewdef(NameData *rname);
|
||||
text *pg_get_indexdef(Oid indexrelid);
|
||||
NameData *pg_get_userbyid(int4 uid);
|
||||
|
||||
|
||||
/* ----------
|
||||
@ -80,15 +99,16 @@ text *pg_get_viewdef(NameData *rname);
|
||||
*/
|
||||
static char *make_ruledef(HeapTuple ruletup, TupleDesc rulettc);
|
||||
static char *make_viewdef(HeapTuple ruletup, TupleDesc rulettc);
|
||||
static char *get_query_def(Query *query);
|
||||
static char *get_select_query_def(Query *query);
|
||||
static char *get_insert_query_def(Query *query);
|
||||
static char *get_update_query_def(Query *query);
|
||||
static char *get_delete_query_def(Query *query);
|
||||
static char *get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix);
|
||||
static char *get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix);
|
||||
static char *get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix);
|
||||
static char *get_query_def(Query *query, QryHier *parentqh);
|
||||
static char *get_select_query_def(Query *query, QryHier *qh);
|
||||
static char *get_insert_query_def(Query *query, QryHier *qh);
|
||||
static char *get_update_query_def(Query *query, QryHier *qh);
|
||||
static char *get_delete_query_def(Query *query, QryHier *qh);
|
||||
static char *get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);
|
||||
static char *get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix);
|
||||
static char *get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix);
|
||||
static char *get_const_expr(Const *constval);
|
||||
static char *get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);
|
||||
static char *get_relation_name(Oid relid);
|
||||
static char *get_attribute_name(Oid relid, int2 attnum);
|
||||
static bool check_if_rte_used(int rt_index, Node *node, int sup);
|
||||
@ -288,6 +308,272 @@ pg_get_viewdef(NameData *rname)
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* get_viewdef - Mainly the same thing, but we
|
||||
* only return the SELECT part of a view
|
||||
* ----------
|
||||
*/
|
||||
text *
|
||||
pg_get_indexdef(Oid indexrelid)
|
||||
{
|
||||
text *indexdef;
|
||||
HeapTuple ht_idx;
|
||||
HeapTuple ht_idxrel;
|
||||
HeapTuple ht_indrel;
|
||||
HeapTuple spi_tup;
|
||||
TupleDesc spi_ttc;
|
||||
int spi_fno;
|
||||
Form_pg_index idxrec;
|
||||
Form_pg_class idxrelrec;
|
||||
Form_pg_class indrelrec;
|
||||
Datum spi_args[1];
|
||||
char spi_nulls[2];
|
||||
int spirc;
|
||||
int len;
|
||||
int keyno;
|
||||
char buf[8192];
|
||||
char keybuf[8192];
|
||||
char *sep;
|
||||
|
||||
/* ----------
|
||||
* Connect to SPI manager
|
||||
* ----------
|
||||
*/
|
||||
if (SPI_connect() != SPI_OK_CONNECT)
|
||||
elog(ERROR, "get_indexdef: cannot connect to SPI manager");
|
||||
|
||||
/* ----------
|
||||
* On the first call prepare the plans to lookup pg_am
|
||||
* and pg_opclass.
|
||||
* ----------
|
||||
*/
|
||||
if (plan_getam == NULL)
|
||||
{
|
||||
Oid argtypes[1];
|
||||
void *plan;
|
||||
|
||||
argtypes[0] = OIDOID;
|
||||
plan = SPI_prepare(query_getam, 1, argtypes);
|
||||
if (plan == NULL)
|
||||
elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);
|
||||
plan_getam = SPI_saveplan(plan);
|
||||
|
||||
argtypes[0] = OIDOID;
|
||||
plan = SPI_prepare(query_getopclass, 1, argtypes);
|
||||
if (plan == NULL)
|
||||
elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);
|
||||
plan_getopclass = SPI_saveplan(plan);
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* Fetch the pg_index tuple by the Oid of the index
|
||||
* ----------
|
||||
*/
|
||||
ht_idx = SearchSysCacheTuple(INDEXRELID,
|
||||
ObjectIdGetDatum(indexrelid), 0, 0, 0);
|
||||
if (!HeapTupleIsValid(ht_idx))
|
||||
elog(ERROR, "syscache lookup for index %d failed", indexrelid);
|
||||
idxrec = (Form_pg_index)GETSTRUCT(ht_idx);
|
||||
|
||||
/* ----------
|
||||
* Fetch the pg_class tuple of the index relation
|
||||
* ----------
|
||||
*/
|
||||
ht_idxrel = SearchSysCacheTuple(RELOID,
|
||||
ObjectIdGetDatum(idxrec->indexrelid), 0, 0, 0);
|
||||
if (!HeapTupleIsValid(ht_idxrel))
|
||||
elog(ERROR, "syscache lookup for relid %d failed", idxrec->indexrelid);
|
||||
idxrelrec = (Form_pg_class)GETSTRUCT(ht_idxrel);
|
||||
|
||||
/* ----------
|
||||
* Fetch the pg_class tuple of the indexed relation
|
||||
* ----------
|
||||
*/
|
||||
ht_indrel = SearchSysCacheTuple(RELOID,
|
||||
ObjectIdGetDatum(idxrec->indrelid), 0, 0, 0);
|
||||
if (!HeapTupleIsValid(ht_indrel))
|
||||
elog(ERROR, "syscache lookup for relid %d failed", idxrec->indrelid);
|
||||
indrelrec = (Form_pg_class)GETSTRUCT(ht_indrel);
|
||||
|
||||
/* ----------
|
||||
* Get the am name for the index relation
|
||||
* ----------
|
||||
*/
|
||||
spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
|
||||
spi_nulls[0] = ' ';
|
||||
spi_nulls[1] = '\0';
|
||||
spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
|
||||
if (spirc != SPI_OK_SELECT)
|
||||
elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));
|
||||
if (SPI_processed != 1)
|
||||
elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));
|
||||
spi_tup = SPI_tuptable->vals[0];
|
||||
spi_ttc = SPI_tuptable->tupdesc;
|
||||
spi_fno = SPI_fnumber(spi_ttc, "amname");
|
||||
|
||||
/* ----------
|
||||
* Start the index definition
|
||||
* ----------
|
||||
*/
|
||||
sprintf(buf, "CREATE %sINDEX %s ON %s USING %s (",
|
||||
idxrec->indisunique ? "UNIQUE " : "",
|
||||
nameout(&(idxrelrec->relname)),
|
||||
nameout(&(indrelrec->relname)),
|
||||
SPI_getvalue(spi_tup, spi_ttc, spi_fno));
|
||||
|
||||
/* ----------
|
||||
* Collect the indexed attributes
|
||||
* ----------
|
||||
*/
|
||||
sep = "";
|
||||
keybuf[0] = '\0';
|
||||
for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)
|
||||
{
|
||||
if (idxrec->indkey[keyno] == InvalidAttrNumber)
|
||||
break;
|
||||
|
||||
strcat(keybuf, sep);
|
||||
sep = ", ";
|
||||
|
||||
/* ----------
|
||||
* Add the indexed field name
|
||||
* ----------
|
||||
*/
|
||||
if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1)
|
||||
strcat(keybuf, "oid");
|
||||
else
|
||||
strcat(keybuf, get_attribute_name(idxrec->indrelid,
|
||||
idxrec->indkey[keyno]));
|
||||
|
||||
/* ----------
|
||||
* If not a functional index, add the operator class name
|
||||
* ----------
|
||||
*/
|
||||
if (idxrec->indproc == InvalidOid)
|
||||
{
|
||||
spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);
|
||||
spi_nulls[0] = ' ';
|
||||
spi_nulls[1] = '\0';
|
||||
spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
|
||||
if (spirc != SPI_OK_SELECT)
|
||||
elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[keyno]);
|
||||
if (SPI_processed != 1)
|
||||
elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[keyno]);
|
||||
spi_tup = SPI_tuptable->vals[0];
|
||||
spi_ttc = SPI_tuptable->tupdesc;
|
||||
spi_fno = SPI_fnumber(spi_ttc, "opcname");
|
||||
strcat(keybuf, " ");
|
||||
strcat(keybuf, SPI_getvalue(spi_tup, spi_ttc, spi_fno));
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* For functional index say 'func (attrs) opclass'
|
||||
* ----------
|
||||
*/
|
||||
if (idxrec->indproc != InvalidOid)
|
||||
{
|
||||
HeapTuple proctup;
|
||||
Form_pg_proc procStruct;
|
||||
|
||||
proctup = SearchSysCacheTuple(PROOID,
|
||||
ObjectIdGetDatum(idxrec->indproc), 0, 0, 0);
|
||||
if (!HeapTupleIsValid(proctup))
|
||||
elog(ERROR, "cache lookup for proc %d failed", idxrec->indproc);
|
||||
|
||||
procStruct = (Form_pg_proc) GETSTRUCT(proctup);
|
||||
strcat(buf, nameout(&(procStruct->proname)));
|
||||
strcat(buf, " (");
|
||||
strcat(buf, keybuf);
|
||||
strcat(buf, ") ");
|
||||
|
||||
spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
|
||||
spi_nulls[0] = ' ';
|
||||
spi_nulls[1] = '\0';
|
||||
spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
|
||||
if (spirc != SPI_OK_SELECT)
|
||||
elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[0]);
|
||||
if (SPI_processed != 1)
|
||||
elog(ERROR, "failed to get pg_opclass tuple %d", idxrec->indclass[0]);
|
||||
spi_tup = SPI_tuptable->vals[0];
|
||||
spi_ttc = SPI_tuptable->tupdesc;
|
||||
spi_fno = SPI_fnumber(spi_ttc, "opcname");
|
||||
strcat(buf, SPI_getvalue(spi_tup, spi_ttc, spi_fno));
|
||||
}
|
||||
else
|
||||
/* ----------
|
||||
* For the others say 'attr opclass [, ...]'
|
||||
* ----------
|
||||
*/
|
||||
{
|
||||
strcat(buf, keybuf);
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* Finish
|
||||
* ----------
|
||||
*/
|
||||
strcat(buf, ")");
|
||||
|
||||
/* ----------
|
||||
* Create the result in upper executor memory
|
||||
* ----------
|
||||
*/
|
||||
len = strlen(buf) + VARHDRSZ;
|
||||
indexdef = SPI_palloc(len);
|
||||
VARSIZE(indexdef) = len;
|
||||
memcpy(VARDATA(indexdef), buf, len - VARHDRSZ);
|
||||
|
||||
/* ----------
|
||||
* Disconnect from SPI manager
|
||||
* ----------
|
||||
*/
|
||||
if (SPI_finish() != SPI_OK_FINISH)
|
||||
elog(ERROR, "get_viewdef: SPI_finish() failed");
|
||||
|
||||
return indexdef;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* get_userbyid - Get a user name by usesysid and
|
||||
* fallback to 'unknown (UID=n)'
|
||||
* ----------
|
||||
*/
|
||||
NameData *
|
||||
pg_get_userbyid(int4 uid)
|
||||
{
|
||||
HeapTuple usertup;
|
||||
Form_pg_shadow user_rec;
|
||||
NameData *result;
|
||||
|
||||
/* ----------
|
||||
* Allocate space for the result
|
||||
* ----------
|
||||
*/
|
||||
result = (NameData *) palloc(NAMEDATALEN);
|
||||
memset(result->data, 0, NAMEDATALEN);
|
||||
|
||||
/* ----------
|
||||
* Get the pg_shadow entry and print the result
|
||||
* ----------
|
||||
*/
|
||||
usertup = SearchSysCacheTuple(USESYSID,
|
||||
ObjectIdGetDatum(uid), 0, 0, 0);
|
||||
if (HeapTupleIsValid(usertup))
|
||||
{
|
||||
user_rec = (Form_pg_shadow)GETSTRUCT(usertup);
|
||||
StrNCpy(result->data, (&(user_rec->usename))->data, NAMEDATALEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf((char *)result, "unknown (UID=%d)", uid);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* make_ruledef - reconstruct the CREATE RULE command
|
||||
* for a given pg_rewrite tuple
|
||||
@ -331,16 +617,13 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
|
||||
|
||||
fno = SPI_fnumber(rulettc, "ev_qual");
|
||||
ev_qual = SPI_getvalue(ruletup, rulettc, fno);
|
||||
if (isnull)
|
||||
ev_qual = NULL;
|
||||
|
||||
fno = SPI_fnumber(rulettc, "ev_action");
|
||||
ev_action = SPI_getvalue(ruletup, rulettc, fno);
|
||||
if (isnull)
|
||||
ev_action = NULL;
|
||||
if (ev_action != NULL)
|
||||
actions = (List *) stringToNode(ev_action);
|
||||
|
||||
|
||||
/* ----------
|
||||
* Build the rules definition text
|
||||
* ----------
|
||||
@ -391,12 +674,15 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
|
||||
{
|
||||
Node *qual;
|
||||
Query *query;
|
||||
QryHier qh;
|
||||
|
||||
qual = stringToNode(ev_qual);
|
||||
query = (Query *) lfirst(actions);
|
||||
qh.parent = NULL;
|
||||
qh.query = query;
|
||||
|
||||
strcat(buf, " WHERE ");
|
||||
strcat(buf, get_rule_expr(query->rtable, 0, qual, TRUE));
|
||||
strcat(buf, get_rule_expr(&qh, 0, qual, TRUE));
|
||||
}
|
||||
|
||||
strcat(buf, " DO ");
|
||||
@ -415,7 +701,7 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
|
||||
foreach(action, actions)
|
||||
{
|
||||
query = (Query *) lfirst(action);
|
||||
strcat(buf, get_query_def(query));
|
||||
strcat(buf, get_query_def(query, NULL));
|
||||
strcat(buf, "; ");
|
||||
}
|
||||
strcat(buf, ");");
|
||||
@ -431,7 +717,7 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
|
||||
Query *query;
|
||||
|
||||
query = (Query *) lfirst(actions);
|
||||
strcat(buf, get_query_def(query));
|
||||
strcat(buf, get_query_def(query, NULL));
|
||||
strcat(buf, ";");
|
||||
}
|
||||
}
|
||||
@ -482,13 +768,9 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
|
||||
|
||||
fno = SPI_fnumber(rulettc, "ev_qual");
|
||||
ev_qual = SPI_getvalue(ruletup, rulettc, fno);
|
||||
if (isnull)
|
||||
ev_qual = "";
|
||||
|
||||
fno = SPI_fnumber(rulettc, "ev_action");
|
||||
ev_action = SPI_getvalue(ruletup, rulettc, fno);
|
||||
if (isnull)
|
||||
ev_action = NULL;
|
||||
if (ev_action != NULL)
|
||||
actions = (List *) stringToNode(ev_action);
|
||||
|
||||
@ -500,7 +782,7 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
|
||||
if (ev_type != '1' || ev_attr >= 0 || !is_instead || strcmp(ev_qual, ""))
|
||||
return "Not a view";
|
||||
|
||||
strcpy(buf, get_select_query_def(query));
|
||||
strcpy(buf, get_query_def(query, NULL));
|
||||
strcat(buf, ";");
|
||||
|
||||
/* ----------
|
||||
@ -518,24 +800,29 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_query_def(Query *query)
|
||||
get_query_def(Query *query, QryHier *parentqh)
|
||||
{
|
||||
QryHier qh;
|
||||
|
||||
qh.parent = parentqh;
|
||||
qh.query = query;
|
||||
|
||||
switch (query->commandType)
|
||||
{
|
||||
case CMD_SELECT:
|
||||
return get_select_query_def(query);
|
||||
return get_select_query_def(query, &qh);
|
||||
break;
|
||||
|
||||
case CMD_UPDATE:
|
||||
return get_update_query_def(query);
|
||||
return get_update_query_def(query, &qh);
|
||||
break;
|
||||
|
||||
case CMD_INSERT:
|
||||
return get_insert_query_def(query);
|
||||
return get_insert_query_def(query, &qh);
|
||||
break;
|
||||
|
||||
case CMD_DELETE:
|
||||
return get_delete_query_def(query);
|
||||
return get_delete_query_def(query, &qh);
|
||||
break;
|
||||
|
||||
case CMD_NOTHING:
|
||||
@ -557,7 +844,7 @@ get_query_def(Query *query)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_select_query_def(Query *query)
|
||||
get_select_query_def(Query *query, QryHier *qh)
|
||||
{
|
||||
char buf[8192];
|
||||
char *sep;
|
||||
@ -635,7 +922,7 @@ get_select_query_def(Query *query)
|
||||
strcat(buf, sep);
|
||||
sep = ", ";
|
||||
|
||||
strcat(buf, get_tle_expr(query->rtable, 0, tle, (rt_numused > 1)));
|
||||
strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1)));
|
||||
|
||||
/* Check if we must say AS ... */
|
||||
if (nodeTag(tle->expr) != T_Var)
|
||||
@ -681,7 +968,7 @@ get_select_query_def(Query *query)
|
||||
strcat(buf, sep);
|
||||
sep = ", ";
|
||||
strcat(buf, rte->relname);
|
||||
if (rt_numused > 1)
|
||||
if (strcmp(rte->relname, rte->refname) != 0)
|
||||
{
|
||||
strcat(buf, " ");
|
||||
strcat(buf, rte->refname);
|
||||
@ -694,7 +981,7 @@ get_select_query_def(Query *query)
|
||||
if (query->qual != NULL)
|
||||
{
|
||||
strcat(buf, " WHERE ");
|
||||
strcat(buf, get_rule_expr(query->rtable, 0, query->qual, (rt_numused > 1)));
|
||||
strcat(buf, get_rule_expr(qh, 0, query->qual, (rt_numused > 1)));
|
||||
}
|
||||
|
||||
/* Add the GROUP BY CLAUSE */
|
||||
@ -706,7 +993,7 @@ get_select_query_def(Query *query)
|
||||
{
|
||||
strcat(buf, sep);
|
||||
sep = ", ";
|
||||
strcat(buf, get_rule_expr(query->rtable, 0, lfirst(l), (rt_numused > 1)));
|
||||
strcat(buf, get_rule_expr(qh, 0, lfirst(l), (rt_numused > 1)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -723,7 +1010,7 @@ get_select_query_def(Query *query)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_insert_query_def(Query *query)
|
||||
get_insert_query_def(Query *query, QryHier *qh)
|
||||
{
|
||||
char buf[8192];
|
||||
char *sep;
|
||||
@ -810,12 +1097,12 @@ get_insert_query_def(Query *query)
|
||||
|
||||
strcat(buf, sep);
|
||||
sep = ", ";
|
||||
strcat(buf, get_tle_expr(query->rtable, 0, tle, (rt_numused > 1)));
|
||||
strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1)));
|
||||
}
|
||||
strcat(buf, ")");
|
||||
}
|
||||
else
|
||||
strcat(buf, get_select_query_def(query));
|
||||
strcat(buf, get_query_def(query, qh));
|
||||
|
||||
/* ----------
|
||||
* Copy the query string into allocated space and return it
|
||||
@ -830,7 +1117,7 @@ get_insert_query_def(Query *query)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_update_query_def(Query *query)
|
||||
get_update_query_def(Query *query, QryHier *qh)
|
||||
{
|
||||
char buf[8192];
|
||||
char *sep;
|
||||
@ -857,7 +1144,7 @@ get_update_query_def(Query *query)
|
||||
sep = ", ";
|
||||
strcat(buf, tle->resdom->resname);
|
||||
strcat(buf, " = ");
|
||||
strcat(buf, get_tle_expr(query->rtable, query->resultRelation,
|
||||
strcat(buf, get_tle_expr(qh, query->resultRelation,
|
||||
tle, TRUE));
|
||||
}
|
||||
|
||||
@ -865,7 +1152,7 @@ get_update_query_def(Query *query)
|
||||
if (query->qual != NULL)
|
||||
{
|
||||
strcat(buf, " WHERE ");
|
||||
strcat(buf, get_rule_expr(query->rtable, query->resultRelation,
|
||||
strcat(buf, get_rule_expr(qh, query->resultRelation,
|
||||
query->qual, TRUE));
|
||||
}
|
||||
|
||||
@ -882,7 +1169,7 @@ get_update_query_def(Query *query)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_delete_query_def(Query *query)
|
||||
get_delete_query_def(Query *query, QryHier *qh)
|
||||
{
|
||||
char buf[8192];
|
||||
RangeTblEntry *rte;
|
||||
@ -899,7 +1186,7 @@ get_delete_query_def(Query *query)
|
||||
if (query->qual != NULL)
|
||||
{
|
||||
strcat(buf, " WHERE ");
|
||||
strcat(buf, get_rule_expr(query->rtable, 0, query->qual, FALSE));
|
||||
strcat(buf, get_rule_expr(qh, 0, query->qual, FALSE));
|
||||
}
|
||||
|
||||
/* ----------
|
||||
@ -915,7 +1202,7 @@ get_delete_query_def(Query *query)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
|
||||
{
|
||||
char buf[8192];
|
||||
|
||||
@ -936,7 +1223,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *) node;
|
||||
|
||||
return get_rule_expr(rtable, rt_index,
|
||||
return get_rule_expr(qh, rt_index,
|
||||
(Node *) (tle->expr), varprefix);
|
||||
}
|
||||
break;
|
||||
@ -947,7 +1234,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
|
||||
strcat(buf, agg->aggname);
|
||||
strcat(buf, "(");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) (agg->target), varprefix));
|
||||
strcat(buf, ")");
|
||||
return pstrdup(buf);
|
||||
@ -958,7 +1245,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
{
|
||||
GroupClause *grp = (GroupClause *) node;
|
||||
|
||||
return get_rule_expr(rtable, rt_index,
|
||||
return get_rule_expr(qh, rt_index,
|
||||
(Node *) (grp->entry), varprefix);
|
||||
}
|
||||
break;
|
||||
@ -974,13 +1261,13 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
switch (expr->opType)
|
||||
{
|
||||
case OP_EXPR:
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) get_leftop(expr),
|
||||
varprefix));
|
||||
strcat(buf, " ");
|
||||
strcat(buf, get_opname(((Oper *) expr->oper)->opno));
|
||||
strcat(buf, " ");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) get_rightop(expr),
|
||||
varprefix));
|
||||
return pstrdup(buf);
|
||||
@ -988,11 +1275,11 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
|
||||
case OR_EXPR:
|
||||
strcat(buf, "(");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) get_leftop(expr),
|
||||
varprefix));
|
||||
strcat(buf, ") OR (");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) get_rightop(expr),
|
||||
varprefix));
|
||||
strcat(buf, ")");
|
||||
@ -1001,11 +1288,11 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
|
||||
case AND_EXPR:
|
||||
strcat(buf, "(");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) get_leftop(expr),
|
||||
varprefix));
|
||||
strcat(buf, ") AND (");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) get_rightop(expr),
|
||||
varprefix));
|
||||
strcat(buf, ")");
|
||||
@ -1014,7 +1301,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
|
||||
case NOT_EXPR:
|
||||
strcat(buf, "NOT (");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
(Node *) get_leftop(expr),
|
||||
varprefix));
|
||||
strcat(buf, ")");
|
||||
@ -1022,7 +1309,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
break;
|
||||
|
||||
case FUNC_EXPR:
|
||||
return get_func_expr(rtable, rt_index,
|
||||
return get_func_expr(qh, rt_index,
|
||||
(Expr *) node,
|
||||
varprefix);
|
||||
break;
|
||||
@ -1037,7 +1324,14 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
case T_Var:
|
||||
{
|
||||
Var *var = (Var *) node;
|
||||
RangeTblEntry *rte = (RangeTblEntry *) nth(var->varno - 1, rtable);
|
||||
RangeTblEntry *rte;
|
||||
int sup = var->varlevelsup;
|
||||
|
||||
while(sup-- > 0) qh = qh->parent;
|
||||
rte = (RangeTblEntry *) nth(var->varno - 1, qh->query->rtable);
|
||||
|
||||
if (qh->parent == NULL && var->varlevelsup > 0)
|
||||
rte = (RangeTblEntry *) nth(var->varno + 1, qh->query->rtable);
|
||||
|
||||
if (!strcmp(rte->refname, "*NEW*"))
|
||||
strcat(buf, "new.");
|
||||
@ -1047,7 +1341,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
strcat(buf, "current.");
|
||||
else
|
||||
{
|
||||
if (varprefix && var->varno != rt_index)
|
||||
if (strcmp(rte->relname, rte->refname) != 0)
|
||||
{
|
||||
strcat(buf, rte->refname);
|
||||
strcat(buf, ".");
|
||||
@ -1069,30 +1363,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
|
||||
case T_SubLink:
|
||||
{
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
Query *query = (Query *) (sublink->subselect);
|
||||
List *l;
|
||||
char *sep;
|
||||
|
||||
if (sublink->lefthand != NULL)
|
||||
{
|
||||
strcat(buf, "(");
|
||||
sep = "";
|
||||
foreach(l, sublink->lefthand)
|
||||
{
|
||||
strcat(buf, sep);
|
||||
sep = ", ";
|
||||
strcat(buf, get_rule_expr(rtable, rt_index,
|
||||
lfirst(l), varprefix));
|
||||
}
|
||||
strcat(buf, ") IN ");
|
||||
}
|
||||
|
||||
strcat(buf, "(");
|
||||
strcat(buf, get_query_def(query));
|
||||
strcat(buf, ")");
|
||||
|
||||
return pstrdup(buf);
|
||||
return get_sublink_expr(qh, rt_index, node, varprefix);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1116,7 +1387,7 @@ get_rule_expr(List *rtable, int rt_index, Node *node, bool varprefix)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
|
||||
get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix)
|
||||
{
|
||||
char buf[8192];
|
||||
HeapTuple proctup;
|
||||
@ -1143,7 +1414,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
|
||||
if (!strcmp(proname, "nullvalue"))
|
||||
{
|
||||
strcpy(buf, "(");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index, lfirst(expr->args),
|
||||
strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args),
|
||||
varprefix));
|
||||
strcat(buf, ") ISNULL");
|
||||
return pstrdup(buf);
|
||||
@ -1151,7 +1422,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
|
||||
if (!strcmp(proname, "nonnullvalue"))
|
||||
{
|
||||
strcpy(buf, "(");
|
||||
strcat(buf, get_rule_expr(rtable, rt_index, lfirst(expr->args),
|
||||
strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args),
|
||||
varprefix));
|
||||
strcat(buf, ") NOTNULL");
|
||||
return pstrdup(buf);
|
||||
@ -1169,7 +1440,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
|
||||
{
|
||||
strcat(buf, sep);
|
||||
sep = ", ";
|
||||
strcat(buf, get_rule_expr(rtable, rt_index, lfirst(l), varprefix));
|
||||
strcat(buf, get_rule_expr(qh, rt_index, lfirst(l), varprefix));
|
||||
}
|
||||
strcat(buf, ")");
|
||||
|
||||
@ -1194,7 +1465,7 @@ get_func_expr(List *rtable, int rt_index, Expr *expr, bool varprefix)
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
|
||||
get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
|
||||
{
|
||||
HeapTuple proctup;
|
||||
Form_pg_proc procStruct;
|
||||
@ -1208,12 +1479,12 @@ get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
|
||||
* ----------
|
||||
*/
|
||||
if (tle->resdom->restypmod < 0)
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
if (nodeTag(tle->expr) != T_Expr)
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
expr = (Expr *) (tle->expr);
|
||||
if (expr->opType != FUNC_EXPR)
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
|
||||
func = (Func *) (expr->oper);
|
||||
|
||||
@ -1235,11 +1506,11 @@ get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
|
||||
* ----------
|
||||
*/
|
||||
if (procStruct->pronargs != 2)
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
if (procStruct->prorettype != procStruct->proargtypes[0])
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
if (procStruct->proargtypes[1] != INT4OID)
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
|
||||
/* ----------
|
||||
* Finally (to be totally safe) the second argument must be a
|
||||
@ -1248,15 +1519,15 @@ get_tle_expr(List *rtable, int rt_index, TargetEntry *tle, bool varprefix)
|
||||
*/
|
||||
second_arg = (Const *) nth(1, expr->args);
|
||||
if (nodeTag((Node *) second_arg) != T_Const)
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
if ((int4) (second_arg->constvalue) != tle->resdom->restypmod)
|
||||
return get_rule_expr(rtable, rt_index, tle->expr, varprefix);
|
||||
return get_rule_expr(qh, rt_index, tle->expr, varprefix);
|
||||
|
||||
/* ----------
|
||||
* Whow - got it. Now get rid of the padding function
|
||||
* ----------
|
||||
*/
|
||||
return get_rule_expr(rtable, rt_index, lfirst(expr->args), varprefix);
|
||||
return get_rule_expr(qh, rt_index, lfirst(expr->args), varprefix);
|
||||
}
|
||||
|
||||
|
||||
@ -1274,6 +1545,7 @@ get_const_expr(Const *constval)
|
||||
char *extval;
|
||||
bool isnull = FALSE;
|
||||
char buf[8192];
|
||||
char namebuf[64];
|
||||
|
||||
if (constval->constisnull)
|
||||
return "NULL";
|
||||
@ -1289,7 +1561,83 @@ get_const_expr(Const *constval)
|
||||
extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue,
|
||||
&isnull, -1);
|
||||
|
||||
sprintf(buf, "'%s'::%s", extval, nameout(&(typeStruct->typname)));
|
||||
sprintf(namebuf, "::%s", nameout(&(typeStruct->typname)));
|
||||
if (strcmp(namebuf, "::unknown") == 0)
|
||||
namebuf[0] = '\0';
|
||||
sprintf(buf, "'%s'%s", extval, namebuf);
|
||||
return pstrdup(buf);
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* get_sublink_expr - Parse back a sublink
|
||||
* ----------
|
||||
*/
|
||||
static char *
|
||||
get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
|
||||
{
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
Query *query = (Query *) (sublink->subselect);
|
||||
Expr *expr;
|
||||
List *l;
|
||||
char *sep;
|
||||
char buf[8192];
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
if (sublink->lefthand != NULL)
|
||||
{
|
||||
if (length(sublink->lefthand) > 1)
|
||||
strcat(buf, "(");
|
||||
|
||||
sep = "";
|
||||
foreach(l, sublink->lefthand)
|
||||
{
|
||||
strcat(buf, sep);
|
||||
sep = ", ";
|
||||
strcat(buf, get_rule_expr(qh, rt_index,
|
||||
lfirst(l), varprefix));
|
||||
}
|
||||
|
||||
if (length(sublink->lefthand) > 1)
|
||||
strcat(buf, ") ");
|
||||
else
|
||||
strcat(buf, " ");
|
||||
}
|
||||
|
||||
switch (sublink->subLinkType) {
|
||||
case EXISTS_SUBLINK:
|
||||
strcat(buf, "EXISTS ");
|
||||
break;
|
||||
|
||||
case ANY_SUBLINK:
|
||||
expr = (Expr *)lfirst(sublink->oper);
|
||||
strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
|
||||
strcat(buf, " ANY ");
|
||||
break;
|
||||
|
||||
case ALL_SUBLINK:
|
||||
expr = (Expr *)lfirst(sublink->oper);
|
||||
strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
|
||||
strcat(buf, " ALL ");
|
||||
break;
|
||||
|
||||
case EXPR_SUBLINK:
|
||||
expr = (Expr *)lfirst(sublink->oper);
|
||||
strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
|
||||
strcat(buf, " ");
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unupported sublink type %d",
|
||||
sublink->subLinkType);
|
||||
break;
|
||||
}
|
||||
|
||||
strcat(buf, "(");
|
||||
strcat(buf, get_query_def(query, qh));
|
||||
strcat(buf, ")");
|
||||
|
||||
return pstrdup(buf);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.55 1998/09/09 18:16:36 momjian Exp $
|
||||
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.56 1998/10/02 16:27:53 momjian Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -435,6 +435,7 @@ echo "REVOKE ALL on pg_shadow FROM public" | \
|
||||
|
||||
echo "Creating view pg_rules"
|
||||
echo "CREATE TABLE xpg_rules ( \
|
||||
tablename name, \
|
||||
rulename name, \
|
||||
definition text);" | postgres $PGSQL_OPT template1 > /dev/null
|
||||
#move it into pg_rules
|
||||
@ -445,12 +446,18 @@ echo "UPDATE pg_type SET typname = 'pg_rules' WHERE typname = 'xpg_rules';" |\
|
||||
mv $PGDATA/base/template1/xpg_rules $PGDATA/base/template1/pg_rules
|
||||
|
||||
echo "CREATE RULE \"_RETpg_rules\" AS ON SELECT TO pg_rules DO INSTEAD \
|
||||
SELECT rulename, pg_get_ruledef(rulename) AS definition \
|
||||
FROM pg_rewrite;" | postgres $PGSQL_OPT template1 > /dev/null
|
||||
SELECT C.relname AS tablename, \
|
||||
R.rulename AS rulename, \
|
||||
pg_get_ruledef(R.rulename) AS definition \
|
||||
FROM pg_rewrite R, pg_class C \
|
||||
WHERE R.rulename !~ '^_RET' \
|
||||
AND C.oid = R.ev_class;" | \
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
|
||||
echo "Creating view pg_views"
|
||||
echo "CREATE TABLE xpg_views ( \
|
||||
viewname name, \
|
||||
viewowner name, \
|
||||
definition text);" | postgres $PGSQL_OPT template1 > /dev/null
|
||||
#move it into pg_views
|
||||
echo "UPDATE pg_class SET relname = 'pg_views' WHERE relname = 'xpg_views';" |\
|
||||
@ -461,11 +468,57 @@ mv $PGDATA/base/template1/xpg_views $PGDATA/base/template1/pg_views
|
||||
|
||||
echo "CREATE RULE \"_RETpg_views\" AS ON SELECT TO pg_views DO INSTEAD \
|
||||
SELECT relname AS viewname, \
|
||||
pg_get_userbyid(relowner) AS viewowner, \
|
||||
pg_get_viewdef(relname) AS definition \
|
||||
FROM pg_class WHERE relhasrules AND \
|
||||
pg_get_viewdef(relname) != 'Not a view';" | \
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
|
||||
echo "Creating view pg_tables"
|
||||
echo "CREATE TABLE xpg_tables ( \
|
||||
tablename name, \
|
||||
tableowner name, \
|
||||
hasindexes bool, \
|
||||
hasrules bool, \
|
||||
hastriggers bool);" | postgres $PGSQL_OPT template1 > /dev/null
|
||||
#move it into pg_tables
|
||||
echo "UPDATE pg_class SET relname = 'pg_tables' WHERE relname = 'xpg_tables';" |\
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
echo "UPDATE pg_type SET typname = 'pg_tables' WHERE typname = 'xpg_tables';" |\
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
mv $PGDATA/base/template1/xpg_tables $PGDATA/base/template1/pg_tables
|
||||
|
||||
echo "CREATE RULE \"_RETpg_tables\" AS ON SELECT TO pg_tables DO INSTEAD \
|
||||
SELECT relname AS tablename, \
|
||||
pg_get_userbyid(relowner) AS tableowner, \
|
||||
relhasindex AS hasindexes, \
|
||||
relhasrules AS hasrules, \
|
||||
(reltriggers > 0) AS hastriggers \
|
||||
FROM pg_class WHERE relkind IN ('r', 's') \
|
||||
AND pg_get_viewdef(relname) = 'Not a view';" | \
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
|
||||
echo "Creating view pg_indexes"
|
||||
echo "CREATE TABLE xpg_indexes ( \
|
||||
tablename name, \
|
||||
indexname name, \
|
||||
indexdef text);" | postgres $PGSQL_OPT template1 > /dev/null
|
||||
#move it into pg_indexes
|
||||
echo "UPDATE pg_class SET relname = 'pg_indexes' WHERE relname = 'xpg_indexes';" |\
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
echo "UPDATE pg_type SET typname = 'pg_indexes' WHERE typname = 'xpg_indexes';" |\
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
mv $PGDATA/base/template1/xpg_indexes $PGDATA/base/template1/pg_indexes
|
||||
|
||||
echo "CREATE RULE \"_RETpg_indexes\" AS ON SELECT TO pg_indexes DO INSTEAD \
|
||||
SELECT C.relname AS tablename, \
|
||||
I.relname AS indexname, \
|
||||
pg_get_indexdef(X.indexrelid) AS indexdef \
|
||||
FROM pg_index X, pg_class C, pg_class I \
|
||||
WHERE C.oid = X.indrelid \
|
||||
AND I.oid = X.indexrelid;" | \
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
|
||||
echo "Loading pg_description"
|
||||
echo "copy pg_description from '$TEMPLATE_DESCR'" | \
|
||||
postgres $PGSQL_OPT template1 > /dev/null
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_proc.h,v 1.69 1998/09/01 04:35:10 momjian Exp $
|
||||
* $Id: pg_proc.h,v 1.70 1998/10/02 16:27:55 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
@ -2040,6 +2040,10 @@ DATA(insert OID = 1640 ( pg_get_ruledef PGUID 11 f t f 1 f 25 "19" 100 0 0 1
|
||||
DESCR("source text of a rule");
|
||||
DATA(insert OID = 1641 ( pg_get_viewdef PGUID 11 f t f 1 f 25 "19" 100 0 0 100 foo bar ));
|
||||
DESCR("select statement of a view");
|
||||
DATA(insert OID = 1642 ( pg_get_userbyid PGUID 11 f t f 1 f 19 "23" 100 0 0 100 foo bar ));
|
||||
DESCR("user name by UID (with fallback)");
|
||||
DATA(insert OID = 1643 ( pg_get_indexdef PGUID 11 f t f 1 f 25 "26" 100 0 0 100 foo bar ));
|
||||
DESCR("index description");
|
||||
|
||||
/*
|
||||
* prototypes for functions pg_proc.c
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: locks.h,v 1.9 1998/09/01 04:37:57 momjian Exp $
|
||||
* $Id: locks.h,v 1.10 1998/10/02 16:27:58 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -19,5 +19,6 @@
|
||||
|
||||
extern List *matchLocks(CmdType event, RuleLock *rulelocks, int varno,
|
||||
Query *parsetree);
|
||||
extern void checkLockPerms(List *locks, Query *parsetree, int rt_index);
|
||||
|
||||
#endif /* LOCKS_H */
|
||||
|
@ -671,3 +671,181 @@ QUERY: select * from rtest_nothn3;
|
||||
200|OK
|
||||
(2 rows)
|
||||
|
||||
QUERY: create table rtest_view1 (a int4, b text, v bool);
|
||||
QUERY: create table rtest_view2 (a int4);
|
||||
QUERY: create table rtest_view3 (a int4, b text);
|
||||
QUERY: create table rtest_view4 (a int4, b text, c int4);
|
||||
QUERY: create view rtest_vview1 as select a, b from rtest_view1 X
|
||||
where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
|
||||
QUERY: create view rtest_vview2 as select a, b from rtest_view1 where v;
|
||||
QUERY: create view rtest_vview3 as select a, b from rtest_vview2 X
|
||||
where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
|
||||
QUERY: create view rtest_vview4 as select X.a, X.b, count(Y.a) as refcount
|
||||
from rtest_view1 X, rtest_view2 Y
|
||||
where X.a = Y.a
|
||||
group by X.a, X.b;
|
||||
QUERY: create function rtest_viewfunc1(int4) returns int4 as
|
||||
'select count(*) from rtest_view2 where a = $1'
|
||||
language 'sql';
|
||||
QUERY: create view rtest_vview5 as select a, b, rtest_viewfunc1(a) as refcount
|
||||
from rtest_view1;
|
||||
QUERY: insert into rtest_view1 values (1, 'item 1', 't');
|
||||
QUERY: insert into rtest_view1 values (2, 'item 2', 't');
|
||||
QUERY: insert into rtest_view1 values (3, 'item 3', 't');
|
||||
QUERY: insert into rtest_view1 values (4, 'item 4', 'f');
|
||||
QUERY: insert into rtest_view1 values (5, 'item 5', 't');
|
||||
QUERY: insert into rtest_view1 values (6, 'item 6', 'f');
|
||||
QUERY: insert into rtest_view1 values (7, 'item 7', 't');
|
||||
QUERY: insert into rtest_view1 values (8, 'item 8', 't');
|
||||
QUERY: insert into rtest_view2 values (2);
|
||||
QUERY: insert into rtest_view2 values (2);
|
||||
QUERY: insert into rtest_view2 values (4);
|
||||
QUERY: insert into rtest_view2 values (5);
|
||||
QUERY: insert into rtest_view2 values (7);
|
||||
QUERY: insert into rtest_view2 values (7);
|
||||
QUERY: insert into rtest_view2 values (7);
|
||||
QUERY: insert into rtest_view2 values (7);
|
||||
QUERY: select * from rtest_vview1;
|
||||
a|b
|
||||
-+------
|
||||
2|item 2
|
||||
4|item 4
|
||||
5|item 5
|
||||
7|item 7
|
||||
(4 rows)
|
||||
|
||||
QUERY: select * from rtest_vview2;
|
||||
a|b
|
||||
-+------
|
||||
1|item 1
|
||||
2|item 2
|
||||
3|item 3
|
||||
5|item 5
|
||||
7|item 7
|
||||
8|item 8
|
||||
(6 rows)
|
||||
|
||||
QUERY: select * from rtest_vview3;
|
||||
a|b
|
||||
-+------
|
||||
2|item 2
|
||||
5|item 5
|
||||
7|item 7
|
||||
(3 rows)
|
||||
|
||||
QUERY: select * from rtest_vview4;
|
||||
a|b |refcount
|
||||
-+------+--------
|
||||
2|item 2| 2
|
||||
4|item 4| 1
|
||||
5|item 5| 1
|
||||
7|item 7| 4
|
||||
(4 rows)
|
||||
|
||||
QUERY: select * from rtest_vview5;
|
||||
a|b |refcount
|
||||
-+------+--------
|
||||
1|item 1| 0
|
||||
2|item 2| 2
|
||||
3|item 3| 0
|
||||
4|item 4| 1
|
||||
5|item 5| 1
|
||||
6|item 6| 0
|
||||
7|item 7| 4
|
||||
8|item 8| 0
|
||||
(8 rows)
|
||||
|
||||
QUERY: insert into rtest_view3 select * from rtest_vview1 where a < 7;
|
||||
QUERY: select * from rtest_view3;
|
||||
a|b
|
||||
-+------
|
||||
2|item 2
|
||||
4|item 4
|
||||
5|item 5
|
||||
(3 rows)
|
||||
|
||||
QUERY: delete from rtest_view3;
|
||||
QUERY: insert into rtest_view3 select * from rtest_vview2 where a != 5 and b !~ '2';
|
||||
QUERY: select * from rtest_view3;
|
||||
a|b
|
||||
-+------
|
||||
1|item 1
|
||||
3|item 3
|
||||
7|item 7
|
||||
8|item 8
|
||||
(4 rows)
|
||||
|
||||
QUERY: delete from rtest_view3;
|
||||
QUERY: insert into rtest_view3 select * from rtest_vview3;
|
||||
QUERY: select * from rtest_view3;
|
||||
a|b
|
||||
-+------
|
||||
2|item 2
|
||||
5|item 5
|
||||
7|item 7
|
||||
(3 rows)
|
||||
|
||||
QUERY: delete from rtest_view3;
|
||||
QUERY: insert into rtest_view4 select * from rtest_vview4 where 3 > refcount;
|
||||
QUERY: select * from rtest_view4;
|
||||
a|b |c
|
||||
-+------+-
|
||||
2|item 2|2
|
||||
4|item 4|1
|
||||
5|item 5|1
|
||||
(3 rows)
|
||||
|
||||
QUERY: delete from rtest_view4;
|
||||
QUERY: insert into rtest_view4 select * from rtest_vview5 where a > 2 and refcount = 0;
|
||||
QUERY: select * from rtest_view4;
|
||||
a|b |c
|
||||
-+------+-
|
||||
3|item 3|0
|
||||
6|item 6|0
|
||||
8|item 8|0
|
||||
(3 rows)
|
||||
|
||||
QUERY: delete from rtest_view4;
|
||||
QUERY: create table rtest_comp (
|
||||
part text,
|
||||
unit char(4),
|
||||
size float
|
||||
);
|
||||
QUERY: create table rtest_unitfact (
|
||||
unit char(4),
|
||||
factor float
|
||||
);
|
||||
QUERY: create view rtest_vcomp as
|
||||
select X.part, (X.size * Y.factor) as size_in_cm
|
||||
from rtest_comp X, rtest_unitfact Y
|
||||
where X.unit = Y.unit;
|
||||
QUERY: insert into rtest_unitfact values ('m', 100.0);
|
||||
QUERY: insert into rtest_unitfact values ('cm', 1.0);
|
||||
QUERY: insert into rtest_unitfact values ('inch', 2.54);
|
||||
QUERY: insert into rtest_comp values ('p1', 'm', 5.0);
|
||||
QUERY: insert into rtest_comp values ('p2', 'm', 3.0);
|
||||
QUERY: insert into rtest_comp values ('p3', 'cm', 5.0);
|
||||
QUERY: insert into rtest_comp values ('p4', 'cm', 15.0);
|
||||
QUERY: insert into rtest_comp values ('p5', 'inch', 7.0);
|
||||
QUERY: insert into rtest_comp values ('p6', 'inch', 4.4);
|
||||
QUERY: select * from rtest_vcomp order by part;
|
||||
part|size_in_cm
|
||||
----+----------
|
||||
p1 | 500
|
||||
p2 | 300
|
||||
p3 | 5
|
||||
p4 | 15
|
||||
p5 | 17.78
|
||||
p6 | 11.176
|
||||
(6 rows)
|
||||
|
||||
QUERY: select * from rtest_vcomp where size_in_cm > 10.0 order by size_in_cm using >;
|
||||
part|size_in_cm
|
||||
----+----------
|
||||
p1 | 500
|
||||
p2 | 300
|
||||
p5 | 17.78
|
||||
p4 | 15
|
||||
p6 | 11.176
|
||||
(5 rows)
|
||||
|
||||
|
@ -404,3 +404,100 @@ insert into rtest_nothn2 select * from rtest_nothn4;
|
||||
select * from rtest_nothn2;
|
||||
select * from rtest_nothn3;
|
||||
|
||||
create table rtest_view1 (a int4, b text, v bool);
|
||||
create table rtest_view2 (a int4);
|
||||
create table rtest_view3 (a int4, b text);
|
||||
create table rtest_view4 (a int4, b text, c int4);
|
||||
create view rtest_vview1 as select a, b from rtest_view1 X
|
||||
where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
|
||||
create view rtest_vview2 as select a, b from rtest_view1 where v;
|
||||
create view rtest_vview3 as select a, b from rtest_vview2 X
|
||||
where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
|
||||
create view rtest_vview4 as select X.a, X.b, count(Y.a) as refcount
|
||||
from rtest_view1 X, rtest_view2 Y
|
||||
where X.a = Y.a
|
||||
group by X.a, X.b;
|
||||
create function rtest_viewfunc1(int4) returns int4 as
|
||||
'select count(*) from rtest_view2 where a = $1'
|
||||
language 'sql';
|
||||
create view rtest_vview5 as select a, b, rtest_viewfunc1(a) as refcount
|
||||
from rtest_view1;
|
||||
|
||||
insert into rtest_view1 values (1, 'item 1', 't');
|
||||
insert into rtest_view1 values (2, 'item 2', 't');
|
||||
insert into rtest_view1 values (3, 'item 3', 't');
|
||||
insert into rtest_view1 values (4, 'item 4', 'f');
|
||||
insert into rtest_view1 values (5, 'item 5', 't');
|
||||
insert into rtest_view1 values (6, 'item 6', 'f');
|
||||
insert into rtest_view1 values (7, 'item 7', 't');
|
||||
insert into rtest_view1 values (8, 'item 8', 't');
|
||||
|
||||
insert into rtest_view2 values (2);
|
||||
insert into rtest_view2 values (2);
|
||||
insert into rtest_view2 values (4);
|
||||
insert into rtest_view2 values (5);
|
||||
insert into rtest_view2 values (7);
|
||||
insert into rtest_view2 values (7);
|
||||
insert into rtest_view2 values (7);
|
||||
insert into rtest_view2 values (7);
|
||||
|
||||
select * from rtest_vview1;
|
||||
select * from rtest_vview2;
|
||||
select * from rtest_vview3;
|
||||
select * from rtest_vview4;
|
||||
select * from rtest_vview5;
|
||||
|
||||
insert into rtest_view3 select * from rtest_vview1 where a < 7;
|
||||
select * from rtest_view3;
|
||||
delete from rtest_view3;
|
||||
|
||||
insert into rtest_view3 select * from rtest_vview2 where a != 5 and b !~ '2';
|
||||
select * from rtest_view3;
|
||||
delete from rtest_view3;
|
||||
|
||||
insert into rtest_view3 select * from rtest_vview3;
|
||||
select * from rtest_view3;
|
||||
delete from rtest_view3;
|
||||
|
||||
insert into rtest_view4 select * from rtest_vview4 where 3 > refcount;
|
||||
select * from rtest_view4;
|
||||
delete from rtest_view4;
|
||||
|
||||
insert into rtest_view4 select * from rtest_vview5 where a > 2 and refcount = 0;
|
||||
select * from rtest_view4;
|
||||
delete from rtest_view4;
|
||||
--
|
||||
-- Test for computations in views
|
||||
--
|
||||
create table rtest_comp (
|
||||
part text,
|
||||
unit char(4),
|
||||
size float
|
||||
);
|
||||
|
||||
|
||||
create table rtest_unitfact (
|
||||
unit char(4),
|
||||
factor float
|
||||
);
|
||||
|
||||
create view rtest_vcomp as
|
||||
select X.part, (X.size * Y.factor) as size_in_cm
|
||||
from rtest_comp X, rtest_unitfact Y
|
||||
where X.unit = Y.unit;
|
||||
|
||||
|
||||
insert into rtest_unitfact values ('m', 100.0);
|
||||
insert into rtest_unitfact values ('cm', 1.0);
|
||||
insert into rtest_unitfact values ('inch', 2.54);
|
||||
|
||||
insert into rtest_comp values ('p1', 'm', 5.0);
|
||||
insert into rtest_comp values ('p2', 'm', 3.0);
|
||||
insert into rtest_comp values ('p3', 'cm', 5.0);
|
||||
insert into rtest_comp values ('p4', 'cm', 15.0);
|
||||
insert into rtest_comp values ('p5', 'inch', 7.0);
|
||||
insert into rtest_comp values ('p6', 'inch', 4.4);
|
||||
|
||||
select * from rtest_vcomp order by part;
|
||||
|
||||
select * from rtest_vcomp where size_in_cm > 10.0 order by size_in_cm using >;
|
||||
|
Loading…
x
Reference in New Issue
Block a user