Scanner performance improvements
authorPeter Eisentraut
Sat, 20 Apr 2002 21:56:15 +0000 (21:56 +0000)
committerPeter Eisentraut
Sat, 20 Apr 2002 21:56:15 +0000 (21:56 +0000)
Use flex flags -CF.  Pass the to-be-scanned string around as StringInfo
type, to avoid querying the length repeatedly.  Clean up some code and
remove lex-compatibility cruft.  Escape backslash sequences inline.  Use
flex-provided yy_scan_buffer() function to set up input, rather than using
myinput().

src/backend/parser/Makefile
src/backend/parser/parse_type.c
src/backend/parser/parser.c
src/backend/parser/scan.l
src/backend/tcop/postgres.c
src/include/parser/gramparse.h
src/include/parser/parser.h
src/include/tcop/tcopprot.h

index 043852f3de66de0a0e1a09bbf461f4fc5fa59dad..d5d4f4372d8780b4ffc3a8e34571107418201f1d 100644 (file)
@@ -2,7 +2,7 @@
 #
 # Makefile for parser
 #
-# $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.36 2002/03/08 07:12:11 tgl Exp $
+# $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.37 2002/04/20 21:56:14 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,6 +14,8 @@ OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o \
       parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \
       parse_type.o parse_coerce.o parse_target.o scan.o scansup.o
 
+FLEXFLAGS = -CF
+
 
 all: SUBSYS.o
 
@@ -42,7 +44,7 @@ endif
 
 $(srcdir)/scan.c: scan.l
 ifdef FLEX
-   $(FLEX) $(FLEXFLAGS) -Pbase_yy -o'$@' $<
+   $(FLEX) $(FLEXFLAGS) -o'$@' $<
 else
    @$(missing) flex $< $@
 endif
@@ -59,13 +61,3 @@ clean:
    rm -f SUBSYS.o $(OBJS)
 # And the garbage that might have been left behind by partial build:
    @rm -f y.tab.c y.tab.h lex.yy.c
-
-
-# This is unusual:  We actually have to build some of the parts before
-# we know what the header file dependencies are.  
-dep depend: gram.c scan.c
-   $(CC) -MM $(CFLAGS) *.c >depend
-
-ifeq (depend,$(wildcard depend))
-include depend
-endif
index a6ba9661951a8a33a90d8db1e7919ac9e69abd5c..0901164389d84d64e3561063d5beb4a090af1984 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.39 2002/03/30 01:02:41 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.40 2002/04/20 21:56:14 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -473,17 +473,17 @@ typeidTypeRelid(Oid type_id)
 void
 parseTypeString(const char *str, Oid *type_id, int32 *typmod)
 {
-   char       *buf;
+   StringInfoData 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);
+   initStringInfo(&buf);
+   appendStringInfo(&buf, "SELECT (NULL::%s)", str);
 
-   raw_parsetree_list = parser(buf, NULL, 0);
+   raw_parsetree_list = parser(&buf, NULL, 0);
 
    /*
     * Make sure we got back exactly what we expected and no more;
@@ -528,5 +528,5 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
    *type_id = typenameTypeId(typename);
    *typmod = typename->typmod;
 
-   pfree(buf);
+   pfree(buf.data);
 }
index f83d04e69ccca0488473b2f8cb2c12d16e5350e7..4eadbef5f44e64c211946f073cdde8e2afa93834 100644 (file)
@@ -14,7 +14,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.51 2001/11/05 17:46:26 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.52 2002/04/20 21:56:14 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "parser/parse_expr.h"
 
 
-#if defined(FLEX_SCANNER)
-extern void DeleteBuffer(void);
-#endif   /* FLEX_SCANNER */
-
-char      *parseString;        /* the char* which holds the string to be
-                                * parsed */
 List      *parsetree;          /* result of parsing is left here */
 
 static int lookahead_token;    /* one-token lookahead */
@@ -48,24 +42,20 @@ static bool have_lookahead;     /* lookahead_token set? */
  * Returns a list of raw (un-analyzed) parse trees.
  */
 List *
