Change plpgsql to depend on main parser's type-declaration grammar,

rather than having its own somewhat half-baked notion of what a type
declaration looks like.  This is necessary now to ensure that plpgsql
will think a 'timestamp' variable has the same semantics as 'timestamp'
does in the main SQL grammar; and it should avoid divergences in future.
This commit is contained in:
Tom Lane 2001-10-09 04:15:38 +00:00
parent 7ecc40c2df
commit 0b3bca6c6f
8 changed files with 282 additions and 179 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.40 2001/09/18 12:08:26 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/plsql.sgml,v 2.41 2001/10/09 04:15:38 tgl Exp $
--> -->
<chapter id="plpgsql"> <chapter id="plpgsql">
@ -229,7 +229,7 @@ END;
re-create them. For example: re-create them. For example:
<programlisting> <programlisting>
drop function testfunc(integer); drop function testfunc(integer);
create function testfunc(integer) return integer as ' create function testfunc(integer) returns integer as '
.... ....
end; end;
' language 'plpgsql'; ' language 'plpgsql';
@ -360,7 +360,7 @@ END;
Here are some examples of variable declarations: Here are some examples of variable declarations:
<programlisting> <programlisting>
user_id INTEGER; user_id INTEGER;
quantity NUMBER(5); quantity NUMERIC(5);
url VARCHAR; url VARCHAR;
</programlisting> </programlisting>
</para> </para>
@ -437,7 +437,7 @@ END;
<para> <para>
Using the <type>%TYPE</type> and <type>%ROWTYPE</type> Using the <type>%TYPE</type> and <type>%ROWTYPE</type>
attributes, you can declare variables with the same attributes, you can declare variables with the same
data type or structure of another database item (e.g: a data type or structure as another database item (e.g: a
table field). table field).
</para> </para>
@ -512,7 +512,7 @@ create function cs_refresh_one_mv(integer) returns integer as '
WHERE sort_key=key; WHERE sort_key=key;
IF NOT FOUND THEN IF NOT FOUND THEN
RAISE EXCEPTION ''View '' || key || '' not found''; RAISE EXCEPTION ''View % not found'', key;
RETURN 0; RETURN 0;
END IF; END IF;
@ -575,8 +575,7 @@ SELECT <replaceable>expression</replaceable>
identifiers are substituted by parameters and the actual values from identifiers are substituted by parameters and the actual values from
the variables are passed to the executor in the parameter array. All the variables are passed to the executor in the parameter array. All
expressions used in a <application>PL/pgSQL</application> function are only prepared and expressions used in a <application>PL/pgSQL</application> function are only prepared and
saved once. The only exception to this rule is an EXECUTE statement saved once. The only exception to this rule is an EXECUTE statement.
if parsing of a query is needed each time it is encountered.
</para> </para>
<para> <para>

View File

