* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.42 2003/04/27 22:21:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.43 2003/05/05 16:46:27 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
/* Composite type --- treat as rowtype */
PLpgSQL_row *row;
- row = build_rowtype($3->typrelid);
+ row = plpgsql_build_rowtype($3->typrelid);
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = $1.name;
row->lineno = $1.lineno;
new->dtype = PLPGSQL_DTYPE_ROW;
new->refname = strdup("*internal*");
- new->lineno = yylineno;
+ new->lineno = plpgsql_scanner_lineno();
new->rowtypeclass = InvalidOid;
/*
* We make temporary fieldnames/varnos arrays that
nsi = plpgsql_ns_lookup(name, NULL);
if (nsi == NULL)
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "function has no parameter %s", name);
}
plpgsql_convert_ident(yytext, &name, 1);
/* name should be malloc'd for use as varname */
$$.name = strdup(name);
- $$.lineno = yylineno;
+ $$.lineno = plpgsql_scanner_lineno();
pfree(name);
}
;
PLpgSQL_dstring ds;
PLpgSQL_expr *expr;
- lno = yylineno;
+ lno = plpgsql_scanner_lineno();
expr = malloc(sizeof(PLpgSQL_expr));
plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT ");
plpgsql_convert_ident(yytext, &name, 1);
/* name should be malloc'd for use as varname */
$$.name = strdup(name);
- $$.lineno = yylineno;
+ $$.lineno = plpgsql_scanner_lineno();
pfree(name);
}
| T_WORD
plpgsql_convert_ident(yytext, &name, 1);
/* name should be malloc'd for use as varname */
$$.name = strdup(name);
- $$.lineno = yylineno;
+ $$.lineno = plpgsql_scanner_lineno();
pfree(name);
}
;
if (tok != '(')
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "cursor %s has arguments",
$3->refname);
}
if (strncmp(cp, "SELECT", 6) != 0)
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "expected 'SELECT (', got '%s' (internal error)",
new->argquery->query);
}
cp++;
if (*cp != '(')
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "expected 'SELECT (', got '%s' (internal error)",
new->argquery->query);
}
if (tok == '(')
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "cursor %s has no arguments", $3->refname);
}
if (tok != ';')
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "syntax error at \"%s\"", yytext);
}
}
if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID)
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "%s must be of type cursor or refcursor",
((PLpgSQL_var *) yylval.variable)->refname);
}
if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID)
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "%s must be of type refcursor",
((PLpgSQL_var *) yylval.variable)->refname);
}
lno :
{
- plpgsql_error_lineno = yylineno;
- $$ = yylineno;
+ $$ = plpgsql_error_lineno = plpgsql_scanner_lineno();
}
;
char buf[32];
PLpgSQL_expr *expr;
- lno = yylineno;
+ lno = plpgsql_scanner_lineno();
plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, (char *) sqlstart);
bool needspace = false;
int parenlevel = 0;
- lno = yylineno;
+ lno = plpgsql_scanner_lineno();
/* Often there will be a lookahead token, but if not, get one */
if (tok == YYEMPTY)
break;
if (tok == 0)
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "unexpected end of file");
}
if (tok == K_INTO)
{
if (have_into)
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "INTO specified more than once");
}
tok = yylex();
break;
default:
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "plpgsql: %s is not a variable",
yytext);
}
row = malloc(sizeof(PLpgSQL_row));
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = strdup("*internal*");
- row->lineno = yylineno;
+ row->lineno = plpgsql_scanner_lineno();
row->rowtypeclass = InvalidOid;
row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields);
break;
default:
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "plpgsql: %s is not a variable",
yytext);
}
row = malloc(sizeof(PLpgSQL_row));
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = strdup("*internal*");
- row->lineno = yylineno;
+ row->lineno = plpgsql_scanner_lineno();
row->rowtypeclass = InvalidOid;
row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields);
case PLPGSQL_DTYPE_VAR:
if (((PLpgSQL_var *) datum)->isconst)
{
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "%s is declared CONSTANT",
((PLpgSQL_var *) datum)->refname);
}
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.57 2003/04/27 22:21:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.58 2003/05/05 16:46:27 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
proc_source = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&procStruct->prosrc)));
- plpgsql_setinput(proc_source, functype);
+ plpgsql_scanner_init(proc_source, functype);
+ pfree(proc_source);
plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
plpgsql_error_lineno = 0;
* For tuple type parameters, we set up a record of
* that type
*/
- row = build_rowtype(typeStruct->typrelid);
+ row = plpgsql_build_rowtype(typeStruct->typrelid);
row->refname = strdup(buf);
if (parse_rc != 0)
elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
+ plpgsql_scanner_finish();
+
/*
* If that was successful, complete the functions info.
*/
/*
* Build and return the complete row definition
*/
- plpgsql_yylval.row = build_rowtype(classOid);
+ plpgsql_yylval.row = plpgsql_build_rowtype(classOid);
pfree(cp[0]);
pfree(cp[1]);
/*
* Build and return the complete row definition
*/
- plpgsql_yylval.row = build_rowtype(classOid);
+ plpgsql_yylval.row = plpgsql_build_rowtype(classOid);
pfree(cp);
* Build a rowtype data structure given the pg_class OID.
*/
PLpgSQL_row *
-build_rowtype(Oid classOid)
+plpgsql_build_rowtype(Oid classOid)
{
PLpgSQL_row *row;
HeapTuple classtup;
void
plpgsql_yyerror(const char *s)
{
- plpgsql_error_lineno = plpgsql_yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext);
}
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.35 2003/04/27 22:21:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.36 2003/05/05 16:46:28 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
extern int plpgsql_error_lineno;
extern char *plpgsql_error_funcname;
-/* linkage to the real yytext and yylineno variables */
+/* linkage to the real yytext variable */
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;
extern int plpgsql_parse_wordrowtype(char *word);
extern int plpgsql_parse_dblwordrowtype(char *word);
extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
-extern PLpgSQL_row *build_rowtype(Oid classOid);
+extern PLpgSQL_row *plpgsql_build_rowtype(Oid classOid);
extern void plpgsql_adddatum(PLpgSQL_datum * new);
extern int plpgsql_add_initdatums(int **varnos);
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);
+extern int plpgsql_scanner_lineno(void);
+extern void plpgsql_scanner_init(const char *str, int functype);
+extern void plpgsql_scanner_finish(void);
#endif /* PLPGSQL_H */
* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.24 2002/11/07 06:06:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.25 2003/05/05 16:46:28 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
#include "plpgsql.h"
-static char *plpgsql_source;
-static int plpgsql_bytes_left;
+/* No reason to constrain amount of data slurped */
+#define YY_READ_BUF_SIZE 16777216
+
+/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
+#define fprintf(file, fmt, msg) ereport(FATAL, (errmsg_internal("%s", msg)))
+
+/* Handles to the buffer that the lexer uses internally */
+static YY_BUFFER_STATE scanbufhandle;
+static char *scanbuf;
+
static int scanner_functype;
static int scanner_typereported;
static int pushback_token;
static bool have_pushback_token;
static int lookahead_token;
static bool have_lookahead_token;
+static const char *cur_line_start;
+static int cur_line_num;
int plpgsql_SpaceScanned = 0;
-
-static void plpgsql_input(char *buf, int *result, int max);
-
-#define YY_INPUT(buf,res,max) plpgsql_input(buf, &res, max)
%}
%option 8bit
%option nounput
%option noyywrap
-%option yylineno
%option case-insensitive
%%
/* ----------
- * Local variable in scanner to remember where
+ * Local variables in scanner to remember where
* a string or comment started
* ----------
*/
int start_lineno = 0;
+ char *start_charpos = NULL;
/* ----------
* Reset the state when entering the scanner
{digit}+ { return T_NUMBER; }
\". {
- plpgsql_error_lineno = yylineno;
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "unterminated quoted identifier");
}
*/
--[^\r\n]* ;
-\/\* { start_lineno = yylineno;
+\/\* { start_lineno = plpgsql_scanner_lineno();
BEGIN IN_COMMENT;
}
<IN_COMMENT>\*\/ { BEGIN INITIAL; plpgsql_SpaceScanned = 1; }
/* ----------
* Collect anything inside of ''s and return one STRING
+ *
+ * Hacking yytext/yyleng here lets us avoid using yymore(), which is
+ * a win for performance. It's safe because we know the underlying
+ * input buffer is not changing.
* ----------
*/
-' { start_lineno = yylineno;
+' {
+ start_lineno = plpgsql_scanner_lineno();
+ start_charpos = yytext;
BEGIN IN_STRING;
- yymore();
}
-<IN_STRING>\\. |
-<IN_STRING>'' { yymore(); }
-<IN_STRING>' { BEGIN INITIAL;
+<IN_STRING>\\. { }
+<IN_STRING>'' { }
+<IN_STRING>' {
+ yyleng -= (yytext - start_charpos);
+ yytext = start_charpos;
+ BEGIN INITIAL;
return T_STRING;
}
<IN_STRING><<EOF>> {
plpgsql_error_lineno = start_lineno;
elog(ERROR, "unterminated string");
}
-<IN_STRING>[^'\\]* { yymore(); }
+<IN_STRING>[^'\\]* { }
/* ----------
* Any unmatched character is returned as is
%%
-static void
-plpgsql_input(char *buf, int *result, int max)
-{
- int n = max;
-
- if (n > plpgsql_bytes_left)
- n = plpgsql_bytes_left;
-
- if (n == 0)
- {
- *result = YY_NULL;
- return;
- }
-
- *result = n;
- memcpy(buf, plpgsql_source, n);
- plpgsql_source += n;
- plpgsql_bytes_left -= n;
-}
-
/*
* This is the yylex routine called from outside. It exists to provide
* a pushback facility, as well as to allow us to parse syntax that
have_pushback_token = true;
}
+/*
+ * Get the line number at which the current token ends. This substitutes
+ * for flex's very poorly implemented yylineno facility.
+ *
+ * We assume that flex has written a '\0' over the character following the
+ * current token in scanbuf. So, we just have to count the '\n' characters
+ * before that. We optimize this a little by keeping track of the last
+ * '\n' seen so far.
+ */
+int
+plpgsql_scanner_lineno(void)
+{
+ const char *c;
+
+ while ((c = strchr(cur_line_start, '\n')) != NULL)
+ {
+ cur_line_start = c + 1;
+ cur_line_num++;
+ }
+ return cur_line_num;
+}
/*
- * Initialize the scanner for new input.
+ * Called before any actual parsing is done
*/
void
-plpgsql_setinput(char *source, int functype)
+plpgsql_scanner_init(const char *str, int functype)
{
- yyrestart(NULL);
- yylineno = 1;
-
- plpgsql_source = source;
+ Size slen;
/*----------
* Hack: skip any initial newline, so that in the common coding layout
* we will think "line 1" is what the programmer thinks of as line 1.
*----------
*/
- if (*plpgsql_source == '\r')
- plpgsql_source++;
- if (*plpgsql_source == '\n')
- plpgsql_source++;
+ if (*str == '\r')
+ str++;
+ if (*str == '\n')
+ str++;
- plpgsql_bytes_left = strlen(plpgsql_source);
+ slen = strlen(str);
+ /*
+ * Might be left over after ereport()
+ */
+ if (YY_CURRENT_BUFFER)
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+
+ /*
+ * Make a scan buffer with special termination needed by flex.
+ */
+ scanbuf = palloc(slen + 2);
+ memcpy(scanbuf, str, slen);
+ scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
+ scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
+
+ /* Other setup */
scanner_functype = functype;
scanner_typereported = 0;
have_pushback_token = false;
have_lookahead_token = false;
+
+ cur_line_start = scanbuf;
+ cur_line_num = 1;
+
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Called after parsing is done to clean up after plpgsql_scanner_init()
+ */
+void
+plpgsql_scanner_finish(void)
+{
+ yy_delete_buffer(scanbufhandle);
+ pfree(scanbuf);
}