-parser(char *str, Oid *typev, int nargs)
+parser(StringInfo str, Oid *typev, int nargs)
 {
    int         yyresult;
 
-   parseString = str;
    parsetree = NIL;            /* in case parser forgets to set it */
    have_lookahead = false;
 
-   scanner_init();
+   scanner_init(str);
    parser_init(typev, nargs);
    parse_expr_init();
 
    yyresult = yyparse();
 
-#if defined(FLEX_SCANNER)
-   DeleteBuffer();
-#endif   /* FLEX_SCANNER */
-
+   scanner_finish();
    clearerr(stdin);
 
    if (yyresult)               /* error */
index e8b43ec0d76516c5d2baee7e8441cbce07f6790e..cb8610c87ac384a3e0730eb67e33283ff4af7365 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.91 2002/03/06 06:09:56 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.92 2002/04/20 21:56:14 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,9 +17,6 @@
 
 #include 
 #include 
-#ifndef __linux__
-#include 
-#endif
 #include 
 
 #include "miscadmin.h"
 #include "parser/gramparse.h"
 #include "parser/keywords.h"
 #include "parser/parse.h"
-#include "parser/scansup.h"
 #include "utils/builtins.h"
 
 #ifdef MULTIBYTE
 #include "mb/pg_wchar.h"
 #endif
 
-extern char *parseString;
-static char *parseCh;
-
-/* some versions of lex define this as a macro */
-#if defined(yywrap)
-#undef yywrap
-#endif /* yywrap */
-
-/* set up my input handler --- need one flavor for flex, one for lex */
-#if defined(FLEX_SCANNER)
-
-#define YY_NEVER_INTERACTIVE 1
-#define YY_NO_UNPUT
-static int myinput(char* buf, int max);
-#undef YY_INPUT
-#define YY_INPUT(buf,result,max) {result = myinput(buf,max);}
-
-/* No reason to constrain amount of data slurped per myinput() call. */
+/* 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)  elog(FATAL, "%s", (msg))
 
-#else /* !FLEX_SCANNER */
-
-#undef input
-int input();
-#undef unput
-void unput(char);
-
-#endif /* FLEX_SCANNER */
-
 extern YYSTYPE yylval;
 
 static int     xcdepth = 0;    /* depth of nesting in slash-star comments */
@@ -83,8 +53,23 @@ static int       literalalloc;   /* current allocated buffer size */
 
 #define startlit()  (literalbuf[0] = '\0', literallen = 0)
 static void addlit(char *ytext, int yleng);
+static void addlitchar(unsigned char ychar);
+static char *litbufdup(void);
+
+/* Handles to the buffer that the lexer uses internally */
+static YY_BUFFER_STATE scanbufhandle;
+static char *scanbuf;
+
+unsigned char unescape_single_char(unsigned char c);
 
 %}
+
+%option 8bit
+%option never-interactive
+%option nounput
+%option noyywrap
+%option prefix="base_yy"
+
 /*
  * OK, here is a short description of lex/flex rules behavior.
  * The longest pattern which matches an input string is always chosen.
@@ -126,18 +111,17 @@ xhcat         {quote}{whitespace_with_newline}{quote}
 /* Extended quote
  * xqdouble implements SQL92 embedded quote
  * xqcat allows strings to cross input lines
- * Note: reduction of '' and \ sequences to output text is done in scanstr(),
- * not by rules here.  But we do get rid of xqcat sequences here.
  */
 quote          '
 xqstart            {quote}
 xqstop         {quote}
 xqdouble       {quote}{quote}
 xqinside       [^\\']+
-xqliteral      [\\](.|\n)
+xqescape       [\\][^0-7]
+xqoctesc       [\\][0-7]{1,3}
 xqcat          {quote}{whitespace_with_newline}{quote}
 
-/* Delimited quote
+/* Double quote
  * Allows embedded spaces and other special characters into identifiers.
  */
 dquote         \"
@@ -238,10 +222,7 @@ whitespace_with_newline    ({horiz_whitespace}*{newline}{whitespace}*)
 
 other          .
 
-/* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
- * AT&T lex does not properly handle C-style comments in this second lex block.
- * So, put comments here. thomas - 1997-09-08
- *
+/*
  * Quoted strings must allow some special characters such as single-quote
  *  and newline.
  * Embedded single-quotes are implemented both in the SQL92-standard
@@ -285,14 +266,14 @@ other         .
 {xbitstart}        {
                    BEGIN(xbit);
                    startlit();
-                   addlit("b", 1);
+                   addlitchar('b');
                }
 {xbitstop}   {
                    BEGIN(INITIAL);
                    if (literalbuf[strspn(literalbuf + 1, "01") + 1] != '\0')
                        elog(ERROR, "invalid bit string input: '%s'",
                             literalbuf);
-                   yylval.str = pstrdup(literalbuf);
+                   yylval.str = litbufdup();
                    return BITCONST;
                }
 {xhinside} |
@@ -335,14 +316,22 @@ other         .
                }
 {xqstop}   {
                    BEGIN(INITIAL);
-                   yylval.str = scanstr(literalbuf);
+                   yylval.str = litbufdup();
                    return SCONST;
                }
-{xqdouble} |
-{xqinside} |
-{xqliteral} {
+{xqdouble}  {
+                   addlitchar('\'');
+               }
+{xqinside}  {
                    addlit(yytext, yyleng);
                }
+{xqescape}  {
+                   addlitchar(unescape_single_char(yytext[1]));
+               }
+{xqoctesc}  {
+                   unsigned char c = strtoul(yytext+1, NULL, 8);
+                   addlitchar(c);
+               }
 {xqcat}        {
                    /* ignore */
                }