@ -8,13 +8,16 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.35 2001/03/22 03:59:42 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.36 2001/10/09 04:15:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "nodes/parsenodes.h"
#include "parser/parser.h"
#include "parser/parse_expr.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/syscache.h" #include "utils/syscache.h"
@ -263,3 +266,73 @@ typenameTypeId(char *s)
ReleaseSysCache(typ); ReleaseSysCache(typ);
return result; return result;
} }
/*
* Given a string that is supposed to be a SQL-compatible type declaration,
* such as "int4" or "integer" or "character varying(32)", parse
* the string and convert it to a type OID and type modifier.
*
* This routine is not currently used by the main backend, but it is
* exported for use by add-on modules such as plpgsql, in hopes of
* centralizing parsing knowledge about SQL type declarations.
*/
void
parseTypeString(const char *str, Oid *type_id, int32 *typmod)
{
char *buf;
List *raw_parsetree_list;
SelectStmt *stmt;
ResTarget *restarget;
A_Const *aconst;
TypeName *typename;
buf = (char *) palloc(strlen(str) + 16);
sprintf(buf, "SELECT (NULL::%s)", str);
raw_parsetree_list = parser(buf, NULL, 0);
/*
* Make sure we got back exactly what we expected and no more;
* paranoia is justified since the string might contain anything.
*/
if (length(raw_parsetree_list) != 1)
elog(ERROR, "Invalid type name '%s'", str);
stmt = (SelectStmt *) lfirst(raw_parsetree_list);
if (stmt == NULL ||
!IsA(stmt, SelectStmt) ||
stmt->distinctClause != NIL ||
stmt->into != NULL ||
stmt->fromClause != NIL ||
stmt->whereClause != NULL ||
stmt->groupClause != NIL ||
stmt->havingClause != NULL ||
stmt->sortClause != NIL ||
stmt->portalname != NULL ||
stmt->limitOffset != NULL ||
stmt->limitCount != NULL ||
stmt->forUpdate != NIL ||
stmt->op != SETOP_NONE)
elog(ERROR, "Invalid type name '%s'", str);
if (length(stmt->targetList) != 1)
elog(ERROR, "Invalid type name '%s'", str);
restarget = (ResTarget *) lfirst(stmt->targetList);
if (restarget == NULL ||
!IsA(restarget, ResTarget) ||
restarget->name != NULL ||
restarget->indirection != NIL)
elog(ERROR, "Invalid type name '%s'", str);
aconst = (A_Const *) restarget->val;
if (aconst == NULL ||
!IsA(aconst, A_Const) ||
aconst->val.type != T_Null)
elog(ERROR, "Invalid type name '%s'", str);
typename = aconst->typename;
if (typename == NULL ||
!IsA(typename, TypeName))
elog(ERROR, "Invalid type name '%s'", str);
*type_id = typenameTypeId(TypeNameToInternalName(typename));
*typmod = typename->typmod;
pfree(buf);
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_type.h,v 1.16 2001/01/24 19:43:27 momjian Exp $ * $Id: parse_type.h,v 1.17 2001/10/09 04:15:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -34,6 +34,8 @@ extern char *typeidTypeName(Oid id);
extern Oid typeidTypeRelid(Oid type_id); extern Oid typeidTypeRelid(Oid type_id);
extern Oid typenameTypeId(char *s); extern Oid typenameTypeId(char *s);
extern void parseTypeString(const char *str, Oid *type_id, int32 *typmod);
#define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid) #define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid)
#endif /* PARSE_TYPE_H */ #endif /* PARSE_TYPE_H */

View File

@ -2,7 +2,7 @@
# #
# Makefile for the plpgsql shared object # Makefile for the plpgsql shared object
# #
# $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Makefile,v 1.18 2001/09/16 16:11:11 petere Exp $ # $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Makefile,v 1.19 2001/10/09 04:15:38 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -23,7 +23,7 @@ override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
override DLLLIBS := $(BE_DLLLIBS) $(DLLLIBS) override DLLLIBS := $(BE_DLLLIBS) $(DLLLIBS)
rpath := rpath :=
OBJS = pl_parse.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o OBJS = pl_gram.o pl_scan.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o
ifneq ($(PORTNAME), qnx4) ifneq ($(PORTNAME), qnx4)
all: all-lib all: all-lib
@ -59,10 +59,7 @@ installdirs:
uninstall: uninstall:
rm -f $(DESTDIR)$(pkglibdir)/plpgsql$(DLSUFFIX) rm -f $(DESTDIR)$(pkglibdir)/plpgsql$(DLSUFFIX)
pl_handler.o pl_comp.o pl_exec.o pl_funcs.o: plpgsql.h $(srcdir)/pl.tab.h pl_gram.o pl_scan.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o: plpgsql.h $(srcdir)/pl.tab.h
pl_parse.o: $(srcdir)/pl_gram.c $(srcdir)/pl_scan.c plpgsql.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
# Note: Since the yacc and lex files are shipped in the distribution, # Note: Since the yacc and lex files are shipped in the distribution,
# they must be generated in the srcdir (as opposed to builddir). # they must be generated in the srcdir (as opposed to builddir).
@ -79,17 +76,18 @@ endif
$(srcdir)/pl_scan.c: scan.l $(srcdir)/pl_scan.c: scan.l
ifdef FLEX ifdef FLEX
$(FLEX) -i -l $(FLEXFLAGS) $< $(FLEX) -i $(FLEXFLAGS) -Pplpgsql_base_yy -o'$@' $<
sed -e 's/yy/plpgsql_yy/g' -e 's/YY/PLPGSQL_YY/g' < lex.yy.c > $@
rm -f lex.yy.c
else else
@$(missing) flex $< $@ @$(missing) flex $< $@
endif endif
distprep: $(srcdir)/pl_scan.c $(srcdir)/pl.tab.h $(srcdir)/pl_gram.c distprep: $(srcdir)/pl_scan.c $(srcdir)/pl.tab.h $(srcdir)/pl_gram.c
# pl_gram.c, pl.tab.h, and pl_scan.c are in the distribution tarball,
# so they are not cleaned here.
clean distclean: clean-lib clean distclean: clean-lib
rm -f $(OBJS) rm -f $(OBJS)
# And the garbage that might have been left behind by partial build:
@rm -f y.tab.c y.tab.h lex.yy.c @rm -f y.tab.c y.tab.h lex.yy.c
maintainer-clean: clean maintainer-clean: clean

View File

@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.25 2001/09/26 21:35:28 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.26 2001/10/09 04:15:38 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -36,16 +36,11 @@
* *
**********************************************************************/ **********************************************************************/
#include <stdio.h>
#include <string.h>
#include "plpgsql.h" #include "plpgsql.h"
#ifdef YYBISON
#include "pl_scan.c" /* GNU bison wants it here */
#endif
static PLpgSQL_expr *read_sqlstmt(int until, char *s, char *sqlstart); static PLpgSQL_expr *read_sqlstmt(int until, char *s, char *sqlstart);
static PLpgSQL_type *read_datatype(int tok);
static PLpgSQL_stmt *make_select_stmt(void); static PLpgSQL_stmt *make_select_stmt(void);
static PLpgSQL_stmt *make_fetch_stmt(void); static PLpgSQL_stmt *make_fetch_stmt(void);
static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row); static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
@ -99,9 +94,9 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
%type <declhdr> decl_sect %type <declhdr> decl_sect
%type <varname> decl_varname %type <varname> decl_varname
%type <str> decl_renname %type <str> decl_renname
%type <ival> decl_const, decl_notnull, decl_atttypmod, decl_atttypmodval %type <ival> decl_const, decl_notnull
%type <expr> decl_defval, decl_cursor_query %type <expr> decl_defval, decl_cursor_query
%type <dtype> decl_datatype, decl_dtypename %type <dtype> decl_datatype
%type <row> decl_rowtype, decl_cursor_args, decl_cursor_arglist %type <row> decl_rowtype, decl_cursor_args, decl_cursor_arglist
%type <nsitem> decl_aliasitem %type <nsitem> decl_aliasitem
%type <str> decl_stmts, decl_stmt %type <str> decl_stmts, decl_stmt
@ -189,9 +184,6 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
*/ */
%token T_FUNCTION %token T_FUNCTION
%token T_TRIGGER %token T_TRIGGER
%token T_CHAR
%token T_BPCHAR
%token T_VARCHAR
%token T_LABEL %token T_LABEL
%token T_STRING %token T_STRING
%token T_VARIABLE %token T_VARIABLE
@ -394,8 +386,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
curname_def->query = strdup(buf); curname_def->query = strdup(buf);
new->default_val = curname_def; new->default_val = curname_def;
plpgsql_parse_word("refcursor"); new->datatype = plpgsql_parse_datatype("refcursor");
new->datatype = yylval.dtype;
new->cursor_explicit_expr = $6; new->cursor_explicit_expr = $6;
if ($3 == NULL) if ($3 == NULL)
@ -554,48 +545,14 @@ decl_const :
{ $$ = 1; } { $$ = 1; }
; ;
decl_datatype : decl_dtypename decl_datatype :
{ $$ = $1; }
;
decl_dtypename : T_DTYPE
{ $$ = yylval.dtype; }
| T_CHAR decl_atttypmod
{ {
if ($2 < 0) /*
{ * If there's a lookahead token, read_datatype
plpgsql_parse_word("char"); * should consume it.
$$ = yylval.dtype; */
} else $$ = read_datatype(yychar);
{ yyclearin;
plpgsql_parse_word("bpchar");
$$ = yylval.dtype;
$$->atttypmod = $2;
}
}
| T_VARCHAR decl_atttypmod
{
plpgsql_parse_word("varchar");
$$ = yylval.dtype;
$$->atttypmod = $2;
}
| T_BPCHAR '(' decl_atttypmodval ')'
{
plpgsql_parse_word("bpchar");
$$ = yylval.dtype;
$$->atttypmod = $3;
}
;
decl_atttypmod :
{ $$ = -1; }
| '(' decl_atttypmodval ')'
{ $$ = $2; }
;
decl_atttypmodval : T_NUMBER
{
$$ = pg_atoi(yytext, sizeof(int16), '\0') + VARHDRSZ;
} }
; ;
@ -1007,9 +964,7 @@ fori_var : fori_varname
new->refname = $1.name; new->refname = $1.name;
new->lineno = $1.lineno; new->lineno = $1.lineno;
plpgsql_parse_word("integer"); new->datatype = plpgsql_parse_datatype("integer");
new->datatype = yylval.dtype;
new->isconst = false; new->isconst = false;
new->notnull = false; new->notnull = false;
new->default_val = NULL; new->default_val = NULL;
@ -1558,10 +1513,6 @@ lno :
%% %%
#ifndef YYBISON
#include "pl_scan.c" /* BSD yacc wants it here */
#endif
PLpgSQL_expr * PLpgSQL_expr *
plpgsql_read_expression (int until, char *s) plpgsql_read_expression (int until, char *s)
@ -1592,6 +1543,12 @@ read_sqlstmt (int until, char *s, char *sqlstart)
plpgsql_dstring_append(&ds, " "); plpgsql_dstring_append(&ds, " ");
switch (tok) switch (tok)
{ {
case 0:
plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "missing %s at end of SQL statement", s);
break;
case T_VARIABLE: case T_VARIABLE:
params[nparams] = yylval.var->varno; params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams); sprintf(buf, " $%d ", ++nparams);
@ -1611,12 +1568,6 @@ read_sqlstmt (int until, char *s, char *sqlstart)
break; break;
default: default:
if (tok == 0)
{
plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "missing %s at end of SQL statement", s);
}
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
break; break;
} }
@ -1634,6 +1585,64 @@ read_sqlstmt (int until, char *s, char *sqlstart)
return expr; return expr;
} }
static PLpgSQL_type *
read_datatype(int tok)
{
int lno;
PLpgSQL_dstring ds;
PLpgSQL_type *result;
bool needspace = false;
int parenlevel = 0;
lno = yylineno;
/* Often there will be a lookahead token, but if not, get one */
if (tok == YYEMPTY)
tok = yylex();
if (tok == T_DTYPE)
{
/* lexer found word%TYPE and did its thing already */
return yylval.dtype;
}
plpgsql_dstring_init(&ds);
while (tok != ';')
{
if (tok == 0)
{
plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "incomplete datatype declaration");
}
/* Possible followers for datatype in a declaration */
if (tok == K_NOT || tok == K_ASSIGN || tok == K_DEFAULT)
break;
/* Possible followers for datatype in a cursor_arg list */
if ((tok == ',' || tok == ')') && parenlevel == 0)
break;
if (tok == '(')
parenlevel++;
else if (tok == ')')
parenlevel--;
if (needspace)
plpgsql_dstring_append(&ds, " ");
needspace = true;
plpgsql_dstring_append(&ds, yytext);
tok = yylex();
}
plpgsql_push_back_token(tok);
result = plpgsql_parse_datatype(plpgsql_dstring_get(&ds));
plpgsql_dstring_free(&ds);
return result;
}
static PLpgSQL_stmt * static PLpgSQL_stmt *
make_select_stmt() make_select_stmt()

