33 *back to source text
44 *
55 * IDENTIFICATION
6- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.197 2005/05/30 01:57:27 tgl Exp $
6+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.198 2005/05/31 03:03:59 tgl Exp $
77 *
88 * This software is copyrighted by Jan Wieck - Hamburg.
99 *
5555#include "catalog/pg_shadow.h"
5656#include "catalog/pg_trigger.h"
5757#include "executor/spi.h"
58+ #include "funcapi.h"
5859#include "lib/stringinfo.h"
5960#include "miscadmin.h"
6061#include "nodes/makefuncs.h"
@@ -2421,30 +2422,18 @@ get_utility_query_def(Query *query, deparse_context *context)
24212422
24222423
24232424/*
2424- * Get theschemaname, refname and attname for a (possibly nonlocal) Var.
2425+ * Get theRTE referenced by a (possibly nonlocal) Var.
24252426 *
24262427 * In some cases (currently only when recursing into an unnamed join)
24272428 * the Var's varlevelsup has to be interpreted with respect to a context
24282429 * above the current one; levelsup indicates the offset.
2429- *
2430- * schemaname is usually returned as NULL.It will be non-null only if
2431- * use of the unqualified refname would find the wrong RTE.
2432- *
2433- * refname will be returned as NULL if the Var references an unnamed join.
2434- * In this case the Var *must* be displayed without any qualification.
2435- *
2436- * attname will be returned as NULL if the Var represents a whole tuple
2437- * of the relation. (Typically we'd want to display the Var as "foo.*",
2438- * but it's convenient to return NULL to make it easier for callers to
2439- * distinguish this case.)
24402430 */
2441- static void
2442- get_names_for_var (Var * var ,int levelsup ,deparse_context * context ,
2443- char * * schemaname ,char * * refname ,char * * attname )
2431+ static RangeTblEntry *
2432+ get_rte_for_var (Var * var ,int levelsup ,deparse_context * context )
24442433{
2434+ RangeTblEntry * rte ;
24452435int netlevelsup ;
24462436deparse_namespace * dpns ;
2447- RangeTblEntry * rte ;
24482437
24492438/* Find appropriate nesting depth */
24502439netlevelsup = var -> varlevelsup + levelsup ;
@@ -2465,6 +2454,36 @@ get_names_for_var(Var *var, int levelsup, deparse_context *context,
24652454rte = NULL ;
24662455if (rte == NULL )
24672456elog (ERROR ,"bogus varno: %d" ,var -> varno );
2457+ return rte ;
2458+ }
2459+
2460+
2461+ /*
2462+ * Get the schemaname, refname and attname for a (possibly nonlocal) Var.
2463+ *
2464+ * In some cases (currently only when recursing into an unnamed join)
2465+ * the Var's varlevelsup has to be interpreted with respect to a context
2466+ * above the current one; levelsup indicates the offset.
2467+ *
2468+ * schemaname is usually returned as NULL.It will be non-null only if
2469+ * use of the unqualified refname would find the wrong RTE.
2470+ *
2471+ * refname will be returned as NULL if the Var references an unnamed join.
2472+ * In this case the Var *must* be displayed without any qualification.
2473+ *
2474+ * attname will be returned as NULL if the Var represents a whole tuple
2475+ * of the relation. (Typically we'd want to display the Var as "foo.*",
2476+ * but it's convenient to return NULL to make it easier for callers to
2477+ * distinguish this case.)
2478+ */
2479+ static void
2480+ get_names_for_var (Var * var ,int levelsup ,deparse_context * context ,
2481+ char * * schemaname ,char * * refname ,char * * attname )
2482+ {
2483+ RangeTblEntry * rte ;
2484+
2485+ /* Find appropriate RTE */
2486+ rte = get_rte_for_var (var ,levelsup ,context );
24682487
24692488/* Emit results */
24702489* schemaname = NULL ;/* default assumptions */
@@ -2505,7 +2524,8 @@ get_names_for_var(Var *var, int levelsup, deparse_context *context,
25052524var -> varattno - 1 );
25062525if (IsA (aliasvar ,Var ))
25072526{
2508- get_names_for_var (aliasvar ,netlevelsup ,context ,
2527+ get_names_for_var (aliasvar ,
2528+ var -> varlevelsup + levelsup ,context ,
25092529schemaname ,refname ,attname );
25102530return ;
25112531}
@@ -2521,6 +2541,127 @@ get_names_for_var(Var *var, int levelsup, deparse_context *context,
25212541* attname = get_rte_attribute_name (rte ,var -> varattno );
25222542}
25232543
2544+
2545+ /*
2546+ * Get the name of a field of a Var of type RECORD.
2547+ *
2548+ * Since no actual table or view column is allowed to have type RECORD, such
2549+ * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
2550+ * drill down to find the ultimate defining expression and attempt to infer
2551+ * the field name from it. We ereport if we can't determine the name.
2552+ *
2553+ * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
2554+ *
2555+ * Note: this has essentially the same logic as the parser's
2556+ * expandRecordVariable() function, but we are dealing with a different
2557+ * representation of the input context, and we only need one field name not
2558+ * a TupleDesc.
2559+ */
2560+ static const char *
2561+ get_name_for_var_field (Var * var ,int fieldno ,
2562+ int levelsup ,deparse_context * context )
2563+ {
2564+ RangeTblEntry * rte ;
2565+ AttrNumber attnum ;
2566+ TupleDesc tupleDesc ;
2567+ Node * expr ;
2568+
2569+ /* Check my caller didn't mess up */
2570+ Assert (IsA (var ,Var ));
2571+ Assert (var -> vartype == RECORDOID );
2572+
2573+ /* Find appropriate RTE */
2574+ rte = get_rte_for_var (var ,levelsup ,context );
2575+
2576+ attnum = var -> varattno ;
2577+
2578+ if (attnum == InvalidAttrNumber )
2579+ {
2580+ /* Var is whole-row reference to RTE, so select the right field */
2581+ return get_rte_attribute_name (rte ,fieldno );
2582+ }
2583+
2584+ expr = (Node * )var ;/* default if we can't drill down */
2585+
2586+ switch (rte -> rtekind )
2587+ {
2588+ case RTE_RELATION :
2589+ case RTE_SPECIAL :
2590+ /*
2591+ * This case should not occur: a column of a table shouldn't have
2592+ * type RECORD. Fall through and fail (most likely) at the
2593+ * bottom.
2594+ */
2595+ break ;
2596+ case RTE_SUBQUERY :
2597+ {
2598+ /* Subselect-in-FROM: examine sub-select's output expr */
2599+ TargetEntry * ste = get_tle_by_resno (rte -> subquery -> targetList ,
2600+ attnum );
2601+
2602+ if (ste == NULL || ste -> resjunk )
2603+ elog (ERROR ,"subquery %s does not have attribute %d" ,
2604+ rte -> eref -> aliasname ,attnum );
2605+ expr = (Node * )ste -> expr ;
2606+ if (IsA (expr ,Var ))
2607+ {
2608+ /*
2609+ * Recurse into the sub-select to see what its Var refers
2610+ * to. We have to build an additional level of namespace
2611+ * to keep in step with varlevelsup in the subselect.
2612+ */
2613+ deparse_namespace mydpns ;
2614+ const char * result ;
2615+
2616+ mydpns .rtable = rte -> subquery -> rtable ;
2617+ mydpns .outer_varno = mydpns .inner_varno = 0 ;
2618+ mydpns .outer_rte = mydpns .inner_rte = NULL ;
2619+
2620+ context -> namespaces = lcons (& mydpns ,context -> namespaces );
2621+
2622+ result = get_name_for_var_field ((Var * )expr ,fieldno ,
2623+ 0 ,context );
2624+
2625+ context -> namespaces = list_delete_first (context -> namespaces );
2626+
2627+ return result ;
2628+ }
2629+ /* else fall through to inspect the expression */
2630+ }
2631+ break ;
2632+ case RTE_JOIN :
2633+ /* Join RTE --- recursively inspect the alias variable */
2634+ Assert (attnum > 0 && attnum <=list_length (rte -> joinaliasvars ));
2635+ expr = (Node * )list_nth (rte -> joinaliasvars ,attnum - 1 );
2636+ if (IsA (expr ,Var ))
2637+ return get_name_for_var_field ((Var * )expr ,fieldno ,
2638+ var -> varlevelsup + levelsup ,
2639+ context );
2640+ /* else fall through to inspect the expression */
2641+ break ;
2642+ case RTE_FUNCTION :
2643+ /*
2644+ * We couldn't get here unless a function is declared with one
2645+ * of its result columns as RECORD, which is not allowed.
2646+ */
2647+ break ;
2648+ }
2649+
2650+ /*
2651+ * We now have an expression we can't expand any more, so see if
2652+ * get_expr_result_type() can do anything with it. If not, pass
2653+ * to lookup_rowtype_tupdesc() which will probably fail, but will
2654+ * give an appropriate error message while failing.
2655+ */
2656+ if (get_expr_result_type (expr ,NULL ,& tupleDesc )!= TYPEFUNC_COMPOSITE )
2657+ tupleDesc = lookup_rowtype_tupdesc (exprType (expr ),exprTypmod (expr ));
2658+
2659+ /* Got the tupdesc, so we can extract the field name */
2660+ Assert (fieldno >=1 && fieldno <=tupleDesc -> natts );
2661+ return NameStr (tupleDesc -> attrs [fieldno - 1 ]-> attname );
2662+ }
2663+
2664+
25242665/*
25252666 * find_rte_by_refname- look up an RTE by refname in a deparse context
25262667 *
@@ -3109,33 +3250,48 @@ get_rule_expr(Node *node, deparse_context *context,
31093250case T_FieldSelect :
31103251{
31113252FieldSelect * fselect = (FieldSelect * )node ;
3112- Oid argType = exprType (( Node * )fselect -> arg ) ;
3113- Oid typrelid ;
3114- char * fieldname ;
3253+ Node * arg = ( Node * )fselect -> arg ;
3254+ int fno = fselect -> fieldnum ;
3255+ const char * fieldname ;
31153256bool need_parens ;
31163257
3117- /* lookup arg type and get the field name */
3118- typrelid = get_typ_typrelid (argType );
3119- if (!OidIsValid (typrelid ))
3120- elog (ERROR ,"argument type %s of FieldSelect is not a tuple type" ,
3121- format_type_be (argType ));
3122- fieldname = get_relid_attribute_name (typrelid ,
3123- fselect -> fieldnum );
3124-
31253258/*
31263259 * Parenthesize the argument unless it's an ArrayRef or
31273260 * another FieldSelect. Note in particular that it would
31283261 * be WRONG to not parenthesize a Var argument; simplicity
31293262 * is not the issue here, having the right number of names
31303263 * is.
31313264 */
3132- need_parens = !IsA (fselect -> arg ,ArrayRef )&&
3133- !IsA (fselect -> arg ,FieldSelect );
3265+ need_parens = !IsA (arg ,ArrayRef )&& !IsA (arg ,FieldSelect );
31343266if (need_parens )
31353267appendStringInfoChar (buf ,'(' );
3136- get_rule_expr (( Node * ) fselect -> arg ,context , true);
3268+ get_rule_expr (arg ,context , true);
31373269if (need_parens )
31383270appendStringInfoChar (buf ,')' );
3271+
3272+ /*
3273+ * If it's a Var of type RECORD, we have to find what the Var
3274+ * refers to; otherwise we can use get_expr_result_type.
3275+ * If that fails, we try lookup_rowtype_tupdesc, which will
3276+ * probably fail too, but will ereport an acceptable message.
3277+ */
3278+ if (IsA (arg ,Var )&&
3279+ ((Var * )arg )-> vartype == RECORDOID )
3280+ fieldname = get_name_for_var_field ((Var * )arg ,fno ,
3281+ 0 ,context );
3282+ else
3283+ {
3284+ TupleDesc tupdesc ;
3285+
3286+ if (get_expr_result_type (arg ,NULL ,& tupdesc )!= TYPEFUNC_COMPOSITE )
3287+ tupdesc = lookup_rowtype_tupdesc (exprType (arg ),
3288+ exprTypmod (arg ));
3289+ Assert (tupdesc );
3290+ /* Got the tupdesc, so we can extract the field name */
3291+ Assert (fno >=1 && fno <=tupdesc -> natts );
3292+ fieldname = NameStr (tupdesc -> attrs [fno - 1 ]-> attname );
3293+ }
3294+
31393295appendStringInfo (buf ,".%s" ,quote_identifier (fieldname ));
31403296}
31413297break ;