@@ -371,11 +360,11 @@ other         .
                        literalbuf[NAMEDATALEN-1] = '\0';
 #endif
                    }
-                   yylval.str = pstrdup(literalbuf);
+                   yylval.str = litbufdup();
                    return IDENT;
                }
 {xddouble} {
-                   addlit(yytext, yyleng-1);
+                   addlitchar('"');
                }
 {xdinside} {
                    addlit(yytext, yyleng);
@@ -540,36 +529,44 @@ yyerror(const char *message)
    elog(ERROR, "parser: %s at or near \"%s\"", message, yytext);
 }
 
-int
-yywrap(void)
-{
-   return(1);
-}
 
 /*
- scanner_init:
-   called by postgres before any actual parsing is done
-*/
+ * Called before any actual parsing is done
+ */
 void
-scanner_init(void)
+scanner_init(StringInfo str)
 {
-   /* it's important to set this to NULL
-      because input()/myinput() checks the non-nullness of parseCh
-      to know when to pass the string to lex/flex */
-   parseCh = NULL;
+   /*
+    * Might be left over after elog()
+    */
+   if (YY_CURRENT_BUFFER)
+       yy_delete_buffer(YY_CURRENT_BUFFER);
+
+   scanbuf = palloc(str->len + 2);
+   memcpy(scanbuf, str->data, str->len);
+   scanbuf[str->len] = scanbuf[str->len + 1] = YY_END_OF_BUFFER_CHAR;
+   scanbufhandle = yy_scan_buffer(scanbuf, str->len + 2);
 
    /* initialize literal buffer to a reasonable but expansible size */
    literalalloc = 128;
    literalbuf = (char *) palloc(literalalloc);
    startlit();
 
-#if defined(FLEX_SCANNER)
-   if (YY_CURRENT_BUFFER)
-       yy_flush_buffer(YY_CURRENT_BUFFER);
-#endif /* FLEX_SCANNER */
-   BEGIN INITIAL;
+   BEGIN(INITIAL);
 }
 
+
+/*
+ * Called after parsing is done to clean up after scanner_init()
+ */
+void
+scanner_finish(void)
+{
+   yy_delete_buffer(scanbufhandle);
+   pfree(scanbuf);
+}
+
+
 static void
 addlit(char *ytext, int yleng)
 {
@@ -587,54 +584,55 @@ addlit(char *ytext, int yleng)
    literalbuf[literallen] = '\0';
 }
 
-#if !defined(FLEX_SCANNER)
 