View File

@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.34 2001/10/06 23:21:44 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.35 2001/10/09 04:15:38 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -35,15 +35,12 @@
* *
**********************************************************************/ **********************************************************************/
#include <stdio.h> #include "plpgsql.h"
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <string.h>
#include <ctype.h> #include <ctype.h>
#include "plpgsql.h"
#include "pl.tab.h" #include "pl.tab.h"
#include "access/heapam.h" #include "access/heapam.h"
@ -57,6 +54,7 @@
#include "executor/spi.h" #include "executor/spi.h"
#include "fmgr.h" #include "fmgr.h"
#include "parser/gramparse.h" #include "parser/gramparse.h"
#include "parser/parse_type.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
@ -66,8 +64,6 @@
* ---------- * ----------
*/ */
extern PLPGSQL_YYSTYPE plpgsql_yylval; extern PLPGSQL_YYSTYPE plpgsql_yylval;
extern char plpgsql_yytext[];
extern int plpgsql_yylineno;
/* ---------- /* ----------
* Our own local and global variables * Our own local and global variables
@ -152,8 +148,7 @@ plpgsql_compile(Oid fn_oid, int functype)
proc_source = DatumGetCString(DirectFunctionCall1(textout, proc_source = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&procStruct->prosrc))); PointerGetDatum(&procStruct->prosrc)));
plpgsql_setinput(proc_source, functype); plpgsql_setinput(proc_source, functype);
plpgsql_error_funcname = DatumGetCString(DirectFunctionCall1(nameout, plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
NameGetDatum(&(procStruct->proname))));
plpgsql_error_lineno = 0; plpgsql_error_lineno = 0;
/* /*
@ -165,8 +160,7 @@ plpgsql_compile(Oid fn_oid, int functype)
function->fn_functype = functype; function->fn_functype = functype;
function->fn_oid = fn_oid; function->fn_oid = fn_oid;
function->fn_name = strdup(DatumGetCString(DirectFunctionCall1(nameout, function->fn_name = strdup(NameStr(procStruct->proname));
NameGetDatum(&(procStruct->proname)))));
switch (functype) switch (functype)
{ {
@ -237,9 +231,7 @@ plpgsql_compile(Oid fn_oid, int functype)
* For tuple type parameters, we set up a record of * For tuple type parameters, we set up a record of
* that type * that type
*/ */
sprintf(buf, "%s%%rowtype", sprintf(buf, "%s%%rowtype", NameStr(typeStruct->typname));
DatumGetCString(DirectFunctionCall1(nameout,
NameGetDatum(&(typeStruct->typname)))));
if (plpgsql_parse_wordrowtype(buf) != T_ROW) if (plpgsql_parse_wordrowtype(buf) != T_ROW)
{ {
plpgsql_comperrinfo(); plpgsql_comperrinfo();
@ -272,8 +264,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup(buf); var->refname = strdup(buf);
var->lineno = 0; var->lineno = 0;
var->datatype->typname = DatumGetCString(DirectFunctionCall1(nameout, var->datatype->typname = strdup(NameStr(typeStruct->typname));
NameGetDatum(&(typeStruct->typname))));
var->datatype->typoid = procStruct->proargtypes[i]; var->datatype->typoid = procStruct->proargtypes[i];
perm_fmgr_info(typeStruct->typinput, &(var->datatype->typinput)); perm_fmgr_info(typeStruct->typinput, &(var->datatype->typinput));
var->datatype->typelem = typeStruct->typelem; var->datatype->typelem = typeStruct->typelem;
@ -340,8 +331,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_name"); var->refname = strdup("tg_name");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("name"); var->datatype = plpgsql_parse_datatype("name");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -359,8 +349,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_when"); var->refname = strdup("tg_when");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("text"); var->datatype = plpgsql_parse_datatype("text");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -378,8 +367,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_level"); var->refname = strdup("tg_level");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("text"); var->datatype = plpgsql_parse_datatype("text");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -397,8 +385,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_op"); var->refname = strdup("tg_op");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("text"); var->datatype = plpgsql_parse_datatype("text");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -416,8 +403,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_relid"); var->refname = strdup("tg_relid");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("oid"); var->datatype = plpgsql_parse_datatype("oid");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -435,8 +421,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_relname"); var->refname = strdup("tg_relname");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("name"); var->datatype = plpgsql_parse_datatype("name");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -454,8 +439,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_nargs"); var->refname = strdup("tg_nargs");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("int4"); var->datatype = plpgsql_parse_datatype("int4");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -482,8 +466,7 @@ plpgsql_compile(Oid fn_oid, int functype)
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("found"); var->refname = strdup("found");
var->lineno = 0; var->lineno = 0;
plpgsql_parse_word("bool"); var->datatype = plpgsql_parse_datatype("bool");
var->datatype = plpgsql_yylval.dtype;
var->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
@ -541,9 +524,6 @@ plpgsql_parse_word(char *word)
{ {
PLpgSQL_nsitem *nse; PLpgSQL_nsitem *nse;
char *cp; char *cp;
HeapTuple typeTup;
Form_pg_type typeStruct;
char *typeXlated;
/* /*
* We do our lookups case insensitive * We do our lookups case insensitive
@ -606,45 +586,6 @@ plpgsql_parse_word(char *word)
} }
} }
/*
* Try to find a data type with that name, but ignore pg_type entries
* that are in fact class types.
*/
typeXlated = xlateSqlType(cp);
typeTup = SearchSysCache(TYPENAME,
PointerGetDatum(typeXlated),
0, 0, 0);
if (HeapTupleIsValid(typeTup))
{
PLpgSQL_type *typ;
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
if (typeStruct->typrelid != InvalidOid)
{
ReleaseSysCache(typeTup);
pfree(cp);
return T_WORD;
}
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
typ->typname = DatumGetCString(DirectFunctionCall1(nameout,
NameGetDatum(&(typeStruct->typname))));
typ->typoid = typeTup->t_data->t_oid;
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
typ->typelem = typeStruct->typelem;
typ->typbyval = typeStruct->typbyval;
typ->typlen = typeStruct->typlen;
typ->atttypmod = -1;
plpgsql_yylval.dtype = typ;
ReleaseSysCache(typeTup);
pfree(cp);
return T_DTYPE;
}
/* /*
* Nothing found - up to now it's a word without any special meaning * Nothing found - up to now it's a word without any special meaning
* for us. * for us.
@ -946,8 +887,7 @@ plpgsql_parse_wordtype(char *word)
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
typ->typname = DatumGetCString(DirectFunctionCall1(nameout, typ->typname = strdup(NameStr(typeStruct->typname));
NameGetDatum(&(typeStruct->typname))));
typ->typoid = typeTup->t_data->t_oid; typ->typoid = typeTup->t_data->t_oid;
perm_fmgr_info(typeStruct->typinput, &(typ->typinput)); perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
typ->typelem = typeStruct->typelem; typ->typelem = typeStruct->typelem;
@ -1090,8 +1030,7 @@ plpgsql_parse_dblwordtype(char *string)
*/ */
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
typ->typname = DatumGetCString(DirectFunctionCall1(nameout, typ->typname = strdup(NameStr(typeStruct->typname));
NameGetDatum(&(typeStruct->typname))));
typ->typoid = typetup->t_data->t_oid; typ->typoid = typetup->t_data->t_oid;
perm_fmgr_info(typeStruct->typinput, &(typ->typinput)); perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
typ->typelem = typeStruct->typelem; typ->typelem = typeStruct->typelem;
@ -1199,8 +1138,7 @@ plpgsql_parse_wordrowtype(char *string)
} }
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
cp = DatumGetCString(DirectFunctionCall1(nameout, cp = pstrdup(NameStr(attrStruct->attname));
NameGetDatum(&(attrStruct->attname))));
typetup = SearchSysCache(TYPEOID, typetup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(attrStruct->atttypid), ObjectIdGetDatum(attrStruct->atttypid),
@ -1268,6 +1206,47 @@ plpgsql_parse_wordrowtype(char *string)
} }
/* ----------
* plpgsql_parse_datatype Scanner found something that should
* be a datatype name.
* ----------
*/
PLpgSQL_type *
plpgsql_parse_datatype(char *string)
{
Oid type_id;
int32 typmod;
HeapTuple typeTup;
Form_pg_type typeStruct;
PLpgSQL_type *typ;
/* Let the main parser try to parse it under standard SQL rules */
parseTypeString(string, &type_id, &typmod);
/* Okay, build a PLpgSQL_type data structure for it */
typeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(type_id),
0, 0, 0);
if (!HeapTupleIsValid(typeTup))
elog(ERROR, "cache lookup failed for type %u", type_id);
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
typ->typname = strdup(NameStr(typeStruct->typname));
typ->typoid = type_id;
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
typ->typelem = typeStruct->typelem;
typ->typbyval = typeStruct->typbyval;
typ->typlen = typeStruct->typlen;
typ->atttypmod = typmod;
ReleaseSysCache(typeTup);
return typ;
}
/* ---------- /* ----------
* plpgsql_adddatum Add a variable, record or row * plpgsql_adddatum Add a variable, record or row
* to the compilers datum list. * to the compilers datum list.

View File

@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.17 2001/08/02 21:31:23 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.18 2001/10/09 04:15:38 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -523,8 +523,13 @@ extern PLpgSQL_datum **plpgsql_Datums;
extern int plpgsql_error_lineno; extern int plpgsql_error_lineno;
extern char *plpgsql_error_funcname; extern char *plpgsql_error_funcname;
extern PLpgSQL_function *plpgsql_curr_compile; /* linkage to the real yytext and yylineno variables */
extern char *plpgsql_base_yytext;
#define plpgsql_yytext plpgsql_base_yytext
extern int plpgsql_base_yylineno;
#define plpgsql_yylineno plpgsql_base_yylineno
extern PLpgSQL_function *plpgsql_curr_compile;
/********************************************************************** /**********************************************************************
* Function declarations * Function declarations
@ -541,9 +546,11 @@ extern int plpgsql_parse_tripword(char *string);
extern int plpgsql_parse_wordtype(char *string); extern int plpgsql_parse_wordtype(char *string);
extern int plpgsql_parse_dblwordtype(char *string); extern int plpgsql_parse_dblwordtype(char *string);
extern int plpgsql_parse_wordrowtype(char *string); extern int plpgsql_parse_wordrowtype(char *string);
extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
extern void plpgsql_adddatum(PLpgSQL_datum * new); extern void plpgsql_adddatum(PLpgSQL_datum * new);
extern int plpgsql_add_initdatums(int **varnos); extern int plpgsql_add_initdatums(int **varnos);
extern void plpgsql_comperrinfo(void); extern void plpgsql_comperrinfo(void);
extern void plpgsql_yyerror(const char *s);
/* ---------- /* ----------
* Functions in pl_handler.c * Functions in pl_handler.c
@ -594,10 +601,10 @@ extern char *plpgsql_tolower(char *s);
* ---------- * ----------
*/ */
extern PLpgSQL_expr *plpgsql_read_expression(int until, char *s); extern PLpgSQL_expr *plpgsql_read_expression(int until, char *s);
extern void plpgsql_yyrestart(FILE *fp);
extern int plpgsql_yylex(void);
extern void plpgsql_setinput(char *s, int functype);
extern int plpgsql_yyparse(void); extern int plpgsql_yyparse(void);
extern void plpgsql_yyerror(const char *s); extern int plpgsql_base_yylex(void);
extern int plpgsql_yylex(void);
extern void plpgsql_push_back_token(int token);
extern void plpgsql_setinput(char *s, int functype);
#endif /* PLPGSQL_H */ #endif /* PLPGSQL_H */

