Commit cd243d27 authored by Tom Lane's avatar Tom Lane

Revise rule-printing routines to use expandable StringInfo buffers, so that

they have no hardwired limit on the length of a rule's text.  Fix a couple
of minor bugs in passing --- deparsed UPDATE queries didn't have quotes
around relation name, and quotes and backslashes in constant values weren't
backslash-quoted.
parent 4e907385
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* out of it's tuple * out of it's tuple
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.25 1999/09/02 03:04:04 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.26 1999/10/02 01:07:51 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "postgres.h" #include "postgres.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "lib/stringinfo.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/tlist.h" #include "optimizer/tlist.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -47,7 +48,6 @@ ...@@ -47,7 +48,6 @@
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#define BUFSIZE 8192
/* ---------- /* ----------
* Local data types * Local data types
...@@ -92,21 +92,29 @@ NameData *pg_get_userbyid(int4 uid); ...@@ -92,21 +92,29 @@ NameData *pg_get_userbyid(int4 uid);
/* ---------- /* ----------
* Local functions * Local functions
*
* Most of these functions used to use fixed-size buffers to build their
* results. Now, they take an (already initialized) StringInfo object
* as a parameter, and append their text output to its contents.
* ---------- * ----------
*/ */
static char *make_ruledef(HeapTuple ruletup, TupleDesc rulettc); static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
static char *make_viewdef(HeapTuple ruletup, TupleDesc rulettc); static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
static char *get_query_def(Query *query, QryHier *parentqh); static void get_query_def(StringInfo buf, Query *query, QryHier *parentqh);
static char *get_select_query_def(Query *query, QryHier *qh); static void get_select_query_def(StringInfo buf, Query *query, QryHier *qh);
static char *get_insert_query_def(Query *query, QryHier *qh); static void get_insert_query_def(StringInfo buf, Query *query, QryHier *qh);
static char *get_update_query_def(Query *query, QryHier *qh); static void get_update_query_def(StringInfo buf, Query *query, QryHier *qh);
static char *get_delete_query_def(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 RangeTblEntry *get_rte_for_var(Var *var, QryHier *qh);
static char *get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix); static void get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
static char *get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix); Node *node, bool varprefix);
static char *get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix); static void get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
static char *get_const_expr(Const *constval); Expr *expr, bool varprefix);
static char *get_sublink_expr(QryHier *qh, int rt_index, Node *node, 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 char *get_relation_name(Oid relid); static char *get_relation_name(Oid relid);
static char *get_attribute_name(Oid relid, int2 attnum); static char *get_attribute_name(Oid relid, int2 attnum);
static bool check_if_rte_used(Node *node, Index rt_index, int levelsup); static bool check_if_rte_used(Node *node, Index rt_index, int levelsup);
...@@ -129,7 +137,7 @@ pg_get_ruledef(NameData *rname) ...@@ -129,7 +137,7 @@ pg_get_ruledef(NameData *rname)
int spirc; int spirc;
HeapTuple ruletup; HeapTuple ruletup;
TupleDesc rulettc; TupleDesc rulettc;
char *tmp; StringInfoData buf;
int len; int len;
/* ---------- /* ----------
...@@ -190,11 +198,13 @@ pg_get_ruledef(NameData *rname) ...@@ -190,11 +198,13 @@ pg_get_ruledef(NameData *rname)
* Get the rules definition and put it into executors memory * Get the rules definition and put it into executors memory
* ---------- * ----------
*/ */
tmp = make_ruledef(ruletup, rulettc); initStringInfo(&buf);
len = strlen(tmp) + VARHDRSZ; make_ruledef(&buf, ruletup, rulettc);
len = buf.len + VARHDRSZ;
ruledef = SPI_palloc(len); ruledef = SPI_palloc(len);
VARSIZE(ruledef) = len; VARSIZE(ruledef) = len;
memcpy(VARDATA(ruledef), tmp, len - VARHDRSZ); memcpy(VARDATA(ruledef), buf.data, buf.len);
pfree(buf.data);
/* ---------- /* ----------
* Disconnect from SPI manager * Disconnect from SPI manager
...@@ -225,7 +235,7 @@ pg_get_viewdef(NameData *rname) ...@@ -225,7 +235,7 @@ pg_get_viewdef(NameData *rname)
int spirc; int spirc;
HeapTuple ruletup; HeapTuple ruletup;
TupleDesc rulettc; TupleDesc rulettc;
char *tmp; StringInfoData buf;
int len; int len;
char name1[NAMEDATALEN + 5]; char name1[NAMEDATALEN + 5];
char name2[NAMEDATALEN + 5]; char name2[NAMEDATALEN + 5];
...@@ -276,8 +286,9 @@ pg_get_viewdef(NameData *rname) ...@@ -276,8 +286,9 @@ pg_get_viewdef(NameData *rname)
spirc = SPI_execp(plan_getview, args, nulls, 1); spirc = SPI_execp(plan_getview, args, nulls, 1);
if (spirc != SPI_OK_SELECT) if (spirc != SPI_OK_SELECT)
elog(ERROR, "failed to get pg_rewrite tuple for view %s", rulename); elog(ERROR, "failed to get pg_rewrite tuple for view %s", rulename);
initStringInfo(&buf);
if (SPI_processed != 1) if (SPI_processed != 1)
tmp = "Not a view"; appendStringInfo(&buf, "Not a view");
else else
{ {
/* ---------- /* ----------
...@@ -286,12 +297,13 @@ pg_get_viewdef(NameData *rname) ...@@ -286,12 +297,13 @@ pg_get_viewdef(NameData *rname)
*/ */
ruletup = SPI_tuptable->vals[0]; ruletup = SPI_tuptable->vals[0];
rulettc = SPI_tuptable->tupdesc; rulettc = SPI_tuptable->tupdesc;
tmp = make_viewdef(ruletup, rulettc); make_viewdef(&buf, ruletup, rulettc);
} }
len = strlen(tmp) + VARHDRSZ; len = buf.len + VARHDRSZ;
ruledef = SPI_palloc(len); ruledef = SPI_palloc(len);
VARSIZE(ruledef) = len; VARSIZE(ruledef) = len;
memcpy(VARDATA(ruledef), tmp, len - VARHDRSZ); memcpy(VARDATA(ruledef), buf.data, buf.len);
pfree(buf.data);
/* ---------- /* ----------
* Disconnect from SPI manager * Disconnect from SPI manager
...@@ -309,8 +321,7 @@ pg_get_viewdef(NameData *rname) ...@@ -309,8 +321,7 @@ pg_get_viewdef(NameData *rname)
/* ---------- /* ----------
* get_viewdef - Mainly the same thing, but we * get_indexdef - Get the definition of an index
* only return the SELECT part of a view
* ---------- * ----------
*/ */
text * text *
...@@ -331,8 +342,8 @@ pg_get_indexdef(Oid indexrelid) ...@@ -331,8 +342,8 @@ pg_get_indexdef(Oid indexrelid)
int spirc; int spirc;
int len; int len;
int keyno; int keyno;
char buf[BUFSIZE]; StringInfoData buf;
char keybuf[BUFSIZE]; StringInfoData keybuf;
char *sep; char *sep;
/* ---------- /* ----------
...@@ -415,37 +426,37 @@ pg_get_indexdef(Oid indexrelid) ...@@ -415,37 +426,37 @@ pg_get_indexdef(Oid indexrelid)
* Start the index definition * Start the index definition
* ---------- * ----------
*/ */
sprintf(buf, "CREATE %sINDEX \"%s\" ON \"%s\" USING %s (", initStringInfo(&buf);
idxrec->indisunique ? "UNIQUE " : "", appendStringInfo(&buf, "CREATE %sINDEX \"%s\" ON \"%s\" USING %s (",
nameout(&(idxrelrec->relname)), idxrec->indisunique ? "UNIQUE " : "",
nameout(&(indrelrec->relname)), nameout(&(idxrelrec->relname)),
SPI_getvalue(spi_tup, spi_ttc, spi_fno)); nameout(&(indrelrec->relname)),
SPI_getvalue(spi_tup, spi_ttc, spi_fno));
/* ---------- /* ----------
* Collect the indexed attributes * Collect the indexed attributes
* ---------- * ----------
*/ */
initStringInfo(&keybuf);
sep = ""; sep = "";
keybuf[0] = '\0';
for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++) for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)
{ {
if (idxrec->indkey[keyno] == InvalidAttrNumber) if (idxrec->indkey[keyno] == InvalidAttrNumber)
break; break;
strcat(keybuf, sep); appendStringInfo(&keybuf, sep);
sep = ", "; sep = ", ";
/* ---------- /* ----------
* Add the indexed field name * Add the indexed field name
* ---------- * ----------
*/ */
strcat(keybuf, "\"");
if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1) if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1)
strcat(keybuf, "oid"); appendStringInfo(&keybuf, "\"oid\"");
else else
strcat(keybuf, get_attribute_name(idxrec->indrelid, appendStringInfo(&keybuf, "\"%s\"",
idxrec->indkey[keyno])); get_attribute_name(idxrec->indrelid,
strcat(keybuf, "\""); idxrec->indkey[keyno]));
/* ---------- /* ----------
* If not a functional index, add the operator class name * If not a functional index, add the operator class name
...@@ -464,9 +475,8 @@ pg_get_indexdef(Oid indexrelid) ...@@ -464,9 +475,8 @@ pg_get_indexdef(Oid indexrelid)
spi_tup = SPI_tuptable->vals[0]; spi_tup = SPI_tuptable->vals[0];
spi_ttc = SPI_tuptable->tupdesc; spi_ttc = SPI_tuptable->tupdesc;
spi_fno = SPI_fnumber(spi_ttc, "opcname"); spi_fno = SPI_fnumber(spi_ttc, "opcname");
strcat(keybuf, " \""); appendStringInfo(&keybuf, " \"%s\"",
strcat(keybuf, SPI_getvalue(spi_tup, spi_ttc, spi_fno)); SPI_getvalue(spi_tup, spi_ttc, spi_fno));
strcat(keybuf, "\"");
} }
} }
...@@ -485,11 +495,9 @@ pg_get_indexdef(Oid indexrelid) ...@@ -485,11 +495,9 @@ pg_get_indexdef(Oid indexrelid)
elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc); elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
procStruct = (Form_pg_proc) GETSTRUCT(proctup); procStruct = (Form_pg_proc) GETSTRUCT(proctup);
strcat(buf, "\""); appendStringInfo(&buf, "\"%s\" (%s) ",
strcat(buf, nameout(&(procStruct->proname))); nameout(&(procStruct->proname)),
strcat(buf, "\" ("); keybuf.data);
strcat(buf, keybuf);
strcat(buf, ") ");
spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]); spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
spi_nulls[0] = ' '; spi_nulls[0] = ' ';
...@@ -502,31 +510,32 @@ pg_get_indexdef(Oid indexrelid) ...@@ -502,31 +510,32 @@ pg_get_indexdef(Oid indexrelid)
spi_tup = SPI_tuptable->vals[0]; spi_tup = SPI_tuptable->vals[0];
spi_ttc = SPI_tuptable->tupdesc; spi_ttc = SPI_tuptable->tupdesc;
spi_fno = SPI_fnumber(spi_ttc, "opcname"); spi_fno = SPI_fnumber(spi_ttc, "opcname");
strcat(buf, "\""); appendStringInfo(&buf, "\"%s\"",
strcat(buf, SPI_getvalue(spi_tup, spi_ttc, spi_fno)); SPI_getvalue(spi_tup, spi_ttc, spi_fno));
strcat(buf, "\"");
} }
else else
/* ---------- /* ----------
* For the others say 'attr opclass [, ...]' * For the others say 'attr opclass [, ...]'
* ---------- * ----------
*/ */
strcat(buf, keybuf); appendStringInfo(&buf, "%s", keybuf.data);
/* ---------- /* ----------
* Finish * Finish
* ---------- * ----------
*/ */
strcat(buf, ")"); appendStringInfo(&buf, ")");
/* ---------- /* ----------
* Create the result in upper executor memory * Create the result in upper executor memory
* ---------- * ----------
*/ */
len = strlen(buf) + VARHDRSZ; len = buf.len + VARHDRSZ;
indexdef = SPI_palloc(len); indexdef = SPI_palloc(len);
VARSIZE(indexdef) = len; VARSIZE(indexdef) = len;
memcpy(VARDATA(indexdef), buf, len - VARHDRSZ); memcpy(VARDATA(indexdef), buf.data, buf.len);
pfree(buf.data);
pfree(keybuf.data);
/* ---------- /* ----------
* Disconnect from SPI manager * Disconnect from SPI manager
...@@ -581,10 +590,9 @@ pg_get_userbyid(int4 uid) ...@@ -581,10 +590,9 @@ pg_get_userbyid(int4 uid)
* for a given pg_rewrite tuple * for a given pg_rewrite tuple
* ---------- * ----------
*/ */
static char * static void
make_ruledef(HeapTuple ruletup, TupleDesc rulettc) make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
{ {
char *buf;
char ev_type; char ev_type;
Oid ev_class; Oid ev_class;
int2 ev_attr; int2 ev_attr;
...@@ -595,12 +603,6 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -595,12 +603,6 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
int fno; int fno;
bool isnull; bool isnull;
/* ----------
* Allocate space for the returned rule definition text
* ----------
*/
buf = palloc(BUFSIZE);
/* ---------- /* ----------
* Get the attribute values from the rules tuple * Get the attribute values from the rules tuple
* ---------- * ----------
...@@ -630,29 +632,25 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -630,29 +632,25 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
* Build the rules definition text * Build the rules definition text
* ---------- * ----------
*/ */
strcpy(buf, "CREATE RULE \""); appendStringInfo(buf, "CREATE RULE \"%s\" AS ON ", rulename);
/* The rule name */
strcat(buf, rulename);
strcat(buf, "\" AS ON ");
/* The event the rule is fired for */ /* The event the rule is fired for */
switch (ev_type) switch (ev_type)
{ {
case '1': case '1':
strcat(buf, "SELECT TO \""); appendStringInfo(buf, "SELECT");
break; break;
case '2': case '2':
strcat(buf, "UPDATE TO \""); appendStringInfo(buf, "UPDATE");
break; break;
case '3': case '3':
strcat(buf, "INSERT TO \""); appendStringInfo(buf, "INSERT");
break; break;
case '4': case '4':
strcat(buf, "DELETE TO \""); appendStringInfo(buf, "DELETE");
break; break;
default: default:
...@@ -662,14 +660,10 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -662,14 +660,10 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
} }
/* The relation the rule is fired on */ /* The relation the rule is fired on */
strcat(buf, get_relation_name(ev_class)); appendStringInfo(buf, " TO \"%s\"", get_relation_name(ev_class));
strcat(buf, "\"");
if (ev_attr > 0) if (ev_attr > 0)
{ appendStringInfo(buf, ".\"%s\"",
strcat(buf, ".\""); get_attribute_name(ev_class, ev_attr));
strcat(buf, get_attribute_name(ev_class, ev_attr));
strcat(buf, "\"");
}
/* If the rule has an event qualification, add it */ /* If the rule has an event qualification, add it */
if (ev_qual == NULL) if (ev_qual == NULL)
...@@ -685,15 +679,15 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -685,15 +679,15 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
qh.parent = NULL; qh.parent = NULL;
qh.query = query; qh.query = query;
strcat(buf, " WHERE "); appendStringInfo(buf, " WHERE ");
strcat(buf, get_rule_expr(&qh, 0, qual, TRUE)); get_rule_expr(buf, &qh, 0, qual, TRUE);
} }
strcat(buf, " DO "); appendStringInfo(buf, " DO ");
/* The INSTEAD keyword (if so) */ /* The INSTEAD keyword (if so) */
if (is_instead) if (is_instead)
strcat(buf, "INSTEAD "); appendStringInfo(buf, "INSTEAD ");
/* Finally the rules actions */ /* Finally the rules actions */
if (length(actions) > 1) if (length(actions) > 1)
...@@ -701,36 +695,30 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -701,36 +695,30 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
List *action; List *action;
Query *query; Query *query;
strcat(buf, "("); appendStringInfo(buf, "(");
foreach(action, actions) foreach(action, actions)
{ {
query = (Query *) lfirst(action); query = (Query *) lfirst(action);
strcat(buf, get_query_def(query, NULL)); get_query_def(buf, query, NULL);
strcat(buf, "; "); appendStringInfo(buf, "; ");
} }
strcat(buf, ");"); appendStringInfo(buf, ");");
} }
else else
{ {
if (length(actions) == 0) if (length(actions) == 0)
{ {
strcat(buf, "NOTHING;"); appendStringInfo(buf, "NOTHING;");
} }
else else
{ {
Query *query; Query *query;
query = (Query *) lfirst(actions); query = (Query *) lfirst(actions);
strcat(buf, get_query_def(query, NULL)); get_query_def(buf, query, NULL);
strcat(buf, ";"); appendStringInfo(buf, ";");
} }
} }
/* ----------
* That's it
* ----------
*/
return buf;
} }
...@@ -739,10 +727,9 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -739,10 +727,9 @@ make_ruledef(HeapTuple ruletup, TupleDesc rulettc)
* view rewrite rule * view rewrite rule
* ---------- * ----------
*/ */
static char * static void
make_viewdef(HeapTuple ruletup, TupleDesc rulettc) make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
{ {
char buf[BUFSIZE];
Query *query; Query *query;
char ev_type; char ev_type;
Oid ev_class; Oid ev_class;
...@@ -779,21 +766,21 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -779,21 +766,21 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
actions = (List *) stringToNode(ev_action); actions = (List *) stringToNode(ev_action);
if (length(actions) != 1) if (length(actions) != 1)
return "Not a view"; {
appendStringInfo(buf, "Not a view");
return;
}
query = (Query *) lfirst(actions); query = (Query *) lfirst(actions);
if (ev_type != '1' || ev_attr >= 0 || !is_instead || strcmp(ev_qual, "<>")) if (ev_type != '1' || ev_attr >= 0 || !is_instead || strcmp(ev_qual, "<>"))
return "Not a view"; {
appendStringInfo(buf, "Not a view");
strcpy(buf, get_query_def(query, NULL)); return;
strcat(buf, ";"); }
/* ---------- get_query_def(buf, query, NULL);
* That's it appendStringInfo(buf, ";");
* ----------
*/
return pstrdup(buf);
} }
...@@ -803,8 +790,8 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc) ...@@ -803,8 +790,8 @@ make_viewdef(HeapTuple ruletup, TupleDesc rulettc)
* list * list
* ---------- * ----------
*/ */
static char * static void
get_query_def(Query *query, QryHier *parentqh) get_query_def(StringInfo buf, Query *query, QryHier *parentqh)
{ {
QryHier qh; QryHier qh;
...@@ -814,23 +801,23 @@ get_query_def(Query *query, QryHier *parentqh) ...@@ -814,23 +801,23 @@ get_query_def(Query *query, QryHier *parentqh)
switch (query->commandType) switch (query->commandType)
{ {
case CMD_SELECT: case CMD_SELECT:
return get_select_query_def(query, &qh); get_select_query_def(buf, query, &qh);
break; break;
case CMD_UPDATE: case CMD_UPDATE:
return get_update_query_def(query, &qh); get_update_query_def(buf, query, &qh);
break; break;
case CMD_INSERT: case CMD_INSERT:
return get_insert_query_def(query, &qh); get_insert_query_def(buf, query, &qh);
break; break;
case CMD_DELETE: case CMD_DELETE:
return get_delete_query_def(query, &qh); get_delete_query_def(buf, query, &qh);
break; break;
case CMD_NOTHING: case CMD_NOTHING:
return "NOTHING"; appendStringInfo(buf, "NOTHING");
break; break;
default: default:
...@@ -838,8 +825,6 @@ get_query_def(Query *query, QryHier *parentqh) ...@@ -838,8 +825,6 @@ get_query_def(Query *query, QryHier *parentqh)
rulename, query->commandType); rulename, query->commandType);
break; break;
} }
return NULL;
} }
...@@ -847,10 +832,9 @@ get_query_def(Query *query, QryHier *parentqh) ...@@ -847,10 +832,9 @@ get_query_def(Query *query, QryHier *parentqh)
* get_select_query_def - Parse back a SELECT parsetree * get_select_query_def - Parse back a SELECT parsetree
* ---------- * ----------
*/ */
static char * static void
get_select_query_def(Query *query, QryHier *qh) get_select_query_def(StringInfo buf, Query *query, QryHier *qh)
{ {
char buf[BUFSIZE];
char *sep; char *sep;
TargetEntry *tle; TargetEntry *tle;
RangeTblEntry *rte; RangeTblEntry *rte;
...@@ -908,7 +892,7 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -908,7 +892,7 @@ get_select_query_def(Query *query, QryHier *qh)
* Build up the query string - first we say SELECT * Build up the query string - first we say SELECT
* ---------- * ----------
*/ */
strcpy(buf, "SELECT"); appendStringInfo(buf, "SELECT");
/* Then we tell what to select (the targetlist) */ /* Then we tell what to select (the targetlist) */
sep = " "; sep = " ";
...@@ -917,10 +901,10 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -917,10 +901,10 @@ get_select_query_def(Query *query, QryHier *qh)
bool tell_as = FALSE; bool tell_as = FALSE;
tle = (TargetEntry *) lfirst(l); tle = (TargetEntry *) lfirst(l);
strcat(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1))); get_tle_expr(buf, qh, 0, tle, (rt_numused > 1));
/* Check if we must say AS ... */ /* Check if we must say AS ... */
if (! IsA(tle->expr, Var)) if (! IsA(tle->expr, Var))
...@@ -938,17 +922,13 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -938,17 +922,13 @@ get_select_query_def(Query *query, QryHier *qh)
/* and do if so */ /* and do if so */
if (tell_as) if (tell_as)
{ appendStringInfo(buf, " AS \"%s\"", tle->resdom->resname);
strcat(buf, " AS \"");
strcat(buf, tle->resdom->resname);
strcat(buf, "\"");
}
} }
/* If we need other tables that *NEW* or *CURRENT* add the FROM clause */ /* If we need other tables that *NEW* or *CURRENT* add the FROM clause */
if (!rt_constonly && rt_numused > 0) if (!rt_constonly && rt_numused > 0)
{ {
strcat(buf, " FROM"); appendStringInfo(buf, " FROM");
i = 0; i = 0;
sep = " "; sep = " ";
...@@ -964,17 +944,11 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -964,17 +944,11 @@ get_select_query_def(Query *query, QryHier *qh)
if (!strcmp(rte->refname, "*CURRENT*")) if (!strcmp(rte->refname, "*CURRENT*"))
continue; continue;
strcat(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
strcat(buf, "\""); appendStringInfo(buf, "\"%s\"", rte->relname);
strcat(buf, rte->relname);
strcat(buf, "\"");
if (strcmp(rte->relname, rte->refname) != 0) if (strcmp(rte->relname, rte->refname) != 0)
{ appendStringInfo(buf, " \"%s\"", rte->refname);
strcat(buf, " \"");
strcat(buf, rte->refname);
strcat(buf, "\"");
}
} }
} }
} }
...@@ -982,14 +956,14 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -982,14 +956,14 @@ get_select_query_def(Query *query, QryHier *qh)
/* Add the WHERE clause if given */ /* Add the WHERE clause if given */
if (query->qual != NULL) if (query->qual != NULL)
{ {
strcat(buf, " WHERE "); appendStringInfo(buf, " WHERE ");
strcat(buf, get_rule_expr(qh, 0, query->qual, (rt_numused > 1))); get_rule_expr(buf, qh, 0, query->qual, (rt_numused > 1));
} }
/* Add the GROUP BY CLAUSE */ /* Add the GROUP BY CLAUSE */
if (query->groupClause != NULL) if (query->groupClause != NULL)
{ {
strcat(buf, " GROUP BY "); appendStringInfo(buf, " GROUP BY ");
sep = ""; sep = "";
foreach(l, query->groupClause) foreach(l, query->groupClause)
{ {
...@@ -998,17 +972,11 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -998,17 +972,11 @@ get_select_query_def(Query *query, QryHier *qh)
groupexpr = get_sortgroupclause_expr(grp, groupexpr = get_sortgroupclause_expr(grp,
query->targetList); query->targetList);
strcat(buf, sep); appendStringInfo(buf, sep);
strcat(buf, get_rule_expr(qh, 0, groupexpr, (rt_numused > 1))); get_rule_expr(buf, qh, 0, groupexpr, (rt_numused > 1));
sep = ", "; sep = ", ";
} }
} }
/* ----------
* Copy the query string into allocated space and return it
* ----------
*/
return pstrdup(buf);
} }
...@@ -1016,10 +984,9 @@ get_select_query_def(Query *query, QryHier *qh) ...@@ -1016,10 +984,9 @@ get_select_query_def(Query *query, QryHier *qh)
* get_insert_query_def - Parse back an INSERT parsetree * get_insert_query_def - Parse back an INSERT parsetree
* ---------- * ----------
*/ */
static char * static void
get_insert_query_def(Query *query, QryHier *qh) get_insert_query_def(StringInfo buf, Query *query, QryHier *qh)
{ {
char buf[BUFSIZE];
char *sep; char *sep;
TargetEntry *tle; TargetEntry *tle;
RangeTblEntry *rte; RangeTblEntry *rte;
...@@ -1072,9 +1039,7 @@ get_insert_query_def(Query *query, QryHier *qh) ...@@ -1072,9 +1039,7 @@ get_insert_query_def(Query *query, QryHier *qh)
* ---------- * ----------
*/ */
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable);
strcpy(buf, "INSERT INTO \""); appendStringInfo(buf, "INSERT INTO \"%s\"", rte->relname);
strcat(buf, rte->relname);
strcat(buf, "\"");
/* Add the target list */ /* Add the target list */
sep = " ("; sep = " (";
...@@ -1082,37 +1047,29 @@ get_insert_query_def(Query *query, QryHier *qh) ...@@ -1082,37 +1047,29 @@ get_insert_query_def(Query *query, QryHier *qh)
{ {
tle = (TargetEntry *) lfirst(l); tle = (TargetEntry *) lfirst(l);
strcat(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
strcat(buf, "\""); appendStringInfo(buf, "\"%s\"", tle->resdom->resname);
strcat(buf, tle->resdom->resname);
strcat(buf, "\"");
} }
strcat(buf, ") "); appendStringInfo(buf, ") ");
/* Add the VALUES or the SELECT */ /* Add the VALUES or the SELECT */
if (rt_constonly && query->qual == NULL) if (rt_constonly && query->qual == NULL)
{ {
strcat(buf, "VALUES ("); appendStringInfo(buf, "VALUES (");
sep = ""; sep = "";
foreach(l, query->targetList) foreach(l, query->targetList)
{ {
tle = (TargetEntry *) lfirst(l); tle = (TargetEntry *) lfirst(l);
strcat(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
strcat(buf, get_tle_expr(qh, 0, tle, (rt_numused > 1))); get_tle_expr(buf, qh, 0, tle, (rt_numused > 1));
} }
strcat(buf, ")"); appendStringInfo(buf, ")");
} }
else else
strcat(buf, get_select_query_def(query, qh)); get_select_query_def(buf, query, qh);
/* ----------
* Copy the query string into allocated space and return it
* ----------
*/
return pstrdup(buf);
} }
...@@ -1120,10 +1077,9 @@ get_insert_query_def(Query *query, QryHier *qh) ...@@ -1120,10 +1077,9 @@ get_insert_query_def(Query *query, QryHier *qh)
* get_update_query_def - Parse back an UPDATE parsetree * get_update_query_def - Parse back an UPDATE parsetree
* ---------- * ----------
*/ */
static char * static void
get_update_query_def(Query *query, QryHier *qh) get_update_query_def(StringInfo buf, Query *query, QryHier *qh)
{ {
char buf[BUFSIZE];
char *sep; char *sep;
TargetEntry *tle; TargetEntry *tle;
RangeTblEntry *rte; RangeTblEntry *rte;
...@@ -1134,9 +1090,7 @@ get_update_query_def(Query *query, QryHier *qh) ...@@ -1134,9 +1090,7 @@ get_update_query_def(Query *query, QryHier *qh)
* ---------- * ----------
*/ */
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable);
strcpy(buf, "UPDATE "); appendStringInfo(buf, "UPDATE \"%s\" SET ", rte->relname);
strcat(buf, rte->relname);
strcat(buf, " SET ");
/* Add the comma separated list of 'attname = value' */ /* Add the comma separated list of 'attname = value' */
sep = ""; sep = "";
...@@ -1144,28 +1098,18 @@ get_update_query_def(Query *query, QryHier *qh) ...@@ -1144,28 +1098,18 @@ get_update_query_def(Query *query, QryHier *qh)
{ {
tle = (TargetEntry *) lfirst(l); tle = (TargetEntry *) lfirst(l);
strcat(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
strcat(buf, "\""); appendStringInfo(buf, "\"%s\" = ", tle->resdom->resname);
strcat(buf, tle->resdom->resname); get_tle_expr(buf, qh, query->resultRelation, tle, TRUE);
strcat(buf, "\" = ");
strcat(buf, get_tle_expr(qh, query->resultRelation,
tle, TRUE));
} }
/* Finally add a WHERE clause if given */ /* Finally add a WHERE clause if given */
if (query->qual != NULL) if (query->qual != NULL)
{ {
strcat(buf, " WHERE "); appendStringInfo(buf, " WHERE ");
strcat(buf, get_rule_expr(qh, query->resultRelation, get_rule_expr(buf, qh, query->resultRelation, query->qual, TRUE);
query->qual, TRUE));
} }
/* ----------
* Copy the query string into allocated space and return it
* ----------
*/
return pstrdup(buf);
} }
...@@ -1173,10 +1117,9 @@ get_update_query_def(Query *query, QryHier *qh) ...@@ -1173,10 +1117,9 @@ get_update_query_def(Query *query, QryHier *qh)
* get_delete_query_def - Parse back a DELETE parsetree * get_delete_query_def - Parse back a DELETE parsetree
* ---------- * ----------
*/ */
static char * static void
get_delete_query_def(Query *query, QryHier *qh) get_delete_query_def(StringInfo buf, Query *query, QryHier *qh)
{ {
char buf[BUFSIZE];
RangeTblEntry *rte; RangeTblEntry *rte;
/* ---------- /* ----------
...@@ -1184,22 +1127,14 @@ get_delete_query_def(Query *query, QryHier *qh) ...@@ -1184,22 +1127,14 @@ get_delete_query_def(Query *query, QryHier *qh)
* ---------- * ----------
*/ */
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable);
strcpy(buf, "DELETE FROM \""); appendStringInfo(buf, "DELETE FROM \"%s\"", rte->relname);
strcat(buf, rte->relname);
strcat(buf, "\"");
/* Add a WHERE clause if given */ /* Add a WHERE clause if given */
if (query->qual != NULL) if (query->qual != NULL)
{ {
strcat(buf, " WHERE "); appendStringInfo(buf, " WHERE ");
strcat(buf, get_rule_expr(qh, 0, query->qual, FALSE)); get_rule_expr(buf, qh, 0, query->qual, FALSE);
} }
/* ----------
* Copy the query string into allocated space and return it
* ----------
*/
return pstrdup(buf);
} }
/* /*
...@@ -1221,28 +1156,26 @@ get_rte_for_var(Var *var, QryHier *qh) ...@@ -1221,28 +1156,26 @@ get_rte_for_var(Var *var, QryHier *qh)
* get_rule_expr - Parse back an expression * get_rule_expr - Parse back an expression
* ---------- * ----------
*/ */
static char * static void
get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) get_rule_expr(StringInfo buf, QryHier *qh, int rt_index,
Node *node, bool varprefix)
{ {
char buf[BUFSIZE];
if (node == NULL) if (node == NULL)
return pstrdup(""); return;
buf[0] = '\0';
/* ---------- /* ----------
* Each level of get_rule_expr must return an indivisible term * Each level of get_rule_expr must emit an indivisible term
* (parenthesized if necessary) to ensure result is reparsed into * (parenthesized if necessary) to ensure result is reparsed into
* the same expression tree. * the same expression tree.
* *
* There might be some work left here to support additional node types... * There might be some work left here to support additional node types.
* Can we ever see Param nodes here?
* ---------- * ----------
*/ */
switch (nodeTag(node)) switch (nodeTag(node))
{ {
case T_Const: case T_Const:
return get_const_expr((Const *) node); get_const_expr(buf, (Const *) node);
break; break;
case T_Var: case T_Var:
...@@ -1251,20 +1184,14 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1251,20 +1184,14 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
RangeTblEntry *rte = get_rte_for_var(var, qh); RangeTblEntry *rte = get_rte_for_var(var, qh);
if (!strcmp(rte->refname, "*NEW*")) if (!strcmp(rte->refname, "*NEW*"))
strcat(buf, "new."); appendStringInfo(buf, "new.");
else if (!strcmp(rte->refname, "*CURRENT*")) else if (!strcmp(rte->refname, "*CURRENT*"))
strcat(buf, "old."); appendStringInfo(buf, "old.");
else else
{ appendStringInfo(buf, "\"%s\".", rte->refname);
strcat(buf, "\""); appendStringInfo(buf, "\"%s\"",
strcat(buf, rte->refname); get_attribute_name(rte->relid,
strcat(buf, "\"."); var->varattno));
}
strcat(buf, "\"");
strcat(buf, get_attribute_name(rte->relid, var->varattno));
strcat(buf, "\"");
return pstrdup(buf);
} }
break; break;
...@@ -1280,22 +1207,18 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1280,22 +1207,18 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
switch (expr->opType) switch (expr->opType)
{ {
case OP_EXPR: case OP_EXPR:
strcat(buf, "("); appendStringInfo(buf, "(");
if (length(args) == 2) if (length(args) == 2)
{ {
/* binary operator */ /* binary operator */
strcat(buf, get_rule_expr(buf, qh, rt_index,
get_rule_expr(qh, rt_index, (Node *) lfirst(args),
(Node *) lfirst(args), varprefix);
varprefix)); appendStringInfo(buf, " %s ",
strcat(buf, " "); get_opname(((Oper *) expr->oper)->opno));
strcat(buf, get_rule_expr(buf, qh, rt_index,
get_opname(((Oper *) expr->oper)->opno)); (Node *) lsecond(args),
strcat(buf, " "); varprefix);
strcat(buf,
get_rule_expr(qh, rt_index,
(Node *) lsecond(args),
varprefix));
} }
else else
{ {
...@@ -1312,82 +1235,76 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1312,82 +1235,76 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
switch (optup->oprkind) switch (optup->oprkind)
{ {
case 'l': case 'l':
strcat(buf, get_opname(opno)); appendStringInfo(buf, "%s ",
strcat(buf, " "); get_opname(opno));
strcat(buf, get_rule_expr(buf, qh, rt_index,
get_rule_expr(qh, rt_index, (Node *) lfirst(args),
(Node *) lfirst(args), varprefix);
varprefix));
break; break;
case 'r': case 'r':
strcat(buf, get_rule_expr(buf, qh, rt_index,
get_rule_expr(qh, rt_index, (Node *) lfirst(args),
(Node *) lfirst(args), varprefix);
varprefix)); appendStringInfo(buf, " %s",
strcat(buf, " "); get_opname(opno));
strcat(buf, get_opname(opno));
break; break;
default: default:
elog(ERROR, "get_rule_expr: bogus oprkind"); elog(ERROR, "get_rule_expr: bogus oprkind");
} }
} }
strcat(buf, ")"); appendStringInfo(buf, ")");
return pstrdup(buf);
break; break;
case OR_EXPR: case OR_EXPR:
strcat(buf, "("); appendStringInfo(buf, "(");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
(Node *) lfirst(args), (Node *) lfirst(args),
varprefix)); varprefix);
/* It's not clear that we can ever see N-argument /* It's not clear that we can ever see N-argument
* OR/AND clauses here, but might as well cope... * OR/AND clauses here, but might as well cope...
*/ */
while ((args = lnext(args)) != NIL) while ((args = lnext(args)) != NIL)
{ {
strcat(buf, " OR "); appendStringInfo(buf, " OR ");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
(Node *) lfirst(args), (Node *) lfirst(args),
varprefix)); varprefix);
} }
strcat(buf, ")"); appendStringInfo(buf, ")");
return pstrdup(buf);
break; break;
case AND_EXPR: case AND_EXPR:
strcat(buf, "("); appendStringInfo(buf, "(");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
(Node *) lfirst(args), (Node *) lfirst(args),
varprefix)); varprefix);
while ((args = lnext(args)) != NIL) while ((args = lnext(args)) != NIL)
{ {
strcat(buf, " AND "); appendStringInfo(buf, " AND ");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
(Node *) lfirst(args), (Node *) lfirst(args),
varprefix)); varprefix);
} }
strcat(buf, ")"); appendStringInfo(buf, ")");
return pstrdup(buf);
break; break;
case NOT_EXPR: case NOT_EXPR:
strcat(buf, "(NOT "); appendStringInfo(buf, "(NOT ");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
(Node *) get_leftop(expr), (Node *) lfirst(args),
varprefix)); varprefix);
strcat(buf, ")"); appendStringInfo(buf, ")");
return pstrdup(buf);
break; break;
case FUNC_EXPR: case FUNC_EXPR:
return get_func_expr(qh, rt_index, get_func_expr(buf, qh, rt_index,
(Expr *) node, (Expr *) node,
varprefix); varprefix);
break; break;
default: default:
printf("\n%s\n", nodeToString(node)); elog(ERROR, "get_rule_expr: expr opType %d not supported",
elog(ERROR, "get_rule_expr: expr type not supported"); expr->opType);
} }
} }
break; break;
...@@ -1396,43 +1313,44 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1396,43 +1313,44 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
{ {
Aggref *aggref = (Aggref *) node; Aggref *aggref = (Aggref *) node;
strcat(buf, "\""); appendStringInfo(buf, "\"%s\"(", aggref->aggname);
strcat(buf, aggref->aggname); get_rule_expr(buf, qh, rt_index,
strcat(buf, "\"("); (Node *) (aggref->target), varprefix);
strcat(buf, get_rule_expr(qh, rt_index, appendStringInfo(buf, ")");
(Node *) (aggref->target), varprefix));
strcat(buf, ")");
return pstrdup(buf);
} }
break; break;
case T_Iter:
get_rule_expr(buf, qh, rt_index,
((Iter *) node)->iterexpr, varprefix);
break;
case T_ArrayRef: case T_ArrayRef:
{ {
ArrayRef *aref = (ArrayRef *) node; ArrayRef *aref = (ArrayRef *) node;
List *lowlist; List *lowlist;
List *uplist; List *uplist;
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
aref->refexpr, varprefix)); aref->refexpr, varprefix);
lowlist = aref->reflowerindexpr; lowlist = aref->reflowerindexpr;
foreach(uplist, aref->refupperindexpr) foreach(uplist, aref->refupperindexpr)
{ {
strcat(buf, "["); appendStringInfo(buf, "[");
if (lowlist) if (lowlist)
{ {
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
(Node *) lfirst(lowlist), (Node *) lfirst(lowlist),
varprefix)); varprefix);
strcat(buf, ":"); appendStringInfo(buf, ":");
lowlist = lnext(lowlist); lowlist = lnext(lowlist);
} }
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
(Node *) lfirst(uplist), (Node *) lfirst(uplist),
varprefix)); varprefix);
strcat(buf, "]"); appendStringInfo(buf, "]");
} }
/* XXX need to do anything with refassgnexpr? */ /* XXX need to do anything with refassgnexpr? */
return pstrdup(buf);
} }
break; break;
...@@ -1441,28 +1359,27 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1441,28 +1359,27 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
CaseExpr *caseexpr = (CaseExpr *) node; CaseExpr *caseexpr = (CaseExpr *) node;
List *temp; List *temp;
strcat(buf, "CASE"); appendStringInfo(buf, "CASE");
foreach(temp, caseexpr->args) foreach(temp, caseexpr->args)
{ {
CaseWhen *when = (CaseWhen *) lfirst(temp); CaseWhen *when = (CaseWhen *) lfirst(temp);
strcat(buf, " WHEN "); appendStringInfo(buf, " WHEN ");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
when->expr, varprefix)); when->expr, varprefix);
strcat(buf, " THEN "); appendStringInfo(buf, " THEN ");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
when->result, varprefix)); when->result, varprefix);
} }
strcat(buf, " ELSE "); appendStringInfo(buf, " ELSE ");
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index,
caseexpr->defresult, varprefix)); caseexpr->defresult, varprefix);
strcat(buf, " END"); appendStringInfo(buf, " END");
return pstrdup(buf);
} }
break; break;
case T_SubLink: case T_SubLink:
return get_sublink_expr(qh, rt_index, node, varprefix); get_sublink_expr(buf, qh, rt_index, node, varprefix);
break; break;
default: default:
...@@ -1471,8 +1388,6 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1471,8 +1388,6 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
rulename, nodeTag(node)); rulename, nodeTag(node));
break; break;
} }
return FALSE;
} }
...@@ -1480,10 +1395,10 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) ...@@ -1480,10 +1395,10 @@ get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
* get_func_expr - Parse back a Func node * get_func_expr - Parse back a Func node
* ---------- * ----------
*/ */
static char * static void
get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix) get_func_expr(StringInfo buf, QryHier *qh, int rt_index,
Expr *expr, bool varprefix)
{ {
char buf[BUFSIZE];
HeapTuple proctup; HeapTuple proctup;
Form_pg_proc procStruct; Form_pg_proc procStruct;
List *l; List *l;
...@@ -1503,23 +1418,24 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix) ...@@ -1503,23 +1418,24 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix)
procStruct = (Form_pg_proc) GETSTRUCT(proctup); procStruct = (Form_pg_proc) GETSTRUCT(proctup);
proname = nameout(&(procStruct->proname)); proname = nameout(&(procStruct->proname));
/*
* nullvalue() and nonnullvalue() should get turned into special syntax
*/
if (procStruct->pronargs == 1 && procStruct->proargtypes[0] == InvalidOid) if (procStruct->pronargs == 1 && procStruct->proargtypes[0] == InvalidOid)
{ {
if (!strcmp(proname, "nullvalue")) if (!strcmp(proname, "nullvalue"))
{ {
strcpy(buf, "("); appendStringInfo(buf, "(");
strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args), get_rule_expr(buf, qh, rt_index, lfirst(expr->args), varprefix);
varprefix)); appendStringInfo(buf, " ISNULL)");
strcat(buf, " ISNULL)"); return;
return pstrdup(buf);
} }
if (!strcmp(proname, "nonnullvalue")) if (!strcmp(proname, "nonnullvalue"))
{ {
strcpy(buf, "("); appendStringInfo(buf, "(");
strcat(buf, get_rule_expr(qh, rt_index, lfirst(expr->args), get_rule_expr(buf, qh, rt_index, lfirst(expr->args), varprefix);
varprefix)); appendStringInfo(buf, " NOTNULL)");
strcat(buf, " NOTNULL)"); return;
return pstrdup(buf);
} }
} }
...@@ -1527,40 +1443,31 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix) ...@@ -1527,40 +1443,31 @@ get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix)
* Build a string of proname(args) * Build a string of proname(args)
* ---------- * ----------
*/ */
strcpy(buf, "\""); appendStringInfo(buf, "\"%s\"(", proname);
strcat(buf, proname);
strcat(buf, "\"(");
sep = ""; sep = "";
foreach(l, expr->args) foreach(l, expr->args)
{ {
strcat(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
strcat(buf, get_rule_expr(qh, rt_index, lfirst(l), varprefix)); get_rule_expr(buf, qh, rt_index, lfirst(l), varprefix);
} }
strcat(buf, ")"); appendStringInfo(buf, ")");
/* ----------
* Copy the function call string into allocated space and return it
* ----------
*/
return pstrdup(buf);
} }
/* ---------- /* ----------
* get_tle_expr - A target list expression is a bit * get_tle_expr
* different from a normal expression. *
* If the target column has an * A target list expression is a bit different from a normal expression.
* an atttypmod, the parser usually * If the target column has an atttypmod, the parser usually puts a
* puts a padding-/cut-function call * padding-/cut-function call around the expression itself.
* around the expression itself. We * We must get rid of it, otherwise dump/reload/dump... would blow up
* we must get rid of it, otherwise * the expressions.
* dump/reload/dump... would blow up
* the expressions.
* ---------- * ----------
*/ */
static char * static void
get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) get_tle_expr(StringInfo buf, QryHier *qh, int rt_index,
TargetEntry *tle, bool varprefix)
{ {
Expr *expr = (Expr *) (tle->expr); Expr *expr = (Expr *) (tle->expr);
Func *func; Func *func;
...@@ -1577,7 +1484,10 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) ...@@ -1577,7 +1484,10 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
if (tle->resdom->restypmod < 0 || if (tle->resdom->restypmod < 0 ||
! IsA(expr, Expr) || ! IsA(expr, Expr) ||
expr->opType != FUNC_EXPR) expr->opType != FUNC_EXPR)
return get_rule_expr(qh, rt_index, tle->expr, varprefix); {
get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
return;
}
func = (Func *) (expr->oper); func = (Func *) (expr->oper);
...@@ -1600,7 +1510,10 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) ...@@ -1600,7 +1510,10 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
if (procStruct->pronargs != 2 || if (procStruct->pronargs != 2 ||
procStruct->prorettype != procStruct->proargtypes[0] || procStruct->prorettype != procStruct->proargtypes[0] ||
procStruct->proargtypes[1] != INT4OID) procStruct->proargtypes[1] != INT4OID)
return get_rule_expr(qh, rt_index, tle->expr, varprefix); {
get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
return;
}
/* /*
* Furthermore, the name of the function must be the same * Furthermore, the name of the function must be the same
...@@ -1615,47 +1528,57 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix) ...@@ -1615,47 +1528,57 @@ get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix)
typeStruct = (Form_pg_type) GETSTRUCT(tup); typeStruct = (Form_pg_type) GETSTRUCT(tup);
if (strncmp(procStruct->proname.data, typeStruct->typname.data, if (strncmp(procStruct->proname.data, typeStruct->typname.data,
NAMEDATALEN) != 0) NAMEDATALEN) != 0)
return get_rule_expr(qh, rt_index, tle->expr, varprefix); {
get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
return;
}
/* ---------- /* ----------
* Finally (to be totally safe) the second argument must be a * Finally (to be totally safe) the second argument must be a
* const and match the value in the results atttypmod. * const and match the value in the results atttypmod.
* ---------- * ----------
*/ */
second_arg = (Const *) nth(1, expr->args); second_arg = (Const *) lsecond(expr->args);
if (! IsA(second_arg, Const) || if (! IsA(second_arg, Const) ||
((int4) second_arg->constvalue) != tle->resdom->restypmod) DatumGetInt32(second_arg->constvalue) != tle->resdom->restypmod)
return get_rule_expr(qh, rt_index, tle->expr, varprefix); {
get_rule_expr(buf, qh, rt_index, tle->expr, varprefix);
return;
}
/* ---------- /* ----------
* Whow - got it. Now get rid of the padding function * Whow - got it. Now get rid of the padding function
* ---------- * ----------
*/ */
return get_rule_expr(qh, rt_index, lfirst(expr->args), varprefix); get_rule_expr(buf, qh, rt_index, lfirst(expr->args), varprefix);
} }
/* ---------- /* ----------
* get_const_expr - Make a string representation * get_const_expr
* with the type cast out of a Const *
* Make a string representation with the type cast out of a Const
* ---------- * ----------
*/ */
static char * static void
get_const_expr(Const *constval) get_const_expr(StringInfo buf, Const *constval)
{ {
HeapTuple typetup; HeapTuple typetup;
Form_pg_type typeStruct; Form_pg_type typeStruct;
FmgrInfo finfo_output; FmgrInfo finfo_output;
char *extval; char *extval;
char *valptr;
bool isnull = FALSE; bool isnull = FALSE;
char buf[BUFSIZE];
char namebuf[64];
if (constval->constisnull) if (constval->constisnull)
return pstrdup("NULL"); {
appendStringInfo(buf, "NULL");
return;
}
typetup = SearchSysCacheTuple(TYPOID, typetup = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(constval->consttype), 0, 0, 0); ObjectIdGetDatum(constval->consttype),
0, 0, 0);
if (!HeapTupleIsValid(typetup)) if (!HeapTupleIsValid(typetup))
elog(ERROR, "cache lookup of type %u failed", constval->consttype); elog(ERROR, "cache lookup of type %u failed", constval->consttype);
...@@ -1665,11 +1588,34 @@ get_const_expr(Const *constval) ...@@ -1665,11 +1588,34 @@ get_const_expr(Const *constval)
extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue, extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue,
&isnull, -1); &isnull, -1);
sprintf(namebuf, "::\"%s\"", nameout(&(typeStruct->typname))); /*
if (strcmp(namebuf, "::unknown") == 0) * We must quote any funny characters in the constant's representation.
namebuf[0] = '\0'; * XXX Any MULTIBYTE considerations here?
sprintf(buf, "'%s'%s", extval, namebuf); */
return pstrdup(buf); appendStringInfoChar(buf, '\'');
for (valptr = extval; *valptr; valptr++)
{
char ch = *valptr;
if (ch == '\'' || ch == '\\')
{
appendStringInfoChar(buf, '\\');
appendStringInfoChar(buf, ch);
}
else if (ch >= 0 && ch < ' ')
{
appendStringInfo(buf, "\\%03o", ch);
}
else
appendStringInfoChar(buf, ch);
}
appendStringInfoChar(buf, '\'');
pfree(extval);
extval = (char *) nameout(&(typeStruct->typname));
/* probably would be better to recognize UNKNOWN by OID... */
if (strcmp(extval, "unknown") != 0)
appendStringInfo(buf, "::\"%s\"", extval);
pfree(extval);
} }
...@@ -1677,75 +1623,67 @@ get_const_expr(Const *constval) ...@@ -1677,75 +1623,67 @@ get_const_expr(Const *constval)
* get_sublink_expr - Parse back a sublink * get_sublink_expr - Parse back a sublink
* ---------- * ----------
*/ */
static char * static void
get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix) get_sublink_expr(StringInfo buf, QryHier *qh, int rt_index,
Node *node, bool varprefix)
{ {
SubLink *sublink = (SubLink *) node; SubLink *sublink = (SubLink *) node;
Query *query = (Query *) (sublink->subselect); Query *query = (Query *) (sublink->subselect);
Oper *oper; Oper *oper;
List *l; List *l;
char *sep; char *sep;
char buf[BUFSIZE];
buf[0] = '\0';
strcat(buf, "("); appendStringInfo(buf, "(");
if (sublink->lefthand != NULL) if (sublink->lefthand != NULL)
{ {
if (length(sublink->lefthand) > 1) if (length(sublink->lefthand) > 1)
strcat(buf, "("); appendStringInfo(buf, "(");
sep = ""; sep = "";
foreach(l, sublink->lefthand) foreach(l, sublink->lefthand)
{ {
strcat(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
strcat(buf, get_rule_expr(qh, rt_index, get_rule_expr(buf, qh, rt_index, lfirst(l), varprefix);
lfirst(l), varprefix));
} }
if (length(sublink->lefthand) > 1) if (length(sublink->lefthand) > 1)
strcat(buf, ") "); appendStringInfo(buf, ") ");
else else
strcat(buf, " "); appendStringInfo(buf, " ");
} }
switch (sublink->subLinkType) switch (sublink->subLinkType)
{ {
case EXISTS_SUBLINK: case EXISTS_SUBLINK:
strcat(buf, "EXISTS "); appendStringInfo(buf, "EXISTS ");
break; break;
case ANY_SUBLINK: case ANY_SUBLINK:
oper = (Oper *) lfirst(sublink->oper); oper = (Oper *) lfirst(sublink->oper);
strcat(buf, get_opname(oper->opno)); appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
strcat(buf, " ANY ");
break; break;
case ALL_SUBLINK: case ALL_SUBLINK:
oper = (Oper *) lfirst(sublink->oper); oper = (Oper *) lfirst(sublink->oper);
strcat(buf, get_opname(oper->opno)); appendStringInfo(buf, "%s ALL ", get_opname(oper->opno));
strcat(buf, " ALL ");
break; break;
case EXPR_SUBLINK: case EXPR_SUBLINK:
oper = (Oper *) lfirst(sublink->oper); oper = (Oper *) lfirst(sublink->oper);
strcat(buf, get_opname(oper->opno)); appendStringInfo(buf, "%s ", get_opname(oper->opno));
strcat(buf, " ");
break; break;
default: default:
elog(ERROR, "unupported sublink type %d", elog(ERROR, "get_sublink_expr: unsupported sublink type %d",
sublink->subLinkType); sublink->subLinkType);
break; break;
} }
strcat(buf, "("); appendStringInfo(buf, "(");
strcat(buf, get_query_def(query, qh)); get_query_def(buf, query, qh);
strcat(buf, "))"); appendStringInfo(buf, "))");
return pstrdup(buf);
} }
......
...@@ -1091,34 +1091,34 @@ toyemp |SELECT "emp"."name", "emp"."age", "emp"."location", ('12'::"i ...@@ -1091,34 +1091,34 @@ toyemp |SELECT "emp"."name", "emp"."age", "emp"."location", ('12'::"i
QUERY: SELECT tablename, rulename, definition FROM pg_rules QUERY: SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename; ORDER BY tablename, rulename;
tablename |rulename |definition tablename |rulename |definition
-------------+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -------------+---------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
rtest_emp |rtest_emp_del |CREATE RULE "rtest_emp_del" AS ON DELETE TO "rtest_emp" DO INSERT INTO "rtest_emplog" ("ename", "who", "action", "newsal", "oldsal") VALUES (old."ename", "getpgusername"(), 'fired'::"bpchar", '$0.00'::"money", old."salary"); rtest_emp |rtest_emp_del |CREATE RULE "rtest_emp_del" AS ON DELETE TO "rtest_emp" DO INSERT INTO "rtest_emplog" ("ename", "who", "action", "newsal", "oldsal") VALUES (old."ename", "getpgusername"(), 'fired'::"bpchar", '$0.00'::"money", old."salary");
rtest_emp |rtest_emp_ins |CREATE RULE "rtest_emp_ins" AS ON INSERT TO "rtest_emp" DO INSERT INTO "rtest_emplog" ("ename", "who", "action", "newsal", "oldsal") VALUES (new."ename", "getpgusername"(), 'hired'::"bpchar", new."salary", '$0.00'::"money"); rtest_emp |rtest_emp_ins |CREATE RULE "rtest_emp_ins" AS ON INSERT TO "rtest_emp" DO INSERT INTO "rtest_emplog" ("ename", "who", "action", "newsal", "oldsal") VALUES (new."ename", "getpgusername"(), 'hired'::"bpchar", new."salary", '$0.00'::"money");
rtest_emp |rtest_emp_upd |CREATE RULE "rtest_emp_upd" AS ON UPDATE TO "rtest_emp" WHERE (new."salary" <> old."salary") DO INSERT INTO "rtest_emplog" ("ename", "who", "action", "newsal", "oldsal") VALUES (new."ename", "getpgusername"(), 'honored'::"bpchar", new."salary", old."salary"); rtest_emp |rtest_emp_upd |CREATE RULE "rtest_emp_upd" AS ON UPDATE TO "rtest_emp" WHERE (new."salary" <> old."salary") DO INSERT INTO "rtest_emplog" ("ename", "who", "action", "newsal", "oldsal") VALUES (new."ename", "getpgusername"(), 'honored'::"bpchar", new."salary", old."salary");
rtest_nothn1 |rtest_nothn_r1 |CREATE RULE "rtest_nothn_r1" AS ON INSERT TO "rtest_nothn1" WHERE ((new."a" >= '10'::"int4") AND (new."a" < '20'::"int4")) DO INSTEAD SELECT '1'::"int4"; rtest_nothn1 |rtest_nothn_r1 |CREATE RULE "rtest_nothn_r1" AS ON INSERT TO "rtest_nothn1" WHERE ((new."a" >= '10'::"int4") AND (new."a" < '20'::"int4")) DO INSTEAD SELECT '1'::"int4";
rtest_nothn1 |rtest_nothn_r2 |CREATE RULE "rtest_nothn_r2" AS ON INSERT TO "rtest_nothn1" WHERE ((new."a" >= '30'::"int4") AND (new."a" < '40'::"int4")) DO INSTEAD NOTHING; rtest_nothn1 |rtest_nothn_r2 |CREATE RULE "rtest_nothn_r2" AS ON INSERT TO "rtest_nothn1" WHERE ((new."a" >= '30'::"int4") AND (new."a" < '40'::"int4")) DO INSTEAD NOTHING;
rtest_nothn2 |rtest_nothn_r3 |CREATE RULE "rtest_nothn_r3" AS ON INSERT TO "rtest_nothn2" WHERE (new."a" >= '100'::"int4") DO INSTEAD INSERT INTO "rtest_nothn3" ("a", "b") VALUES (new."a", new."b"); rtest_nothn2 |rtest_nothn_r3 |CREATE RULE "rtest_nothn_r3" AS ON INSERT TO "rtest_nothn2" WHERE (new."a" >= '100'::"int4") DO INSTEAD INSERT INTO "rtest_nothn3" ("a", "b") VALUES (new."a", new."b");
rtest_nothn2 |rtest_nothn_r4 |CREATE RULE "rtest_nothn_r4" AS ON INSERT TO "rtest_nothn2" DO INSTEAD NOTHING; rtest_nothn2 |rtest_nothn_r4 |CREATE RULE "rtest_nothn_r4" AS ON INSERT TO "rtest_nothn2" DO INSTEAD NOTHING;
rtest_order1 |rtest_order_r1 |CREATE RULE "rtest_order_r1" AS ON INSERT TO "rtest_order1" DO INSTEAD INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 1 - this should run 3rd or 4th'::"text"); rtest_order1 |rtest_order_r1 |CREATE RULE "rtest_order_r1" AS ON INSERT TO "rtest_order1" DO INSTEAD INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 1 - this should run 3rd or 4th'::"text");
rtest_order1 |rtest_order_r2 |CREATE RULE "rtest_order_r2" AS ON INSERT TO "rtest_order1" DO INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 2 - this should run 1st'::"text"); rtest_order1 |rtest_order_r2 |CREATE RULE "rtest_order_r2" AS ON INSERT TO "rtest_order1" DO INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 2 - this should run 1st'::"text");
rtest_order1 |rtest_order_r3 |CREATE RULE "rtest_order_r3" AS ON INSERT TO "rtest_order1" DO INSTEAD INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 3 - this should run 3rd or 4th'::"text"); rtest_order1 |rtest_order_r3 |CREATE RULE "rtest_order_r3" AS ON INSERT TO "rtest_order1" DO INSTEAD INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 3 - this should run 3rd or 4th'::"text");
rtest_order1 |rtest_order_r4 |CREATE RULE "rtest_order_r4" AS ON INSERT TO "rtest_order1" WHERE ("rtest_order2"."a" < '100'::"int4") DO INSTEAD INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 4 - this should run 2nd'::"text"); rtest_order1 |rtest_order_r4 |CREATE RULE "rtest_order_r4" AS ON INSERT TO "rtest_order1" WHERE ("rtest_order2"."a" < '100'::"int4") DO INSTEAD INSERT INTO "rtest_order2" ("a", "b", "c") VALUES (new."a", "nextval"('rtest_seq'::"text"), 'rule 4 - this should run 2nd'::"text");
rtest_person |rtest_pers_del |CREATE RULE "rtest_pers_del" AS ON DELETE TO "rtest_person" DO DELETE FROM "rtest_admin" WHERE ("rtest_admin"."pname" = old."pname"); rtest_person |rtest_pers_del |CREATE RULE "rtest_pers_del" AS ON DELETE TO "rtest_person" DO DELETE FROM "rtest_admin" WHERE ("rtest_admin"."pname" = old."pname");
rtest_person |rtest_pers_upd |CREATE RULE "rtest_pers_upd" AS ON UPDATE TO "rtest_person" DO UPDATE rtest_admin SET "pname" = new."pname" WHERE ("rtest_admin"."pname" = old."pname"); rtest_person |rtest_pers_upd |CREATE RULE "rtest_pers_upd" AS ON UPDATE TO "rtest_person" DO UPDATE "rtest_admin" SET "pname" = new."pname" WHERE ("rtest_admin"."pname" = old."pname");
rtest_system |rtest_sys_del |CREATE RULE "rtest_sys_del" AS ON DELETE TO "rtest_system" DO (DELETE FROM "rtest_interface" WHERE ("rtest_interface"."sysname" = old."sysname"); DELETE FROM "rtest_admin" WHERE ("rtest_admin"."sysname" = old."sysname"); ); rtest_system |rtest_sys_del |CREATE RULE "rtest_sys_del" AS ON DELETE TO "rtest_system" DO (DELETE FROM "rtest_interface" WHERE ("rtest_interface"."sysname" = old."sysname"); DELETE FROM "rtest_admin" WHERE ("rtest_admin"."sysname" = old."sysname"); );
rtest_system |rtest_sys_upd |CREATE RULE "rtest_sys_upd" AS ON UPDATE TO "rtest_system" DO (UPDATE rtest_interface SET "sysname" = new."sysname" WHERE ("rtest_interface"."sysname" = old."sysname"); UPDATE rtest_admin SET "sysname" = new."sysname" WHERE ("rtest_admin"."sysname" = old."sysname"); ); rtest_system |rtest_sys_upd |CREATE RULE "rtest_sys_upd" AS ON UPDATE TO "rtest_system" DO (UPDATE "rtest_interface" SET "sysname" = new."sysname" WHERE ("rtest_interface"."sysname" = old."sysname"); UPDATE "rtest_admin" SET "sysname" = new."sysname" WHERE ("rtest_admin"."sysname" = old."sysname"); );
rtest_t4 |rtest_t4_ins1 |CREATE RULE "rtest_t4_ins1" AS ON INSERT TO "rtest_t4" WHERE ((new."a" >= '10'::"int4") AND (new."a" < '20'::"int4")) DO INSTEAD INSERT INTO "rtest_t5" ("a", "b") VALUES (new."a", new."b"); rtest_t4 |rtest_t4_ins1 |CREATE RULE "rtest_t4_ins1" AS ON INSERT TO "rtest_t4" WHERE ((new."a" >= '10'::"int4") AND (new."a" < '20'::"int4")) DO INSTEAD INSERT INTO "rtest_t5" ("a", "b") VALUES (new."a", new."b");
rtest_t4 |rtest_t4_ins2 |CREATE RULE "rtest_t4_ins2" AS ON INSERT TO "rtest_t4" WHERE ((new."a" >= '20'::"int4") AND (new."a" < '30'::"int4")) DO INSERT INTO "rtest_t6" ("a", "b") VALUES (new."a", new."b"); rtest_t4 |rtest_t4_ins2 |CREATE RULE "rtest_t4_ins2" AS ON INSERT TO "rtest_t4" WHERE ((new."a" >= '20'::"int4") AND (new."a" < '30'::"int4")) DO INSERT INTO "rtest_t6" ("a", "b") VALUES (new."a", new."b");
rtest_t5 |rtest_t5_ins |CREATE RULE "rtest_t5_ins" AS ON INSERT TO "rtest_t5" WHERE (new."a" > '15'::"int4") DO INSERT INTO "rtest_t7" ("a", "b") VALUES (new."a", new."b"); rtest_t5 |rtest_t5_ins |CREATE RULE "rtest_t5_ins" AS ON INSERT TO "rtest_t5" WHERE (new."a" > '15'::"int4") DO INSERT INTO "rtest_t7" ("a", "b") VALUES (new."a", new."b");
rtest_t6 |rtest_t6_ins |CREATE RULE "rtest_t6_ins" AS ON INSERT TO "rtest_t6" WHERE (new."a" > '25'::"int4") DO INSTEAD INSERT INTO "rtest_t8" ("a", "b") VALUES (new."a", new."b"); rtest_t6 |rtest_t6_ins |CREATE RULE "rtest_t6_ins" AS ON INSERT TO "rtest_t6" WHERE (new."a" > '25'::"int4") DO INSTEAD INSERT INTO "rtest_t8" ("a", "b") VALUES (new."a", new."b");
rtest_v1 |rtest_v1_del |CREATE RULE "rtest_v1_del" AS ON DELETE TO "rtest_v1" DO INSTEAD DELETE FROM "rtest_t1" WHERE ("rtest_t1"."a" = old."a"); rtest_v1 |rtest_v1_del |CREATE RULE "rtest_v1_del" AS ON DELETE TO "rtest_v1" DO INSTEAD DELETE FROM "rtest_t1" WHERE ("rtest_t1"."a" = old."a");
rtest_v1 |rtest_v1_ins |CREATE RULE "rtest_v1_ins" AS ON INSERT TO "rtest_v1" DO INSTEAD INSERT INTO "rtest_t1" ("a", "b") VALUES (new."a", new."b"); rtest_v1 |rtest_v1_ins |CREATE RULE "rtest_v1_ins" AS ON INSERT TO "rtest_v1" DO INSTEAD INSERT INTO "rtest_t1" ("a", "b") VALUES (new."a", new."b");
rtest_v1 |rtest_v1_upd |CREATE RULE "rtest_v1_upd" AS ON UPDATE TO "rtest_v1" DO INSTEAD UPDATE rtest_t1 SET "a" = new."a", "b" = new."b" WHERE ("rtest_t1"."a" = old."a"); rtest_v1 |rtest_v1_upd |CREATE RULE "rtest_v1_upd" AS ON UPDATE TO "rtest_v1" DO INSTEAD UPDATE "rtest_t1" SET "a" = new."a", "b" = new."b" WHERE ("rtest_t1"."a" = old."a");
shoelace |shoelace_del |CREATE RULE "shoelace_del" AS ON DELETE TO "shoelace" DO INSTEAD DELETE FROM "shoelace_data" WHERE ("shoelace_data"."sl_name" = old."sl_name"); shoelace |shoelace_del |CREATE RULE "shoelace_del" AS ON DELETE TO "shoelace" DO INSTEAD DELETE FROM "shoelace_data" WHERE ("shoelace_data"."sl_name" = old."sl_name");
shoelace |shoelace_ins |CREATE RULE "shoelace_ins" AS ON INSERT TO "shoelace" DO INSTEAD INSERT INTO "shoelace_data" ("sl_name", "sl_avail", "sl_color", "sl_len", "sl_unit") VALUES (new."sl_name", new."sl_avail", new."sl_color", new."sl_len", new."sl_unit"); shoelace |shoelace_ins |CREATE RULE "shoelace_ins" AS ON INSERT TO "shoelace" DO INSTEAD INSERT INTO "shoelace_data" ("sl_name", "sl_avail", "sl_color", "sl_len", "sl_unit") VALUES (new."sl_name", new."sl_avail", new."sl_color", new."sl_len", new."sl_unit");
shoelace |shoelace_upd |CREATE RULE "shoelace_upd" AS ON UPDATE TO "shoelace" DO INSTEAD UPDATE shoelace_data SET "sl_name" = new."sl_name", "sl_avail" = new."sl_avail", "sl_color" = new."sl_color", "sl_len" = new."sl_len", "sl_unit" = new."sl_unit" WHERE ("shoelace_data"."sl_name" = old."sl_name"); shoelace |shoelace_upd |CREATE RULE "shoelace_upd" AS ON UPDATE TO "shoelace" DO INSTEAD UPDATE "shoelace_data" SET "sl_name" = new."sl_name", "sl_avail" = new."sl_avail", "sl_color" = new."sl_color", "sl_len" = new."sl_len", "sl_unit" = new."sl_unit" WHERE ("shoelace_data"."sl_name" = old."sl_name");
shoelace_data|log_shoelace |CREATE RULE "log_shoelace" AS ON UPDATE TO "shoelace_data" WHERE (new."sl_avail" <> old."sl_avail") DO INSERT INTO "shoelace_log" ("sl_name", "sl_avail", "log_who", "log_when") VALUES (new."sl_name", new."sl_avail", 'Al Bundy'::"name", 'epoch'::"datetime"); shoelace_data|log_shoelace |CREATE RULE "log_shoelace" AS ON UPDATE TO "shoelace_data" WHERE (new."sl_avail" <> old."sl_avail") DO INSERT INTO "shoelace_log" ("sl_name", "sl_avail", "log_who", "log_when") VALUES (new."sl_name", new."sl_avail", 'Al Bundy'::"name", 'epoch'::"datetime");
shoelace_ok |shoelace_ok_ins|CREATE RULE "shoelace_ok_ins" AS ON INSERT TO "shoelace_ok" DO INSTEAD UPDATE shoelace SET "sl_avail" = ("shoelace"."sl_avail" + new."ok_quant") WHERE ("shoelace"."sl_name" = new."ok_name"); shoelace_ok |shoelace_ok_ins|CREATE RULE "shoelace_ok_ins" AS ON INSERT TO "shoelace_ok" DO INSTEAD UPDATE "shoelace" SET "sl_avail" = ("shoelace"."sl_avail" + new."ok_quant") WHERE ("shoelace"."sl_name" = new."ok_name");
(27 rows) (27 rows)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment