Skip to content

Commit b3f5232

Browse files
committed
> Sean Chittenden <sean@chittenden.org> writes:
> >>::sigh:: Is it me or does it look like all >>of pl/pgsql is schema un-aware (ie, all of the declarations). -sc > > > Yeah. The group of routines parse_word, parse_dblword, etc that are > called by the lexer certainly all need work. There are some > definitional issues to think about, too --- plpgsql presently relies on > the number of names to give it some idea of what to look for, and those > rules are probably all toast now. Please come up with a sketch of what > you think the behavior should be before you start hacking code. Attached is a diff -c format proposal to fix this. I've also attached a short test script. Seems to work OK and passes all regression tests. Here's a breakdown of how I understand plpgsql's "Special word rules" -- I think it illustrates the behavior reasonably well. New functions added by this patch are plpgsql_parse_tripwordtype and plpgsql_parse_dblwordrowtype: Joe Conway
1 parent 8118686 commit b3f5232

File tree

4 files changed

+216
-3
lines changed

4 files changed

+216
-3
lines changed

src/pl/plpgsql/src/pl_comp.c

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.51 2002/09/04 20:31:47 momjian Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.52 2002/09/12 00:24:09 momjian Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -1092,6 +1092,126 @@ plpgsql_parse_dblwordtype(char *word)
10921092
return T_DTYPE;
10931093
}
10941094

1095+
/* ----------
1096+
* plpgsql_parse_tripwordtype Same lookup for word.word.word%TYPE
1097+
* ----------
1098+
*/
1099+
#define TYPE_JUNK_LEN 5
1100+
1101+
int
1102+
plpgsql_parse_tripwordtype(char *word)
1103+
{
1104+
Oid classOid;
1105+
HeapTuple classtup;
1106+
Form_pg_class classStruct;
1107+
HeapTuple attrtup;
1108+
Form_pg_attribute attrStruct;
1109+
HeapTuple typetup;
1110+
Form_pg_type typeStruct;
1111+
PLpgSQL_type *typ;
1112+
char *cp[2];
1113+
int qualified_att_len;
1114+
int numdots = 0;
1115+
int i;
1116+
RangeVar *relvar;
1117+
1118+
/* Do case conversion and word separation */
1119+
qualified_att_len = strlen(word) - TYPE_JUNK_LEN;
1120+
Assert(word[qualified_att_len] == '%');
1121+
1122+
for (i = 0; i < qualified_att_len; i++)
1123+
{
1124+
if (word[i] == '.' && ++numdots == 2)
1125+
{
1126+
cp[0] = (char *) palloc((i + 1) * sizeof(char));
1127+
memset(cp[0], 0, (i + 1) * sizeof(char));
1128+
memcpy(cp[0], word, i * sizeof(char));
1129+
1130+
/* qualified_att_len - one based position + 1 (null terminator) */
1131+
cp[1] = (char *) palloc((qualified_att_len - i) * sizeof(char));
1132+
memset(cp[1], 0, (qualified_att_len - i) * sizeof(char));
1133+
memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 1) * sizeof(char));
1134+
1135+
break;
1136+
}
1137+
}
1138+
1139+
relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0], "plpgsql_parse_dblwordtype"));
1140+
classOid = RangeVarGetRelid(relvar, true);
1141+
if (!OidIsValid(classOid))
1142+
{
1143+
pfree(cp[0]);
1144+
pfree(cp[1]);
1145+
return T_ERROR;
1146+
}
1147+
classtup = SearchSysCache(RELOID,
1148+
ObjectIdGetDatum(classOid),
1149+
0, 0, 0);
1150+
if (!HeapTupleIsValid(classtup))
1151+
{
1152+
pfree(cp[0]);
1153+
pfree(cp[1]);
1154+
return T_ERROR;
1155+
}
1156+
1157+
/*
1158+
* It must be a relation, sequence, view, or type
1159+
*/
1160+
classStruct = (Form_pg_class) GETSTRUCT(classtup);
1161+
if (classStruct->relkind != RELKIND_RELATION &&
1162+
classStruct->relkind != RELKIND_SEQUENCE &&
1163+
classStruct->relkind != RELKIND_VIEW &&
1164+
classStruct->relkind != RELKIND_COMPOSITE_TYPE)
1165+
{
1166+
ReleaseSysCache(classtup);
1167+
pfree(cp[0]);
1168+
pfree(cp[1]);
1169+
return T_ERROR;
1170+
}
1171+
1172+
/*
1173+
* Fetch the named table field and it's type
1174+
*/
1175+
attrtup = SearchSysCacheAttName(classOid, cp[1]);
1176+
if (!HeapTupleIsValid(attrtup))
1177+
{
1178+
ReleaseSysCache(classtup);
1179+
pfree(cp[0]);
1180+
pfree(cp[1]);
1181+
return T_ERROR;
1182+
}
1183+
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
1184+
1185+
typetup = SearchSysCache(TYPEOID,
1186+
ObjectIdGetDatum(attrStruct->atttypid),
1187+
0, 0, 0);
1188+
if (!HeapTupleIsValid(typetup))
1189+
elog(ERROR, "cache lookup for type %u of %s.%s failed",
1190+
attrStruct->atttypid, cp[0], cp[1]);
1191+
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1192+
1193+
/*
1194+
* Found that - build a compiler type struct and return it
1195+
*/
1196+
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
1197+
1198+
typ->typname = strdup(NameStr(typeStruct->typname));
1199+
typ->typoid = attrStruct->atttypid;
1200+
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
1201+
typ->typelem = typeStruct->typelem;
1202+
typ->typbyval = typeStruct->typbyval;
1203+
typ->typlen = typeStruct->typlen;
1204+
typ->atttypmod = attrStruct->atttypmod;
1205+
1206+
plpgsql_yylval.dtype = typ;
1207+
1208+
ReleaseSysCache(classtup);
1209+
ReleaseSysCache(attrtup);
1210+
ReleaseSysCache(typetup);
1211+
pfree(cp[0]);
1212+
pfree(cp[1]);
1213+
return T_DTYPE;
1214+
}
10951215