View File

@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.14 2001/07/12 17:42:08 momjian Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.15 2001/10/09 04:15:38 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -36,21 +36,28 @@
* *
**********************************************************************/ **********************************************************************/
#include "plpgsql.h"
#include "pl.tab.h"
static char *plpgsql_source; static char *plpgsql_source;
static int plpgsql_bytes_left; static int plpgsql_bytes_left;
static int scanner_functype; static int scanner_functype;
static int scanner_typereported; static int scanner_typereported;
static int pushback_token;
static bool have_pushback_token;
int plpgsql_SpaceScanned = 0; int plpgsql_SpaceScanned = 0;
extern int yylineno;
static void plpgsql_input(char *buf, int *result, int max); static void plpgsql_input(char *buf, int *result, int max);
#define YY_INPUT(buf,res,max) plpgsql_input(buf, &res, max) #define YY_INPUT(buf,res,max) plpgsql_input(buf, &res, max)
#define YY_NO_UNPUT #define YY_NO_UNPUT
%} %}
%option yylineno
WS [\200-\377_A-Za-z"] WS [\200-\377_A-Za-z"]
WC [\200-\377_A-Za-z0-9"] WC [\200-\377_A-Za-z0-9"]
@ -91,8 +98,6 @@ WC [\200-\377_A-Za-z0-9"]
\.\. { return K_DOTDOT; } \.\. { return K_DOTDOT; }
alias { return K_ALIAS; } alias { return K_ALIAS; }
begin { return K_BEGIN; } begin { return K_BEGIN; }
bpchar { return T_BPCHAR; }
char { return T_CHAR; }
close { return K_CLOSE; } close { return K_CLOSE; }
constant { return K_CONSTANT; } constant { return K_CONSTANT; }
cursor { return K_CURSOR; } cursor { return K_CURSOR; }
@ -131,7 +136,6 @@ select { return K_SELECT; }
then { return K_THEN; } then { return K_THEN; }
to { return K_TO; } to { return K_TO; }
type { return K_TYPE; } type { return K_TYPE; }
varchar { return T_VARCHAR; }
when { return K_WHEN; } when { return K_WHEN; }
while { return K_WHILE; } while { return K_WHILE; }
@ -235,7 +239,37 @@ plpgsql_input(char *buf, int *result, int max)
plpgsql_bytes_left -= n; plpgsql_bytes_left -= n;
} }
/*
* This is the yylex routine called from outside. It exists to provide
* a token pushback facility.
*/
int
plpgsql_yylex(void)
{
if (have_pushback_token)
{
have_pushback_token = false;
return pushback_token;
}
return yylex();
}
/*
* Push back a single token to be re-read by next plpgsql_yylex() call.
*/
void
plpgsql_push_back_token(int token)
{
if (have_pushback_token)
elog(ERROR, "plpgsql_push_back_token: can't push back multiple tokens");
pushback_token = token;
have_pushback_token = true;
}
/*
* Initialize the scanner for new input.
*/
void void
plpgsql_setinput(char *source, int functype) plpgsql_setinput(char *source, int functype)
{ {
@ -261,4 +295,6 @@ plpgsql_setinput(char *source, int functype)
scanner_functype = functype; scanner_functype = functype;
scanner_typereported = 0; scanner_typereported = 0;
have_pushback_token = false;
} }