diff options
author | Bruce Momjian <bruce@momjian.us> | 2002-09-12 00:24:10 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 2002-09-12 00:24:10 +0000 |
commit | b3f52320f6cb8374f3db5397e63b82f595c90681 (patch) | |
tree | 838a5b8f866b54fce0996e9b7a433bc10a119b3c /src/pl | |
parent | 81186865fec2e39a6a66e9435b32d7048c03dd32 (diff) | |
download | postgresql-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.c | 162 | ||||
-rw-r--r-- | src/pl/plpgsql/src/plpgsql.h | 4 | ||||
-rw-r--r-- | src/pl/plpgsql/src/scan.l | 6 |
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; } |