-/* get lex input from a string instead of from stdin */
-int
-input()
+static void
+addlitchar(unsigned char ychar)
 {
-   if (parseCh == NULL)
-       parseCh = parseString;
-   if (*parseCh == '\0')
-       return(0);
-   else
-       return(*parseCh++);
+   /* enlarge buffer if needed */
+   if ((literallen+1) >= literalalloc)
+   {
+       literalalloc *= 2;
+       literalbuf = (char *) repalloc(literalbuf, literalalloc);
+   }
+   /* append new data, add trailing null */
+   literalbuf[literallen] = ychar;
+   literallen += 1;
+   literalbuf[literallen] = '\0';
 }
 
-/* undo lex input from a string instead of from stdin */
-void
-unput(char c)
+
+/*
+ * One might be tempted to write pstrdup(literalbuf) instead of this,
+ * but for long literals this is much faster because the length is
+ * already known.
+ */
+static char *
+litbufdup(void)
 {
-   if (parseCh == NULL)
-       elog(FATAL, "Unput() failed.\n");
-   else if (c != 0)
-       *--parseCh = c;
-}
+   char *new;
 
-#endif /* !defined(FLEX_SCANNER) */
+   new = palloc(literallen + 1);
+   memcpy(new, literalbuf, literallen+1);
+   return new;
+}
 
-#ifdef FLEX_SCANNER
 
-/* input routine for flex to read input from a string instead of a file */
-static int
-myinput(char* buf, int max)
+unsigned char
+unescape_single_char(unsigned char c)
 {
-   int len;
-
-   if (parseCh == NULL)
-       parseCh = parseString;
-   len = strlen(parseCh);      /* remaining data available */
-   /* Note: this code used to think that flex wants a null-terminated
-    * string.  It does NOT, and returning 1 less character than it asks
-    * for will cause failure under the right boundary conditions.  So
-    * shut up and fill the buffer to the limit, you hear?
-    */
-   if (len > max)
-       len = max;
-   if (len > 0)
-       memcpy(buf, parseCh, len);
-   parseCh += len;
-   return len;
+   switch (c)
+   {
+       case 'b':
+           return '\b';
+       case 'f':
+           return '\f';
+       case 'n':
+           return '\n';
+       case 'r':
+           return '\r';
+       case 't':
+           return '\t';
+       default:
+           return c;
+   }
 }
-
-#endif /* FLEX_SCANNER */
index d8c2065258b0ef4bbe151ccb367cf0da6a720388..5305f1b2f754b9eede4103bcdf8416ae02c0fd88 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.261 2002/04/18 20:01:09 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.262 2002/04/20 21:56:15 petere Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -120,7 +120,7 @@ int         XfuncMode = 0;
 static int InteractiveBackend(StringInfo inBuf);
 static int SocketBackend(StringInfo inBuf);
 static int ReadCommand(StringInfo inBuf);
-static List *pg_parse_query(char *query_string, Oid *typev, int nargs);
+static List *pg_parse_query(StringInfo query_string, Oid *typev, int nargs);
 static List *pg_analyze_and_rewrite(Node *parsetree);
 static void start_xact_command(void);
 static void finish_xact_command(void);