10961216
/* ----------
10971217
* plpgsql_parse_wordrowtype Scanner found word%ROWTYPE.
@@ -1129,6 +1249,46 @@ plpgsql_parse_wordrowtype(char *word)
11291249
return T_ROW;
11301250
}
11311251

1252+
/* ----------
1253+
* plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE.
1254+
* So word must be namespace qualified a table name.
1255+
* ----------
1256+
*/
1257+
#define ROWTYPE_JUNK_LEN 8
1258+
1259+
int
1260+
plpgsql_parse_dblwordrowtype(char *word)
1261+
{
1262+
Oid classOid;
1263+
char *cp;
1264+
int i;
1265+
RangeVar *relvar;
1266+
1267+
/* Do case conversion and word separation */
1268+
/* We convert %rowtype to .rowtype momentarily to keep converter happy */
1269+
i = strlen(word) - ROWTYPE_JUNK_LEN;
1270+
Assert(word[i] == '%');
1271+
1272+
cp = (char *) palloc((i + 1) * sizeof(char));
1273+
memset(cp, 0, (i + 1) * sizeof(char));
1274+
memcpy(cp, word, i * sizeof(char));
1275+
1276+
/* Lookup the relation */
1277+
relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp, "plpgsql_parse_dblwordtype"));
1278+
classOid = RangeVarGetRelid(relvar, true);
1279+
if (!OidIsValid(classOid))
1280+
elog(ERROR, "%s: no such class", cp);
1281+
1282+
/*
1283+
* Build and return the complete row definition
1284+
*/
1285+
plpgsql_yylval.row = build_rowtype(classOid);
1286+
1287+
pfree(cp);
1288+
1289+
return T_ROW;
1290+
}
1291+
11321292
/*
11331293
* Build a rowtype data structure given the pg_class OID.
11341294
*/

