Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6dfe64e

Browse files
committed
Teach ruleutils to drill down into RECORD-type Vars in the same way
that the parser now can, so that it can reverse-list cases involvingFieldSelect from a RECORD Var.
1 parent83b72ee commit6dfe64e

File tree

1 file changed

+188
-32
lines changed

1 file changed

+188
-32
lines changed

‎src/backend/utils/adt/ruleutils.c

Lines changed: 188 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
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
*
@@ -55,6 +55,7 @@
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-
staticvoid
2442-
get_names_for_var(Var*var,intlevelsup,deparse_context*context,
2443-
char**schemaname,char**refname,char**attname)
2431+
staticRangeTblEntry*
2432+
get_rte_for_var(Var*var,intlevelsup,deparse_context*context)
24442433
{
2434+
RangeTblEntry*rte;
24452435
intnetlevelsup;
24462436
deparse_namespace*dpns;
2447-
RangeTblEntry*rte;
24482437

24492438
/* Find appropriate nesting depth */
24502439
netlevelsup=var->varlevelsup+levelsup;
@@ -2465,6 +2454,36 @@ get_names_for_var(Var *var, int levelsup, deparse_context *context,
24652454
rte=NULL;
24662455
if (rte==NULL)
24672456
elog(ERROR,"bogus varno: %d",var->varno);
2457+
returnrte;
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+
staticvoid
2480+
get_names_for_var(Var*var,intlevelsup,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,
25052524
var->varattno-1);
25062525
if (IsA(aliasvar,Var))
25072526
{
2508-
get_names_for_var(aliasvar,netlevelsup,context,
2527+
get_names_for_var(aliasvar,
2528+
var->varlevelsup+levelsup,context,
25092529
schemaname,refname,attname);
25102530
return;
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+
staticconstchar*
2561+
get_name_for_var_field(Var*var,intfieldno,
2562+
intlevelsup,deparse_context*context)
2563+
{
2564+
RangeTblEntry*rte;
2565+
AttrNumberattnum;
2566+
TupleDesctupleDesc;
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+
returnget_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+
caseRTE_RELATION:
2589+
caseRTE_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+
caseRTE_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_namespacemydpns;
2614+
constchar*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+
returnresult;
2628+
}
2629+
/* else fall through to inspect the expression */
2630+
}
2631+
break;
2632+
caseRTE_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+
returnget_name_for_var_field((Var*)expr,fieldno,
2638+
var->varlevelsup+levelsup,
2639+
context);
2640+
/* else fall through to inspect the expression */
2641+
break;
2642+
caseRTE_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+
returnNameStr(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,
31093250
caseT_FieldSelect:
31103251
{
31113252
FieldSelect*fselect= (FieldSelect*)node;
3112-
OidargType=exprType((Node*)fselect->arg);
3113-
Oidtyprelid;
3114-
char*fieldname;
3253+
Node*arg= (Node*)fselect->arg;
3254+
intfno=fselect->fieldnum;
3255+
constchar*fieldname;
31153256
boolneed_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);
31343266
if (need_parens)
31353267
appendStringInfoChar(buf,'(');
3136-
get_rule_expr((Node*)fselect->arg,context, true);
3268+
get_rule_expr(arg,context, true);
31373269
if (need_parens)
31383270
appendStringInfoChar(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+
TupleDesctupdesc;
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+
31393295
appendStringInfo(buf,".%s",quote_identifier(fieldname));
31403296
}
31413297
break;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp