summaryrefslogtreecommitdiff
path: root/src/pl
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2002-09-12 00:24:10 +0000
committerBruce Momjian <bruce@momjian.us>2002-09-12 00:24:10 +0000
commitb3f52320f6cb8374f3db5397e63b82f595c90681 (patch)
tree838a5b8f866b54fce0996e9b7a433bc10a119b3c /src/pl
parent81186865fec2e39a6a66e9435b32d7048c03dd32 (diff)
downloadpostgresql-b3f52320f6cb8374f3db5397e63b82f595c90681.tar.gz
> 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
Diffstat (limited to 'src/pl')
-rw-r--r--src/pl/plpgsql/src/pl_comp.c162
-rw-r--r--src/pl/plpgsql/src/plpgsql.h4
-rw-r--r--src/pl/plpgsql/src/scan.l6
3 files changed, 169 insertions, 3 deletions
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index c25f964f7c..00f2997ae3 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.51 2002/09/04 20:31:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.52 2002/09/12 00:24:09 momjian Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -1092,6 +1092,126 @@ plpgsql_parse_dblwordtype(char *word)
return T_DTYPE;
}
+/* ----------
+ * plpgsql_parse_tripwordtype Same lookup for word.word.word%TYPE
+ * ----------
+ */
+#define TYPE_JUNK_LEN 5
+
+int
+plpgsql_parse_tripwordtype(char *word)
+{
+ Oid classOid;
+ HeapTuple classtup;
+ Form_pg_class classStruct;
+ HeapTuple attrtup;
+ Form_pg_attribute attrStruct;
+ HeapTuple typetup;
+ Form_pg_type typeStruct;
+ PLpgSQL_type *typ;
+ char *cp[2];
+ int qualified_att_len;
+ int numdots = 0;
+ int i;
+ RangeVar *relvar;
+
+ /* Do case conversion and word separation */
+ qualified_att_len = strlen(word) - TYPE_JUNK_LEN;
+ Assert(word[qualified_att_len] == '%');
+
+ for (i = 0; i < qualified_att_len; i++)
+ {
+ if (word[i] == '.' && ++numdots == 2)
+ {
+ cp[0] = (char *) palloc((i + 1) * sizeof(char));
+ memset(cp[0], 0, (i + 1) * sizeof(char));
+ memcpy(cp[0], word, i * sizeof(char));
+
+ /* qualified_att_len - one based position + 1 (null terminator) */
+ cp[1] = (char *) palloc((qualified_att_len - i) * sizeof(char));
+ memset(cp[1], 0, (qualified_att_len - i) * sizeof(char));
+ memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 1) * sizeof(char));
+
+ break;
+ }
+ }
+
+ relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0], "plpgsql_parse_dblwordtype"));
+ classOid = RangeVarGetRelid(relvar, true);
+ if (!OidIsValid(classOid))
+ {
+ pfree(cp[0]);
+ pfree(cp[1]);
+ return T_ERROR;
+ }
+ classtup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(classOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(classtup))
+ {
+ pfree(cp[0]);
+ pfree(cp[1]);
+ return T_ERROR;
+ }
+
+ /*
+ * It must be a relation, sequence, view, or type
+ */
+ classStruct = (Form_pg_class) GETSTRUCT(classtup);
+ if (classStruct->relkind != RELKIND_RELATION &&
+ classStruct->relkind != RELKIND_SEQUENCE &&
+ classStruct->relkind != RELKIND_VIEW &&
+ classStruct->relkind != RELKIND_COMPOSITE_TYPE)
+ {
+ ReleaseSysCache(classtup);
+ pfree(cp[0]);
+ pfree(cp[1]);
+ return T_ERROR;
+ }
+
+ /*
+ * Fetch the named table field and it's type
+ */
+ attrtup = SearchSysCacheAttName(classOid, cp[1]);
+ if (!HeapTupleIsValid(attrtup))
+ {
+ ReleaseSysCache(classtup);
+ pfree(cp[0]);
+ pfree(cp[1]);
+ return T_ERROR;
+ }
+ attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
+
+ typetup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(attrStruct->atttypid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typetup))
+ elog(ERROR, "cache lookup for type %u of %s.%s failed",
+ attrStruct->atttypid, cp[0], cp[1]);
+ typeStruct = (Form_pg_type) GETSTRUCT(typetup);
+
+ /*
+ * Found that - build a compiler type struct and return it
+ */
+ typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
+
+ typ->typname = strdup(NameStr(typeStruct->typname));
+ typ->typoid = attrStruct->atttypid;
+ perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
+ typ->typelem = typeStruct->typelem;
+ typ->typbyval = typeStruct->typbyval;
+ typ->typlen = typeStruct->typlen;
+ typ->atttypmod = attrStruct->atttypmod;
+
+ plpgsql_yylval.dtype = typ;
+
+ ReleaseSysCache(classtup);
+ ReleaseSysCache(attrtup);
+ ReleaseSysCache(typetup);
+ pfree(cp[0]);
+ pfree(cp[1]);
+ return T_DTYPE;
+}
/* ----------
* plpgsql_parse_wordrowtype Scanner found word%ROWTYPE.
@@ -1129,6 +1249,46 @@ plpgsql_parse_wordrowtype(char *word)
return T_ROW;
}
+/* ----------
+ * plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE.
+ * So word must be namespace qualified a table name.
+ * ----------
+ */
+#define ROWTYPE_JUNK_LEN 8
+
+int
+plpgsql_parse_dblwordrowtype(char *word)
+{
+ Oid classOid;
+ char *cp;
+ int i;
+ RangeVar *relvar;
+
+ /* Do case conversion and word separation */
+ /* We convert %rowtype to .rowtype momentarily to keep converter happy */
+ i = strlen(word) - ROWTYPE_JUNK_LEN;
+ Assert(word[i] == '%');
+
+ cp = (char *) palloc((i + 1) * sizeof(char));
+ memset(cp, 0, (i + 1) * sizeof(char));
+ memcpy(cp, word, i * sizeof(char));
+
+ /* Lookup the relation */
+ relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp, "plpgsql_parse_dblwordtype"));
+ classOid = RangeVarGetRelid(relvar, true);
+ if (!OidIsValid(classOid))
+ elog(ERROR, "%s: no such class", cp);
+
+ /*
+ * Build and return the complete row definition
+ */
+ plpgsql_yylval.row = build_rowtype(classOid);
+
+ pfree(cp);
+
+ return T_ROW;
+}
+
/*
* Build a rowtype data structure given the pg_class OID.
*/
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 1d5ab78a32..cf3e1942d8 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.27 2002/09/04 20:31:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.28 2002/09/12 00:24:09 momjian Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -568,7 +568,9 @@ extern int plpgsql_parse_dblword(char *word);
extern int plpgsql_parse_tripword(char *word);
extern int plpgsql_parse_wordtype(char *word);
extern int plpgsql_parse_dblwordtype(char *word);
+extern int plpgsql_parse_tripwordtype(char *word);
extern int plpgsql_parse_wordrowtype(char *word);
+extern int plpgsql_parse_dblwordrowtype(char *word);
extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
extern void plpgsql_adddatum(PLpgSQL_datum * new);
extern int plpgsql_add_initdatums(int **varnos);
diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l
index 3976b54275..697be51393 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.22 2002/08/30 00:28:41 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.23 2002/09/12 00:24:09 momjian Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -170,14 +170,18 @@ dump { return O_DUMP; }
{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
{identifier}{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
+{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_tripwordtype(yytext); }
{identifier}{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
+{identifier}{space}*\.{space}*{identifier}{space}*%ROWTYPE { return plpgsql_parse_dblwordrowtype(yytext); }
\${digit}+ { return plpgsql_parse_word(yytext); }
\${digit}+{space}*\.{space}*{identifier} { return plpgsql_parse_dblword(yytext); }
\${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { return plpgsql_parse_tripword(yytext); }
\${digit}+{space}*%TYPE { return plpgsql_parse_wordtype(yytext); }
\${digit}+{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_dblwordtype(yytext); }
+\${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return plpgsql_parse_tripwordtype(yytext); }
\${digit}+{space}*%ROWTYPE { return plpgsql_parse_wordrowtype(yytext); }
+\${digit}+{space}*\.{space}*{identifier}{space}*%ROWTYPE { return plpgsql_parse_dblwordrowtype(yytext); }
{digit}+ { return T_NUMBER; }