@@ -330,11 +330,15 @@ pg_parse_and_rewrite(char *query_string,      /* string to execute */
    List       *raw_parsetree_list;
    List       *querytree_list;
    List       *list_item;
+   StringInfoData stri;
+
+   initStringInfo(&stri);
+   appendStringInfo(&stri, "%s", query_string);
 
    /*
     * (1) parse the request string into a list of raw parse trees.
     */
-   raw_parsetree_list = pg_parse_query(query_string, typev, nargs);
+   raw_parsetree_list = pg_parse_query(&stri, typev, nargs);
 
    /*
     * (2) Do parse analysis and rule rewrite.
@@ -365,12 +369,12 @@ pg_parse_and_rewrite(char *query_string,      /* string to execute */
  * commands are not processed any further than the raw parse stage.
  */
 static List *
-pg_parse_query(char *query_string, Oid *typev, int nargs)
+pg_parse_query(StringInfo query_string, Oid *typev, int nargs)
 {
    List       *raw_parsetree_list;
 
    if (Debug_print_query)
-       elog(LOG, "query: %s", query_string);
+       elog(LOG, "query: %s", query_string->data);
 
    if (Show_parser_stats)
        ResetUsage();
@@ -549,7 +553,7 @@ pg_plan_query(Query *querytree)
  */
 
 void
-pg_exec_query_string(char *query_string,       /* string to execute */
+pg_exec_query_string(StringInfo query_string,      /* string to execute */
                     CommandDest dest,  /* where results should go */
                     MemoryContext parse_context)       /* context for
                                                         * parsetrees */
@@ -559,7 +563,7 @@ pg_exec_query_string(char *query_string,        /* string to execute */
    List       *parsetree_list,
               *parsetree_item;
 
-   debug_query_string = query_string;  /* used by pgmonitor */
+   debug_query_string = query_string->data;    /* used by pgmonitor */
 
    /*
     * Start up a transaction command.  All queries generated by the
@@ -725,7 +729,7 @@ pg_exec_query_string(char *query_string,        /* string to execute */
                 * process utility functions (create, destroy, etc..)
                 */
                if (Debug_print_query)
-                   elog(LOG, "ProcessUtility: %s", query_string);
+                   elog(LOG, "ProcessUtility: %s", query_string->data);
                else elog(DEBUG2, "ProcessUtility");
 
                if (querytree->originalQuery)
@@ -1688,7 +1692,7 @@ PostgresMain(int argc, char *argv[], const char *username)
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.261 $ $Date: 2002/04/18 20:01:09 $\n");
+       puts("$Revision: 1.262 $ $Date: 2002/04/20 21:56:15 $\n");
    }
 
    /*
@@ -1913,7 +1917,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 
                    pgstat_report_activity(parser_input->data);
 
-                   pg_exec_query_string(parser_input->data,
+                   pg_exec_query_string(parser_input,
                                         whereToSendOutput,
                                         QueryContext);
 
index 42ae42d9e63b084e5d3db3fb6f2821d71d197e3a..3a1c9353bbfb84420ee168c77c0d5c72360e6756 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: gramparse.h,v 1.20 2002/04/09 20:35:55 tgl Exp $
+ * $Id: gramparse.h,v 1.21 2002/04/20 21:56:15 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GRAMPARSE_H
 #define GRAMPARSE_H
 
+#include "lib/stringinfo.h"
+
 /* from parser.c */
 extern int yylex(void);
 
 /* from scan.l */
-extern void scanner_init(void);
+extern void scanner_init(StringInfo str);
+extern void scanner_finish(void);
 extern int base_yylex(void);
 extern void yyerror(const char *message);
 
index 8547a66cc14b313ca70b7bfe5361bb830b20131c..30d9a11fe460ac3f92231c27948f56efe28d005c 100644 (file)
@@ -7,15 +7,16 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parser.h,v 1.11 2001/11/05 17:46:35 momjian Exp $
+ * $Id: parser.h,v 1.12 2002/04/20 21:56:15 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef PARSER_H
 #define PARSER_H
 
+#include "lib/stringinfo.h"
 #include "parser/parse_node.h"
 
-extern List *parser(char *str, Oid *typev, int nargs);
+extern List *parser(StringInfo str, Oid *typev, int nargs);
 
 #endif   /* PARSER_H */
index 28e45e7b5e98068b53cc444f1381ba3243219513..0f79e8ab9d6d1760a25114a7162266093c7ce3d8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tcopprot.h,v 1.47 2001/11/10 23:51:14 tgl Exp $
+ * $Id: tcopprot.h,v 1.48 2002/04/20 21:56:15 petere Exp $
  *
  * OLD COMMENTS
  *   This file was created so that other c files could get the two
@@ -22,6 +22,7 @@
 #include 
 
 #include "executor/execdesc.h"
+#include "lib/stringinfo.h"
 #include "tcop/dest.h"
 
 
@@ -37,7 +38,7 @@ extern bool ShowPortNumber;
 extern List *pg_parse_and_rewrite(char *query_string,
                     Oid *typev, int nargs);
 extern Plan *pg_plan_query(Query *querytree);
-extern void pg_exec_query_string(char *query_string,
+extern void pg_exec_query_string(StringInfo query_string,
                     CommandDest dest,
                     MemoryContext parse_context);
 #endif   /* BOOTSTRAP_INCLUDE */