diff options
author | Bruce Momjian <bruce@momjian.us> | 1998-10-02 16:28:04 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1998-10-02 16:28:04 +0000 |
commit | f93b6974f91491a895e875d37b474de48d4b9d8e (patch) | |
tree | c9aa857e0e241d6aa1290b2e49498b4733a8beb9 /src/backend/utils/adt/ruleutils.c | |
parent | 9b21a18cee705fa972e5b8f8ab106145015bafe7 (diff) | |
download | postgresql-f93b6974f91491a895e875d37b474de48d4b9d8e.tar.gz postgresql-f93b6974f91491a895e875d37b474de48d4b9d8e.zip |
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
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 532 |
1 files changed, 440 insertions, 92 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index f9774bf62f5..b3a1db8c069 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * out of it's tuple * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.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,10 +52,23 @@ #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); @@ -289,6 +309,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); } |