<!--
-$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">
re-create them. For example:
<programlisting>
drop function testfunc(integer);
-create function testfunc(integer) return integer as '
+create function testfunc(integer) returns integer as '
....
end;
' language 'plpgsql';
Here are some examples of variable declarations:
<programlisting>
user_id INTEGER;
-quantity NUMBER(5);
+quantity NUMERIC(5);
url VARCHAR;
</programlisting>
</para>
<para>
Using the <type>%TYPE</type> and <type>%ROWTYPE</type>
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).
</para>
WHERE sort_key=key;
IF NOT FOUND THEN
- RAISE EXCEPTION ''View '' || key || '' not found'';
+ RAISE EXCEPTION ''View % not found'', key;
RETURN 0;
END IF;
identifiers are substituted by parameters and the actual values from
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
- saved once. The only exception to this rule is an EXECUTE statement
- if parsing of a query is needed each time it is encountered.
+ saved once. The only exception to this rule is an EXECUTE statement.
</para>
<para>
*
*
* 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 "catalog/pg_type.h"
+#include "nodes/parsenodes.h"
+#include "parser/parser.h"
+#include "parser/parse_expr.h"
#include "parser/parse_type.h"
#include "utils/syscache.h"
ReleaseSysCache(typ);
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);
+}
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
extern Oid typeidTypeRelid(Oid type_id);
extern Oid typenameTypeId(char *s);
+extern void parseTypeString(const char *str, Oid *type_id, int32 *typmod);
+
#define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid)
#endif /* PARSE_TYPE_H */
#
# 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 $
#
#-------------------------------------------------------------------------
override DLLLIBS := $(BE_DLLLIBS) $(DLLLIBS)
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)
all: all-lib
uninstall:
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_parse.o: $(srcdir)/pl_gram.c $(srcdir)/pl_scan.c plpgsql.h
- $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
+pl_gram.o pl_scan.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o: plpgsql.h $(srcdir)/pl.tab.h
# Note: Since the yacc and lex files are shipped in the distribution,
# they must be generated in the srcdir (as opposed to builddir).
$(srcdir)/pl_scan.c: scan.l
ifdef FLEX
- $(FLEX) -i -l $(FLEXFLAGS) $<
- sed -e 's/yy/plpgsql_yy/g' -e 's/YY/PLPGSQL_YY/g' < lex.yy.c > $@
- rm -f lex.yy.c
+ $(FLEX) -i $(FLEXFLAGS) -Pplpgsql_base_yy -o'$@' $<
else
@$(missing) flex $< $@
endif
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
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
maintainer-clean: clean
* procedural language
*
* 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.
*
*
**********************************************************************/
-#include <stdio.h>
-#include <string.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_type *read_datatype(int tok);
static PLpgSQL_stmt *make_select_stmt(void);
static PLpgSQL_stmt *make_fetch_stmt(void);
static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
%type <declhdr> decl_sect
%type <varname> decl_varname
%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 <dtype> decl_datatype, decl_dtypename
+%type <dtype> decl_datatype
%type <row> decl_rowtype, decl_cursor_args, decl_cursor_arglist
%type <nsitem> decl_aliasitem
%type <str> decl_stmts, decl_stmt
*/
%token T_FUNCTION
%token T_TRIGGER
-%token T_CHAR
-%token T_BPCHAR
-%token T_VARCHAR
%token T_LABEL
%token T_STRING
%token T_VARIABLE
curname_def->query = strdup(buf);
new->default_val = curname_def;
- plpgsql_parse_word("refcursor");
- new->datatype = yylval.dtype;
+ new->datatype = plpgsql_parse_datatype("refcursor");
new->cursor_explicit_expr = $6;
if ($3 == NULL)
{ $$ = 1; }
;
-decl_datatype : decl_dtypename
- { $$ = $1; }
- ;
-
-decl_dtypename : T_DTYPE
- { $$ = yylval.dtype; }
- | T_CHAR decl_atttypmod
- {
- if ($2 < 0)
- {
- plpgsql_parse_word("char");
- $$ = yylval.dtype;
- } else
- {
- 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
+decl_datatype :
{
- $$ = pg_atoi(yytext, sizeof(int16), '\0') + VARHDRSZ;
+ /*
+ * If there's a lookahead token, read_datatype
+ * should consume it.
+ */
+ $$ = read_datatype(yychar);
+ yyclearin;
}
;
new->refname = $1.name;
new->lineno = $1.lineno;
- plpgsql_parse_word("integer");
-
- new->datatype = yylval.dtype;
+ new->datatype = plpgsql_parse_datatype("integer");
new->isconst = false;
new->notnull = false;
new->default_val = NULL;
%%
-#ifndef YYBISON
-#include "pl_scan.c" /* BSD yacc wants it here */
-#endif
-
PLpgSQL_expr *
plpgsql_read_expression (int until, char *s)
plpgsql_dstring_append(&ds, " ");
switch (tok)
{
+ case 0:
+ plpgsql_error_lineno = lno;
+ plpgsql_comperrinfo();
+ elog(ERROR, "missing %s at end of SQL statement", s);
+ break;
+
case T_VARIABLE:
params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams);
break;
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);
break;
}
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 *
make_select_stmt()
* procedural language
*
* 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.
*
*
**********************************************************************/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
+#include "plpgsql.h"
+
#include <unistd.h>
#include <fcntl.h>
-#include <string.h>
#include <ctype.h>
-#include "plpgsql.h"
#include "pl.tab.h"
#include "access/heapam.h"
#include "executor/spi.h"
#include "fmgr.h"
#include "parser/gramparse.h"
+#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
* ----------
*/
extern PLPGSQL_YYSTYPE plpgsql_yylval;
-extern char plpgsql_yytext[];
-extern int plpgsql_yylineno;
/* ----------
* Our own local and global variables
proc_source = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&procStruct->prosrc)));
plpgsql_setinput(proc_source, functype);
- plpgsql_error_funcname = DatumGetCString(DirectFunctionCall1(nameout,
- NameGetDatum(&(procStruct->proname))));
+ plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
plpgsql_error_lineno = 0;
/*
function->fn_functype = functype;
function->fn_oid = fn_oid;
- function->fn_name = strdup(DatumGetCString(DirectFunctionCall1(nameout,
- NameGetDatum(&(procStruct->proname)))));
+ function->fn_name = strdup(NameStr(procStruct->proname));
switch (functype)
{
* For tuple type parameters, we set up a record of
* that type
*/
- sprintf(buf, "%s%%rowtype",
- DatumGetCString(DirectFunctionCall1(nameout,
- NameGetDatum(&(typeStruct->typname)))));
+ sprintf(buf, "%s%%rowtype", NameStr(typeStruct->typname));
if (plpgsql_parse_wordrowtype(buf) != T_ROW)
{
plpgsql_comperrinfo();
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup(buf);
var->lineno = 0;
- var->datatype->typname = DatumGetCString(DirectFunctionCall1(nameout,
- NameGetDatum(&(typeStruct->typname))));
+ var->datatype->typname = strdup(NameStr(typeStruct->typname));
var->datatype->typoid = procStruct->proargtypes[i];
perm_fmgr_info(typeStruct->typinput, &(var->datatype->typinput));
var->datatype->typelem = typeStruct->typelem;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_name");
var->lineno = 0;
- plpgsql_parse_word("name");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("name");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_when");
var->lineno = 0;
- plpgsql_parse_word("text");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("text");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_level");
var->lineno = 0;
- plpgsql_parse_word("text");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("text");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_op");
var->lineno = 0;
- plpgsql_parse_word("text");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("text");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_relid");
var->lineno = 0;
- plpgsql_parse_word("oid");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("oid");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_relname");
var->lineno = 0;
- plpgsql_parse_word("name");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("name");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("tg_nargs");
var->lineno = 0;
- plpgsql_parse_word("int4");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("int4");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup("found");
var->lineno = 0;
- plpgsql_parse_word("bool");
- var->datatype = plpgsql_yylval.dtype;
+ var->datatype = plpgsql_parse_datatype("bool");
var->isconst = false;
var->notnull = false;
var->default_val = NULL;
{
PLpgSQL_nsitem *nse;
char *cp;
- HeapTuple typeTup;
- Form_pg_type typeStruct;
- char *typeXlated;
/*
* We do our lookups case insensitive
}
}
- /*
- * 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
* for us.
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
- typ->typname = DatumGetCString(DirectFunctionCall1(nameout,
- NameGetDatum(&(typeStruct->typname))));
+ typ->typname = strdup(NameStr(typeStruct->typname));
typ->typoid = typeTup->t_data->t_oid;
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
typ->typelem = typeStruct->typelem;
*/
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
- typ->typname = DatumGetCString(DirectFunctionCall1(nameout,
- NameGetDatum(&(typeStruct->typname))));
+ typ->typname = strdup(NameStr(typeStruct->typname));
typ->typoid = typetup->t_data->t_oid;
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
typ->typelem = typeStruct->typelem;
}
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
- cp = DatumGetCString(DirectFunctionCall1(nameout,
- NameGetDatum(&(attrStruct->attname))));
+ cp = pstrdup(NameStr(attrStruct->attname));
typetup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(attrStruct->atttypid),
}
+/* ----------
+ * 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
* to the compilers datum list.
* procedural language
*
* 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.
*
extern int plpgsql_error_lineno;
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
extern int plpgsql_parse_wordtype(char *string);
extern int plpgsql_parse_dblwordtype(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 int plpgsql_add_initdatums(int **varnos);
extern void plpgsql_comperrinfo(void);
+extern void plpgsql_yyerror(const char *s);
/* ----------
* Functions in pl_handler.c
* ----------
*/
extern PLpgSQL_expr *plpgsql_read_expression(int until, char *s);
-extern void plpgsql_yyrestart(FILE *fp);
+extern int plpgsql_yyparse(void);
+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);
-extern int plpgsql_yyparse(void);
-extern void plpgsql_yyerror(const char *s);
#endif /* PLPGSQL_H */
* procedural language
*
* 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.
*
*
**********************************************************************/
+#include "plpgsql.h"
+#include "pl.tab.h"
+
+
static char *plpgsql_source;
static int plpgsql_bytes_left;
static int scanner_functype;
static int scanner_typereported;
+static int pushback_token;
+static bool have_pushback_token;
int plpgsql_SpaceScanned = 0;
-extern int yylineno;
-
static void plpgsql_input(char *buf, int *result, int max);
#define YY_INPUT(buf,res,max) plpgsql_input(buf, &res, max)
#define YY_NO_UNPUT
%}
+%option yylineno
+
+
WS [\200-\377_A-Za-z"]
WC [\200-\377_A-Za-z0-9"]
\.\. { return K_DOTDOT; }
alias { return K_ALIAS; }
begin { return K_BEGIN; }
-bpchar { return T_BPCHAR; }
-char { return T_CHAR; }
close { return K_CLOSE; }
constant { return K_CONSTANT; }
cursor { return K_CURSOR; }
then { return K_THEN; }
to { return K_TO; }
type { return K_TYPE; }
-varchar { return T_VARCHAR; }
when { return K_WHEN; }
while { return K_WHILE; }
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
plpgsql_setinput(char *source, int functype)
{
scanner_functype = functype;
scanner_typereported = 0;
+
+ have_pushback_token = false;
}