src/pl/plpgsql/src/plpgsql.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.27 2002/09/04 20:31:47 momjian Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.28 2002/09/12 00:24:09 momjian Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -568,7 +568,9 @@ extern int plpgsql_parse_dblword(char *word);
568568
extern int plpgsql_parse_tripword(char *word);
569569
extern int plpgsql_parse_wordtype(char *word);
570570
extern int plpgsql_parse_dblwordtype(char *word);
571+
extern int plpgsql_parse_tripwordtype(char *word);
571572
extern int plpgsql_parse_wordrowtype(char *word);
573+
extern int plpgsql_parse_dblwordrowtype(char *word);
572574
extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
573575
extern void plpgsql_adddatum(PLpgSQL_datum * new);
574576
extern int plpgsql_add_initdatums(int **varnos);

src/pl/plpgsql/src/scan.l

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* procedural language
55
*
66
* IDENTIFICATION
7-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.22 2002/08/30 00:28:41 tgl Exp $
7+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.23 2002/09/12 00:24:09 momjian Exp $
88
*
99
* This software is copyrighted by Jan Wieck - Hamburg.
1010
*
@@ -170,14 +170,18 @@ dump { return O_DUMP; }
170170
{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
171171
{identifier}{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
172172
{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
173+
{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_tripwordtype(yytext); }
173174
{identifier}{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
175+
{identifier}{space}*\.{space}*{identifier}{space}*%ROWTYPE { return plpgsql_parse_dblwordrowtype(yytext); }
174176

175177
\${digit}+ { return plpgsql_parse_word(yytext); }
176178
\${digit}+{space}*\.{space}*{identifier} { return plpgsql_parse_dblword(yytext); }
177179
\${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
178180
\${digit}+{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
179181
\${digit}+{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
182+
\${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_tripwordtype(yytext); }
180183
\${digit}+{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
184+
\${digit}+{space}*\.{space}*{identifier}{space}*%ROWTYPE { return plpgsql_parse_dblwordrowtype(yytext); }
181185

182186
{digit}+ { return T_NUMBER; }
183187

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
-- nspname.relname.attname%TYPE
2+
DROP FUNCTION t();
3+
CREATE OR REPLACE FUNCTION t() RETURNS TEXT AS '
4+
DECLARE
5+
col_name pg_catalog.pg_attribute.attname%TYPE;
6+
BEGIN
7+
col_name := ''uga'';
8+
RETURN col_name;
9+
END;
10+
' LANGUAGE 'plpgsql';
11+
SELECT t();
12+
13+
-- nspname.relname%ROWTYPE
14+
DROP FUNCTION t();
15+
CREATE OR REPLACE FUNCTION t() RETURNS pg_catalog.pg_attribute AS '
16+
DECLARE
17+
rec pg_catalog.pg_attribute%ROWTYPE;
18+
BEGIN
19+
SELECT INTO rec * FROM pg_catalog.pg_attribute WHERE attrelid = 1247 AND attname = ''typname'';
20+
RETURN rec;
21+
END;
22+
' LANGUAGE 'plpgsql';
23+
SELECT * FROM t();
24+
25+
-- nspname.relname.attname%TYPE
26+
DROP FUNCTION t();
27+
CREATE OR REPLACE FUNCTION t() RETURNS pg_catalog.pg_attribute.attname%TYPE AS '
28+
DECLARE
29+
rec pg_catalog.pg_attribute.attname%TYPE;
30+
BEGIN
31+
SELECT INTO rec pg_catalog.pg_attribute.attname FROM pg_catalog.pg_attribute WHERE attrelid = 1247 AND attname = ''typname'';
32+
RETURN rec;
33+
END;
34+
' LANGUAGE 'plpgsql';
35+
SELECT t();
36+
37+
-- nspname.relname%ROWTYPE
38+
DROP FUNCTION t();
39+
CREATE OR REPLACE FUNCTION t() RETURNS pg_catalog.pg_attribute AS '
40+
DECLARE
41+
rec pg_catalog.pg_attribute%ROWTYPE;
42+
BEGIN
43+
SELECT INTO rec * FROM pg_catalog.pg_attribute WHERE attrelid = 1247 AND attname = ''typname'';
44+
RETURN rec;
45+
END;
46+
' LANGUAGE 'plpgsql';
47+
SELECT * FROM t();

0 commit comments

Comments
 (0)