aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/parser/analyze.c118
-rw-r--r--src/backend/parser/gram.y22
-rw-r--r--src/backend/parser/parse_expr.c3
-rw-r--r--src/include/nodes/parsenodes.h3
-rw-r--r--src/test/regress/input/create_function_2.source6
-rw-r--r--src/test/regress/input/misc.source1
-rw-r--r--src/test/regress/output/create_function_2.source6
-rw-r--r--src/test/regress/output/misc.source6
8 files changed, 157 insertions, 8 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 2bef065b11a..c6f21e77b03 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -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)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 37c28495e54..6cf2adcb5ba 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -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;
+ }
+ ;
/*****************************************************************************
*
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 4cbbc1c980c..a196779f44c 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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)
{
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ff4cc278312..31aadb449d5 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.129 2001/05/21 18:42:08 momjian Exp $
+ * $Id: parsenodes.h,v 1.130 2001/06/04 23:27:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -951,6 +951,7 @@ typedef struct TypeName
bool setof; /* is a set? */
int32 typmod; /* type modifier */
List *arrayBounds; /* array bounds */
+ char *attrname; /* field name when using %TYPE */
} TypeName;
/*
diff --git a/src/test/regress/input/create_function_2.source b/src/test/regress/input/create_function_2.source
index b1c0eab1386..4bcf24c6011 100644
--- a/src/test/regress/input/create_function_2.source
+++ b/src/test/regress/input/create_function_2.source
@@ -13,6 +13,12 @@ CREATE FUNCTION hobby_construct(text, text)
LANGUAGE 'sql';
+CREATE FUNCTION hobbies_by_name(hobbies_r.name%TYPE)
+ RETURNS hobbies_r.person%TYPE
+ AS 'select person from hobbies_r where name = $1'
+ LANGUAGE 'sql';
+
+
CREATE FUNCTION equipment(hobbies_r)
RETURNS setof equipment_r
AS 'select * from equipment_r where hobby = $1.name'
diff --git a/src/test/regress/input/misc.source b/src/test/regress/input/misc.source
index dbb8df84709..0fa63839e60 100644
--- a/src/test/regress/input/misc.source
+++ b/src/test/regress/input/misc.source
@@ -214,6 +214,7 @@ SELECT user_relns() AS user_relns
--SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
+SELECT hobbies_by_name('basketball');
--
-- check that old-style C functions work properly with TOASTed values
diff --git a/src/test/regress/output/create_function_2.source b/src/test/regress/output/create_function_2.source
index a5f39a00bb0..137242da705 100644
--- a/src/test/regress/output/create_function_2.source
+++ b/src/test/regress/output/create_function_2.source
@@ -9,6 +9,12 @@ CREATE FUNCTION hobby_construct(text, text)
RETURNS hobbies_r
AS 'select $1 as name, $2 as hobby'
LANGUAGE 'sql';
+CREATE FUNCTION hobbies_by_name(hobbies_r.name%TYPE)
+ RETURNS hobbies_r.person%TYPE
+ AS 'select person from hobbies_r where name = $1'
+ LANGUAGE 'sql';
+NOTICE: hobbies_r.name%TYPE converted to text
+NOTICE: hobbies_r.person%TYPE converted to text
CREATE FUNCTION equipment(hobbies_r)
RETURNS setof equipment_r
AS 'select * from equipment_r where hobby = $1.name'
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index 768dba5c3c7..57dc0fb4a42 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -656,6 +656,12 @@ SELECT user_relns() AS user_relns
(90 rows)
--SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
+SELECT hobbies_by_name('basketball');
+ hobbies_by_name
+-----------------
+ joe
+(1 row)
+
--
-- check that old-style C functions work properly with TOASTed values
--