mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
This patch adds support for %TYPE in CREATE FUNCTION argument and return
types. This version has an elog() to remind the user the type resolution is not dynamic. Ian Lance Taylor
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.188 2001/06/04 16:17:30 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.189 2001/06/04 23:27:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -29,6 +29,7 @@
|
||||
#include "parser/parse_relation.h"
|
||||
#include "parser/parse_target.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "rewrite/rewriteManip.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
@ -51,7 +52,10 @@ static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
|
||||
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
|
||||
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
|
||||
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt);
|
||||
static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
|
||||
|
||||
static void transformTypeRefsList(ParseState *pstate, List *l);
|
||||
static void transformTypeRef(ParseState *pstate, TypeName *tn);
|
||||
static List *getSetColTypes(ParseState *pstate, Node *node);
|
||||
static void transformForUpdate(Query *qry, List *forUpdate);
|
||||
static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid);
|
||||
@ -232,6 +236,17 @@ transformStmt(ParseState *pstate, Node *parseTree)
|
||||
(SelectStmt *) parseTree);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Convert use of %TYPE in statements where it is permitted.
|
||||
*/
|
||||
case T_ProcedureStmt:
|
||||
case T_CommentStmt:
|
||||
case T_RemoveFuncStmt:
|
||||
case T_DefineStmt:
|
||||
result = makeNode(Query);
|
||||
result->commandType = CMD_UTILITY;
|
||||
result->utilityStmt = transformTypeRefs(pstate, parseTree);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@ -2701,6 +2716,107 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
|
||||
return qry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform uses of %TYPE in a statement.
|
||||
*/
|
||||
static Node *
|
||||
transformTypeRefs(ParseState *pstate, Node *stmt)
|
||||
{
|
||||
switch (nodeTag(stmt))
|
||||
{
|
||||
case T_ProcedureStmt:
|
||||
{
|
||||
ProcedureStmt *ps = (ProcedureStmt *) stmt;
|
||||
|
||||
transformTypeRefsList(pstate, ps->argTypes);
|
||||
transformTypeRef(pstate, (TypeName *) ps->returnType);
|
||||
transformTypeRefsList(pstate, ps->withClause);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_CommentStmt:
|
||||
{
|
||||
CommentStmt *cs = (CommentStmt *) stmt;
|
||||
|
||||
transformTypeRefsList(pstate, cs->objlist);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_RemoveFuncStmt:
|
||||
{
|
||||
RemoveFuncStmt *rs = (RemoveFuncStmt *) stmt;
|
||||
|
||||
transformTypeRefsList(pstate, rs->args);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_DefineStmt:
|
||||
{
|
||||
DefineStmt *ds = (DefineStmt *) stmt;
|
||||
List *ele;
|
||||
|
||||
foreach(ele, ds->definition)
|
||||
{
|
||||
DefElem *de = (DefElem *) lfirst(ele);
|
||||
|
||||
if (de->arg != NULL
|
||||
&& IsA(de->arg, TypeName))
|
||||
{
|
||||
transformTypeRef(pstate, (TypeName *) de->arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "Unsupported type %d in transformTypeRefs",
|
||||
nodeTag(stmt));
|
||||
break;
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform uses of %TYPE in a list.
|
||||
*/
|
||||
static void
|
||||
transformTypeRefsList(ParseState *pstate, List *l)
|
||||
{
|
||||
List *ele;
|
||||
|
||||
foreach(ele, l)
|
||||
{
|
||||
if (IsA(lfirst(ele), TypeName))
|
||||
transformTypeRef(pstate, (TypeName *) lfirst(ele));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a TypeName to not use %TYPE.
|
||||
*/
|
||||
static void
|
||||
transformTypeRef(ParseState *pstate, TypeName *tn)
|
||||
{
|
||||
Attr *att;
|
||||
Node *n;
|
||||
Var *v;
|
||||
char *tyn;
|
||||
|
||||
if (tn->attrname == NULL)
|
||||
return;
|
||||
att = makeAttr(tn->name, tn->attrname);
|
||||
n = transformExpr(pstate, (Node *) att, EXPR_COLUMN_FIRST);
|
||||
if (! IsA(n, Var))
|
||||
elog(ERROR, "unsupported expression in %%TYPE");
|
||||
v = (Var *) n;
|
||||
tyn = typeidTypeName(v->vartype);
|
||||
elog(NOTICE, "%s.%s%%TYPE converted to %s", tn->name, tn->attrname, tyn);
|
||||
tn->name = tyn;
|
||||
tn->typmod = v->vartypmod;
|
||||
tn->attrname = NULL;
|
||||
}
|
||||
|
||||
/* exported so planner can check again after rewriting, query pullup, etc */
|
||||
void
|
||||
CheckSelectForUpdate(Query *qry)
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.227 2001/05/27 09:59:29 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.228 2001/06/04 23:27:23 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -192,7 +192,7 @@ static void doNegateFloat(Value *v);
|
||||
def_list, opt_indirection, group_clause, TriggerFuncArgs,
|
||||
select_limit, opt_select_limit
|
||||
|
||||
%type <typnam> func_arg, func_return, aggr_argtype
|
||||
%type <typnam> func_arg, func_return, func_type, aggr_argtype
|
||||
|
||||
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp
|
||||
|
||||
@ -2490,7 +2490,7 @@ func_args_list: func_arg
|
||||
{ $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
func_arg: opt_arg Typename
|
||||
func_arg: opt_arg func_type
|
||||
{
|
||||
/* We can catch over-specified arguments here if we want to,
|
||||
* but for now better to silently swallow typmod, etc.
|
||||
@ -2498,7 +2498,7 @@ func_arg: opt_arg Typename
|
||||
*/
|
||||
$$ = $2;
|
||||
}
|
||||
| Typename
|
||||
| func_type
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
@ -2526,7 +2526,7 @@ func_as: Sconst
|
||||
{ $$ = makeList2(makeString($1), makeString($3)); }
|
||||
;
|
||||
|
||||
func_return: Typename
|
||||
func_return: func_type
|
||||
{
|
||||
/* We can catch over-specified arguments here if we want to,
|
||||
* but for now better to silently swallow typmod, etc.
|
||||
@ -2536,6 +2536,18 @@ func_return: Typename
|
||||
}
|
||||
;
|
||||
|
||||
func_type: Typename
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| IDENT '.' ColId '%' TYPE_P
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
$$->typmod = -1;
|
||||
$$->attrname = $3;
|
||||
}
|
||||
;
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.96 2001/05/21 18:42:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.97 2001/06/04 23:27:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -942,6 +942,7 @@ parser_typecast_expression(ParseState *pstate,
|
||||
char *
|
||||
TypeNameToInternalName(TypeName *typename)
|
||||
{
|
||||
Assert(typename->attrname == NULL);
|
||||
if (typename->arrayBounds != NIL)
|
||||
{
|
||||
|
||||
|
Reference in New Issue
Block a user