xref: /Universal-ctags/parsers/sql.c (revision aaaac7eeac8399141aa8e6d9e6ec0379931848b2)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO  *	Copyright (c) 2002-2003, Darren Hiebert
33ae02089SMasatake YAMATO  *
43ae02089SMasatake YAMATO  *	This source code is released for free distribution under the terms of the
50ce38835Sviccuad  *	GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO  *
73ae02089SMasatake YAMATO  *	This module contains functions for generating tags for PL/SQL language
83ae02089SMasatake YAMATO  *	files.
93ae02089SMasatake YAMATO  */
103ae02089SMasatake YAMATO 
113ae02089SMasatake YAMATO /*
123ae02089SMasatake YAMATO  *	 INCLUDE FILES
133ae02089SMasatake YAMATO  */
143ae02089SMasatake YAMATO #include "general.h"	/* must always come first */
153ae02089SMasatake YAMATO 
163ae02089SMasatake YAMATO #include <ctype.h>	/* to define isalpha () */
173ae02089SMasatake YAMATO #ifdef DEBUG
183ae02089SMasatake YAMATO #include <stdio.h>
193ae02089SMasatake YAMATO #endif
2047acb582SColomban Wendling #include <string.h>
213ae02089SMasatake YAMATO 
223ae02089SMasatake YAMATO #include "debug.h"
233ae02089SMasatake YAMATO #include "entry.h"
243ae02089SMasatake YAMATO #include "keyword.h"
253ae02089SMasatake YAMATO #include "parse.h"
263ae02089SMasatake YAMATO #include "read.h"
273ae02089SMasatake YAMATO #include "routines.h"
283ae02089SMasatake YAMATO #include "vstring.h"
29a1ea012bSMasatake YAMATO #include "xtag.h"
30a9b9ded9SMasatake YAMATO #include "promise.h"
313ae02089SMasatake YAMATO 
323ae02089SMasatake YAMATO /*
333ae02089SMasatake YAMATO  *	On-line "Oracle Database PL/SQL Language Reference":
343ae02089SMasatake YAMATO  *	http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/toc.htm
353ae02089SMasatake YAMATO  *
363ae02089SMasatake YAMATO  *	Sample PL/SQL code is available from:
373ae02089SMasatake YAMATO  *	http://www.orafaq.com/faqscrpt.htm#GENPLSQL
383ae02089SMasatake YAMATO  *
393ae02089SMasatake YAMATO  *	On-line SQL Anywhere Documentation
403ae02089SMasatake YAMATO  *	http://www.ianywhere.com/developer/product_manuals/sqlanywhere/index.html
413ae02089SMasatake YAMATO  */
423ae02089SMasatake YAMATO 
433ae02089SMasatake YAMATO /*
443ae02089SMasatake YAMATO  *	 MACROS
453ae02089SMasatake YAMATO  */
46ce990805SThomas Braun #define isType(token,t)		(bool) ((token)->type == (t))
47ce990805SThomas Braun #define isKeyword(token,k)	(bool) ((token)->keyword == (k))
488005ca8cSMasatake YAMATO #define isReservedWord(token) (SqlReservedWord[(token)->keyword].fn \
498005ca8cSMasatake YAMATO 							   ?(bool)SqlReservedWord[(token)->keyword].fn(token) \
508005ca8cSMasatake YAMATO 							   :SqlReservedWord[(token)->keyword].bit)
512b28d0e0SJiří Techet #define isIdentChar1(c) \
522b28d0e0SJiří Techet 	/*
532b28d0e0SJiří Techet 	 * Other databases are less restrictive on the first character of
542b28d0e0SJiří Techet 	 * an identifier.
552b28d0e0SJiří Techet 	 * isIdentChar1 is used to identify the first character of an
562b28d0e0SJiří Techet 	 * identifier, so we are removing some restrictions.
572b28d0e0SJiří Techet 	 */ \
582b28d0e0SJiří Techet 	(isalpha (c) || (c) == '@' || (c) == '_' )
592b28d0e0SJiří Techet #define isIdentChar(c) \
602b28d0e0SJiří Techet 	(isalpha (c) || isdigit (c) || (c) == '$' || \
612b28d0e0SJiří Techet 		(c) == '@' || (c) == '_' || (c) == '#')
623ae02089SMasatake YAMATO 
633ae02089SMasatake YAMATO /*
643ae02089SMasatake YAMATO  *	 DATA DECLARATIONS
653ae02089SMasatake YAMATO  */
663ae02089SMasatake YAMATO 
673ae02089SMasatake YAMATO /*
683ae02089SMasatake YAMATO  * Used to specify type of keyword.
693ae02089SMasatake YAMATO  */
704faa2076SColomban Wendling enum eKeywordId {
7102a6b22dSMasatake YAMATO 	KEYWORD_at,
723ae02089SMasatake YAMATO 	KEYWORD_begin,
733ae02089SMasatake YAMATO 	KEYWORD_body,
7402a6b22dSMasatake YAMATO 	KEYWORD_call,
7502a6b22dSMasatake YAMATO 	KEYWORD_case,
7602a6b22dSMasatake YAMATO 	KEYWORD_check,
77af68835dSMasatake YAMATO 	KEYWORD_commit,
7802a6b22dSMasatake YAMATO 	KEYWORD_comment,
7902a6b22dSMasatake YAMATO 	KEYWORD_constraint,
8002a6b22dSMasatake YAMATO 	KEYWORD_create,
813ae02089SMasatake YAMATO 	KEYWORD_cursor,
82dd3d1aaeSMasatake YAMATO 	KEYWORD_database,
8302a6b22dSMasatake YAMATO 	KEYWORD_datatype,
843ae02089SMasatake YAMATO 	KEYWORD_declare,
8502a6b22dSMasatake YAMATO 	KEYWORD_do,
8602a6b22dSMasatake YAMATO 	KEYWORD_domain,
8702a6b22dSMasatake YAMATO 	KEYWORD_drop,
883ae02089SMasatake YAMATO 	KEYWORD_else,
893ae02089SMasatake YAMATO 	KEYWORD_elseif,
9002a6b22dSMasatake YAMATO 	KEYWORD_end,
913ae02089SMasatake YAMATO 	KEYWORD_endif,
923ae02089SMasatake YAMATO 	KEYWORD_event,
933ae02089SMasatake YAMATO 	KEYWORD_exception,
947831b8dcSMasatake YAMATO 	KEYWORD_extension,
9502a6b22dSMasatake YAMATO 	KEYWORD_external,
9602a6b22dSMasatake YAMATO 	KEYWORD_for,
973ae02089SMasatake YAMATO 	KEYWORD_foreign,
9802a6b22dSMasatake YAMATO 	KEYWORD_from,
9902a6b22dSMasatake YAMATO 	KEYWORD_function,
10002a6b22dSMasatake YAMATO 	KEYWORD_go,
10102a6b22dSMasatake YAMATO 	KEYWORD_handler,
10202a6b22dSMasatake YAMATO 	KEYWORD_if,
10302a6b22dSMasatake YAMATO 	KEYWORD_index,
10402a6b22dSMasatake YAMATO 	KEYWORD_internal,
10502a6b22dSMasatake YAMATO 	KEYWORD_is,
106a9b9ded9SMasatake YAMATO 	KEYWORD_language,
10702a6b22dSMasatake YAMATO 	KEYWORD_local,
10802a6b22dSMasatake YAMATO 	KEYWORD_loop,
1093ae02089SMasatake YAMATO 	KEYWORD_ml_conn,
11002a6b22dSMasatake YAMATO 	KEYWORD_ml_conn_chk,
1113ae02089SMasatake YAMATO 	KEYWORD_ml_conn_dnet,
1123ae02089SMasatake YAMATO 	KEYWORD_ml_conn_java,
11302a6b22dSMasatake YAMATO 	KEYWORD_ml_conn_lang,
1143ae02089SMasatake YAMATO 	KEYWORD_ml_prop,
11502a6b22dSMasatake YAMATO 	KEYWORD_ml_table,
11602a6b22dSMasatake YAMATO 	KEYWORD_ml_table_chk,
11702a6b22dSMasatake YAMATO 	KEYWORD_ml_table_dnet,
11802a6b22dSMasatake YAMATO 	KEYWORD_ml_table_java,
11902a6b22dSMasatake YAMATO 	KEYWORD_ml_table_lang,
12002a6b22dSMasatake YAMATO 	KEYWORD_object,
12102a6b22dSMasatake YAMATO 	KEYWORD_on,
12202a6b22dSMasatake YAMATO 	KEYWORD_package,
12302a6b22dSMasatake YAMATO 	KEYWORD_pragma,
1244dbda622SMasatake YAMATO 	KEYWORD_inquiry_directive,
12502a6b22dSMasatake YAMATO 	KEYWORD_primary,
12602a6b22dSMasatake YAMATO 	KEYWORD_procedure,
12702a6b22dSMasatake YAMATO 	KEYWORD_publication,
12802a6b22dSMasatake YAMATO 	KEYWORD_record,
12902a6b22dSMasatake YAMATO 	KEYWORD_ref,
13002a6b22dSMasatake YAMATO 	KEYWORD_references,
13102a6b22dSMasatake YAMATO 	KEYWORD_rem,
13202a6b22dSMasatake YAMATO 	KEYWORD_result,
13302a6b22dSMasatake YAMATO 	KEYWORD_return,
13402a6b22dSMasatake YAMATO 	KEYWORD_returns,
135dd3d1aaeSMasatake YAMATO 	KEYWORD_schema,
13602a6b22dSMasatake YAMATO 	KEYWORD_select,
13702a6b22dSMasatake YAMATO 	KEYWORD_service,
13802a6b22dSMasatake YAMATO 	KEYWORD_subtype,
1393ae02089SMasatake YAMATO 	KEYWORD_synonym,
14002a6b22dSMasatake YAMATO 	KEYWORD_table,
14102a6b22dSMasatake YAMATO 	KEYWORD_temporary,
14202a6b22dSMasatake YAMATO 	KEYWORD_then,
14302a6b22dSMasatake YAMATO 	KEYWORD_trigger,
14402a6b22dSMasatake YAMATO 	KEYWORD_type,
14502a6b22dSMasatake YAMATO 	KEYWORD_unique,
14602a6b22dSMasatake YAMATO 	KEYWORD_url,
14702a6b22dSMasatake YAMATO 	KEYWORD_variable,
14802a6b22dSMasatake YAMATO 	KEYWORD_view,
14902a6b22dSMasatake YAMATO 	KEYWORD_when,
15002a6b22dSMasatake YAMATO 	KEYWORD_while,
151b36b4b38SColomban Wendling 	KEYWORD_with,
152b36b4b38SColomban Wendling 	KEYWORD_without,
153254b017aSMasatake YAMATO 	SQLKEYWORD_COUNT,
1544faa2076SColomban Wendling };
1554faa2076SColomban Wendling typedef int keywordId; /* to allow KEYWORD_NONE */
1563ae02089SMasatake YAMATO 
1573ae02089SMasatake YAMATO typedef enum eTokenType {
1583ae02089SMasatake YAMATO 	TOKEN_UNDEFINED,
1593ae02089SMasatake YAMATO 	TOKEN_EOF,
1603ae02089SMasatake YAMATO 	TOKEN_BLOCK_LABEL_BEGIN,
1613ae02089SMasatake YAMATO 	TOKEN_BLOCK_LABEL_END,
1623ae02089SMasatake YAMATO 	TOKEN_CHARACTER,
1633ae02089SMasatake YAMATO 	TOKEN_CLOSE_PAREN,
1643ae02089SMasatake YAMATO 	TOKEN_COLON,
1653ae02089SMasatake YAMATO 	TOKEN_SEMICOLON,
1663ae02089SMasatake YAMATO 	TOKEN_COMMA,
1673ae02089SMasatake YAMATO 	TOKEN_IDENTIFIER,
1683ae02089SMasatake YAMATO 	TOKEN_KEYWORD,
1693ae02089SMasatake YAMATO 	TOKEN_OPEN_PAREN,
1703ae02089SMasatake YAMATO 	TOKEN_OPERATOR,
1713ae02089SMasatake YAMATO 	TOKEN_OTHER,
1723ae02089SMasatake YAMATO 	TOKEN_STRING,
1733ae02089SMasatake YAMATO 	TOKEN_PERIOD,
1743ae02089SMasatake YAMATO 	TOKEN_OPEN_CURLY,
1753ae02089SMasatake YAMATO 	TOKEN_CLOSE_CURLY,
1763ae02089SMasatake YAMATO 	TOKEN_OPEN_SQUARE,
1773ae02089SMasatake YAMATO 	TOKEN_CLOSE_SQUARE,
1783ae02089SMasatake YAMATO 	TOKEN_TILDE,
1793ae02089SMasatake YAMATO 	TOKEN_FORWARD_SLASH,
1803ae02089SMasatake YAMATO 	TOKEN_EQUAL
1813ae02089SMasatake YAMATO } tokenType;
1823ae02089SMasatake YAMATO 
1833ae02089SMasatake YAMATO typedef struct sTokenInfoSQL {
1843ae02089SMasatake YAMATO 	tokenType	type;
1853ae02089SMasatake YAMATO 	keywordId	keyword;
1863ae02089SMasatake YAMATO 	vString *	string;
1873ae02089SMasatake YAMATO 	vString *	scope;
1883ae02089SMasatake YAMATO 	int         scopeKind;
1893ae02089SMasatake YAMATO 	int         begin_end_nest_lvl;
1903ae02089SMasatake YAMATO 	unsigned long lineNumber;
191509a47dbSJiří Techet 	MIOPos filePosition;
192a9b9ded9SMasatake YAMATO 
193a9b9ded9SMasatake YAMATO 	/* When the "guest" extra is enabled, a promise is
194a9b9ded9SMasatake YAMATO 	 * made always when reading a string (literal or dollar quote).
195a9b9ded9SMasatake YAMATO 	 * The lexer stores the id of promise to this member.
196a9b9ded9SMasatake YAMATO 	 * When making the promise, the language of guest parser
197a9b9ded9SMasatake YAMATO 	 * may not be determined yet.
198a9b9ded9SMasatake YAMATO 	 *
199a9b9ded9SMasatake YAMATO 	 *   CREATE FUNCTION ... AS ' sub code_written_in_perl {... ' LANGUAGE plperl;
200a9b9ded9SMasatake YAMATO 	 *
201a9b9ded9SMasatake YAMATO 	 * After reading a string, the parser may find LANGUAGE keyword. In the case,
202a9b9ded9SMasatake YAMATO 	 * the parser updates the language of the promies.
203a9b9ded9SMasatake YAMATO 	 *
204a9b9ded9SMasatake YAMATO 	 * This field is filled only when `guest` extra is enabled.
205a9b9ded9SMasatake YAMATO 	 *
206a9b9ded9SMasatake YAMATO 	 */
207a9b9ded9SMasatake YAMATO 	int promise;
2083ae02089SMasatake YAMATO } tokenInfo;
2093ae02089SMasatake YAMATO 
2103ae02089SMasatake YAMATO /*
2113ae02089SMasatake YAMATO  *	DATA DEFINITIONS
2123ae02089SMasatake YAMATO  */
2133ae02089SMasatake YAMATO 
2143ae02089SMasatake YAMATO static langType Lang_sql;
2153ae02089SMasatake YAMATO 
2163ae02089SMasatake YAMATO typedef enum {
2176383f885SMasatake YAMATO 	SQLTAG_PLSQL_CCFLAGS,
2186383f885SMasatake YAMATO 	SQLTAG_DOMAIN,
2193ae02089SMasatake YAMATO 	SQLTAG_FIELD,
2203ae02089SMasatake YAMATO 	SQLTAG_BLOCK_LABEL,
2213ae02089SMasatake YAMATO 	SQLTAG_PACKAGE,
2226383f885SMasatake YAMATO 	SQLTAG_SERVICE,
223dd3d1aaeSMasatake YAMATO 	SQLTAG_SCHEMA,
2246383f885SMasatake YAMATO 	SQLTAG_TRIGGER,
2256383f885SMasatake YAMATO 	SQLTAG_PUBLICATION,
2266383f885SMasatake YAMATO 	SQLTAG_VIEW,
227dd3d1aaeSMasatake YAMATO 	SQLTAG_DATABASE,
2286383f885SMasatake YAMATO 	SQLTAG_CURSOR,
2296383f885SMasatake YAMATO 	SQLTAG_PROTOTYPE,
2306383f885SMasatake YAMATO 	SQLTAG_EVENT,
2316383f885SMasatake YAMATO 	SQLTAG_FUNCTION,
2326383f885SMasatake YAMATO 	SQLTAG_INDEX,
2336383f885SMasatake YAMATO 	SQLTAG_LOCAL_VARIABLE,
2346383f885SMasatake YAMATO 	SQLTAG_SYNONYM,
2353ae02089SMasatake YAMATO 	SQLTAG_PROCEDURE,
2363ae02089SMasatake YAMATO 	SQLTAG_RECORD,
2373ae02089SMasatake YAMATO 	SQLTAG_SUBTYPE,
2383ae02089SMasatake YAMATO 	SQLTAG_TABLE,
2393ae02089SMasatake YAMATO 	SQLTAG_VARIABLE,
2403ae02089SMasatake YAMATO 	SQLTAG_MLTABLE,
2413ae02089SMasatake YAMATO 	SQLTAG_MLCONN,
2423ae02089SMasatake YAMATO 	SQLTAG_MLPROP,
2433ae02089SMasatake YAMATO 	SQLTAG_COUNT
2443ae02089SMasatake YAMATO } sqlKind;
2453ae02089SMasatake YAMATO 
246e112e8abSMasatake YAMATO static kindDefinition SqlKinds [] = {
2476383f885SMasatake YAMATO 	{ true,  'C', "ccflag",		  "PLSQL_CCFLAGS"          },
2486383f885SMasatake YAMATO 	{ true,  'D', "domain",		  "domains"				   },
2498050d8baSMasatake YAMATO 	{ true,  'E', "field",		  "record fields"		   },
250ce990805SThomas Braun 	{ true,  'L', "label",		  "block label"			   },
251ce990805SThomas Braun 	{ true,  'P', "package",	  "packages"			   },
2526383f885SMasatake YAMATO 	{ true,  'R', "service",	  "services"			   },
253dd3d1aaeSMasatake YAMATO 	{ true,  'S', "schema",		  "schemas"			  	   },
2546383f885SMasatake YAMATO 	{ true,  'T', "trigger",	  "triggers"			   },
2556383f885SMasatake YAMATO 	{ true,  'U', "publication",  "publications"		   },
2566383f885SMasatake YAMATO 	{ true,  'V', "view",		  "views"				   },
257dd3d1aaeSMasatake YAMATO 	{ true,  'b', "database",	  "database"			   },
2586383f885SMasatake YAMATO 	{ true,  'c', "cursor",		  "cursors"				   },
2596383f885SMasatake YAMATO 	{ false, 'd', "prototype",	  "prototypes"			   },
2606383f885SMasatake YAMATO 	{ true,  'e', "event",		  "events"				   },
2616383f885SMasatake YAMATO 	{ true,  'f', "function",	  "functions"			   },
2626383f885SMasatake YAMATO 	{ true,  'i', "index",		  "indexes"				   },
2636383f885SMasatake YAMATO 	{ false, 'l', "local",		  "local variables"		   },
2646383f885SMasatake YAMATO 	{ true,  'n', "synonym",	  "synonyms"			   },
265ce990805SThomas Braun 	{ true,  'p', "procedure",	  "procedures"			   },
266ce990805SThomas Braun 	{ false, 'r', "record",		  "records"				   },
267ce990805SThomas Braun 	{ true,  's', "subtype",	  "subtypes"			   },
268ce990805SThomas Braun 	{ true,  't', "table",		  "tables"				   },
269ce990805SThomas Braun 	{ true,  'v', "variable",	  "variables"			   },
270ce990805SThomas Braun 	{ true,  'x', "mltable",	  "MobiLink Table Scripts" },
271ce990805SThomas Braun 	{ true,  'y', "mlconn",		  "MobiLink Conn Scripts"  },
2725b62af54SMasatake YAMATO 	{ true,  'z', "mlprop",		  "MobiLink Properties"    },
2733ae02089SMasatake YAMATO };
2743ae02089SMasatake YAMATO 
27582c11d8cSRich Siegel static const keywordTable SqlKeywordTable [] = {
2763ae02089SMasatake YAMATO 	/* keyword		keyword ID */
2773ae02089SMasatake YAMATO 	{ "as",								KEYWORD_is				      },
27802a6b22dSMasatake YAMATO 	{ "at",								KEYWORD_at				      },
2793ae02089SMasatake YAMATO 	{ "begin",							KEYWORD_begin			      },
2803ae02089SMasatake YAMATO 	{ "body",							KEYWORD_body			      },
28102a6b22dSMasatake YAMATO 	{ "call",							KEYWORD_call			      },
28202a6b22dSMasatake YAMATO 	{ "case",							KEYWORD_case			      },
28302a6b22dSMasatake YAMATO 	{ "check",							KEYWORD_check			      },
284af68835dSMasatake YAMATO 	{ "commit",							KEYWORD_commit				  },
28502a6b22dSMasatake YAMATO 	{ "comment",						KEYWORD_comment			      },
28602a6b22dSMasatake YAMATO 	{ "constraint",						KEYWORD_constraint		      },
28702a6b22dSMasatake YAMATO 	{ "create",							KEYWORD_create				  },
2883ae02089SMasatake YAMATO 	{ "cursor",							KEYWORD_cursor			      },
289dd3d1aaeSMasatake YAMATO 	{ "database",						KEYWORD_database		      },
29002a6b22dSMasatake YAMATO 	{ "datatype",						KEYWORD_datatype		      },
2913ae02089SMasatake YAMATO 	{ "declare",						KEYWORD_declare			      },
29202a6b22dSMasatake YAMATO 	{ "do",								KEYWORD_do				      },
29302a6b22dSMasatake YAMATO 	{ "domain",							KEYWORD_domain				  },
29402a6b22dSMasatake YAMATO 	{ "drop",							KEYWORD_drop			      },
2953ae02089SMasatake YAMATO 	{ "else",							KEYWORD_else			      },
2963ae02089SMasatake YAMATO 	{ "elseif",							KEYWORD_elseif			      },
29702a6b22dSMasatake YAMATO 	{ "end",							KEYWORD_end				      },
2983ae02089SMasatake YAMATO 	{ "endif",							KEYWORD_endif			      },
29902a6b22dSMasatake YAMATO 	{ "event",							KEYWORD_event			      },
30002a6b22dSMasatake YAMATO 	{ "exception",						KEYWORD_exception		      },
3017831b8dcSMasatake YAMATO 	{ "extension",						KEYWORD_extension		      },
30202a6b22dSMasatake YAMATO 	{ "external",						KEYWORD_external		      },
3033ae02089SMasatake YAMATO 	{ "for",							KEYWORD_for				      },
30402a6b22dSMasatake YAMATO 	{ "foreign",						KEYWORD_foreign			      },
30502a6b22dSMasatake YAMATO 	{ "from",							KEYWORD_from			      },
30602a6b22dSMasatake YAMATO 	{ "function",						KEYWORD_function		      },
30702a6b22dSMasatake YAMATO 	{ "go",								KEYWORD_go				      },
30802a6b22dSMasatake YAMATO 	{ "handler",						KEYWORD_handler			      },
30902a6b22dSMasatake YAMATO 	{ "if",								KEYWORD_if				      },
31002a6b22dSMasatake YAMATO 	{ "index",							KEYWORD_index			      },
31102a6b22dSMasatake YAMATO 	{ "internal",						KEYWORD_internal		      },
31202a6b22dSMasatake YAMATO 	{ "is",								KEYWORD_is				      },
313a9b9ded9SMasatake YAMATO 	{ "language",						KEYWORD_language              },
31402a6b22dSMasatake YAMATO 	{ "local",							KEYWORD_local			      },
31502a6b22dSMasatake YAMATO 	{ "loop",							KEYWORD_loop			      },
31602a6b22dSMasatake YAMATO 	{ "ml_add_connection_script",		KEYWORD_ml_conn			      },
31702a6b22dSMasatake YAMATO 	{ "ml_add_dnet_connection_script",	KEYWORD_ml_conn_dnet	      },
31802a6b22dSMasatake YAMATO 	{ "ml_add_dnet_table_script",		KEYWORD_ml_table_dnet	      },
31902a6b22dSMasatake YAMATO 	{ "ml_add_java_connection_script",	KEYWORD_ml_conn_java	      },
32002a6b22dSMasatake YAMATO 	{ "ml_add_java_table_script",		KEYWORD_ml_table_java	      },
32102a6b22dSMasatake YAMATO 	{ "ml_add_lang_conn_script_chk",	KEYWORD_ml_conn_chk 	      },
32202a6b22dSMasatake YAMATO 	{ "ml_add_lang_connection_script",	KEYWORD_ml_conn_lang	      },
32302a6b22dSMasatake YAMATO 	{ "ml_add_lang_table_script",		KEYWORD_ml_table_lang	      },
32402a6b22dSMasatake YAMATO 	{ "ml_add_lang_table_script_chk",	KEYWORD_ml_table_chk	      },
32502a6b22dSMasatake YAMATO 	{ "ml_add_property",				KEYWORD_ml_prop		 	      },
32602a6b22dSMasatake YAMATO 	{ "ml_add_table_script",			KEYWORD_ml_table		      },
32702a6b22dSMasatake YAMATO 	{ "object",							KEYWORD_object			      },
32802a6b22dSMasatake YAMATO 	{ "on",								KEYWORD_on				      },
3293ae02089SMasatake YAMATO 	{ "package",						KEYWORD_package			      },
3303ae02089SMasatake YAMATO 	{ "pragma",							KEYWORD_pragma			      },
33102a6b22dSMasatake YAMATO 	{ "primary",						KEYWORD_primary			      },
3323ae02089SMasatake YAMATO 	{ "procedure",						KEYWORD_procedure		      },
33302a6b22dSMasatake YAMATO 	{ "publication",					KEYWORD_publication		      },
3343ae02089SMasatake YAMATO 	{ "record",							KEYWORD_record			      },
3353ae02089SMasatake YAMATO 	{ "ref",							KEYWORD_ref				      },
33602a6b22dSMasatake YAMATO 	{ "references",						KEYWORD_references		      },
3373ae02089SMasatake YAMATO 	{ "rem",							KEYWORD_rem				      },
33802a6b22dSMasatake YAMATO 	{ "result",							KEYWORD_result			      },
3393ae02089SMasatake YAMATO 	{ "return",							KEYWORD_return			      },
3403ae02089SMasatake YAMATO 	{ "returns",						KEYWORD_returns			      },
341dd3d1aaeSMasatake YAMATO 	{ "schema",							KEYWORD_schema			      },
34202a6b22dSMasatake YAMATO 	{ "select",							KEYWORD_select			      },
34302a6b22dSMasatake YAMATO 	{ "service",						KEYWORD_service			      },
3443ae02089SMasatake YAMATO 	{ "subtype",						KEYWORD_subtype			      },
34502a6b22dSMasatake YAMATO 	{ "synonym",						KEYWORD_synonym			      },
3463ae02089SMasatake YAMATO 	{ "table",							KEYWORD_table			      },
34702a6b22dSMasatake YAMATO 	{ "temporary",						KEYWORD_temporary		      },
34802a6b22dSMasatake YAMATO 	{ "then",							KEYWORD_then			      },
3493ae02089SMasatake YAMATO 	{ "trigger",						KEYWORD_trigger			      },
3503ae02089SMasatake YAMATO 	{ "type",							KEYWORD_type			      },
3513ae02089SMasatake YAMATO 	{ "unique",							KEYWORD_unique			      },
35202a6b22dSMasatake YAMATO 	{ "url",							KEYWORD_url				      },
35302a6b22dSMasatake YAMATO 	{ "variable",						KEYWORD_variable		      },
3543ae02089SMasatake YAMATO 	{ "view",							KEYWORD_view			      },
35502a6b22dSMasatake YAMATO 	{ "when",							KEYWORD_when			      },
35602a6b22dSMasatake YAMATO 	{ "while",							KEYWORD_while			      },
357b36b4b38SColomban Wendling 	{ "with",							KEYWORD_with			      },
358b36b4b38SColomban Wendling 	{ "without",						KEYWORD_without			      },
3593ae02089SMasatake YAMATO };
3603ae02089SMasatake YAMATO 
3614dbda622SMasatake YAMATO const static struct keywordGroup predefinedInquiryDirective = {
3624dbda622SMasatake YAMATO 	.value = KEYWORD_inquiry_directive,
3634dbda622SMasatake YAMATO 	.addingUnlessExisting = false,
3644dbda622SMasatake YAMATO 	.keywords = {
3654dbda622SMasatake YAMATO 		/* https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-language-fundamentals.html#GUID-3DABF5E1-AC84-448B-810F-31196991EA10 */
3664dbda622SMasatake YAMATO 		"PLSQL_LINE",
3674dbda622SMasatake YAMATO 		"PLSQL_UNIT",
3684dbda622SMasatake YAMATO 		"PLSQL_UNIT_OWNER",
3694dbda622SMasatake YAMATO 		"PLSQL_UNIT_TYPE",
3704dbda622SMasatake YAMATO 		/* https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/overview.html#GUID-DF63BC59-22C2-4BA8-9240-F74D505D5102 */
3714dbda622SMasatake YAMATO 		"PLSCOPE_SETTINGS",
3724dbda622SMasatake YAMATO 		"PLSQL_CCFLAGS",
3734dbda622SMasatake YAMATO 		"PLSQL_CODE_TYPE",
3744dbda622SMasatake YAMATO 		"PLSQL_OPTIMIZE_LEVEL",
3754dbda622SMasatake YAMATO 		"PLSQL_WARNINGS",
3764dbda622SMasatake YAMATO 		"NLS_LENGTH_SEMANTICS",
3774dbda622SMasatake YAMATO 		"PERMIT_92_WRAP_FORMAT",
3784dbda622SMasatake YAMATO 		NULL
3794dbda622SMasatake YAMATO 	},
3804dbda622SMasatake YAMATO };
3814dbda622SMasatake YAMATO 
382254b017aSMasatake YAMATO /* A table representing whether a keyword is "reserved word" or not.
383254b017aSMasatake YAMATO  * "reserved word" cannot be used as an name.
384254b017aSMasatake YAMATO  * See https://dev.mysql.com/doc/refman/8.0/en/keywords.html about the
385254b017aSMasatake YAMATO  * difference between keywords and the reserved words.
386254b017aSMasatake YAMATO  *
387254b017aSMasatake YAMATO  * We will mark a keyword as a reserved word only if all the SQL dialects
388254b017aSMasatake YAMATO  * specify it as a reserved word.
3898005ca8cSMasatake YAMATO  */
3908005ca8cSMasatake YAMATO struct SqlReservedWord {
3918005ca8cSMasatake YAMATO 	/* If fn is non-NULL, value returned from fn(token) is used
3928005ca8cSMasatake YAMATO 	 * to repreesnt whether a keyword is reserved (true) or not.
3938005ca8cSMasatake YAMATO 	 * If fn is NULL, bit is used. */
3948005ca8cSMasatake YAMATO 	unsigned int bit;
3958005ca8cSMasatake YAMATO 	bool (* fn) (tokenInfo *const token);
3968005ca8cSMasatake YAMATO };
3978005ca8cSMasatake YAMATO 
3988005ca8cSMasatake YAMATO /*
399254b017aSMasatake YAMATO  * MYSQL
400254b017aSMasatake YAMATO  * => https://dev.mysql.com/doc/refman/8.0/en/keywords.html
401254b017aSMasatake YAMATO  * POSTGRESQL,SQL2016,SQL2011,SQL92
402254b017aSMasatake YAMATO  * => https://www.postgresql.org/docs/12/sql-keywords-appendix.html
403254b017aSMasatake YAMATO  * ORACLE11g, PLSQL
404254b017aSMasatake YAMATO  * => https://docs.oracle.com/cd/B28359_01/appdev.111/b31231/appb.htm#CJHIIICD
405254b017aSMasatake YAMATO  * SQLANYWERE
406aa49e87eSMasatake YAMATO  * => http://dcx.sap.com/1200/en/dbreference/alhakeywords.html <the page is gone>
407254b017aSMasatake YAMATO  */
4088005ca8cSMasatake YAMATO static bool SqlReservedWordPredicatorForIsOrAs (tokenInfo *const token);
4098005ca8cSMasatake YAMATO static struct SqlReservedWord SqlReservedWord [SQLKEYWORD_COUNT] = {
410254b017aSMasatake YAMATO 	/*
411254b017aSMasatake YAMATO 	 * RESERVED_BIT: MYSQL & POSTGRESQL&SQL2016&SQL2011&SQL92 & ORACLE11g&PLSQL & SQLANYWERE
412dd3d1aaeSMasatake YAMATO 	 *
413dd3d1aaeSMasatake YAMATO 	 * {  0  } means we have not inspect whether the keyword is reserved or not.
414254b017aSMasatake YAMATO 	 */
4158005ca8cSMasatake YAMATO 	[KEYWORD_at]            = {0 & 0&1&1&1 & 0&1 & 0},
4168005ca8cSMasatake YAMATO 	[KEYWORD_begin]         = {0 & 0&1&1&1 & 0&1 & 1},
4178005ca8cSMasatake YAMATO 	[KEYWORD_body]          = {0 & 0&0&0&0 & 0&1 & 0},
4188005ca8cSMasatake YAMATO 	[KEYWORD_call]          = {1 & 0&1&1&0 & 0&0 & 1},
4198005ca8cSMasatake YAMATO 	[KEYWORD_case]          = {1 & 1&1&1&1 & 0&1 & 1},
4208005ca8cSMasatake YAMATO 	[KEYWORD_check]         = {1 & 1&1&1&1 & 1&1 & 1},
421af68835dSMasatake YAMATO 	[KEYWORD_commit]        = {0 & 0&1&1&1 & 0&0 & 0}, /* SQLANYWERE:??? */
4228005ca8cSMasatake YAMATO 	[KEYWORD_comment]       = {0 & 0&0&0&0 & 1&1 & 1},
4238005ca8cSMasatake YAMATO 	[KEYWORD_constraint]    = {1 & 1&1&1&1 & 0&1 & 1},
4248005ca8cSMasatake YAMATO 	[KEYWORD_create]        = {1 & 1&1&1&1 & 1&1 & 1},
4258005ca8cSMasatake YAMATO 	[KEYWORD_cursor]        = {1 & 0&1&1&1 & 0&1 & 1},
426dd3d1aaeSMasatake YAMATO 	[KEYWORD_database]      = {         0           },
4278005ca8cSMasatake YAMATO 	[KEYWORD_datatype]      = {0 & 0&0&0&0 & 0&0 & 0},
4288005ca8cSMasatake YAMATO 	[KEYWORD_declare]       = {1 & 0&1&1&1 & 0&1 & 1},
4298005ca8cSMasatake YAMATO 	[KEYWORD_do]            = {0 & 1&0&0&0 & 0&1 & 1},
4308005ca8cSMasatake YAMATO 	[KEYWORD_domain]        = {0 & 0&0&0&1 & 0&0 & 0},
4318005ca8cSMasatake YAMATO 	[KEYWORD_drop]          = {1 & 0&1&1&1 & 1&1 & 1},
4328005ca8cSMasatake YAMATO 	[KEYWORD_else]          = {1 & 1&1&1&1 & 1&1 & 1},
4338005ca8cSMasatake YAMATO 	[KEYWORD_elseif]        = {1 & 0&0&0&0 & 0&0 & 1},
4348005ca8cSMasatake YAMATO 	[KEYWORD_end]           = {0 & 1&1&1&1 & 0&1 & 1},
4358005ca8cSMasatake YAMATO 	[KEYWORD_endif]         = {0 & 0&0&0&0 & 0&0 & 1},
4368005ca8cSMasatake YAMATO 	[KEYWORD_event]         = {0 & 0&0&0&0 & 0&0 & 0},
4378005ca8cSMasatake YAMATO 	[KEYWORD_exception]     = {0 & 0&0&0&1 & 0&1 & 1},
4387831b8dcSMasatake YAMATO 	[KEYWORD_extension]     = {0 & 0&0&0&0 & 0&0 & 0},
4398005ca8cSMasatake YAMATO 	[KEYWORD_external]      = {0 & 0&1&1&1 & 0&0 & 0},
4408005ca8cSMasatake YAMATO 	[KEYWORD_for]           = {1 & 1&1&1&1 & 1&1 & 1},
4418005ca8cSMasatake YAMATO 	[KEYWORD_foreign]       = {1 & 1&1&1&1 & 0&0 & 1},
4428005ca8cSMasatake YAMATO 	[KEYWORD_from]          = {1 & 1&1&1&1 & 1&1 & 1},
4438005ca8cSMasatake YAMATO 	[KEYWORD_function]      = {1 & 0&1&1&0 & 0&1 & 0},
4448005ca8cSMasatake YAMATO 	[KEYWORD_go]            = {0 & 0&0&0&1 & 0&0 & 0},
4458005ca8cSMasatake YAMATO 	[KEYWORD_handler]       = {0 & 0&0&0&0 & 0&0 & 0},
4468005ca8cSMasatake YAMATO 	[KEYWORD_if]            = {1 & 0&0&0&0 & 0&1 & 1},
4478005ca8cSMasatake YAMATO 	[KEYWORD_index]         = {1 & 0&0&0&0 & 1&1 & 1},
4484dbda622SMasatake YAMATO 	[KEYWORD_inquiry_directive] = {        0        },
4498005ca8cSMasatake YAMATO 	[KEYWORD_internal]      = {1 & 0&1&1&0 & 0&0 & 0},
4508005ca8cSMasatake YAMATO 	[KEYWORD_is]            = {0, SqlReservedWordPredicatorForIsOrAs},
451a9b9ded9SMasatake YAMATO 	[KEYWORD_language]      = {            0        },
4528005ca8cSMasatake YAMATO 	[KEYWORD_local]         = {0 & 0&1&1&1 & 0&0 & 0},
4538005ca8cSMasatake YAMATO 	[KEYWORD_loop]          = {1 & 1&1&1&1 & 0&1 & 0},
4548005ca8cSMasatake YAMATO 	[KEYWORD_ml_conn]       = {0 & 0&0&0&0 & 0&0 & 0},
4558005ca8cSMasatake YAMATO 	[KEYWORD_ml_conn_dnet]  = {0 & 0&0&0&0 & 0&0 & 0},
4568005ca8cSMasatake YAMATO 	[KEYWORD_ml_table_dnet] = {0 & 0&0&0&0 & 0&0 & 0},
4578005ca8cSMasatake YAMATO 	[KEYWORD_ml_conn_java]  = {0 & 0&0&0&0 & 0&0 & 0},
4588005ca8cSMasatake YAMATO 	[KEYWORD_ml_table_java] = {0 & 0&0&0&0 & 0&0 & 0},
4598005ca8cSMasatake YAMATO 	[KEYWORD_ml_conn_chk]   = {0 & 0&0&0&0 & 0&0 & 0},
4608005ca8cSMasatake YAMATO 	[KEYWORD_ml_conn_lang]  = {0 & 0&0&0&0 & 0&0 & 0},
4618005ca8cSMasatake YAMATO 	[KEYWORD_ml_table_lang] = {0 & 0&0&0&0 & 0&0 & 0},
4628005ca8cSMasatake YAMATO 	[KEYWORD_ml_table_chk]  = {0 & 0&0&0&0 & 0&0 & 0},
4638005ca8cSMasatake YAMATO 	[KEYWORD_ml_prop]       = {0 & 0&0&0&0 & 0&0 & 0},
4648005ca8cSMasatake YAMATO 	[KEYWORD_ml_table]      = {0 & 0&0&0&0 & 0&0 & 0},
4658005ca8cSMasatake YAMATO 	[KEYWORD_object]        = {0 & 0&0&0&0 & 0&0 & 0},
4668005ca8cSMasatake YAMATO 	[KEYWORD_on]            = {1 & 1&1&1&1 & 1&1 & 1},
4678005ca8cSMasatake YAMATO 	[KEYWORD_package]       = {0 & 0&0&0&0 & 0&1 & 0},
4688005ca8cSMasatake YAMATO 	[KEYWORD_pragma]        = {0 & 0&0&0&0 & 0&1 & 0},
4698005ca8cSMasatake YAMATO 	[KEYWORD_primary]       = {1 & 1&1&1&1 & 0&0 & 1},
4708005ca8cSMasatake YAMATO 	[KEYWORD_procedure]     = {1 & 0&0&0&0 & 0&1 & 1},
4718005ca8cSMasatake YAMATO 	[KEYWORD_publication]   = {0 & 0&0&0&0 & 0&0 & 1},
4728005ca8cSMasatake YAMATO 	[KEYWORD_record]        = {0 & 0&0&0&0 & 0&1 & 0},
4738005ca8cSMasatake YAMATO 	[KEYWORD_ref]           = {0 & 0&1&1&0 & 0&0 & 0},
4748005ca8cSMasatake YAMATO 	[KEYWORD_references]    = {1 & 1&1&1&1 & 0&0 & 1},
4758005ca8cSMasatake YAMATO 	[KEYWORD_rem]           = {0 & 0&0&0&0 & 0&0 & 0},
4768005ca8cSMasatake YAMATO 	[KEYWORD_result]        = {0 & 0&1&1&0 & 0&0 & 0},
4778005ca8cSMasatake YAMATO 	[KEYWORD_return]        = {1 & 0&1&1&0 & 0&1 & 1},
4788005ca8cSMasatake YAMATO 	[KEYWORD_returns]       = {0 & 0&0&0&0 & 0&0 & 0},
479dd3d1aaeSMasatake YAMATO 	[KEYWORD_schema]        = {0 & 0&0&0&0 & 0&0 & 0},
4808005ca8cSMasatake YAMATO 	[KEYWORD_select]        = {1 & 1&1&1&1 & 1&1 & 1},
4818005ca8cSMasatake YAMATO 	[KEYWORD_service]       = {0 & 0&0&0&0 & 0&0 & 0},
4828005ca8cSMasatake YAMATO 	[KEYWORD_subtype]       = {0 & 0&0&0&0 & 0&1 & 0},
4838005ca8cSMasatake YAMATO 	[KEYWORD_synonym]       = {0 & 0&0&0&0 & 1&0 & 0},
4848005ca8cSMasatake YAMATO 	[KEYWORD_table]         = {1 & 1&1&1&1 & 1&1 & 1},
4858005ca8cSMasatake YAMATO 	[KEYWORD_temporary]     = {0 & 0&0&0&1 & 0&0 & 1},
4868005ca8cSMasatake YAMATO 	[KEYWORD_then]          = {1 & 1&1&1&1 & 1&1 & 1},
4878005ca8cSMasatake YAMATO 	[KEYWORD_trigger]       = {1 & 0&1&1&0 & 1&0 & 1},
4888005ca8cSMasatake YAMATO 	[KEYWORD_type]          = {0 & 0&0&0&0 & 0&1 & 0},
4898005ca8cSMasatake YAMATO 	[KEYWORD_unique]        = {1 & 1&1&1&1 & 1&1 & 1},
4908005ca8cSMasatake YAMATO 	[KEYWORD_url]           = {0 & 0&0&0&0 & 0&0 & 0},
4918005ca8cSMasatake YAMATO 	[KEYWORD_variable]      = {0 & 0&0&0&0 & 0&0 & 1},
4928005ca8cSMasatake YAMATO 	[KEYWORD_view]          = {0 & 0&0&0&1 & 1&1 & 1},
4938005ca8cSMasatake YAMATO 	[KEYWORD_when]          = {1 & 1&1&1&1 & 0&1 & 1},
4948005ca8cSMasatake YAMATO 	[KEYWORD_while]         = {1 & 0&0&0&0 & 0&1 & 1},
4958005ca8cSMasatake YAMATO 	[KEYWORD_with]          = {1 & 1&1&1&1 & 1&1 & 1},
4968005ca8cSMasatake YAMATO 	[KEYWORD_without]       = {0 & 0&1&1&0 & 0&0 & 0},
497254b017aSMasatake YAMATO };
498254b017aSMasatake YAMATO 
4993ae02089SMasatake YAMATO /*
5003ae02089SMasatake YAMATO  *	 FUNCTION DECLARATIONS
5013ae02089SMasatake YAMATO  */
5023ae02089SMasatake YAMATO 
5033ae02089SMasatake YAMATO /* Recursive calls */
504ce990805SThomas Braun static void parseBlock (tokenInfo *const token, const bool local);
505a9b9ded9SMasatake YAMATO static void parseBlockFull (tokenInfo *const token, const bool local, langType lang);
506ce990805SThomas Braun static void parseDeclare (tokenInfo *const token, const bool local);
5073ae02089SMasatake YAMATO static void parseKeywords (tokenInfo *const token);
5083ae02089SMasatake YAMATO static tokenType parseSqlFile (tokenInfo *const token);
5093ae02089SMasatake YAMATO 
5103ae02089SMasatake YAMATO /*
5113ae02089SMasatake YAMATO  *	 FUNCTION DEFINITIONS
5123ae02089SMasatake YAMATO  */
5133ae02089SMasatake YAMATO 
SqlReservedWordPredicatorForIsOrAs(tokenInfo * const token)5148005ca8cSMasatake YAMATO static bool SqlReservedWordPredicatorForIsOrAs (tokenInfo *const token)
5158005ca8cSMasatake YAMATO {
5168005ca8cSMasatake YAMATO 	if (strcasecmp ("as", vStringValue (token->string)) == 0)
5178005ca8cSMasatake YAMATO 		return (bool) (1 & 1&1&1&1 & 1&1 & 1);
5188005ca8cSMasatake YAMATO 	else						/* for "is" */
5198005ca8cSMasatake YAMATO 		return (bool) (1 & 0&1&1&1 & 1&1 & 1);
5208005ca8cSMasatake YAMATO 	/* PostgresSQL can use "is" as a name of function. */
5218005ca8cSMasatake YAMATO }
5228005ca8cSMasatake YAMATO 
isCmdTerm(tokenInfo * const token)523ce990805SThomas Braun static bool isCmdTerm (tokenInfo *const token)
5243ae02089SMasatake YAMATO {
5253ae02089SMasatake YAMATO 	DebugStatement (
5263ae02089SMasatake YAMATO 			debugPrintf (DEBUG_PARSE
5273ae02089SMasatake YAMATO 				, "\n isCmdTerm: token same  tt:%d  tk:%d\n"
5283ae02089SMasatake YAMATO 				, token->type
5293ae02089SMasatake YAMATO 				, token->keyword
5303ae02089SMasatake YAMATO 				);
5313ae02089SMasatake YAMATO 			);
5323ae02089SMasatake YAMATO 
5333ae02089SMasatake YAMATO 	/*
5343ae02089SMasatake YAMATO 	 * Based on the various customer sites I have been at
5353ae02089SMasatake YAMATO 	 * the most common command delimiters are
5363ae02089SMasatake YAMATO 	 *	   ;
5373ae02089SMasatake YAMATO 	 *	   ~
5383ae02089SMasatake YAMATO 	 *	   /
5393ae02089SMasatake YAMATO 	 *	   go
5403ae02089SMasatake YAMATO 	 * This routine will check for any of these, more
5413ae02089SMasatake YAMATO 	 * can easily be added by modifying readToken and
5423ae02089SMasatake YAMATO 	 * either adding the character to:
5433ae02089SMasatake YAMATO 	 *	   enum eTokenType
5443ae02089SMasatake YAMATO 	 *	   enum eTokenType
5453ae02089SMasatake YAMATO 	 */
5463ae02089SMasatake YAMATO 	return (isType (token, TOKEN_SEMICOLON) ||
5473ae02089SMasatake YAMATO 			isType (token, TOKEN_TILDE) ||
5483ae02089SMasatake YAMATO 			isType (token, TOKEN_FORWARD_SLASH) ||
5493ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_go));
5503ae02089SMasatake YAMATO }
5513ae02089SMasatake YAMATO 
isMatchedEnd(tokenInfo * const token,int nest_lvl)552ce990805SThomas Braun static bool isMatchedEnd(tokenInfo *const token, int nest_lvl)
5533ae02089SMasatake YAMATO {
554ce990805SThomas Braun 	bool terminated = false;
5553ae02089SMasatake YAMATO 	/*
5563ae02089SMasatake YAMATO 	 * Since different forms of SQL allow the use of
5573ae02089SMasatake YAMATO 	 * BEGIN
5583ae02089SMasatake YAMATO 	 * ...
5593ae02089SMasatake YAMATO 	 * END
5603ae02089SMasatake YAMATO 	 * blocks, some statements may not be terminated using
5613ae02089SMasatake YAMATO 	 * the standard delimiters:
5623ae02089SMasatake YAMATO 	 *	   ;
5633ae02089SMasatake YAMATO 	 *	   ~
5643ae02089SMasatake YAMATO 	 *	   /
5653ae02089SMasatake YAMATO 	 *	   go
5663ae02089SMasatake YAMATO 	 * This routine will check to see if we encounter and END
5673ae02089SMasatake YAMATO 	 * for the matching nest level of BEGIN ... END statements.
5683ae02089SMasatake YAMATO 	 * If we find one, then we can assume, the statement was terminated
5693ae02089SMasatake YAMATO 	 * since we have fallen through to the END statement of the BEGIN
5703ae02089SMasatake YAMATO 	 * block.
5713ae02089SMasatake YAMATO 	 */
5723ae02089SMasatake YAMATO 	if ( nest_lvl > 0 && isKeyword (token, KEYWORD_end) )
5733ae02089SMasatake YAMATO 	{
5743ae02089SMasatake YAMATO 		if ( token->begin_end_nest_lvl == nest_lvl )
575ce990805SThomas Braun 			terminated = true;
5763ae02089SMasatake YAMATO 	}
5773ae02089SMasatake YAMATO 
5783ae02089SMasatake YAMATO 	return terminated;
5793ae02089SMasatake YAMATO }
5803ae02089SMasatake YAMATO 
newToken(void)5813ae02089SMasatake YAMATO static tokenInfo *newToken (void)
5823ae02089SMasatake YAMATO {
5833ae02089SMasatake YAMATO 	tokenInfo *const token = xMalloc (1, tokenInfo);
5843ae02089SMasatake YAMATO 
5853ae02089SMasatake YAMATO 	token->type               = TOKEN_UNDEFINED;
5863ae02089SMasatake YAMATO 	token->keyword            = KEYWORD_NONE;
5873ae02089SMasatake YAMATO 	token->string             = vStringNew ();
5883ae02089SMasatake YAMATO 	token->scope              = vStringNew ();
5893ae02089SMasatake YAMATO 	token->scopeKind          = SQLTAG_COUNT;
5903ae02089SMasatake YAMATO 	token->begin_end_nest_lvl = 0;
591a31b37dcSMasatake YAMATO 	token->lineNumber         = getInputLineNumber ();
5923ae02089SMasatake YAMATO 	token->filePosition       = getInputFilePosition ();
593a9b9ded9SMasatake YAMATO 	token->promise            = -1;
5943ae02089SMasatake YAMATO 
5953ae02089SMasatake YAMATO 	return token;
5963ae02089SMasatake YAMATO }
5973ae02089SMasatake YAMATO 
deleteToken(tokenInfo * const token)5983ae02089SMasatake YAMATO static void deleteToken (tokenInfo *const token)
5993ae02089SMasatake YAMATO {
6003ae02089SMasatake YAMATO 	vStringDelete (token->string);
6013ae02089SMasatake YAMATO 	vStringDelete (token->scope);
6023ae02089SMasatake YAMATO 	eFree (token);
6033ae02089SMasatake YAMATO }
6043ae02089SMasatake YAMATO 
6053ae02089SMasatake YAMATO /*
6063ae02089SMasatake YAMATO  *	 Tag generation functions
6073ae02089SMasatake YAMATO  */
6083ae02089SMasatake YAMATO 
makeSqlTag(tokenInfo * const token,const sqlKind kind)6093ae02089SMasatake YAMATO static void makeSqlTag (tokenInfo *const token, const sqlKind kind)
6103ae02089SMasatake YAMATO {
6113ae02089SMasatake YAMATO 	if (SqlKinds [kind].enabled)
6123ae02089SMasatake YAMATO 	{
6133ae02089SMasatake YAMATO 		const char *const name = vStringValue (token->string);
6143ae02089SMasatake YAMATO 		tagEntryInfo e;
61516a2541cSMasatake YAMATO 		initTagEntry (&e, name, kind);
6163ae02089SMasatake YAMATO 
6173ae02089SMasatake YAMATO 		e.lineNumber   = token->lineNumber;
6183ae02089SMasatake YAMATO 		e.filePosition = token->filePosition;
6193ae02089SMasatake YAMATO 
6203ae02089SMasatake YAMATO 		if (vStringLength (token->scope) > 0)
6213ae02089SMasatake YAMATO 		{
6223ae02089SMasatake YAMATO 			Assert (token->scopeKind < SQLTAG_COUNT);
623f92e6bf2SMasatake YAMATO 			e.extensionFields.scopeKindIndex = token->scopeKind;
624015ab54cSMasatake YAMATO 			e.extensionFields.scopeName = vStringValue (token->scope);
625a1ea012bSMasatake YAMATO 
626a1ea012bSMasatake YAMATO 			if (isXtagEnabled (XTAG_QUALIFIED_TAGS))
627a1ea012bSMasatake YAMATO 			{
628a1ea012bSMasatake YAMATO 				vString *fulltag;
629a1ea012bSMasatake YAMATO 				tagEntryInfo xe = e;
630a1ea012bSMasatake YAMATO 
631a1ea012bSMasatake YAMATO 				fulltag =  vStringNewCopy (token->scope);
632a1ea012bSMasatake YAMATO 				vStringPut (fulltag, '.');
633a1ea012bSMasatake YAMATO 				vStringCat (fulltag, token->string);
634a1ea012bSMasatake YAMATO 				xe.name = vStringValue (fulltag);
635a1ea012bSMasatake YAMATO 				markTagExtraBit (&xe, XTAG_QUALIFIED_TAGS);
636a1ea012bSMasatake YAMATO 				makeTagEntry (&xe);
637a1ea012bSMasatake YAMATO 				vStringDelete (fulltag);
638a1ea012bSMasatake YAMATO 			}
6393ae02089SMasatake YAMATO 		}
6403ae02089SMasatake YAMATO 
6413ae02089SMasatake YAMATO 		makeTagEntry (&e);
6423ae02089SMasatake YAMATO 	}
6433ae02089SMasatake YAMATO }
6443ae02089SMasatake YAMATO 
6453ae02089SMasatake YAMATO /*
6463ae02089SMasatake YAMATO  *	 Parsing functions
6473ae02089SMasatake YAMATO  */
6483ae02089SMasatake YAMATO 
parseString(vString * const string,const int delimiter,int * promise)649a9b9ded9SMasatake YAMATO static void parseString (vString *const string, const int delimiter, int *promise)
6503ae02089SMasatake YAMATO {
651a9b9ded9SMasatake YAMATO 	int offset[2];
652a9b9ded9SMasatake YAMATO 	unsigned long linenum[3];
653a9b9ded9SMasatake YAMATO 	enum { START, END, SOURCE };
654a9b9ded9SMasatake YAMATO 
655a9b9ded9SMasatake YAMATO 	int c0;
656a9b9ded9SMasatake YAMATO 
657a9b9ded9SMasatake YAMATO 	if (promise && !isXtagEnabled(XTAG_GUEST))
658a9b9ded9SMasatake YAMATO 		promise = NULL;
659a9b9ded9SMasatake YAMATO 
660a9b9ded9SMasatake YAMATO 	if (promise)
661a9b9ded9SMasatake YAMATO 	{
662a9b9ded9SMasatake YAMATO 		c0 = getcFromInputFile ();
663a9b9ded9SMasatake YAMATO 		linenum[START] = getInputLineNumber ();
664a9b9ded9SMasatake YAMATO 		offset[START]  = getInputLineOffset ();
665a9b9ded9SMasatake YAMATO 		linenum[SOURCE] = getSourceLineNumber ();
666a9b9ded9SMasatake YAMATO 		ungetcToInputFile(c0);
667a9b9ded9SMasatake YAMATO 	}
668a9b9ded9SMasatake YAMATO 
669ce990805SThomas Braun 	bool end = false;
6703ae02089SMasatake YAMATO 	while (! end)
6713ae02089SMasatake YAMATO 	{
672018bce0bSMasatake YAMATO 		int c = getcFromInputFile ();
6733ae02089SMasatake YAMATO 		if (c == EOF)
674ce990805SThomas Braun 			end = true;
6753ae02089SMasatake YAMATO 		/*
6763ae02089SMasatake YAMATO 		else if (c == '\\')
6773ae02089SMasatake YAMATO 		{
678018bce0bSMasatake YAMATO 			c = getcFromInputFile(); // This maybe a ' or ". //
6793ae02089SMasatake YAMATO 			vStringPut(string, c);
6803ae02089SMasatake YAMATO 		}
6813ae02089SMasatake YAMATO 		*/
6823ae02089SMasatake YAMATO 		else if (c == delimiter)
683a9b9ded9SMasatake YAMATO 		{
684a9b9ded9SMasatake YAMATO 			if (promise)
685a9b9ded9SMasatake YAMATO 			{
686a9b9ded9SMasatake YAMATO 				ungetcToInputFile(c);
687a9b9ded9SMasatake YAMATO 				linenum[END] = getInputLineNumber ();
688a9b9ded9SMasatake YAMATO 				offset[END]  = getInputLineOffset ();
689a9b9ded9SMasatake YAMATO 				(void)getcFromInputFile ();
690a9b9ded9SMasatake YAMATO 				*promise = makePromise (NULL,
691a9b9ded9SMasatake YAMATO 										linenum [START], offset [START],
692a9b9ded9SMasatake YAMATO 										linenum [END], offset [END],
693a9b9ded9SMasatake YAMATO 										linenum [SOURCE]);
694a9b9ded9SMasatake YAMATO 			}
695ce990805SThomas Braun 			end = true;
696a9b9ded9SMasatake YAMATO 		}
6973ae02089SMasatake YAMATO 		else
6983ae02089SMasatake YAMATO 			vStringPut (string, c);
6993ae02089SMasatake YAMATO 	}
7003ae02089SMasatake YAMATO }
7013ae02089SMasatake YAMATO 
7023ae02089SMasatake YAMATO /*	Read a C identifier beginning with "firstChar" and places it into "name".
7033ae02089SMasatake YAMATO */
parseIdentifier(vString * const string,const int firstChar)7043ae02089SMasatake YAMATO static void parseIdentifier (vString *const string, const int firstChar)
7053ae02089SMasatake YAMATO {
7063ae02089SMasatake YAMATO 	int c = firstChar;
7073ae02089SMasatake YAMATO 	Assert (isIdentChar1 (c));
7083ae02089SMasatake YAMATO 	do
7093ae02089SMasatake YAMATO 	{
7103ae02089SMasatake YAMATO 		vStringPut (string, c);
711018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7123ae02089SMasatake YAMATO 	} while (isIdentChar (c));
7133ae02089SMasatake YAMATO 	if (!isspace (c))
7141b312fe7SMasatake YAMATO 		ungetcToInputFile (c);		/* unget non-identifier character */
7153ae02089SMasatake YAMATO }
7163ae02089SMasatake YAMATO 
isCCFlag(const char * str)717293050e3SMasatake YAMATO static bool isCCFlag(const char *str)
718293050e3SMasatake YAMATO {
719*aaaac7eeSMasatake YAMATO 	return (anyKindEntryInScope(CORK_NIL, str, SQLTAG_PLSQL_CCFLAGS, false) != 0);
720293050e3SMasatake YAMATO }
721293050e3SMasatake YAMATO 
72247acb582SColomban Wendling /* Parse a PostgreSQL: dollar-quoted string
7234dbda622SMasatake YAMATO  * https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING
7244dbda622SMasatake YAMATO  *
7254dbda622SMasatake YAMATO  * The syntax for dollar-quoted string ca collide with PL/SQL inquiry directive ($$name).
7264dbda622SMasatake YAMATO  * https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-language-fundamentals.html#GUID-E918087C-D5A8-4CEE-841B-5333DE6D4C15
7274dbda622SMasatake YAMATO  * https://github.com/universal-ctags/ctags/issues/3006
7284dbda622SMasatake YAMATO  */
parseDollarQuote(vString * const string,const int delimiter,int * promise)729a9b9ded9SMasatake YAMATO static tokenType parseDollarQuote (vString *const string, const int delimiter, int *promise)
73047acb582SColomban Wendling {
731a9b9ded9SMasatake YAMATO 	int offset[2];
732a9b9ded9SMasatake YAMATO 	unsigned long linenum[3];
733a9b9ded9SMasatake YAMATO 	enum { START, END, SOURCE };
734a9b9ded9SMasatake YAMATO 
73547acb582SColomban Wendling 	unsigned int len = 0;
73647acb582SColomban Wendling 	char tag[32 /* arbitrary limit */] = {0};
73747acb582SColomban Wendling 	int c = 0;
73847acb582SColomban Wendling 
73947acb582SColomban Wendling 	/* read the tag */
74047acb582SColomban Wendling 	tag[len++] = (char) delimiter;
74147acb582SColomban Wendling 	while ((len + 1) < sizeof tag && c != delimiter)
74247acb582SColomban Wendling 	{
74347acb582SColomban Wendling 		c = getcFromInputFile ();
74447acb582SColomban Wendling 		if (isIdentChar(c))
74547acb582SColomban Wendling 			tag[len++] = (char) c;
74647acb582SColomban Wendling 		else
74747acb582SColomban Wendling 			break;
74847acb582SColomban Wendling 	}
74947acb582SColomban Wendling 	tag[len] = 0;
7505c2ca011SMasatake YAMATO 
7514dbda622SMasatake YAMATO 	bool empty_tag = (len == 2);
75247acb582SColomban Wendling 
75347acb582SColomban Wendling 	if (c != delimiter)
75447acb582SColomban Wendling 	{
75547acb582SColomban Wendling 		/* damn that's not valid, what can we do? */
7565c2ca011SMasatake YAMATO 		ungetcToInputFile (c);
75747acb582SColomban Wendling 		return TOKEN_UNDEFINED;
75847acb582SColomban Wendling 	}
75947acb582SColomban Wendling 
760a9b9ded9SMasatake YAMATO 	if (promise && !isXtagEnabled(XTAG_GUEST))
761a9b9ded9SMasatake YAMATO 		promise = NULL;
762a9b9ded9SMasatake YAMATO 
763a9b9ded9SMasatake YAMATO 	if (promise)
764a9b9ded9SMasatake YAMATO 	{
765a9b9ded9SMasatake YAMATO 		linenum[START] = getInputLineNumber ();
766a9b9ded9SMasatake YAMATO 		offset[START]  = getInputLineOffset ();
767a9b9ded9SMasatake YAMATO 		linenum[SOURCE] = getSourceLineNumber ();
768a9b9ded9SMasatake YAMATO 	}
769a9b9ded9SMasatake YAMATO 
77047acb582SColomban Wendling 	/* and read the content (until a matching end tag) */
77147acb582SColomban Wendling 	while ((c = getcFromInputFile ()) != EOF)
77247acb582SColomban Wendling 	{
77347acb582SColomban Wendling 		if (c != delimiter)
7744dbda622SMasatake YAMATO 		{
77547acb582SColomban Wendling 			vStringPut (string, c);
7764dbda622SMasatake YAMATO 			if (empty_tag
777293050e3SMasatake YAMATO 				&& (KEYWORD_inquiry_directive == lookupCaseKeyword (vStringValue (string),
778293050e3SMasatake YAMATO 																	Lang_sql)
779293050e3SMasatake YAMATO 					|| isCCFlag(vStringValue (string))))
7804dbda622SMasatake YAMATO 			{
7814dbda622SMasatake YAMATO 				/* PL/SQL inquiry directives */
7824dbda622SMasatake YAMATO 				int c0 = getcFromInputFile ();
7834dbda622SMasatake YAMATO 
7844dbda622SMasatake YAMATO 				if (c0 != delimiter && (isalnum(c0) || c0 == '_'))
7854dbda622SMasatake YAMATO 				{
7864dbda622SMasatake YAMATO 					vStringPut (string, c0);
7874dbda622SMasatake YAMATO 					continue;
7884dbda622SMasatake YAMATO 				}
7894dbda622SMasatake YAMATO 
7904dbda622SMasatake YAMATO 				ungetcToInputFile (c0);
7914dbda622SMasatake YAMATO 				/* Oracle PL/SQL's inquiry directive ($$name) */
7924dbda622SMasatake YAMATO 				return TOKEN_UNDEFINED;
7934dbda622SMasatake YAMATO 			}
7944dbda622SMasatake YAMATO 		}
79547acb582SColomban Wendling 		else
79647acb582SColomban Wendling 		{
79747acb582SColomban Wendling 			char *end_p = tag;
79847acb582SColomban Wendling 
79947acb582SColomban Wendling 			while (c != EOF && *end_p && ((int) c) == *end_p)
80047acb582SColomban Wendling 			{
80147acb582SColomban Wendling 				c = getcFromInputFile ();
80247acb582SColomban Wendling 				end_p++;
80347acb582SColomban Wendling 			}
80447acb582SColomban Wendling 
80511e1e747SMasatake YAMATO 			if (c != EOF)
80611e1e747SMasatake YAMATO 				ungetcToInputFile (c);
80711e1e747SMasatake YAMATO 
80847acb582SColomban Wendling 			if (! *end_p) /* full tag match */
809a9b9ded9SMasatake YAMATO 			{
810a9b9ded9SMasatake YAMATO 				if (promise)
811a9b9ded9SMasatake YAMATO 				{
812a9b9ded9SMasatake YAMATO 					linenum[END] = getInputLineNumber ();
813a9b9ded9SMasatake YAMATO 					offset[END]  = getInputLineOffset ();
814a9b9ded9SMasatake YAMATO 					if (offset[END] > len)
815d4bdaa52SMasatake YAMATO 						offset[END] -= len;
816a9b9ded9SMasatake YAMATO 					*promise = makePromise (NULL,
817a9b9ded9SMasatake YAMATO 											linenum [START], offset [START],
818a9b9ded9SMasatake YAMATO 											linenum [END], offset [END],
819a9b9ded9SMasatake YAMATO 											linenum [SOURCE]);
820a9b9ded9SMasatake YAMATO 				}
82147acb582SColomban Wendling 				break;
822a9b9ded9SMasatake YAMATO 			}
82347acb582SColomban Wendling 			else
82447acb582SColomban Wendling 				vStringNCatS (string, tag, (size_t) (end_p - tag));
82547acb582SColomban Wendling 		}
82647acb582SColomban Wendling 	}
82747acb582SColomban Wendling 
82847acb582SColomban Wendling 	return TOKEN_STRING;
82947acb582SColomban Wendling }
83047acb582SColomban Wendling 
readToken(tokenInfo * const token)8313ae02089SMasatake YAMATO static void readToken (tokenInfo *const token)
8323ae02089SMasatake YAMATO {
8333ae02089SMasatake YAMATO 	int c;
8343ae02089SMasatake YAMATO 
8353ae02089SMasatake YAMATO 	token->type			= TOKEN_UNDEFINED;
8363ae02089SMasatake YAMATO 	token->keyword		= KEYWORD_NONE;
8373ae02089SMasatake YAMATO 	vStringClear (token->string);
838a9b9ded9SMasatake YAMATO 	token->promise      = -1;
8393ae02089SMasatake YAMATO 
8403ae02089SMasatake YAMATO getNextChar:
8413ae02089SMasatake YAMATO 	do
8423ae02089SMasatake YAMATO 	{
843018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
844a31b37dcSMasatake YAMATO 		token->lineNumber   = getInputLineNumber ();
8453ae02089SMasatake YAMATO 		token->filePosition = getInputFilePosition ();
8463ae02089SMasatake YAMATO 		/*
8473ae02089SMasatake YAMATO 		 * Added " to the list of ignores, not sure what this
8483ae02089SMasatake YAMATO 		 * might break but it gets by this issue:
8493ae02089SMasatake YAMATO 		 *	  create table "t1" (...)
8503ae02089SMasatake YAMATO 		 *
8513ae02089SMasatake YAMATO 		 * Darren, the code passes all my tests for both
8523ae02089SMasatake YAMATO 		 * Oracle and SQL Anywhere, but maybe you can tell me
8533ae02089SMasatake YAMATO 		 * what this may effect.
8543ae02089SMasatake YAMATO 		 */
8553ae02089SMasatake YAMATO 	}
8563ae02089SMasatake YAMATO 	while (c == '\t'  ||  c == ' ' ||  c == '\n');
8573ae02089SMasatake YAMATO 
8583ae02089SMasatake YAMATO 	switch (c)
8593ae02089SMasatake YAMATO 	{
8603ae02089SMasatake YAMATO 		case EOF: token->type = TOKEN_EOF;				break;
8613ae02089SMasatake YAMATO 		case '(': token->type = TOKEN_OPEN_PAREN;		break;
8623ae02089SMasatake YAMATO 		case ')': token->type = TOKEN_CLOSE_PAREN;		break;
8633ae02089SMasatake YAMATO 		case ':': token->type = TOKEN_COLON;			break;
8643ae02089SMasatake YAMATO 		case ';': token->type = TOKEN_SEMICOLON;		break;
8653ae02089SMasatake YAMATO 		case '.': token->type = TOKEN_PERIOD;			break;
8663ae02089SMasatake YAMATO 		case ',': token->type = TOKEN_COMMA;			break;
8673ae02089SMasatake YAMATO 		case '{': token->type = TOKEN_OPEN_CURLY;		break;
8683ae02089SMasatake YAMATO 		case '}': token->type = TOKEN_CLOSE_CURLY;		break;
8693ae02089SMasatake YAMATO 		case '~': token->type = TOKEN_TILDE;			break;
8703ae02089SMasatake YAMATO 		case '[': token->type = TOKEN_OPEN_SQUARE;		break;
8713ae02089SMasatake YAMATO 		case ']': token->type = TOKEN_CLOSE_SQUARE;		break;
8723ae02089SMasatake YAMATO 		case '=': token->type = TOKEN_EQUAL;			break;
8733ae02089SMasatake YAMATO 
8743ae02089SMasatake YAMATO 		case '\'':
8753ae02089SMasatake YAMATO 		case '"':
8763ae02089SMasatake YAMATO 				  token->type = TOKEN_STRING;
877a9b9ded9SMasatake YAMATO 				  parseString (token->string, c, &token->promise);
878a31b37dcSMasatake YAMATO 				  token->lineNumber = getInputLineNumber ();
8793ae02089SMasatake YAMATO 				  token->filePosition = getInputFilePosition ();
8803ae02089SMasatake YAMATO 				  break;
8813ae02089SMasatake YAMATO 
88238ec24d5SMasatake YAMATO 		case '#':
88338ec24d5SMasatake YAMATO 				skipToCharacterInInputFile ('\n');
88438ec24d5SMasatake YAMATO 				goto getNextChar;
8853ae02089SMasatake YAMATO 		case '-':
886018bce0bSMasatake YAMATO 				  c = getcFromInputFile ();
8873ae02089SMasatake YAMATO 				  if (c == '-')		/* -- is this the start of a comment? */
8883ae02089SMasatake YAMATO 				  {
8894fffc5afSMasatake YAMATO 					  skipToCharacterInInputFile ('\n');
8903ae02089SMasatake YAMATO 					  goto getNextChar;
8913ae02089SMasatake YAMATO 				  }
8923ae02089SMasatake YAMATO 				  else
8933ae02089SMasatake YAMATO 				  {
8943ae02089SMasatake YAMATO 					  if (!isspace (c))
8951b312fe7SMasatake YAMATO 						  ungetcToInputFile (c);
8963ae02089SMasatake YAMATO 					  token->type = TOKEN_OPERATOR;
8973ae02089SMasatake YAMATO 				  }
8983ae02089SMasatake YAMATO 				  break;
8993ae02089SMasatake YAMATO 
9003ae02089SMasatake YAMATO 		case '<':
9013ae02089SMasatake YAMATO 		case '>':
9023ae02089SMasatake YAMATO 				  {
9033ae02089SMasatake YAMATO 					  const int initial = c;
904018bce0bSMasatake YAMATO 					  int d = getcFromInputFile ();
9053ae02089SMasatake YAMATO 					  if (d == initial)
9063ae02089SMasatake YAMATO 					  {
9073ae02089SMasatake YAMATO 						  if (initial == '<')
9083ae02089SMasatake YAMATO 							  token->type = TOKEN_BLOCK_LABEL_BEGIN;
9093ae02089SMasatake YAMATO 						  else
9103ae02089SMasatake YAMATO 							  token->type = TOKEN_BLOCK_LABEL_END;
9113ae02089SMasatake YAMATO 					  }
9123ae02089SMasatake YAMATO 					  else
9133ae02089SMasatake YAMATO 					  {
9141b312fe7SMasatake YAMATO 						  ungetcToInputFile (d);
9153ae02089SMasatake YAMATO 						  token->type = TOKEN_UNDEFINED;
9163ae02089SMasatake YAMATO 					  }
9173ae02089SMasatake YAMATO 					  break;
9183ae02089SMasatake YAMATO 				  }
9193ae02089SMasatake YAMATO 
9203ae02089SMasatake YAMATO 		case '\\':
921018bce0bSMasatake YAMATO 				  c = getcFromInputFile ();
9223ae02089SMasatake YAMATO 				  if (c != '\\'  && c != '"'  && c != '\''  &&  !isspace (c))
9231b312fe7SMasatake YAMATO 					  ungetcToInputFile (c);
9243ae02089SMasatake YAMATO 				  token->type = TOKEN_CHARACTER;
925a31b37dcSMasatake YAMATO 				  token->lineNumber = getInputLineNumber ();
9263ae02089SMasatake YAMATO 				  token->filePosition = getInputFilePosition ();
9273ae02089SMasatake YAMATO 				  break;
9283ae02089SMasatake YAMATO 
9293ae02089SMasatake YAMATO 		case '/':
9303ae02089SMasatake YAMATO 				  {
931018bce0bSMasatake YAMATO 					  int d = getcFromInputFile ();
9323ae02089SMasatake YAMATO 					  if ((d != '*') &&		/* is this the start of a comment? */
9333ae02089SMasatake YAMATO 						  (d != '/'))		/* is a one line comment? */
9343ae02089SMasatake YAMATO 					  {
9353ae02089SMasatake YAMATO 						  token->type = TOKEN_FORWARD_SLASH;
9361b312fe7SMasatake YAMATO 						  ungetcToInputFile (d);
9373ae02089SMasatake YAMATO 					  }
9383ae02089SMasatake YAMATO 					  else
9393ae02089SMasatake YAMATO 					  {
9403ae02089SMasatake YAMATO 						  if (d == '*')
9413ae02089SMasatake YAMATO 						  {
94264a05963SMasatake YAMATO 							  skipToCharacterInInputFile2('*', '/');
9433ae02089SMasatake YAMATO 							  goto getNextChar;
9443ae02089SMasatake YAMATO 						  }
9453ae02089SMasatake YAMATO 						  else if (d == '/')	/* is this the start of a comment?  */
9463ae02089SMasatake YAMATO 						  {
9474fffc5afSMasatake YAMATO 							  skipToCharacterInInputFile ('\n');
9483ae02089SMasatake YAMATO 							  goto getNextChar;
9493ae02089SMasatake YAMATO 						  }
9503ae02089SMasatake YAMATO 					  }
9513ae02089SMasatake YAMATO 					  break;
9523ae02089SMasatake YAMATO 				  }
9533ae02089SMasatake YAMATO 
95447acb582SColomban Wendling 		case '$':
955a9b9ded9SMasatake YAMATO 				  token->type = parseDollarQuote (token->string, c, &token->promise);
95647acb582SColomban Wendling 				  token->lineNumber = getInputLineNumber ();
95747acb582SColomban Wendling 				  token->filePosition = getInputFilePosition ();
95847acb582SColomban Wendling 				  break;
95947acb582SColomban Wendling 
9603ae02089SMasatake YAMATO 		default:
9613ae02089SMasatake YAMATO 				  if (! isIdentChar1 (c))
9623ae02089SMasatake YAMATO 					  token->type = TOKEN_UNDEFINED;
9633ae02089SMasatake YAMATO 				  else
9643ae02089SMasatake YAMATO 				  {
9653ae02089SMasatake YAMATO 					  parseIdentifier (token->string, c);
966a31b37dcSMasatake YAMATO 					  token->lineNumber = getInputLineNumber ();
9673ae02089SMasatake YAMATO 					  token->filePosition = getInputFilePosition ();
96831a85388SJiří Techet 					  token->keyword = lookupCaseKeyword (vStringValue (token->string), Lang_sql);
9693ae02089SMasatake YAMATO 					  if (isKeyword (token, KEYWORD_rem))
9703ae02089SMasatake YAMATO 					  {
9713ae02089SMasatake YAMATO 						  vStringClear (token->string);
9724fffc5afSMasatake YAMATO 						  skipToCharacterInInputFile ('\n');
9733ae02089SMasatake YAMATO 						  goto getNextChar;
9743ae02089SMasatake YAMATO 					  }
9753ae02089SMasatake YAMATO 					  else if (isKeyword (token, KEYWORD_NONE))
9763ae02089SMasatake YAMATO 						  token->type = TOKEN_IDENTIFIER;
9773ae02089SMasatake YAMATO 					  else
9783ae02089SMasatake YAMATO 						  token->type = TOKEN_KEYWORD;
9793ae02089SMasatake YAMATO 				  }
9803ae02089SMasatake YAMATO 				  break;
9813ae02089SMasatake YAMATO 	}
9823ae02089SMasatake YAMATO }
9833ae02089SMasatake YAMATO 
9843ae02089SMasatake YAMATO /*
9859f084dcaSK.Takata  * reads an identifier, possibly quoted:
9863ae02089SMasatake YAMATO  * 		identifier
9873ae02089SMasatake YAMATO  * 		"identifier"
9883ae02089SMasatake YAMATO  * 		[identifier]
9893ae02089SMasatake YAMATO  */
readIdentifier(tokenInfo * const token)9903ae02089SMasatake YAMATO static void readIdentifier (tokenInfo *const token)
9913ae02089SMasatake YAMATO {
9923ae02089SMasatake YAMATO 	readToken (token);
9933ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_SQUARE))
9943ae02089SMasatake YAMATO 	{
9953ae02089SMasatake YAMATO 		tokenInfo *const close_square = newToken ();
9963ae02089SMasatake YAMATO 
9973ae02089SMasatake YAMATO 		readToken (token);
9989f084dcaSK.Takata 		/* eat close square */
9993ae02089SMasatake YAMATO 		readToken (close_square);
10003ae02089SMasatake YAMATO 		deleteToken (close_square);
10013ae02089SMasatake YAMATO 	}
10023ae02089SMasatake YAMATO }
10033ae02089SMasatake YAMATO 
10043ae02089SMasatake YAMATO /*
10053ae02089SMasatake YAMATO  *	 Token parsing functions
10063ae02089SMasatake YAMATO  */
10073ae02089SMasatake YAMATO 
10083ae02089SMasatake YAMATO /*
10093ae02089SMasatake YAMATO  * static void addContext (tokenInfo* const parent, const tokenInfo* const child)
10103ae02089SMasatake YAMATO  * {
10113ae02089SMasatake YAMATO  *	   if (vStringLength (parent->string) > 0)
10123ae02089SMasatake YAMATO  *	   {
10131da6e7e4SMasatake YAMATO  *		   vStringPut (parent->string, '.');
10143ae02089SMasatake YAMATO  *	   }
10154e6bcb7bSColomban Wendling  *	   vStringCat (parent->string, child->string);
10163ae02089SMasatake YAMATO  * }
10173ae02089SMasatake YAMATO  */
10183ae02089SMasatake YAMATO 
addToScope(tokenInfo * const token,vString * const extra,sqlKind kind)10193ae02089SMasatake YAMATO static void addToScope (tokenInfo* const token, vString* const extra, sqlKind kind)
10203ae02089SMasatake YAMATO {
10213ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
10223ae02089SMasatake YAMATO 	{
10231da6e7e4SMasatake YAMATO 		vStringPut (token->scope, '.');
10243ae02089SMasatake YAMATO 	}
10254e6bcb7bSColomban Wendling 	vStringCat (token->scope, extra);
10263ae02089SMasatake YAMATO 	token->scopeKind = kind;
10273ae02089SMasatake YAMATO }
10283ae02089SMasatake YAMATO 
10293ae02089SMasatake YAMATO /*
10303ae02089SMasatake YAMATO  *	 Scanning functions
10313ae02089SMasatake YAMATO  */
10323ae02089SMasatake YAMATO 
isOneOfKeyword(tokenInfo * const token,const keywordId * const keywords,unsigned int count)1033ce990805SThomas Braun static bool isOneOfKeyword (tokenInfo *const token, const keywordId *const keywords, unsigned int count)
1034e8d993efSMasatake YAMATO {
1035e8d993efSMasatake YAMATO 	unsigned int i;
1036e8d993efSMasatake YAMATO 	for (i = 0; i < count; i++)
1037e8d993efSMasatake YAMATO 	{
1038e8d993efSMasatake YAMATO 		if (isKeyword (token, keywords[i]))
1039ce990805SThomas Braun 			return true;
1040e8d993efSMasatake YAMATO 	}
1041ce990805SThomas Braun 	return false;
1042e8d993efSMasatake YAMATO }
1043e8d993efSMasatake YAMATO 
findTokenOrKeywords(tokenInfo * const token,const tokenType type,const keywordId * const keywords,unsigned int kcount)1044e8d993efSMasatake YAMATO static void findTokenOrKeywords (tokenInfo *const token, const tokenType type,
1045e8d993efSMasatake YAMATO 				 const keywordId *const keywords,
1046e8d993efSMasatake YAMATO 				 unsigned int kcount)
1047e8d993efSMasatake YAMATO {
1048e8d993efSMasatake YAMATO 	while (! isType (token, type) &&
1049e8d993efSMasatake YAMATO 	       ! (isType (token, TOKEN_KEYWORD) && isOneOfKeyword (token, keywords, kcount)) &&
1050e8d993efSMasatake YAMATO 	       ! isType (token, TOKEN_EOF))
1051e8d993efSMasatake YAMATO 	{
1052e8d993efSMasatake YAMATO 		readToken (token);
1053e8d993efSMasatake YAMATO 	}
1054e8d993efSMasatake YAMATO }
1055e8d993efSMasatake YAMATO 
findToken(tokenInfo * const token,const tokenType type)10563ae02089SMasatake YAMATO static void findToken (tokenInfo *const token, const tokenType type)
10573ae02089SMasatake YAMATO {
10583ae02089SMasatake YAMATO 	while (! isType (token, type) &&
10593ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF))
10603ae02089SMasatake YAMATO 	{
10613ae02089SMasatake YAMATO 		readToken (token);
10623ae02089SMasatake YAMATO 	}
10633ae02089SMasatake YAMATO }
10643ae02089SMasatake YAMATO 
findCmdTerm(tokenInfo * const token,const bool check_first)1065ce990805SThomas Braun static void findCmdTerm (tokenInfo *const token, const bool check_first)
10663ae02089SMasatake YAMATO {
10673ae02089SMasatake YAMATO 	int begin_end_nest_lvl = token->begin_end_nest_lvl;
10683ae02089SMasatake YAMATO 
10693ae02089SMasatake YAMATO 	if (check_first)
10703ae02089SMasatake YAMATO 	{
10713ae02089SMasatake YAMATO 		if (isCmdTerm(token))
10723ae02089SMasatake YAMATO 			return;
10733ae02089SMasatake YAMATO 	}
10743ae02089SMasatake YAMATO 	do
10753ae02089SMasatake YAMATO 	{
10763ae02089SMasatake YAMATO 		readToken (token);
10773ae02089SMasatake YAMATO 	} while (! isCmdTerm(token) &&
10783ae02089SMasatake YAMATO 			 ! isMatchedEnd(token, begin_end_nest_lvl) &&
10793ae02089SMasatake YAMATO 			 ! isType (token, TOKEN_EOF));
10803ae02089SMasatake YAMATO }
10813ae02089SMasatake YAMATO 
skipToMatched(tokenInfo * const token)10823ae02089SMasatake YAMATO static void skipToMatched(tokenInfo *const token)
10833ae02089SMasatake YAMATO {
10843ae02089SMasatake YAMATO 	int nest_level = 0;
10853ae02089SMasatake YAMATO 	tokenType open_token;
10863ae02089SMasatake YAMATO 	tokenType close_token;
10873ae02089SMasatake YAMATO 
10883ae02089SMasatake YAMATO 	switch (token->type)
10893ae02089SMasatake YAMATO 	{
10903ae02089SMasatake YAMATO 		case TOKEN_OPEN_PAREN:
10913ae02089SMasatake YAMATO 			open_token  = TOKEN_OPEN_PAREN;
10923ae02089SMasatake YAMATO 			close_token = TOKEN_CLOSE_PAREN;
10933ae02089SMasatake YAMATO 			break;
10943ae02089SMasatake YAMATO 		case TOKEN_OPEN_CURLY:
10953ae02089SMasatake YAMATO 			open_token  = TOKEN_OPEN_CURLY;
10963ae02089SMasatake YAMATO 			close_token = TOKEN_CLOSE_CURLY;
10973ae02089SMasatake YAMATO 			break;
10983ae02089SMasatake YAMATO 		case TOKEN_OPEN_SQUARE:
10993ae02089SMasatake YAMATO 			open_token  = TOKEN_OPEN_SQUARE;
11003ae02089SMasatake YAMATO 			close_token = TOKEN_CLOSE_SQUARE;
11013ae02089SMasatake YAMATO 			break;
11023ae02089SMasatake YAMATO 		default:
11033ae02089SMasatake YAMATO 			return;
11043ae02089SMasatake YAMATO 	}
11053ae02089SMasatake YAMATO 
11063ae02089SMasatake YAMATO 	/*
11073ae02089SMasatake YAMATO 	 * This routine will skip to a matching closing token.
11083ae02089SMasatake YAMATO 	 * It will also handle nested tokens like the (, ) below.
11093ae02089SMasatake YAMATO 	 *	 (	name varchar(30), text binary(10)  )
11103ae02089SMasatake YAMATO 	 */
11113ae02089SMasatake YAMATO 
11123ae02089SMasatake YAMATO 	if (isType (token, open_token))
11133ae02089SMasatake YAMATO 	{
11143ae02089SMasatake YAMATO 		nest_level++;
11153ae02089SMasatake YAMATO 		while (nest_level > 0 && !isType (token, TOKEN_EOF))
11163ae02089SMasatake YAMATO 		{
11173ae02089SMasatake YAMATO 			readToken (token);
11183ae02089SMasatake YAMATO 			if (isType (token, open_token))
11193ae02089SMasatake YAMATO 			{
11203ae02089SMasatake YAMATO 				nest_level++;
11213ae02089SMasatake YAMATO 			}
11223ae02089SMasatake YAMATO 			if (isType (token, close_token))
11233ae02089SMasatake YAMATO 			{
11243ae02089SMasatake YAMATO 				if (nest_level > 0)
11253ae02089SMasatake YAMATO 				{
11263ae02089SMasatake YAMATO 					nest_level--;
11273ae02089SMasatake YAMATO 				}
11283ae02089SMasatake YAMATO 			}
11293ae02089SMasatake YAMATO 		}
11303ae02089SMasatake YAMATO 		readToken (token);
11313ae02089SMasatake YAMATO 	}
11323ae02089SMasatake YAMATO }
11333ae02089SMasatake YAMATO 
copyToken(tokenInfo * const dest,tokenInfo * const src)11343ae02089SMasatake YAMATO static void copyToken (tokenInfo *const dest, tokenInfo *const src)
11353ae02089SMasatake YAMATO {
11363ae02089SMasatake YAMATO 	dest->lineNumber = src->lineNumber;
11373ae02089SMasatake YAMATO 	dest->filePosition = src->filePosition;
11383ae02089SMasatake YAMATO 	dest->type = src->type;
11393ae02089SMasatake YAMATO 	dest->keyword = src->keyword;
11403ae02089SMasatake YAMATO 	vStringCopy(dest->string, src->string);
11413ae02089SMasatake YAMATO 	vStringCopy(dest->scope, src->scope);
11423ae02089SMasatake YAMATO 	dest->scopeKind = src->scopeKind;
11433ae02089SMasatake YAMATO }
11443ae02089SMasatake YAMATO 
skipArgumentList(tokenInfo * const token)11453ae02089SMasatake YAMATO static void skipArgumentList (tokenInfo *const token)
11463ae02089SMasatake YAMATO {
11473ae02089SMasatake YAMATO 	/*
11483ae02089SMasatake YAMATO 	 * Other databases can have arguments with fully declared
11493ae02089SMasatake YAMATO 	 * datatypes:
11503ae02089SMasatake YAMATO 	 *	 (	name varchar(30), text binary(10)  )
11519f084dcaSK.Takata 	 * So we must check for nested open and closing parentheses
11523ae02089SMasatake YAMATO 	 */
11533ae02089SMasatake YAMATO 
11543ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))	/* arguments? */
11553ae02089SMasatake YAMATO 	{
11563ae02089SMasatake YAMATO 		skipToMatched (token);
11573ae02089SMasatake YAMATO 	}
11583ae02089SMasatake YAMATO }
11593ae02089SMasatake YAMATO 
getNamedLanguageFromToken(tokenInfo * const token)1160a9b9ded9SMasatake YAMATO static langType getNamedLanguageFromToken(tokenInfo *const token)
1161a9b9ded9SMasatake YAMATO {
1162a9b9ded9SMasatake YAMATO 	langType lang = LANG_IGNORE;
1163a9b9ded9SMasatake YAMATO 
1164a9b9ded9SMasatake YAMATO 	if (isType (token, TOKEN_IDENTIFIER))
1165a9b9ded9SMasatake YAMATO 	{
1166a9b9ded9SMasatake YAMATO 		if (vStringLength (token->string) > 2
1167a9b9ded9SMasatake YAMATO 			&& vStringValue (token->string) [0] == 'p'
1168a9b9ded9SMasatake YAMATO 			&& vStringValue (token->string) [1] == 'l')
1169a9b9ded9SMasatake YAMATO 		{
1170a9b9ded9SMasatake YAMATO 			/* Remove first 'pl' and last 'u' for extracting the
1171a9b9ded9SMasatake YAMATO 			 * name of the language. */
1172a9b9ded9SMasatake YAMATO 			bool unsafe = (vStringLast(token->string) == 'u');
1173a9b9ded9SMasatake YAMATO 			lang = getNamedLanguageOrAlias (vStringValue (token->string) + 2,
1174a9b9ded9SMasatake YAMATO 											vStringLength (token->string)
1175a9b9ded9SMasatake YAMATO 											- 2
1176a9b9ded9SMasatake YAMATO 											- (unsafe? 1: 0));
1177a9b9ded9SMasatake YAMATO 		}
1178a9b9ded9SMasatake YAMATO 	}
1179a9b9ded9SMasatake YAMATO 	return lang;
1180a9b9ded9SMasatake YAMATO }
1181a9b9ded9SMasatake YAMATO 
parseSubProgram(tokenInfo * const token)11823ae02089SMasatake YAMATO static void parseSubProgram (tokenInfo *const token)
11833ae02089SMasatake YAMATO {
11843ae02089SMasatake YAMATO 	tokenInfo *const name  = newToken ();
11853ae02089SMasatake YAMATO 	vString * saveScope = vStringNew ();
11863ae02089SMasatake YAMATO 	sqlKind saveScopeKind;
11873ae02089SMasatake YAMATO 
11883ae02089SMasatake YAMATO 	/*
11893ae02089SMasatake YAMATO 	 * This must handle both prototypes and the body of
11903ae02089SMasatake YAMATO 	 * the procedures.
11913ae02089SMasatake YAMATO 	 *
11923ae02089SMasatake YAMATO 	 * Prototype:
11933ae02089SMasatake YAMATO 	 *	   FUNCTION func_name RETURN integer;
11943ae02089SMasatake YAMATO 	 *	   PROCEDURE proc_name( parameters );
11953ae02089SMasatake YAMATO 	 * Procedure
11963ae02089SMasatake YAMATO 	 *	   FUNCTION GET_ML_USERNAME RETURN VARCHAR2
11973ae02089SMasatake YAMATO 	 *	   IS
11983ae02089SMasatake YAMATO 	 *	   BEGIN
11993ae02089SMasatake YAMATO 	 *		   RETURN v_sync_user_id;
12003ae02089SMasatake YAMATO 	 *	   END GET_ML_USERNAME;
12013ae02089SMasatake YAMATO 	 *
12023ae02089SMasatake YAMATO 	 *	   PROCEDURE proc_name( parameters )
12033ae02089SMasatake YAMATO 	 *		   IS
12043ae02089SMasatake YAMATO 	 *		   BEGIN
12053ae02089SMasatake YAMATO 	 *		   END;
12063ae02089SMasatake YAMATO 	 *	   CREATE PROCEDURE proc_name( parameters )
12073ae02089SMasatake YAMATO 	 *		   EXTERNAL NAME ... ;
12083ae02089SMasatake YAMATO 	 *	   CREATE PROCEDURE proc_name( parameters )
12093ae02089SMasatake YAMATO 	 *		   BEGIN
12103ae02089SMasatake YAMATO 	 *		   END;
12113ae02089SMasatake YAMATO 	 *
12123ae02089SMasatake YAMATO 	 *	   CREATE FUNCTION f_GetClassName(
12133ae02089SMasatake YAMATO 	 *		   IN @object VARCHAR(128)
12143ae02089SMasatake YAMATO 	 *		  ,IN @code   VARCHAR(128)
12153ae02089SMasatake YAMATO 	 *	   )
12163ae02089SMasatake YAMATO 	 *	   RETURNS VARCHAR(200)
12173ae02089SMasatake YAMATO 	 *	   DETERMINISTIC
12183ae02089SMasatake YAMATO 	 *	   BEGIN
12193ae02089SMasatake YAMATO 	 *
12203ae02089SMasatake YAMATO 	 *		   IF( @object = 'user_state' ) THEN
12213ae02089SMasatake YAMATO 	 *			   SET something = something;
12223ae02089SMasatake YAMATO 	 *		   END IF;
12233ae02089SMasatake YAMATO 	 *
12243ae02089SMasatake YAMATO 	 *		   RETURN @name;
12253ae02089SMasatake YAMATO 	 *	   END;
12263ae02089SMasatake YAMATO 	 *
12273ae02089SMasatake YAMATO 	 * Note, a Package adds scope to the items within.
12283ae02089SMasatake YAMATO      *     create or replace package demo_pkg is
12293ae02089SMasatake YAMATO      *         test_var number;
12303ae02089SMasatake YAMATO      *         function test_func return varchar2;
12313ae02089SMasatake YAMATO      *         function more.test_func2 return varchar2;
12323ae02089SMasatake YAMATO      *     end demo_pkg;
12333ae02089SMasatake YAMATO 	 * So the tags generated here, contain the package name:
12343ae02089SMasatake YAMATO      *         demo_pkg.test_var
12353ae02089SMasatake YAMATO      *         demo_pkg.test_func
12363ae02089SMasatake YAMATO      *         demo_pkg.more.test_func2
12373ae02089SMasatake YAMATO 	 */
12383ae02089SMasatake YAMATO 	const sqlKind kind = isKeyword (token, KEYWORD_function) ?
12393ae02089SMasatake YAMATO 		SQLTAG_FUNCTION : SQLTAG_PROCEDURE;
12403ae02089SMasatake YAMATO 	Assert (isKeyword (token, KEYWORD_function) ||
12413ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_procedure));
12423ae02089SMasatake YAMATO 
12433ae02089SMasatake YAMATO 	vStringCopy(saveScope, token->scope);
12443ae02089SMasatake YAMATO 	saveScopeKind = token->scopeKind;
12453ae02089SMasatake YAMATO 	readToken (token);
12463ae02089SMasatake YAMATO 	copyToken (name, token);
12473ae02089SMasatake YAMATO 	readToken (token);
12483ae02089SMasatake YAMATO 
12493ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
12503ae02089SMasatake YAMATO 	{
12513ae02089SMasatake YAMATO 		/*
12523ae02089SMasatake YAMATO 		 * If this is an Oracle package, then the token->scope should
12533ae02089SMasatake YAMATO 		 * already be set.  If this is the case, also add this value to the
12543ae02089SMasatake YAMATO 		 * scope.
12553ae02089SMasatake YAMATO 		 * If this is not an Oracle package, chances are the scope should be
12563ae02089SMasatake YAMATO 		 * blank and the value just read is the OWNER or CREATOR of the
12573ae02089SMasatake YAMATO 		 * function and should not be considered part of the scope.
12583ae02089SMasatake YAMATO 		 */
12593ae02089SMasatake YAMATO 		if (vStringLength(saveScope) > 0)
12603ae02089SMasatake YAMATO 		{
12613ae02089SMasatake YAMATO 			addToScope(token, name->string, kind);
12623ae02089SMasatake YAMATO 		}
12633ae02089SMasatake YAMATO 		readToken (token);
12643ae02089SMasatake YAMATO 		copyToken (name, token);
12653ae02089SMasatake YAMATO 		readToken (token);
12663ae02089SMasatake YAMATO 	}
12673ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
12683ae02089SMasatake YAMATO 	{
12693ae02089SMasatake YAMATO 		/* Reads to the next token after the TOKEN_CLOSE_PAREN */
12703ae02089SMasatake YAMATO 		skipArgumentList(token);
12713ae02089SMasatake YAMATO 	}
12723ae02089SMasatake YAMATO 
12733ae02089SMasatake YAMATO 	if (kind == SQLTAG_FUNCTION)
12743ae02089SMasatake YAMATO 	{
12753ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_return) ||
12763ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_returns))
12773ae02089SMasatake YAMATO 		{
12783ae02089SMasatake YAMATO 			/* Read datatype */
12793ae02089SMasatake YAMATO 			readToken (token);
12803ae02089SMasatake YAMATO 			/*
12813ae02089SMasatake YAMATO 			 * Read token after which could be the
12823ae02089SMasatake YAMATO 			 * command terminator if a prototype
12839f084dcaSK.Takata 			 * or an open parenthesis
12843ae02089SMasatake YAMATO 			 */
12853ae02089SMasatake YAMATO 			readToken (token);
12863ae02089SMasatake YAMATO 			if (isType (token, TOKEN_OPEN_PAREN))
12873ae02089SMasatake YAMATO 			{
12883ae02089SMasatake YAMATO 				/* Reads to the next token after the TOKEN_CLOSE_PAREN */
12893ae02089SMasatake YAMATO 				skipArgumentList(token);
12903ae02089SMasatake YAMATO 			}
12913ae02089SMasatake YAMATO 		}
12923ae02089SMasatake YAMATO 	}
12933ae02089SMasatake YAMATO 	if (isCmdTerm (token))
12943ae02089SMasatake YAMATO 	{
12953ae02089SMasatake YAMATO 		makeSqlTag (name, SQLTAG_PROTOTYPE);
12963ae02089SMasatake YAMATO 	}
12973ae02089SMasatake YAMATO 	else
12983ae02089SMasatake YAMATO 	{
1299a9b9ded9SMasatake YAMATO 		langType lang = LANG_IGNORE;
1300a9b9ded9SMasatake YAMATO 
13013ae02089SMasatake YAMATO 		while (! isKeyword (token, KEYWORD_is) &&
13023ae02089SMasatake YAMATO 			   ! isKeyword (token, KEYWORD_begin) &&
13033ae02089SMasatake YAMATO 			   ! isKeyword (token, KEYWORD_at) &&
13043ae02089SMasatake YAMATO 			   ! isKeyword (token, KEYWORD_internal) &&
13053ae02089SMasatake YAMATO 			   ! isKeyword (token, KEYWORD_external) &&
13063ae02089SMasatake YAMATO 			   ! isKeyword (token, KEYWORD_url) &&
13073ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EQUAL) &&
13083ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF) &&
13093ae02089SMasatake YAMATO 			   ! isCmdTerm (token))
13103ae02089SMasatake YAMATO 		{
13113ae02089SMasatake YAMATO 			if (isKeyword (token, KEYWORD_result))
13123ae02089SMasatake YAMATO 			{
13133ae02089SMasatake YAMATO 				readToken (token);
13143ae02089SMasatake YAMATO 				if (isType (token, TOKEN_OPEN_PAREN))
13153ae02089SMasatake YAMATO 				{
13163ae02089SMasatake YAMATO 					/* Reads to the next token after the TOKEN_CLOSE_PAREN */
13173ae02089SMasatake YAMATO 					skipArgumentList(token);
13183ae02089SMasatake YAMATO 				}
1319a9b9ded9SMasatake YAMATO 			} else if (lang == LANG_IGNORE
1320a9b9ded9SMasatake YAMATO 					   && isKeyword (token, KEYWORD_language)) {
1321a9b9ded9SMasatake YAMATO 				readToken (token);
1322a9b9ded9SMasatake YAMATO 				lang = getNamedLanguageFromToken (token);
1323a9b9ded9SMasatake YAMATO 				if (lang != LANG_IGNORE)
1324a9b9ded9SMasatake YAMATO 					readToken (token);
13253ae02089SMasatake YAMATO 			} else {
13263ae02089SMasatake YAMATO 				readToken (token);
13273ae02089SMasatake YAMATO 			}
13283ae02089SMasatake YAMATO 		}
13293ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_at) ||
13303ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_url) ||
13313ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_internal) ||
13323ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_external))
13333ae02089SMasatake YAMATO 		{
13343ae02089SMasatake YAMATO 			addToScope(token, name->string, kind);
13353ae02089SMasatake YAMATO 			if (isType (name, TOKEN_IDENTIFIER) ||
13363ae02089SMasatake YAMATO 				isType (name, TOKEN_STRING) ||
13373ae02089SMasatake YAMATO 				isType (name, TOKEN_KEYWORD))
13383ae02089SMasatake YAMATO 			{
13393ae02089SMasatake YAMATO 				makeSqlTag (name, kind);
13403ae02089SMasatake YAMATO 			}
13413ae02089SMasatake YAMATO 
13423ae02089SMasatake YAMATO 			vStringClear (token->scope);
13433ae02089SMasatake YAMATO 			token->scopeKind = SQLTAG_COUNT;
13443ae02089SMasatake YAMATO 		}
13453ae02089SMasatake YAMATO 		if (isType (token, TOKEN_EQUAL))
13463ae02089SMasatake YAMATO 			readToken (token);
13473ae02089SMasatake YAMATO 
13483ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_declare))
1349ce990805SThomas Braun 			parseDeclare (token, false);
13503ae02089SMasatake YAMATO 
13513ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_is) ||
13523ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_begin))
13533ae02089SMasatake YAMATO 		{
13543ae02089SMasatake YAMATO 			addToScope(token, name->string, kind);
13553ae02089SMasatake YAMATO 			if (isType (name, TOKEN_IDENTIFIER) ||
13563ae02089SMasatake YAMATO 				isType (name, TOKEN_STRING) ||
13573ae02089SMasatake YAMATO 				isType (name, TOKEN_KEYWORD))
13583ae02089SMasatake YAMATO 			{
13593ae02089SMasatake YAMATO 				makeSqlTag (name, kind);
13603ae02089SMasatake YAMATO 			}
13613ae02089SMasatake YAMATO 
1362a9b9ded9SMasatake YAMATO 			parseBlockFull (token, true, lang);
13633ae02089SMasatake YAMATO 			vStringClear (token->scope);
13643ae02089SMasatake YAMATO 			token->scopeKind = SQLTAG_COUNT;
13653ae02089SMasatake YAMATO 		}
13663ae02089SMasatake YAMATO 	}
13673ae02089SMasatake YAMATO 	vStringCopy(token->scope, saveScope);
13683ae02089SMasatake YAMATO 	token->scopeKind = saveScopeKind;
13693ae02089SMasatake YAMATO 	deleteToken (name);
13703ae02089SMasatake YAMATO 	vStringDelete(saveScope);
13713ae02089SMasatake YAMATO }
13723ae02089SMasatake YAMATO 
parseRecord(tokenInfo * const token)13733ae02089SMasatake YAMATO static void parseRecord (tokenInfo *const token)
13743ae02089SMasatake YAMATO {
13753ae02089SMasatake YAMATO 	/*
13763ae02089SMasatake YAMATO 	 * Make it a bit forgiving, this is called from
13773ae02089SMasatake YAMATO 	 * multiple functions, parseTable, parseType
13783ae02089SMasatake YAMATO 	 */
13793ae02089SMasatake YAMATO 	if (!isType (token, TOKEN_OPEN_PAREN))
13803ae02089SMasatake YAMATO 		readToken (token);
1381eb09c00aSColomban Wendling 	if (!isType (token, TOKEN_OPEN_PAREN))
1382eb09c00aSColomban Wendling 		return;
13833ae02089SMasatake YAMATO 
13843ae02089SMasatake YAMATO 	do
13853ae02089SMasatake YAMATO 	{
13863ae02089SMasatake YAMATO 		if (isType (token, TOKEN_COMMA) ||
13873ae02089SMasatake YAMATO 			isType (token, TOKEN_OPEN_PAREN))
13883ae02089SMasatake YAMATO 		{
13893ae02089SMasatake YAMATO 			readToken (token);
13903ae02089SMasatake YAMATO 		}
13913ae02089SMasatake YAMATO 
13923ae02089SMasatake YAMATO 		/*
13933ae02089SMasatake YAMATO 		 * Create table statements can end with various constraints
13943ae02089SMasatake YAMATO 		 * which must be excluded from the SQLTAG_FIELD.
13953ae02089SMasatake YAMATO 		 *	  create table t1 (
13963ae02089SMasatake YAMATO 		 *		  c1 integer,
13973ae02089SMasatake YAMATO 		 *		  c2 char(30),
13983ae02089SMasatake YAMATO 		 *		  c3 numeric(10,5),
13993ae02089SMasatake YAMATO 		 *		  c4 integer,
14003ae02089SMasatake YAMATO 		 *		  constraint whatever,
14013ae02089SMasatake YAMATO 		 *		  primary key(c1),
14023ae02089SMasatake YAMATO 		 *		  foreign key (),
14033ae02089SMasatake YAMATO 		 *		  check ()
14043ae02089SMasatake YAMATO 		 *	  )
14053ae02089SMasatake YAMATO 		 */
14063ae02089SMasatake YAMATO 		if (! isKeyword(token, KEYWORD_primary) &&
14073ae02089SMasatake YAMATO 			! isKeyword(token, KEYWORD_references) &&
14083ae02089SMasatake YAMATO 			! isKeyword(token, KEYWORD_unique) &&
14093ae02089SMasatake YAMATO 			! isKeyword(token, KEYWORD_check) &&
14103ae02089SMasatake YAMATO 			! isKeyword(token, KEYWORD_constraint) &&
14113ae02089SMasatake YAMATO 			! isKeyword(token, KEYWORD_foreign))
14123ae02089SMasatake YAMATO 		{
14133ae02089SMasatake YAMATO 			/* keyword test above is redundant as only a TOKEN_KEYWORD could
14143ae02089SMasatake YAMATO 			 * match any isKeyword() anyway */
14153ae02089SMasatake YAMATO 			if (isType (token, TOKEN_IDENTIFIER) ||
1416747f593aSMasatake YAMATO 				isType (token, TOKEN_STRING)     ||
1417747f593aSMasatake YAMATO 				(isType (token, TOKEN_KEYWORD)
1418747f593aSMasatake YAMATO 				 && (!isReservedWord (token))))
14193ae02089SMasatake YAMATO 			{
14203ae02089SMasatake YAMATO 				makeSqlTag (token, SQLTAG_FIELD);
14213ae02089SMasatake YAMATO 			}
14223ae02089SMasatake YAMATO 		}
14233ae02089SMasatake YAMATO 
14243ae02089SMasatake YAMATO 		while (! isType (token, TOKEN_COMMA) &&
14253ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_CLOSE_PAREN) &&
14263ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_OPEN_PAREN) &&
14273ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF))
14283ae02089SMasatake YAMATO 		{
14293ae02089SMasatake YAMATO 			readToken (token);
14303ae02089SMasatake YAMATO 			/*
14313ae02089SMasatake YAMATO 			 * A table structure can look like this:
14323ae02089SMasatake YAMATO 			 *	  create table t1 (
14333ae02089SMasatake YAMATO 			 *		  c1 integer,
14343ae02089SMasatake YAMATO 			 *		  c2 char(30),
14353ae02089SMasatake YAMATO 			 *		  c3 numeric(10,5),
14363ae02089SMasatake YAMATO 			 *		  c4 integer
14373ae02089SMasatake YAMATO 			 *	  )
14383ae02089SMasatake YAMATO 			 * We can't just look for a COMMA or CLOSE_PAREN
14393ae02089SMasatake YAMATO 			 * since that will not deal with the numeric(10,5)
14403ae02089SMasatake YAMATO 			 * case.  So we need to skip the argument list
14413ae02089SMasatake YAMATO 			 * when we find an open paren.
14423ae02089SMasatake YAMATO 			 */
14433ae02089SMasatake YAMATO 			if (isType (token, TOKEN_OPEN_PAREN))
14443ae02089SMasatake YAMATO 			{
14453ae02089SMasatake YAMATO 				/* Reads to the next token after the TOKEN_CLOSE_PAREN */
14463ae02089SMasatake YAMATO 				skipArgumentList(token);
14473ae02089SMasatake YAMATO 			}
14483ae02089SMasatake YAMATO 		}
14493ae02089SMasatake YAMATO 	} while (! isType (token, TOKEN_CLOSE_PAREN) &&
14503ae02089SMasatake YAMATO 			 ! isType (token, TOKEN_EOF));
14513ae02089SMasatake YAMATO }
14523ae02089SMasatake YAMATO 
parseType(tokenInfo * const token)14533ae02089SMasatake YAMATO static void parseType (tokenInfo *const token)
14543ae02089SMasatake YAMATO {
14553ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
14563ae02089SMasatake YAMATO 	vString * saveScope = vStringNew ();
14573ae02089SMasatake YAMATO 	sqlKind saveScopeKind;
14583ae02089SMasatake YAMATO 
14593ae02089SMasatake YAMATO 	vStringCopy(saveScope, token->scope);
14603ae02089SMasatake YAMATO 	/* If a scope has been set, add it to the name */
14613ae02089SMasatake YAMATO 	addToScope (name, token->scope, token->scopeKind);
14623ae02089SMasatake YAMATO 	saveScopeKind = token->scopeKind;
14633ae02089SMasatake YAMATO 	readToken (name);
14643ae02089SMasatake YAMATO 	if (isType (name, TOKEN_IDENTIFIER))
14653ae02089SMasatake YAMATO 	{
14663ae02089SMasatake YAMATO 		readToken (token);
14673ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_is))
14683ae02089SMasatake YAMATO 		{
14693ae02089SMasatake YAMATO 			readToken (token);
14703ae02089SMasatake YAMATO 			switch (token->keyword)
14713ae02089SMasatake YAMATO 			{
14723ae02089SMasatake YAMATO 				case KEYWORD_record:
14733ae02089SMasatake YAMATO 				case KEYWORD_object:
14743ae02089SMasatake YAMATO 					makeSqlTag (name, SQLTAG_RECORD);
14753ae02089SMasatake YAMATO 					addToScope (token, name->string, SQLTAG_RECORD);
14763ae02089SMasatake YAMATO 					parseRecord (token);
14773ae02089SMasatake YAMATO 					break;
14783ae02089SMasatake YAMATO 
14793ae02089SMasatake YAMATO 				case KEYWORD_table:
14803ae02089SMasatake YAMATO 					makeSqlTag (name, SQLTAG_TABLE);
14813ae02089SMasatake YAMATO 					break;
14823ae02089SMasatake YAMATO 
14833ae02089SMasatake YAMATO 				case KEYWORD_ref:
14843ae02089SMasatake YAMATO 					readToken (token);
14853ae02089SMasatake YAMATO 					if (isKeyword (token, KEYWORD_cursor))
14863ae02089SMasatake YAMATO 						makeSqlTag (name, SQLTAG_CURSOR);
14873ae02089SMasatake YAMATO 					break;
14883ae02089SMasatake YAMATO 
14893ae02089SMasatake YAMATO 				default: break;
14903ae02089SMasatake YAMATO 			}
14913ae02089SMasatake YAMATO 			vStringClear (token->scope);
14923ae02089SMasatake YAMATO 			token->scopeKind = SQLTAG_COUNT;
14933ae02089SMasatake YAMATO 		}
14943ae02089SMasatake YAMATO 	}
14953ae02089SMasatake YAMATO 	vStringCopy(token->scope, saveScope);
14963ae02089SMasatake YAMATO 	token->scopeKind = saveScopeKind;
14973ae02089SMasatake YAMATO 	deleteToken (name);
14983ae02089SMasatake YAMATO 	vStringDelete(saveScope);
14993ae02089SMasatake YAMATO }
15003ae02089SMasatake YAMATO 
parseSimple(tokenInfo * const token,const sqlKind kind)15013ae02089SMasatake YAMATO static void parseSimple (tokenInfo *const token, const sqlKind kind)
15023ae02089SMasatake YAMATO {
15033ae02089SMasatake YAMATO 	/* This will simply make the tagname from the first word found */
15043ae02089SMasatake YAMATO 	readToken (token);
15053ae02089SMasatake YAMATO 	if (isType (token, TOKEN_IDENTIFIER) ||
15063ae02089SMasatake YAMATO 		isType (token, TOKEN_STRING))
15073ae02089SMasatake YAMATO 	{
15083ae02089SMasatake YAMATO 		makeSqlTag (token, kind);
15093ae02089SMasatake YAMATO 	}
15103ae02089SMasatake YAMATO }
15113ae02089SMasatake YAMATO 
parseDeclare(tokenInfo * const token,const bool local)1512ce990805SThomas Braun static void parseDeclare (tokenInfo *const token, const bool local)
15133ae02089SMasatake YAMATO {
15143ae02089SMasatake YAMATO 	/*
15153ae02089SMasatake YAMATO 	 * PL/SQL declares are of this format:
15163ae02089SMasatake YAMATO 	 *	  IS|AS
15173ae02089SMasatake YAMATO 	 *	  [declare]
15183ae02089SMasatake YAMATO 	 *		 CURSOR curname ...
15193ae02089SMasatake YAMATO 	 *		 varname1 datatype;
15203ae02089SMasatake YAMATO 	 *		 varname2 datatype;
15213ae02089SMasatake YAMATO 	 *		 varname3 datatype;
15223ae02089SMasatake YAMATO 	 *	  begin
15233ae02089SMasatake YAMATO 	 */
15243ae02089SMasatake YAMATO 
15253ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_declare))
15263ae02089SMasatake YAMATO 		readToken (token);
15273ae02089SMasatake YAMATO 	while (! isKeyword (token, KEYWORD_begin) &&
15283ae02089SMasatake YAMATO 		   ! isKeyword (token, KEYWORD_end) &&
15293ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF))
15303ae02089SMasatake YAMATO 	{
1531e8d993efSMasatake YAMATO 		keywordId stoppers [] = {
1532e8d993efSMasatake YAMATO 			KEYWORD_begin,
1533e8d993efSMasatake YAMATO 			KEYWORD_end,
1534e8d993efSMasatake YAMATO 		};
1535e8d993efSMasatake YAMATO 
15363ae02089SMasatake YAMATO 		switch (token->keyword)
15373ae02089SMasatake YAMATO 		{
15383ae02089SMasatake YAMATO 			case KEYWORD_cursor:	parseSimple (token, SQLTAG_CURSOR); break;
15393ae02089SMasatake YAMATO 			case KEYWORD_function:	parseSubProgram (token); break;
15403ae02089SMasatake YAMATO 			case KEYWORD_procedure: parseSubProgram (token); break;
15413ae02089SMasatake YAMATO 			case KEYWORD_subtype:	parseSimple (token, SQLTAG_SUBTYPE); break;
15423ae02089SMasatake YAMATO 			case KEYWORD_trigger:	parseSimple (token, SQLTAG_TRIGGER); break;
15433ae02089SMasatake YAMATO 			case KEYWORD_type:		parseType (token); break;
15443ae02089SMasatake YAMATO 
15453ae02089SMasatake YAMATO 			default:
15463ae02089SMasatake YAMATO 				if (isType (token, TOKEN_IDENTIFIER))
15473ae02089SMasatake YAMATO 				{
1548348f1d4cSMasatake YAMATO 					makeSqlTag (token, local? SQLTAG_LOCAL_VARIABLE: SQLTAG_VARIABLE);
15493ae02089SMasatake YAMATO 				}
15503ae02089SMasatake YAMATO 				break;
15513ae02089SMasatake YAMATO 		}
1552e8d993efSMasatake YAMATO 		findTokenOrKeywords (token, TOKEN_SEMICOLON, stoppers, ARRAY_SIZE (stoppers));
1553e8d993efSMasatake YAMATO 		if (isType (token, TOKEN_SEMICOLON))
15543ae02089SMasatake YAMATO 			readToken (token);
15553ae02089SMasatake YAMATO 	}
15563ae02089SMasatake YAMATO }
15573ae02089SMasatake YAMATO 
parseDeclareANSI(tokenInfo * const token,const bool local)1558ce990805SThomas Braun static void parseDeclareANSI (tokenInfo *const token, const bool local)
15593ae02089SMasatake YAMATO {
15603ae02089SMasatake YAMATO 	tokenInfo *const type = newToken ();
15613ae02089SMasatake YAMATO 	/*
15623ae02089SMasatake YAMATO 	 * ANSI declares are of this format:
15633ae02089SMasatake YAMATO 	 *	 BEGIN
15643ae02089SMasatake YAMATO 	 *		 DECLARE varname1 datatype;
15653ae02089SMasatake YAMATO 	 *		 DECLARE varname2 datatype;
15663ae02089SMasatake YAMATO 	 *		 ...
15673ae02089SMasatake YAMATO 	 *
156846204f78SBen Wiederhake 	 * This differ from PL/SQL where DECLARE precedes the BEGIN block
15693ae02089SMasatake YAMATO 	 * and the DECLARE keyword is not repeated.
15703ae02089SMasatake YAMATO 	 */
15713ae02089SMasatake YAMATO 	while (isKeyword (token, KEYWORD_declare))
15723ae02089SMasatake YAMATO 	{
15733ae02089SMasatake YAMATO 		readToken (token);
15743ae02089SMasatake YAMATO 		readToken (type);
15753ae02089SMasatake YAMATO 
15763ae02089SMasatake YAMATO 		if (isKeyword (type, KEYWORD_cursor))
15773ae02089SMasatake YAMATO 			makeSqlTag (token, SQLTAG_CURSOR);
15783ae02089SMasatake YAMATO 		else if (isKeyword (token, KEYWORD_local) &&
15793ae02089SMasatake YAMATO 				 isKeyword (type, KEYWORD_temporary))
15803ae02089SMasatake YAMATO 		{
15813ae02089SMasatake YAMATO 			/*
15823ae02089SMasatake YAMATO 			 * DECLARE LOCAL TEMPORARY TABLE table_name (
15833ae02089SMasatake YAMATO 			 *	  c1 int,
15843ae02089SMasatake YAMATO 			 *	  c2 int
15853ae02089SMasatake YAMATO 			 * );
15863ae02089SMasatake YAMATO 			 */
15873ae02089SMasatake YAMATO 			readToken (token);
15883ae02089SMasatake YAMATO 			if (isKeyword (token, KEYWORD_table))
15893ae02089SMasatake YAMATO 			{
15903ae02089SMasatake YAMATO 				readToken (token);
15913ae02089SMasatake YAMATO 				if (isType(token, TOKEN_IDENTIFIER) ||
15923ae02089SMasatake YAMATO 					isType(token, TOKEN_STRING))
15933ae02089SMasatake YAMATO 				{
15943ae02089SMasatake YAMATO 					makeSqlTag (token, SQLTAG_TABLE);
15953ae02089SMasatake YAMATO 				}
15963ae02089SMasatake YAMATO 			}
15973ae02089SMasatake YAMATO 		}
15983ae02089SMasatake YAMATO 		else if (isType (token, TOKEN_IDENTIFIER) ||
15993ae02089SMasatake YAMATO 				 isType (token, TOKEN_STRING))
16003ae02089SMasatake YAMATO 		{
1601348f1d4cSMasatake YAMATO 			makeSqlTag (token, local? SQLTAG_LOCAL_VARIABLE: SQLTAG_VARIABLE);
16023ae02089SMasatake YAMATO 		}
16033ae02089SMasatake YAMATO 		findToken (token, TOKEN_SEMICOLON);
16043ae02089SMasatake YAMATO 		readToken (token);
16053ae02089SMasatake YAMATO 	}
16063ae02089SMasatake YAMATO 	deleteToken (type);
16073ae02089SMasatake YAMATO }
16083ae02089SMasatake YAMATO 
parseLabel(tokenInfo * const token)16093ae02089SMasatake YAMATO static void parseLabel (tokenInfo *const token)
16103ae02089SMasatake YAMATO {
16113ae02089SMasatake YAMATO 	/*
16123ae02089SMasatake YAMATO 	 * A label has this format:
16133ae02089SMasatake YAMATO 	 *	   <<tobacco_dependency>>
16143ae02089SMasatake YAMATO 	 *	   DECLARE
16153ae02089SMasatake YAMATO 	 *		  v_senator VARCHAR2(100) := 'THURMOND, JESSE';
16163ae02089SMasatake YAMATO 	 *	   BEGIN
16173ae02089SMasatake YAMATO 	 *		  IF total_contributions (v_senator, 'TOBACCO') > 25000
16183ae02089SMasatake YAMATO 	 *		  THEN
16193ae02089SMasatake YAMATO 	 *			 <<alochol_dependency>>
16203ae02089SMasatake YAMATO 	 *			 DECLARE
16213ae02089SMasatake YAMATO 	 *				v_senator VARCHAR2(100) := 'WHATEVERIT, TAKES';
16223ae02089SMasatake YAMATO 	 *			 BEGIN
16233ae02089SMasatake YAMATO 	 *				...
16243ae02089SMasatake YAMATO 	 */
16253ae02089SMasatake YAMATO 
16263ae02089SMasatake YAMATO 	Assert (isType (token, TOKEN_BLOCK_LABEL_BEGIN));
16273ae02089SMasatake YAMATO 	readToken (token);
16283ae02089SMasatake YAMATO 	if (isType (token, TOKEN_IDENTIFIER))
16293ae02089SMasatake YAMATO 	{
16303ae02089SMasatake YAMATO 		makeSqlTag (token, SQLTAG_BLOCK_LABEL);
16313ae02089SMasatake YAMATO 		readToken (token);		  /* read end of label */
16323ae02089SMasatake YAMATO 	}
16333ae02089SMasatake YAMATO }
16343ae02089SMasatake YAMATO 
parseStatements(tokenInfo * const token,const bool exit_on_endif)1635ce990805SThomas Braun static void parseStatements (tokenInfo *const token, const bool exit_on_endif )
16363ae02089SMasatake YAMATO {
1637ce990805SThomas Braun 	/* bool isAnsi   = true; */
1638ce990805SThomas Braun 	bool stmtTerm = false;
16393ae02089SMasatake YAMATO 	do
16403ae02089SMasatake YAMATO 	{
16413ae02089SMasatake YAMATO 
16423ae02089SMasatake YAMATO 		if (isType (token, TOKEN_BLOCK_LABEL_BEGIN))
16433ae02089SMasatake YAMATO 			parseLabel (token);
16443ae02089SMasatake YAMATO 		else
16453ae02089SMasatake YAMATO 		{
16463ae02089SMasatake YAMATO 			switch (token->keyword)
16473ae02089SMasatake YAMATO 			{
16483ae02089SMasatake YAMATO 				case KEYWORD_exception:
16493ae02089SMasatake YAMATO 					/*
16503ae02089SMasatake YAMATO 					 * EXCEPTION
16513ae02089SMasatake YAMATO 					 *	 <exception handler>;
16523ae02089SMasatake YAMATO 					 *
16533ae02089SMasatake YAMATO 					 * Where an exception handler could be:
16543ae02089SMasatake YAMATO 					 *	 BEGIN
16553ae02089SMasatake YAMATO 					 *		WHEN OTHERS THEN
16563ae02089SMasatake YAMATO 					 *			x := x + 3;
16573ae02089SMasatake YAMATO 					 *	 END;
16583ae02089SMasatake YAMATO 					 * In this case we need to skip this keyword and
16593ae02089SMasatake YAMATO 					 * move on to the next token without reading until
16603ae02089SMasatake YAMATO 					 * TOKEN_SEMICOLON;
16613ae02089SMasatake YAMATO 					 */
16623ae02089SMasatake YAMATO 					readToken (token);
16633ae02089SMasatake YAMATO 					continue;
16643ae02089SMasatake YAMATO 
16653ae02089SMasatake YAMATO 				case KEYWORD_when:
16663ae02089SMasatake YAMATO 					/*
16673ae02089SMasatake YAMATO 					 * WHEN statements can be used in exception clauses
16683ae02089SMasatake YAMATO 					 * and CASE statements.  The CASE statement should skip
16693ae02089SMasatake YAMATO 					 * these given below we skip over to an END statement.
16703ae02089SMasatake YAMATO 					 * But for an exception clause, we can have:
16713ae02089SMasatake YAMATO 					 *	   EXCEPTION
16723ae02089SMasatake YAMATO 					 *		   WHEN OTHERS THEN
16733ae02089SMasatake YAMATO 					 *		   BEGIN
16743ae02089SMasatake YAMATO 					 *				  x := x + 3;
16753ae02089SMasatake YAMATO 					 *		   END;
16763ae02089SMasatake YAMATO 					 * If we skip to the TOKEN_SEMICOLON, we miss the begin
16773ae02089SMasatake YAMATO 					 * of a nested BEGIN END block.  So read the next token
16783ae02089SMasatake YAMATO 					 * after the THEN and restart the LOOP.
16793ae02089SMasatake YAMATO 					 */
16803ae02089SMasatake YAMATO 					while (! isKeyword (token, KEYWORD_then) &&
16813ae02089SMasatake YAMATO 						   ! isType (token, TOKEN_EOF))
16823ae02089SMasatake YAMATO 						readToken (token);
16833ae02089SMasatake YAMATO 
16843ae02089SMasatake YAMATO 					readToken (token);
16853ae02089SMasatake YAMATO 					continue;
16863ae02089SMasatake YAMATO 
16873ae02089SMasatake YAMATO 				case KEYWORD_if:
16883ae02089SMasatake YAMATO 					/*
16893ae02089SMasatake YAMATO 					 * We do not want to look for a ; since for an empty
16903ae02089SMasatake YAMATO 					 * IF block, it would skip over the END.
16913ae02089SMasatake YAMATO 					 *	IF...THEN
16923ae02089SMasatake YAMATO 					 *	END IF;
16933ae02089SMasatake YAMATO 					 *
16943ae02089SMasatake YAMATO 					 *	IF...THEN
16953ae02089SMasatake YAMATO 					 *	ELSE
16963ae02089SMasatake YAMATO 					 *	END IF;
16973ae02089SMasatake YAMATO 					 *
16983ae02089SMasatake YAMATO 					 *	IF...THEN
16993ae02089SMasatake YAMATO 					 *	ELSEIF...THEN
17003ae02089SMasatake YAMATO 					 *	ELSE
17013ae02089SMasatake YAMATO 					 *	END IF;
17023ae02089SMasatake YAMATO 					 *
17033ae02089SMasatake YAMATO 					 *	or non-ANSI
17043ae02089SMasatake YAMATO 					 *	IF ...
17053ae02089SMasatake YAMATO 					 *	BEGIN
17063ae02089SMasatake YAMATO 					 *	END
17073ae02089SMasatake YAMATO 					 */
17083ae02089SMasatake YAMATO 					while (! isKeyword (token, KEYWORD_then)  &&
17093ae02089SMasatake YAMATO 						   ! isKeyword (token, KEYWORD_begin) &&
17103ae02089SMasatake YAMATO 						   ! isType (token, TOKEN_EOF))
17113ae02089SMasatake YAMATO 					{
17123ae02089SMasatake YAMATO 						readToken (token);
17133ae02089SMasatake YAMATO 					}
17143ae02089SMasatake YAMATO 
17153ae02089SMasatake YAMATO 					if (isKeyword (token, KEYWORD_begin))
17163ae02089SMasatake YAMATO 					{
1717ce990805SThomas Braun 						/* isAnsi = false; */
1718ce990805SThomas Braun 						parseBlock(token, false);
17193ae02089SMasatake YAMATO 
17203ae02089SMasatake YAMATO 						/*
17213ae02089SMasatake YAMATO 						 * Handle the non-Ansi IF blocks.
17223ae02089SMasatake YAMATO 						 * parseBlock consumes the END, so if the next
17233ae02089SMasatake YAMATO 						 * token in a command terminator (like GO)
17243ae02089SMasatake YAMATO 						 * we know we are done with this statement.
17253ae02089SMasatake YAMATO 						 */
17263ae02089SMasatake YAMATO 						if (isCmdTerm (token))
1727ce990805SThomas Braun 							stmtTerm = true;
17283ae02089SMasatake YAMATO 					}
17293ae02089SMasatake YAMATO 					else
17303ae02089SMasatake YAMATO 					{
17313ae02089SMasatake YAMATO 						readToken (token);
17323ae02089SMasatake YAMATO 
17333ae02089SMasatake YAMATO 						while (! isKeyword (token, KEYWORD_end) &&
17343ae02089SMasatake YAMATO 							   ! isKeyword (token, KEYWORD_endif) &&
17353ae02089SMasatake YAMATO 							   ! isType (token, TOKEN_EOF))
17363ae02089SMasatake YAMATO 						{
17373ae02089SMasatake YAMATO 							if (isKeyword (token, KEYWORD_else) ||
17383ae02089SMasatake YAMATO 								isKeyword (token, KEYWORD_elseif))
17393ae02089SMasatake YAMATO 							{
17403ae02089SMasatake YAMATO 								readToken (token);
17413ae02089SMasatake YAMATO 							}
17423ae02089SMasatake YAMATO 
1743ce990805SThomas Braun 							parseStatements (token, true);
17443ae02089SMasatake YAMATO 
17453ae02089SMasatake YAMATO 							if (isCmdTerm(token))
17463ae02089SMasatake YAMATO 								readToken (token);
17473ae02089SMasatake YAMATO 
17483ae02089SMasatake YAMATO 						}
17493ae02089SMasatake YAMATO 
17503ae02089SMasatake YAMATO 						/*
17513ae02089SMasatake YAMATO 						 * parseStatements returns when it finds an END, an IF
17523ae02089SMasatake YAMATO 						 * should follow the END for ANSI anyway.
17533ae02089SMasatake YAMATO 						 *	IF...THEN
17543ae02089SMasatake YAMATO 						 *	END IF;
17553ae02089SMasatake YAMATO 						 */
17563ae02089SMasatake YAMATO 						if (isKeyword (token, KEYWORD_end))
17573ae02089SMasatake YAMATO 							readToken (token);
17583ae02089SMasatake YAMATO 
17593ae02089SMasatake YAMATO 						if (isKeyword (token, KEYWORD_if) ||
17603ae02089SMasatake YAMATO 							isKeyword (token, KEYWORD_endif))
17613ae02089SMasatake YAMATO 						{
17623ae02089SMasatake YAMATO 							readToken (token);
17633ae02089SMasatake YAMATO 							if (isCmdTerm(token))
1764ce990805SThomas Braun 								stmtTerm = true;
17653ae02089SMasatake YAMATO 						}
17663ae02089SMasatake YAMATO 						else
17673ae02089SMasatake YAMATO 						{
17683ae02089SMasatake YAMATO 							/*
17693ae02089SMasatake YAMATO 							 * Well we need to do something here.
17703ae02089SMasatake YAMATO 							 * There are lots of different END statements
17713ae02089SMasatake YAMATO 							 * END;
17723ae02089SMasatake YAMATO 							 * END CASE;
17733ae02089SMasatake YAMATO 							 * ENDIF;
17743ae02089SMasatake YAMATO 							 * ENDCASE;
17753ae02089SMasatake YAMATO 							 */
17763ae02089SMasatake YAMATO 						}
17773ae02089SMasatake YAMATO 					}
17783ae02089SMasatake YAMATO 					break;
17793ae02089SMasatake YAMATO 
17803ae02089SMasatake YAMATO 				case KEYWORD_loop:
17813ae02089SMasatake YAMATO 				case KEYWORD_case:
17823ae02089SMasatake YAMATO 				case KEYWORD_for:
17833ae02089SMasatake YAMATO 					/*
17843ae02089SMasatake YAMATO 					 *	LOOP...
17853ae02089SMasatake YAMATO 					 *	END LOOP;
17863ae02089SMasatake YAMATO 					 *
17873ae02089SMasatake YAMATO 					 *	CASE
17883ae02089SMasatake YAMATO 					 *	WHEN '1' THEN
17893ae02089SMasatake YAMATO 					 *	END CASE;
17903ae02089SMasatake YAMATO 					 *
17913ae02089SMasatake YAMATO 					 *	FOR loop_name AS cursor_name CURSOR FOR ...
17923ae02089SMasatake YAMATO 					 *	DO
17933ae02089SMasatake YAMATO 					 *	END FOR;
17943ae02089SMasatake YAMATO 					 */
17953ae02089SMasatake YAMATO 					if (isKeyword (token, KEYWORD_for))
17963ae02089SMasatake YAMATO 					{
17973ae02089SMasatake YAMATO 						/* loop name */
17983ae02089SMasatake YAMATO 						readToken (token);
17993ae02089SMasatake YAMATO 						/* AS */
18003ae02089SMasatake YAMATO 						readToken (token);
18013ae02089SMasatake YAMATO 
18023ae02089SMasatake YAMATO 						while (! isKeyword (token, KEYWORD_is) &&
18033ae02089SMasatake YAMATO 							   ! isType (token, TOKEN_EOF))
18043ae02089SMasatake YAMATO 						{
18053ae02089SMasatake YAMATO 							/*
18063ae02089SMasatake YAMATO 							 * If this is not an AS keyword this is
18073ae02089SMasatake YAMATO 							 * not a proper FOR statement and should
18083ae02089SMasatake YAMATO 							 * simply be ignored
18093ae02089SMasatake YAMATO 							 */
18103ae02089SMasatake YAMATO 							return;
18113ae02089SMasatake YAMATO 						}
18123ae02089SMasatake YAMATO 
18133ae02089SMasatake YAMATO 						while (! isKeyword (token, KEYWORD_do) &&
18143ae02089SMasatake YAMATO 							   ! isType (token, TOKEN_EOF))
18153ae02089SMasatake YAMATO 							readToken (token);
18163ae02089SMasatake YAMATO 					}
18173ae02089SMasatake YAMATO 
18183ae02089SMasatake YAMATO 
18193ae02089SMasatake YAMATO 					readToken (token);
18203ae02089SMasatake YAMATO 					while (! isKeyword (token, KEYWORD_end) &&
18213ae02089SMasatake YAMATO 						   ! isType (token, TOKEN_EOF))
18223ae02089SMasatake YAMATO 					{
18233ae02089SMasatake YAMATO 						/*
18243ae02089SMasatake YAMATO 						if ( isKeyword (token, KEYWORD_else) ||
18253ae02089SMasatake YAMATO 								isKeyword (token, KEYWORD_elseif)    )
18263ae02089SMasatake YAMATO 							readToken (token);
18273ae02089SMasatake YAMATO 							*/
18283ae02089SMasatake YAMATO 
1829ce990805SThomas Braun 						parseStatements (token, false);
18303ae02089SMasatake YAMATO 
18313ae02089SMasatake YAMATO 						if (isCmdTerm(token))
18323ae02089SMasatake YAMATO 							readToken (token);
18333ae02089SMasatake YAMATO 					}
18343ae02089SMasatake YAMATO 
18353ae02089SMasatake YAMATO 
18363ae02089SMasatake YAMATO 					if (isKeyword (token, KEYWORD_end ))
18373ae02089SMasatake YAMATO 						readToken (token);
18383ae02089SMasatake YAMATO 
18393ae02089SMasatake YAMATO 					/*
18403ae02089SMasatake YAMATO 					 * Typically ended with
18413ae02089SMasatake YAMATO 					 *    END LOOP [loop name];
18423ae02089SMasatake YAMATO 					 *    END CASE
18433ae02089SMasatake YAMATO 					 *    END FOR [loop name];
18443ae02089SMasatake YAMATO 					 */
18453ae02089SMasatake YAMATO 					if (isKeyword (token, KEYWORD_loop) ||
18463ae02089SMasatake YAMATO 						isKeyword (token, KEYWORD_case) ||
18473ae02089SMasatake YAMATO 						isKeyword (token, KEYWORD_for))
18483ae02089SMasatake YAMATO 					{
18493ae02089SMasatake YAMATO 						readToken (token);
18503ae02089SMasatake YAMATO 					}
18513ae02089SMasatake YAMATO 
18523ae02089SMasatake YAMATO 					if (isCmdTerm(token))
1853ce990805SThomas Braun 						stmtTerm = true;
18543ae02089SMasatake YAMATO 
18553ae02089SMasatake YAMATO 					break;
18563ae02089SMasatake YAMATO 
18573ae02089SMasatake YAMATO 				case KEYWORD_create:
18583ae02089SMasatake YAMATO 					readToken (token);
18593ae02089SMasatake YAMATO 					parseKeywords(token);
18603ae02089SMasatake YAMATO 					break;
18613ae02089SMasatake YAMATO 
18623ae02089SMasatake YAMATO 				case KEYWORD_declare:
18633ae02089SMasatake YAMATO 				case KEYWORD_begin:
1864ce990805SThomas Braun 					parseBlock (token, true);
18653ae02089SMasatake YAMATO 					break;
18663ae02089SMasatake YAMATO 
18673ae02089SMasatake YAMATO 				case KEYWORD_end:
18683ae02089SMasatake YAMATO 					break;
18693ae02089SMasatake YAMATO 
18703ae02089SMasatake YAMATO 				default:
18713ae02089SMasatake YAMATO 					readToken (token);
18723ae02089SMasatake YAMATO 					break;
18733ae02089SMasatake YAMATO 			}
18743ae02089SMasatake YAMATO 			/*
18753ae02089SMasatake YAMATO 			 * Not all statements must end in a semi-colon
18763ae02089SMasatake YAMATO 			 *	   begin
18773ae02089SMasatake YAMATO 			 *		   if current publisher <> 'publish' then
18783ae02089SMasatake YAMATO 			 *			 signal UE_FailStatement
18793ae02089SMasatake YAMATO 			 *		   end if
18803ae02089SMasatake YAMATO 			 *	   end;
18813ae02089SMasatake YAMATO 			 * The last statement prior to an end ("signal" above) does
18823ae02089SMasatake YAMATO 			 * not need a semi-colon, nor does the end if, since it is
18833ae02089SMasatake YAMATO 			 * also the last statement prior to the end of the block.
18843ae02089SMasatake YAMATO 			 *
18853ae02089SMasatake YAMATO 			 * So we must read to the first semi-colon or an END block
18863ae02089SMasatake YAMATO 			 */
18873ae02089SMasatake YAMATO 			while (! stmtTerm &&
18883ae02089SMasatake YAMATO 				   ! isKeyword (token, KEYWORD_end) &&
18893ae02089SMasatake YAMATO 				   ! isCmdTerm(token) &&
18903ae02089SMasatake YAMATO 				   ! isType(token, TOKEN_EOF))
18913ae02089SMasatake YAMATO 			{
18923ae02089SMasatake YAMATO 				if (exit_on_endif && isKeyword (token, KEYWORD_endif))
18933ae02089SMasatake YAMATO 					return;
18943ae02089SMasatake YAMATO 
18953ae02089SMasatake YAMATO 				if (isType (token, TOKEN_COLON) )
18963ae02089SMasatake YAMATO 				{
18973ae02089SMasatake YAMATO 					/*
18983ae02089SMasatake YAMATO 					 * A : can signal a loop name
18993ae02089SMasatake YAMATO 					 *    myloop:
19003ae02089SMasatake YAMATO 					 *    LOOP
19013ae02089SMasatake YAMATO 					 *        LEAVE myloop;
19023ae02089SMasatake YAMATO 					 *    END LOOP;
19033ae02089SMasatake YAMATO 					 * Unfortunately, labels do not have a
19043ae02089SMasatake YAMATO 					 * cmd terminator, therefore we have to check
19053ae02089SMasatake YAMATO 					 * if the next token is a keyword and process
19063ae02089SMasatake YAMATO 					 * it accordingly.
19073ae02089SMasatake YAMATO 					 */
19083ae02089SMasatake YAMATO 					readToken (token);
19093ae02089SMasatake YAMATO 					if (isKeyword (token, KEYWORD_loop) ||
19103ae02089SMasatake YAMATO 						isKeyword (token, KEYWORD_while) ||
19113ae02089SMasatake YAMATO 						isKeyword (token, KEYWORD_for))
19123ae02089SMasatake YAMATO 					{
19133ae02089SMasatake YAMATO 						/* parseStatements (token); */
19143ae02089SMasatake YAMATO 						return;
19153ae02089SMasatake YAMATO 					}
19163ae02089SMasatake YAMATO 				}
19173ae02089SMasatake YAMATO 
19183ae02089SMasatake YAMATO 				readToken (token);
19193ae02089SMasatake YAMATO 
19203ae02089SMasatake YAMATO 				if (isType (token, TOKEN_OPEN_PAREN) ||
19213ae02089SMasatake YAMATO 				    isType (token, TOKEN_OPEN_CURLY) ||
19223ae02089SMasatake YAMATO 				    isType (token, TOKEN_OPEN_SQUARE))
19233ae02089SMasatake YAMATO 				{
19243ae02089SMasatake YAMATO 					skipToMatched (token);
19253ae02089SMasatake YAMATO 				}
19263ae02089SMasatake YAMATO 
19273ae02089SMasatake YAMATO 				/*
19283ae02089SMasatake YAMATO 				 * Since we know how to parse various statements
19293ae02089SMasatake YAMATO 				 * if we detect them, parse them to completion
19303ae02089SMasatake YAMATO 				 */
19313ae02089SMasatake YAMATO 				if (isType (token, TOKEN_BLOCK_LABEL_BEGIN) ||
19323ae02089SMasatake YAMATO 					isKeyword (token, KEYWORD_exception) ||
19333ae02089SMasatake YAMATO 					isKeyword (token, KEYWORD_loop) ||
19343ae02089SMasatake YAMATO 					isKeyword (token, KEYWORD_case) ||
19353ae02089SMasatake YAMATO 					isKeyword (token, KEYWORD_for) ||
19363ae02089SMasatake YAMATO 					isKeyword (token, KEYWORD_begin))
19373ae02089SMasatake YAMATO 				{
1938ce990805SThomas Braun 					parseStatements (token, false);
19393ae02089SMasatake YAMATO 				}
19403ae02089SMasatake YAMATO 				else if (isKeyword (token, KEYWORD_if))
1941ce990805SThomas Braun 					parseStatements (token, true);
19423ae02089SMasatake YAMATO 
19433ae02089SMasatake YAMATO 			}
19443ae02089SMasatake YAMATO 		}
19453ae02089SMasatake YAMATO 		/*
19463ae02089SMasatake YAMATO 		 * We assumed earlier all statements ended with a command terminator.
19473ae02089SMasatake YAMATO 		 * See comment above, now, only read if the current token
19483ae02089SMasatake YAMATO 		 * is not a command terminator.
19493ae02089SMasatake YAMATO 		 */
19503ae02089SMasatake YAMATO 		if (isCmdTerm(token) && ! stmtTerm)
1951ce990805SThomas Braun 			stmtTerm = true;
19523ae02089SMasatake YAMATO 
19533ae02089SMasatake YAMATO 	} while (! isKeyword (token, KEYWORD_end) &&
19543ae02089SMasatake YAMATO 			 ! (exit_on_endif && isKeyword (token, KEYWORD_endif) ) &&
19553ae02089SMasatake YAMATO 			 ! isType (token, TOKEN_EOF) &&
19563ae02089SMasatake YAMATO 			 ! stmtTerm );
19573ae02089SMasatake YAMATO }
19583ae02089SMasatake YAMATO 
parseBlock(tokenInfo * const token,const bool local)1959ce990805SThomas Braun static void parseBlock (tokenInfo *const token, const bool local)
19603ae02089SMasatake YAMATO {
1961a9b9ded9SMasatake YAMATO 	parseBlockFull (token, local, LANG_IGNORE);
1962a9b9ded9SMasatake YAMATO }
1963a9b9ded9SMasatake YAMATO 
parseBlockFull(tokenInfo * const token,const bool local,langType lang)1964a9b9ded9SMasatake YAMATO static void parseBlockFull (tokenInfo *const token, const bool local, langType lang)
1965a9b9ded9SMasatake YAMATO {
1966a9b9ded9SMasatake YAMATO 	int promise = -1;
1967a9b9ded9SMasatake YAMATO 
19683ae02089SMasatake YAMATO 	if (isType (token, TOKEN_BLOCK_LABEL_BEGIN))
19693ae02089SMasatake YAMATO 	{
19703ae02089SMasatake YAMATO 		parseLabel (token);
19713ae02089SMasatake YAMATO 		readToken (token);
19723ae02089SMasatake YAMATO 	}
19733ae02089SMasatake YAMATO 	if (! isKeyword (token, KEYWORD_begin))
19743ae02089SMasatake YAMATO 	{
19753ae02089SMasatake YAMATO 		readToken (token);
1976cc0f045dSColomban Wendling 		if (isType (token, TOKEN_STRING))
1977cc0f045dSColomban Wendling 		{
1978cc0f045dSColomban Wendling 			/* Likely a PostgreSQL FUNCTION name AS '...'
1979cc0f045dSColomban Wendling 			 * https://www.postgresql.org/docs/current/static/sql-createfunction.html */
1980a9b9ded9SMasatake YAMATO 			promise = token->promise;
1981a9b9ded9SMasatake YAMATO 			token->promise = -1;
1982a9b9ded9SMasatake YAMATO 
1983a9b9ded9SMasatake YAMATO 			readToken (token);
1984a9b9ded9SMasatake YAMATO 			while (! isCmdTerm (token)
1985a9b9ded9SMasatake YAMATO 				   && !isType (token, TOKEN_EOF))
1986a9b9ded9SMasatake YAMATO 			{
1987a9b9ded9SMasatake YAMATO 				if (lang == LANG_IGNORE &&
1988a9b9ded9SMasatake YAMATO 					isKeyword (token, KEYWORD_language))
1989a9b9ded9SMasatake YAMATO 				{
1990a9b9ded9SMasatake YAMATO 					readToken (token);
1991a9b9ded9SMasatake YAMATO 					lang = getNamedLanguageFromToken (token);
1992a9b9ded9SMasatake YAMATO 					if (lang != LANG_IGNORE)
1993a9b9ded9SMasatake YAMATO 						readToken (token);
1994a9b9ded9SMasatake YAMATO 				}
1995a9b9ded9SMasatake YAMATO 				else
1996a9b9ded9SMasatake YAMATO 					readToken (token);
1997a9b9ded9SMasatake YAMATO 			}
1998a9b9ded9SMasatake YAMATO 
1999a9b9ded9SMasatake YAMATO 			if (promise != -1 && lang != LANG_IGNORE)
2000a9b9ded9SMasatake YAMATO 				promiseUpdateLanguage(promise, lang);
2001cc0f045dSColomban Wendling 		}
2002cc0f045dSColomban Wendling 		else
2003cc0f045dSColomban Wendling 		{
20043ae02089SMasatake YAMATO 			/*
20053ae02089SMasatake YAMATO 			 * These are Oracle style declares which generally come
20063ae02089SMasatake YAMATO 			 * between an IS/AS and BEGIN block.
20073ae02089SMasatake YAMATO 			 */
20083ae02089SMasatake YAMATO 			parseDeclare (token, local);
20093ae02089SMasatake YAMATO 		}
2010cc0f045dSColomban Wendling 	}
20113ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_begin))
20123ae02089SMasatake YAMATO 	{
2013af68835dSMasatake YAMATO 		bool is_transaction = false;
2014af68835dSMasatake YAMATO 
20153ae02089SMasatake YAMATO 		readToken (token);
2016af68835dSMasatake YAMATO 
2017af68835dSMasatake YAMATO 		/* BEGIN of Postgresql initiates a transaction.
2018af68835dSMasatake YAMATO 		 *
2019af68835dSMasatake YAMATO 		 *   BEGIN [ WORK | TRANSACTION ] [ transaction_mode [, ...] ]
2020af68835dSMasatake YAMATO 		 *
2021af68835dSMasatake YAMATO 		 * BEGIN of MySQL does the same.
2022af68835dSMasatake YAMATO 		 *
2023af68835dSMasatake YAMATO 		 *   BEGIN [WORK]
2024af68835dSMasatake YAMATO 		 *
2025af68835dSMasatake YAMATO 		 * BEGIN of SQLite does the same.
2026af68835dSMasatake YAMATO 		 *
2027af68835dSMasatake YAMATO 		 *   BEGIN [[DEFERRED | IMMEDIATE | EXCLUSIVE] TRANSACTION]
2028af68835dSMasatake YAMATO 		 *
2029af68835dSMasatake YAMATO 		 */
2030af68835dSMasatake YAMATO 		if (isCmdTerm(token))
2031af68835dSMasatake YAMATO 		{
2032af68835dSMasatake YAMATO 			is_transaction = true;
2033af68835dSMasatake YAMATO 			readToken (token);
2034af68835dSMasatake YAMATO 		}
2035af68835dSMasatake YAMATO 		else if (isType (token, TOKEN_IDENTIFIER)
2036af68835dSMasatake YAMATO 				 && (strcasecmp (vStringValue(token->string), "work") == 0
2037af68835dSMasatake YAMATO 					 || strcasecmp (vStringValue(token->string), "transaction") == 0
2038af68835dSMasatake YAMATO 					 || (
2039af68835dSMasatake YAMATO 						 strcasecmp (vStringValue(token->string), "deferred") == 0
2040af68835dSMasatake YAMATO 						 || strcasecmp (vStringValue(token->string), "immediate") == 0
2041af68835dSMasatake YAMATO 						 || strcasecmp (vStringValue(token->string), "exclusive") == 0
2042af68835dSMasatake YAMATO 						 )
2043af68835dSMasatake YAMATO 					 ))
2044af68835dSMasatake YAMATO 			is_transaction = true;
2045af68835dSMasatake YAMATO 		else
2046af68835dSMasatake YAMATO 		{
20473ae02089SMasatake YAMATO 			/*
20483ae02089SMasatake YAMATO 			 * Check for ANSI declarations which always follow
20493ae02089SMasatake YAMATO 			 * a BEGIN statement.  This routine will not advance
20503ae02089SMasatake YAMATO 			 * the token if none are found.
20513ae02089SMasatake YAMATO 			 */
20523ae02089SMasatake YAMATO 			parseDeclareANSI (token, local);
2053af68835dSMasatake YAMATO 		}
2054af68835dSMasatake YAMATO 
20553ae02089SMasatake YAMATO 		token->begin_end_nest_lvl++;
20563ae02089SMasatake YAMATO 		while (! isKeyword (token, KEYWORD_end) &&
2057af68835dSMasatake YAMATO 			   ! (is_transaction && isKeyword(token, KEYWORD_commit)) &&
20583ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF))
20593ae02089SMasatake YAMATO 		{
2060ce990805SThomas Braun 			parseStatements (token, false);
20613ae02089SMasatake YAMATO 
20623ae02089SMasatake YAMATO 			if (isCmdTerm(token))
20633ae02089SMasatake YAMATO 				readToken (token);
20643ae02089SMasatake YAMATO 		}
20653ae02089SMasatake YAMATO 		token->begin_end_nest_lvl--;
20663ae02089SMasatake YAMATO 
20673ae02089SMasatake YAMATO 		/*
20683ae02089SMasatake YAMATO 		 * Read the next token (we will assume
20693ae02089SMasatake YAMATO 		 * it is the command delimiter)
20703ae02089SMasatake YAMATO 		 */
20713ae02089SMasatake YAMATO 		readToken (token);
20723ae02089SMasatake YAMATO 
20733ae02089SMasatake YAMATO 		/*
20743ae02089SMasatake YAMATO 		 * Check if the END block is terminated
20753ae02089SMasatake YAMATO 		 */
20763ae02089SMasatake YAMATO 		if (! isCmdTerm (token))
20773ae02089SMasatake YAMATO 		{
20783ae02089SMasatake YAMATO 			/*
20793ae02089SMasatake YAMATO 			 * Not sure what to do here at the moment.
20803ae02089SMasatake YAMATO 			 * I think the routine that calls parseBlock
20813ae02089SMasatake YAMATO 			 * must expect the next token has already
20823ae02089SMasatake YAMATO 			 * been read since it is possible this
20833ae02089SMasatake YAMATO 			 * token is not a command delimiter.
20843ae02089SMasatake YAMATO 			 */
2085ce990805SThomas Braun 			/* findCmdTerm (token, false); */
20863ae02089SMasatake YAMATO 		}
20873ae02089SMasatake YAMATO 	}
20883ae02089SMasatake YAMATO }
20893ae02089SMasatake YAMATO 
parsePackage(tokenInfo * const token)20903ae02089SMasatake YAMATO static void parsePackage (tokenInfo *const token)
20913ae02089SMasatake YAMATO {
20923ae02089SMasatake YAMATO 	/*
20933ae02089SMasatake YAMATO 	 * Packages can be specified in a number of ways:
20943ae02089SMasatake YAMATO 	 *		CREATE OR REPLACE PACKAGE pkg_name AS
20953ae02089SMasatake YAMATO 	 * or
20963ae02089SMasatake YAMATO 	 *		CREATE OR REPLACE PACKAGE owner.pkg_name AS
20973ae02089SMasatake YAMATO 	 * or by specifying a package body
20983ae02089SMasatake YAMATO 	 *	   CREATE OR REPLACE PACKAGE BODY pkg_name AS
20993ae02089SMasatake YAMATO 	 *	   CREATE OR REPLACE PACKAGE BODY owner.pkg_name AS
21003ae02089SMasatake YAMATO 	 */
21013ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
21023ae02089SMasatake YAMATO 	readIdentifier (name);
21033ae02089SMasatake YAMATO 	if (isKeyword (name, KEYWORD_body))
21043ae02089SMasatake YAMATO 	{
21053ae02089SMasatake YAMATO 		/*
21063ae02089SMasatake YAMATO 		 * Ignore the BODY tag since we will process
21073ae02089SMasatake YAMATO 		 * the body or prototypes in the same manner
21083ae02089SMasatake YAMATO 		 */
21093ae02089SMasatake YAMATO 		readIdentifier (name);
21103ae02089SMasatake YAMATO 	}
21113ae02089SMasatake YAMATO 	/* Check for owner.pkg_name */
21123ae02089SMasatake YAMATO 	while (! isKeyword (token, KEYWORD_is) &&
21133ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF))
21143ae02089SMasatake YAMATO 	{
21153ae02089SMasatake YAMATO 		readToken (token);
21163ae02089SMasatake YAMATO 		if ( isType(token, TOKEN_PERIOD) )
21173ae02089SMasatake YAMATO 		{
21183ae02089SMasatake YAMATO 			readIdentifier (name);
21193ae02089SMasatake YAMATO 		}
21203ae02089SMasatake YAMATO 	}
21213ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_is))
21223ae02089SMasatake YAMATO 	{
21233ae02089SMasatake YAMATO 		if (isType (name, TOKEN_IDENTIFIER) ||
21243ae02089SMasatake YAMATO 			isType (name, TOKEN_STRING))
21253ae02089SMasatake YAMATO 		{
21263ae02089SMasatake YAMATO 			makeSqlTag (name, SQLTAG_PACKAGE);
21273ae02089SMasatake YAMATO 		}
21283ae02089SMasatake YAMATO 		addToScope (token, name->string, SQLTAG_PACKAGE);
2129ce990805SThomas Braun 		parseBlock (token, false);
21303ae02089SMasatake YAMATO 		vStringClear (token->scope);
21313ae02089SMasatake YAMATO 		token->scopeKind = SQLTAG_COUNT;
21323ae02089SMasatake YAMATO 	}
2133ce990805SThomas Braun 	findCmdTerm (token, false);
21343ae02089SMasatake YAMATO 	deleteToken (name);
21353ae02089SMasatake YAMATO }
21363ae02089SMasatake YAMATO 
parseColumnsAndAliases(tokenInfo * const token)2137876763c9SMasatake YAMATO static void parseColumnsAndAliases (tokenInfo *const token)
2138876763c9SMasatake YAMATO {
2139876763c9SMasatake YAMATO 	bool columnAcceptable = true;
2140876763c9SMasatake YAMATO 	tokenInfo *const lastId = newToken ();
2141876763c9SMasatake YAMATO 
2142876763c9SMasatake YAMATO 	/*
2143876763c9SMasatake YAMATO 	 * -- A
2144876763c9SMasatake YAMATO 	 * create table foo as select A;
2145876763c9SMasatake YAMATO 	 *
2146876763c9SMasatake YAMATO 	 * -- B
2147876763c9SMasatake YAMATO 	 * create table foo as select B from ...;
2148876763c9SMasatake YAMATO 	 *
2149876763c9SMasatake YAMATO 	 * -- D
2150876763c9SMasatake YAMATO 	 * create table foo as select C as D from ...;
2151876763c9SMasatake YAMATO 	 *
2152876763c9SMasatake YAMATO 	 * -- E, F
2153876763c9SMasatake YAMATO 	 * create table foo as select E, a.F;
2154876763c9SMasatake YAMATO 	 *
2155876763c9SMasatake YAMATO 	 * -- G, H
2156876763c9SMasatake YAMATO 	 * create table foo as select G, a.H from ...;
2157876763c9SMasatake YAMATO 	 *
2158876763c9SMasatake YAMATO 	 * -- J, K
2159876763c9SMasatake YAMATO 	 * create table foo as select I as J, a.K from ...;
2160876763c9SMasatake YAMATO 	 *
2161876763c9SMasatake YAMATO 	 * lastID is used for capturing A, B, E, F, G, H, and K.
2162876763c9SMasatake YAMATO 	 */
2163876763c9SMasatake YAMATO 	readToken (token);
2164876763c9SMasatake YAMATO 	do
2165876763c9SMasatake YAMATO 	{
2166876763c9SMasatake YAMATO 		if (isType (token, TOKEN_KEYWORD)
2167876763c9SMasatake YAMATO 			&& isKeyword (token, KEYWORD_is))
2168876763c9SMasatake YAMATO 		{
2169876763c9SMasatake YAMATO 			readToken (token);
2170876763c9SMasatake YAMATO 			if (isType (token, TOKEN_IDENTIFIER))
2171876763c9SMasatake YAMATO 			{
2172876763c9SMasatake YAMATO 				/* Emit the alias */
2173876763c9SMasatake YAMATO 				makeSqlTag (token, SQLTAG_FIELD);
2174876763c9SMasatake YAMATO 				columnAcceptable = true;
2175876763c9SMasatake YAMATO 			}
2176876763c9SMasatake YAMATO 			lastId->type = TOKEN_UNDEFINED;
2177876763c9SMasatake YAMATO 		}
2178876763c9SMasatake YAMATO 		else if ((isType (token, TOKEN_KEYWORD)
2179876763c9SMasatake YAMATO 				  && isKeyword (token, KEYWORD_from))
2180876763c9SMasatake YAMATO 				 || isType (token, TOKEN_SEMICOLON)
2181876763c9SMasatake YAMATO 				 || isType(token, TOKEN_COMMA))
2182876763c9SMasatake YAMATO 		{
2183876763c9SMasatake YAMATO 			if (lastId->type == TOKEN_IDENTIFIER)
2184876763c9SMasatake YAMATO 			{
2185876763c9SMasatake YAMATO 				/* Emit the column */
2186876763c9SMasatake YAMATO 				makeSqlTag(lastId, SQLTAG_FIELD);
2187876763c9SMasatake YAMATO 				columnAcceptable = true;
2188876763c9SMasatake YAMATO 			}
2189876763c9SMasatake YAMATO 
2190876763c9SMasatake YAMATO 			if (isType(token, TOKEN_COMMA))
2191876763c9SMasatake YAMATO 				lastId->type = TOKEN_UNDEFINED;
2192876763c9SMasatake YAMATO 			else
2193876763c9SMasatake YAMATO 				break;
2194876763c9SMasatake YAMATO 		}
2195876763c9SMasatake YAMATO 		else if (isType (token, TOKEN_OPEN_PAREN))
2196876763c9SMasatake YAMATO 		{
2197876763c9SMasatake YAMATO 			columnAcceptable = false;
2198876763c9SMasatake YAMATO 			skipToMatched (token);
2199876763c9SMasatake YAMATO 			lastId->type = TOKEN_UNDEFINED;
2200876763c9SMasatake YAMATO 			continue;
2201876763c9SMasatake YAMATO 		}
2202876763c9SMasatake YAMATO 		else if (isType (token, TOKEN_PERIOD))
2203876763c9SMasatake YAMATO 		{
2204876763c9SMasatake YAMATO 			lastId->type = TOKEN_UNDEFINED;
2205876763c9SMasatake YAMATO 		}
2206876763c9SMasatake YAMATO 		else if (isType (token, TOKEN_IDENTIFIER))
2207876763c9SMasatake YAMATO 		{
2208876763c9SMasatake YAMATO 			if (columnAcceptable)
2209876763c9SMasatake YAMATO 				copyToken (lastId, token);
2210876763c9SMasatake YAMATO 		}
2211876763c9SMasatake YAMATO 		else
2212876763c9SMasatake YAMATO 		{
2213876763c9SMasatake YAMATO 			columnAcceptable = false;
2214876763c9SMasatake YAMATO 			lastId->type = TOKEN_UNDEFINED;
2215876763c9SMasatake YAMATO 		}
2216876763c9SMasatake YAMATO 
2217876763c9SMasatake YAMATO 		readToken (token);
2218876763c9SMasatake YAMATO 	} while (! isType (token, TOKEN_EOF));
2219876763c9SMasatake YAMATO 
2220876763c9SMasatake YAMATO 	deleteToken (lastId);
2221876763c9SMasatake YAMATO }
2222876763c9SMasatake YAMATO 
2223dd3d1aaeSMasatake YAMATO /* Skip "IF NOT EXISTS"
2224dd3d1aaeSMasatake YAMATO  * https://dev.mysql.com/doc/refman/8.0/en/create-table.html
2225dd3d1aaeSMasatake YAMATO  * https://www.postgresql.org/docs/current/sql-createtable.html
2226dd3d1aaeSMasatake YAMATO  * https://sqlite.org/lang_createtable.html
2227dd3d1aaeSMasatake YAMATO  */
parseIdAfterIfNotExists(tokenInfo * const name,tokenInfo * const token,bool authorization_following)2228dd3d1aaeSMasatake YAMATO static bool parseIdAfterIfNotExists(tokenInfo *const name,
2229dd3d1aaeSMasatake YAMATO 									tokenInfo *const token,
2230dd3d1aaeSMasatake YAMATO 									bool authorization_following)
2231dd3d1aaeSMasatake YAMATO {
2232dd3d1aaeSMasatake YAMATO 	if (isKeyword (name, KEYWORD_if)
2233dd3d1aaeSMasatake YAMATO 		&& (isType (token, TOKEN_IDENTIFIER)
2234dd3d1aaeSMasatake YAMATO 			&& vStringLength (token->string) == 3
2235dd3d1aaeSMasatake YAMATO 			&& strcasecmp ("not", vStringValue (token->string)) == 0))
2236dd3d1aaeSMasatake YAMATO 	{
2237dd3d1aaeSMasatake YAMATO 		readToken (token);
2238dd3d1aaeSMasatake YAMATO 		if (isType (token, TOKEN_IDENTIFIER)
2239dd3d1aaeSMasatake YAMATO 			&& vStringLength (token->string) == 6
2240dd3d1aaeSMasatake YAMATO 			&& strcasecmp ("exists", vStringValue (token->string)) == 0)
2241dd3d1aaeSMasatake YAMATO 		{
2242dd3d1aaeSMasatake YAMATO 			readIdentifier (name);
2243dd3d1aaeSMasatake YAMATO 			if (authorization_following
2244dd3d1aaeSMasatake YAMATO 				&& isType (name, TOKEN_IDENTIFIER)
2245dd3d1aaeSMasatake YAMATO 				&& vStringLength (name->string) == 13
2246dd3d1aaeSMasatake YAMATO 				&& strcasecmp("authorization", vStringValue(name->string)) == 0)
2247dd3d1aaeSMasatake YAMATO 			{
2248dd3d1aaeSMasatake YAMATO 				/*
2249dd3d1aaeSMasatake YAMATO 				 * PostgreSQL:
2250dd3d1aaeSMasatake YAMATO 				 * - CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification
2251dd3d1aaeSMasatake YAMATO 				 */
2252dd3d1aaeSMasatake YAMATO 				readIdentifier (name);
2253dd3d1aaeSMasatake YAMATO 			}
2254dd3d1aaeSMasatake YAMATO 			readToken (token);
2255dd3d1aaeSMasatake YAMATO 			return true;
2256dd3d1aaeSMasatake YAMATO 		}
2257dd3d1aaeSMasatake YAMATO 	}
2258dd3d1aaeSMasatake YAMATO 	return false;
2259dd3d1aaeSMasatake YAMATO }
2260dd3d1aaeSMasatake YAMATO 
parseTable(tokenInfo * const token)22613ae02089SMasatake YAMATO static void parseTable (tokenInfo *const token)
22623ae02089SMasatake YAMATO {
22633ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
22646e74a9bbSMasatake YAMATO 	bool emitted = false;
22653ae02089SMasatake YAMATO 
22663ae02089SMasatake YAMATO 	/*
22673ae02089SMasatake YAMATO 	 * This deals with these formats:
22683ae02089SMasatake YAMATO 	 *	   create table t1 (c1 int);
22699f084dcaSK.Takata 	 *	   create global temporary table t2 (c1 int);
22703ae02089SMasatake YAMATO 	 *	   create table "t3" (c1 int);
22713ae02089SMasatake YAMATO 	 *	   create table bob.t4 (c1 int);
22723ae02089SMasatake YAMATO 	 *	   create table bob."t5" (c1 int);
22733ae02089SMasatake YAMATO 	 *	   create table "bob"."t6" (c1 int);
22743ae02089SMasatake YAMATO 	 *	   create table bob."t7" (c1 int);
22753ae02089SMasatake YAMATO 	 * Proxy tables use this format:
22763ae02089SMasatake YAMATO 	 *	   create existing table bob."t7" AT '...';
22773ae02089SMasatake YAMATO 	 * SQL Server and Sybase formats
22783ae02089SMasatake YAMATO      *     create table OnlyTable (
22793ae02089SMasatake YAMATO      *     create table dbo.HasOwner (
22803ae02089SMasatake YAMATO      *     create table [dbo].[HasOwnerSquare] (
22813ae02089SMasatake YAMATO      *     create table master.dbo.HasDb (
22823ae02089SMasatake YAMATO      *     create table master..HasDbNoOwner (
22833ae02089SMasatake YAMATO      *     create table [master].dbo.[HasDbAndOwnerSquare] (
22843ae02089SMasatake YAMATO      *     create table [master]..[HasDbNoOwnerSquare] (
2285146d04f4SMasatake YAMATO 	 * Oracle and PostgreSQL use this format:
2286146d04f4SMasatake YAMATO 	 *     create table FOO as select...
22876e74a9bbSMasatake YAMATO 	 * MySQL allows omitting "as" like:
22886e74a9bbSMasatake YAMATO 	 *     create table FOO select...
22896e74a9bbSMasatake YAMATO 	 *     create table FOO (...) select...
229057e7caedSMasatake YAMATO 	 * (At least) MYSQL, PostgreSQL, and SQLite takes "IF NOT EXISTS"
229157e7caedSMasatake YAMATO 	 * between "table" and a table name:
229257e7caedSMasatake YAMATO 	 *     create table if not exists foo ...
22933ae02089SMasatake YAMATO 	 */
22943ae02089SMasatake YAMATO 
22953ae02089SMasatake YAMATO 	/* This could be a database, owner or table name */
22963ae02089SMasatake YAMATO 	readIdentifier (name);
22973ae02089SMasatake YAMATO 	readToken (token);
229857e7caedSMasatake YAMATO 
2299dd3d1aaeSMasatake YAMATO 	parseIdAfterIfNotExists(name, token, false);
230057e7caedSMasatake YAMATO 
23013ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
23023ae02089SMasatake YAMATO 	{
23033ae02089SMasatake YAMATO 		/*
23043ae02089SMasatake YAMATO 		 * This could be a owner or table name.
23053ae02089SMasatake YAMATO 		 * But this is also a special case since the table can be
23063ae02089SMasatake YAMATO 		 * referenced with a blank owner:
23073ae02089SMasatake YAMATO 		 *     dbname..tablename
23083ae02089SMasatake YAMATO 		 */
23093ae02089SMasatake YAMATO 		readIdentifier (name);
23103ae02089SMasatake YAMATO 		/* Check if a blank name was provided */
23113ae02089SMasatake YAMATO 		if (isType (name, TOKEN_PERIOD))
23123ae02089SMasatake YAMATO 		{
23133ae02089SMasatake YAMATO 			readIdentifier (name);
23143ae02089SMasatake YAMATO 		}
23153ae02089SMasatake YAMATO 		readToken (token);
23163ae02089SMasatake YAMATO 		if (isType (token, TOKEN_PERIOD))
23173ae02089SMasatake YAMATO 		{
23183ae02089SMasatake YAMATO 			/* This can only be the table name */
23193ae02089SMasatake YAMATO 			readIdentifier (name);
23203ae02089SMasatake YAMATO 			readToken (token);
23213ae02089SMasatake YAMATO 		}
23223ae02089SMasatake YAMATO 	}
23233ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
23243ae02089SMasatake YAMATO 	{
23253ae02089SMasatake YAMATO 		if (isType (name, TOKEN_IDENTIFIER) ||
2326451789beSMasatake YAMATO 			isType (name, TOKEN_STRING) ||
2327451789beSMasatake YAMATO 			(isType (name, TOKEN_KEYWORD)
2328451789beSMasatake YAMATO 			 && (!isReservedWord (name))))
23293ae02089SMasatake YAMATO 		{
23303ae02089SMasatake YAMATO 			makeSqlTag (name, SQLTAG_TABLE);
23316e74a9bbSMasatake YAMATO 			emitted = true;
23326e74a9bbSMasatake YAMATO 
23333ae02089SMasatake YAMATO 			vStringCopy(token->scope, name->string);
23343ae02089SMasatake YAMATO 			token->scopeKind = SQLTAG_TABLE;
23353ae02089SMasatake YAMATO 			parseRecord (token);
23363ae02089SMasatake YAMATO 			vStringClear (token->scope);
23373ae02089SMasatake YAMATO 			token->scopeKind = SQLTAG_COUNT;
23386e74a9bbSMasatake YAMATO 			readToken (token);
23393ae02089SMasatake YAMATO 		}
23406e74a9bbSMasatake YAMATO 		else
23416e74a9bbSMasatake YAMATO 			skipToMatched(token);
23423ae02089SMasatake YAMATO 	}
23433ae02089SMasatake YAMATO 	else if (isKeyword (token, KEYWORD_at))
23443ae02089SMasatake YAMATO 	{
23453ae02089SMasatake YAMATO 		if (isType (name, TOKEN_IDENTIFIER))
23463ae02089SMasatake YAMATO 		{
23473ae02089SMasatake YAMATO 			makeSqlTag (name, SQLTAG_TABLE);
23483ae02089SMasatake YAMATO 		}
23493ae02089SMasatake YAMATO 	}
23506e74a9bbSMasatake YAMATO 
23516e74a9bbSMasatake YAMATO 	if (isKeyword (token, KEYWORD_select)
2352146d04f4SMasatake YAMATO 			 /* KEYWORD_is is for recognizing "as" */
23536e74a9bbSMasatake YAMATO 			 || isKeyword (token, KEYWORD_is))
23546e74a9bbSMasatake YAMATO 	{
2355146d04f4SMasatake YAMATO 		if (isType (name, TOKEN_IDENTIFIER))
2356146d04f4SMasatake YAMATO 		{
23576e74a9bbSMasatake YAMATO 			if (!emitted)
2358146d04f4SMasatake YAMATO 				makeSqlTag (name, SQLTAG_TABLE);
23596e74a9bbSMasatake YAMATO 
23606e74a9bbSMasatake YAMATO 			if (isKeyword (token, KEYWORD_is))
2361876763c9SMasatake YAMATO 				readToken (token);
23626e74a9bbSMasatake YAMATO 
2363876763c9SMasatake YAMATO 			if (isKeyword (token, KEYWORD_select))
2364876763c9SMasatake YAMATO 			{
2365876763c9SMasatake YAMATO 				addToScope (token, name->string, SQLTAG_TABLE);
2366876763c9SMasatake YAMATO 				parseColumnsAndAliases (token);
2367876763c9SMasatake YAMATO 				vStringClear (token->scope);
2368146d04f4SMasatake YAMATO 			}
2369146d04f4SMasatake YAMATO 		}
2370876763c9SMasatake YAMATO 	}
2371876763c9SMasatake YAMATO 	findCmdTerm (token, true);
23723ae02089SMasatake YAMATO 	deleteToken (name);
23733ae02089SMasatake YAMATO }
23743ae02089SMasatake YAMATO 
parseIndex(tokenInfo * const token)23753ae02089SMasatake YAMATO static void parseIndex (tokenInfo *const token)
23763ae02089SMasatake YAMATO {
23773ae02089SMasatake YAMATO 	tokenInfo *const name  = newToken ();
23783ae02089SMasatake YAMATO 	tokenInfo *const owner = newToken ();
23793ae02089SMasatake YAMATO 
23803ae02089SMasatake YAMATO 	/*
23813ae02089SMasatake YAMATO 	 * This deals with these formats
23823ae02089SMasatake YAMATO 	 *	   create index i1 on t1(c1) create index "i2" on t1(c1)
23833ae02089SMasatake YAMATO 	 *	   create virtual unique clustered index "i3" on t1(c1)
23843ae02089SMasatake YAMATO 	 *	   create unique clustered index "i4" on t1(c1)
23853ae02089SMasatake YAMATO 	 *	   create clustered index "i5" on t1(c1)
23863ae02089SMasatake YAMATO 	 *	   create bitmap index "i6" on t1(c1)
23873ae02089SMasatake YAMATO 	 */
23883ae02089SMasatake YAMATO 
23893ae02089SMasatake YAMATO 	readIdentifier (name);
23903ae02089SMasatake YAMATO 	readToken (token);
23913ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
23923ae02089SMasatake YAMATO 	{
23933ae02089SMasatake YAMATO 		readIdentifier (name);
23943ae02089SMasatake YAMATO 		readToken (token);
23953ae02089SMasatake YAMATO 	}
23963ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_on) &&
23973ae02089SMasatake YAMATO 		(isType (name, TOKEN_IDENTIFIER) ||
23983ae02089SMasatake YAMATO 		 isType (name, TOKEN_STRING)))
23993ae02089SMasatake YAMATO 	{
24003ae02089SMasatake YAMATO 		readIdentifier (owner);
24013ae02089SMasatake YAMATO 		readToken (token);
24023ae02089SMasatake YAMATO 		if (isType (token, TOKEN_PERIOD))
24033ae02089SMasatake YAMATO 		{
24043ae02089SMasatake YAMATO 			readIdentifier (owner);
24053ae02089SMasatake YAMATO 			readToken (token);
24063ae02089SMasatake YAMATO 		}
24073ae02089SMasatake YAMATO 		addToScope(name, owner->string, SQLTAG_TABLE /* FIXME? */);
24083ae02089SMasatake YAMATO 		makeSqlTag (name, SQLTAG_INDEX);
24093ae02089SMasatake YAMATO 	}
2410ce990805SThomas Braun 	findCmdTerm (token, false);
24113ae02089SMasatake YAMATO 	deleteToken (name);
24123ae02089SMasatake YAMATO 	deleteToken (owner);
24133ae02089SMasatake YAMATO }
24143ae02089SMasatake YAMATO 
parseEvent(tokenInfo * const token)24153ae02089SMasatake YAMATO static void parseEvent (tokenInfo *const token)
24163ae02089SMasatake YAMATO {
24173ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
24183ae02089SMasatake YAMATO 
24193ae02089SMasatake YAMATO 	/*
24203ae02089SMasatake YAMATO 	 * This deals with these formats
24213ae02089SMasatake YAMATO 	 *	   create event e1 handler begin end;
24223ae02089SMasatake YAMATO 	 *	   create event "e2" handler begin end;
24233ae02089SMasatake YAMATO 	 *	   create event dba."e3" handler begin end;
24243ae02089SMasatake YAMATO 	 *	   create event "dba"."e4" handler begin end;
24253ae02089SMasatake YAMATO 	 */
24263ae02089SMasatake YAMATO 
24273ae02089SMasatake YAMATO 	readIdentifier (name);
24283ae02089SMasatake YAMATO 	readToken (token);
24293ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
24303ae02089SMasatake YAMATO 	{
24313ae02089SMasatake YAMATO 		readIdentifier (name);
24323ae02089SMasatake YAMATO 	}
24333ae02089SMasatake YAMATO 	while (! isKeyword (token, KEYWORD_handler) &&
24343ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_SEMICOLON) &&
24353ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF))
24363ae02089SMasatake YAMATO 	{
24373ae02089SMasatake YAMATO 		readToken (token);
24383ae02089SMasatake YAMATO 	}
24393ae02089SMasatake YAMATO 
2440053eedf5SMasatake YAMATO 	if ((isKeyword (token, KEYWORD_handler) ||
24413ae02089SMasatake YAMATO 		 isType (token, TOKEN_SEMICOLON))
2442053eedf5SMasatake YAMATO 		&& (isType (name, TOKEN_IDENTIFIER) ||
2443053eedf5SMasatake YAMATO 			isType (name, TOKEN_STRING)     ||
2444053eedf5SMasatake YAMATO 			(isType (name, TOKEN_KEYWORD)
2445053eedf5SMasatake YAMATO 			 && (!isReservedWord (name)))))
24463ae02089SMasatake YAMATO 	{
24473ae02089SMasatake YAMATO 		makeSqlTag (name, SQLTAG_EVENT);
24483ae02089SMasatake YAMATO 	}
24493ae02089SMasatake YAMATO 
24503ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_handler))
24513ae02089SMasatake YAMATO 	{
24523ae02089SMasatake YAMATO 		readToken (token);
24533ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_begin))
24543ae02089SMasatake YAMATO 		{
2455ce990805SThomas Braun 			parseBlock (token, true);
24563ae02089SMasatake YAMATO 		}
2457ce990805SThomas Braun 		findCmdTerm (token, true);
24583ae02089SMasatake YAMATO 	}
24593ae02089SMasatake YAMATO 	deleteToken (name);
24603ae02089SMasatake YAMATO }
24613ae02089SMasatake YAMATO 
parseTrigger(tokenInfo * const token)24623ae02089SMasatake YAMATO static void parseTrigger (tokenInfo *const token)
24633ae02089SMasatake YAMATO {
24643ae02089SMasatake YAMATO 	tokenInfo *const name  = newToken ();
24653ae02089SMasatake YAMATO 	tokenInfo *const table = newToken ();
24663ae02089SMasatake YAMATO 
24673ae02089SMasatake YAMATO 	/*
24683ae02089SMasatake YAMATO 	 * This deals with these formats
24693ae02089SMasatake YAMATO 	 *	   create or replace trigger tr1 begin end;
24703ae02089SMasatake YAMATO 	 *	   create trigger "tr2" begin end;
24713ae02089SMasatake YAMATO 	 *	   drop trigger "droptr1";
24723ae02089SMasatake YAMATO 	 *	   create trigger "tr3" CALL sp_something();
24733ae02089SMasatake YAMATO 	 *	   create trigger "owner"."tr4" begin end;
24743ae02089SMasatake YAMATO 	 *	   create trigger "tr5" not valid;
24753ae02089SMasatake YAMATO 	 *	   create trigger "tr6" begin end;
24763ae02089SMasatake YAMATO 	 */
24773ae02089SMasatake YAMATO 
24783ae02089SMasatake YAMATO 	readIdentifier (name);
24793ae02089SMasatake YAMATO 	readToken (token);
24803ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
24813ae02089SMasatake YAMATO 	{
24823ae02089SMasatake YAMATO 		readIdentifier (name);
24833ae02089SMasatake YAMATO 		readToken (token);
24843ae02089SMasatake YAMATO 	}
24853ae02089SMasatake YAMATO 
24863ae02089SMasatake YAMATO 	while (! isKeyword (token, KEYWORD_on) &&
24873ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF) &&
24883ae02089SMasatake YAMATO 		   ! isCmdTerm (token))
24893ae02089SMasatake YAMATO 	{
24903ae02089SMasatake YAMATO 		readToken (token);
24913ae02089SMasatake YAMATO 	}
24923ae02089SMasatake YAMATO 
24933ae02089SMasatake YAMATO 	/*if (! isType (token, TOKEN_SEMICOLON) ) */
24943ae02089SMasatake YAMATO 	if (! isCmdTerm (token))
24953ae02089SMasatake YAMATO 	{
24963ae02089SMasatake YAMATO 		readToken (table);
24973ae02089SMasatake YAMATO 		readToken (token);
24983ae02089SMasatake YAMATO 		if (isType (token, TOKEN_PERIOD))
24993ae02089SMasatake YAMATO 		{
25003ae02089SMasatake YAMATO 			readToken (table);
25013ae02089SMasatake YAMATO 			readToken (token);
25023ae02089SMasatake YAMATO 		}
25033ae02089SMasatake YAMATO 
25043ae02089SMasatake YAMATO 		while (! isKeyword (token, KEYWORD_begin) &&
25053ae02089SMasatake YAMATO 			   ! isKeyword (token, KEYWORD_call) &&
25063ae02089SMasatake YAMATO 			   ! isCmdTerm (token) &&
25073ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF))
25083ae02089SMasatake YAMATO 		{
25093ae02089SMasatake YAMATO 			if (isKeyword (token, KEYWORD_declare))
25103ae02089SMasatake YAMATO 			{
25113ae02089SMasatake YAMATO 				addToScope(token, name->string, SQLTAG_TRIGGER);
2512ce990805SThomas Braun 				parseDeclare(token, true);
25133ae02089SMasatake YAMATO 				vStringClear(token->scope);
25143ae02089SMasatake YAMATO 				token->scopeKind = SQLTAG_COUNT;
25153ae02089SMasatake YAMATO 			}
25163ae02089SMasatake YAMATO 			else
25173ae02089SMasatake YAMATO 				readToken (token);
25183ae02089SMasatake YAMATO 		}
25193ae02089SMasatake YAMATO 
25203ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_begin) ||
25213ae02089SMasatake YAMATO 			isKeyword (token, KEYWORD_call))
25223ae02089SMasatake YAMATO 		{
25233ae02089SMasatake YAMATO 			addToScope(name, table->string, SQLTAG_TABLE);
25243ae02089SMasatake YAMATO 			makeSqlTag (name, SQLTAG_TRIGGER);
25253ae02089SMasatake YAMATO 			addToScope(token, table->string, SQLTAG_TABLE);
25263ae02089SMasatake YAMATO 			if (isKeyword (token, KEYWORD_begin))
25273ae02089SMasatake YAMATO 			{
2528ce990805SThomas Braun 				parseBlock (token, true);
25293ae02089SMasatake YAMATO 			}
25303ae02089SMasatake YAMATO 			vStringClear(token->scope);
25313ae02089SMasatake YAMATO 			token->scopeKind = SQLTAG_COUNT;
25323ae02089SMasatake YAMATO 		}
25333ae02089SMasatake YAMATO 	}
25343ae02089SMasatake YAMATO 
2535ce990805SThomas Braun 	findCmdTerm (token, true);
25363ae02089SMasatake YAMATO 	deleteToken (name);
25373ae02089SMasatake YAMATO 	deleteToken (table);
25383ae02089SMasatake YAMATO }
25393ae02089SMasatake YAMATO 
parsePublication(tokenInfo * const token)25403ae02089SMasatake YAMATO static void parsePublication (tokenInfo *const token)
25413ae02089SMasatake YAMATO {
25423ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
25433ae02089SMasatake YAMATO 
25443ae02089SMasatake YAMATO 	/*
25453ae02089SMasatake YAMATO 	 * This deals with these formats
25463ae02089SMasatake YAMATO 	 *	   create or replace publication pu1 ()
25473ae02089SMasatake YAMATO 	 *	   create publication "pu2" ()
25483ae02089SMasatake YAMATO 	 *	   create publication dba."pu3" ()
25493ae02089SMasatake YAMATO 	 *	   create publication "dba"."pu4" ()
25503ae02089SMasatake YAMATO 	 */
25513ae02089SMasatake YAMATO 
25523ae02089SMasatake YAMATO 	readIdentifier (name);
25533ae02089SMasatake YAMATO 	readToken (token);
25543ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
25553ae02089SMasatake YAMATO 	{
25563ae02089SMasatake YAMATO 		readIdentifier (name);
25573ae02089SMasatake YAMATO 		readToken (token);
25583ae02089SMasatake YAMATO 	}
25593ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
25603ae02089SMasatake YAMATO 	{
25613ae02089SMasatake YAMATO 		if (isType (name, TOKEN_IDENTIFIER) ||
25623ae02089SMasatake YAMATO 			isType (name, TOKEN_STRING))
25633ae02089SMasatake YAMATO 		{
25643ae02089SMasatake YAMATO 			makeSqlTag (name, SQLTAG_PUBLICATION);
25653ae02089SMasatake YAMATO 		}
25663ae02089SMasatake YAMATO 	}
2567ce990805SThomas Braun 	findCmdTerm (token, false);
25683ae02089SMasatake YAMATO 	deleteToken (name);
25693ae02089SMasatake YAMATO }
parseService(tokenInfo * const token)25703ae02089SMasatake YAMATO static void parseService (tokenInfo *const token)
25713ae02089SMasatake YAMATO {
25723ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
25733ae02089SMasatake YAMATO 
25743ae02089SMasatake YAMATO 	/*
25753ae02089SMasatake YAMATO 	 * This deals with these formats
25763ae02089SMasatake YAMATO 	 *	   CREATE SERVICE s1 TYPE 'HTML'
25773ae02089SMasatake YAMATO 	 *		   AUTHORIZATION OFF USER DBA AS
25783ae02089SMasatake YAMATO 	 *		   SELECT *
25793ae02089SMasatake YAMATO 	 *			 FROM SYS.SYSTABLE;
25803ae02089SMasatake YAMATO 	 *	   CREATE SERVICE "s2" TYPE 'HTML'
25813ae02089SMasatake YAMATO 	 *		   AUTHORIZATION OFF USER DBA AS
25823ae02089SMasatake YAMATO 	 *		   CALL sp_Something();
25833ae02089SMasatake YAMATO 	 */
25843ae02089SMasatake YAMATO 
25853ae02089SMasatake YAMATO 	readIdentifier (name);
25863ae02089SMasatake YAMATO 	readToken (token);
25873ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_type))
25883ae02089SMasatake YAMATO 	{
25893ae02089SMasatake YAMATO 		if (isType (name, TOKEN_IDENTIFIER) ||
25903ae02089SMasatake YAMATO 			isType (name, TOKEN_STRING))
25913ae02089SMasatake YAMATO 		{
25923ae02089SMasatake YAMATO 			makeSqlTag (name, SQLTAG_SERVICE);
25933ae02089SMasatake YAMATO 		}
25943ae02089SMasatake YAMATO 	}
2595ce990805SThomas Braun 	findCmdTerm (token, false);
25963ae02089SMasatake YAMATO 	deleteToken (name);
25973ae02089SMasatake YAMATO }
25983ae02089SMasatake YAMATO 
parseDomain(tokenInfo * const token)25993ae02089SMasatake YAMATO static void parseDomain (tokenInfo *const token)
26003ae02089SMasatake YAMATO {
26013ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
26023ae02089SMasatake YAMATO 
26033ae02089SMasatake YAMATO 	/*
26043ae02089SMasatake YAMATO 	 * This deals with these formats
26053ae02089SMasatake YAMATO 	 *	   CREATE DOMAIN|DATATYPE [AS] your_name ...;
26063ae02089SMasatake YAMATO 	 */
26073ae02089SMasatake YAMATO 
26083ae02089SMasatake YAMATO 	readIdentifier (name);
26093ae02089SMasatake YAMATO 	if (isKeyword (name, KEYWORD_is))
26103ae02089SMasatake YAMATO 	{
26113ae02089SMasatake YAMATO 		readIdentifier (name);
26123ae02089SMasatake YAMATO 	}
26133ae02089SMasatake YAMATO 	readToken (token);
26143ae02089SMasatake YAMATO 	if (isType (name, TOKEN_IDENTIFIER) ||
26153ae02089SMasatake YAMATO 		isType (name, TOKEN_STRING))
26163ae02089SMasatake YAMATO 	{
26173ae02089SMasatake YAMATO 		makeSqlTag (name, SQLTAG_DOMAIN);
26183ae02089SMasatake YAMATO 	}
2619ce990805SThomas Braun 	findCmdTerm (token, false);
26203ae02089SMasatake YAMATO 	deleteToken (name);
26213ae02089SMasatake YAMATO }
26223ae02089SMasatake YAMATO 
parseDrop(tokenInfo * const token)26233ae02089SMasatake YAMATO static void parseDrop (tokenInfo *const token)
26243ae02089SMasatake YAMATO {
26253ae02089SMasatake YAMATO 	/*
26263ae02089SMasatake YAMATO 	 * This deals with these formats
26273ae02089SMasatake YAMATO 	 *	   DROP TABLE|PROCEDURE|DOMAIN|DATATYPE name;
26283ae02089SMasatake YAMATO 	 *
26293ae02089SMasatake YAMATO 	 * Just simply skip over these statements.
26303ae02089SMasatake YAMATO 	 * They are often confused with PROCEDURE prototypes
26313ae02089SMasatake YAMATO 	 * since the syntax is similar, this effectively deals with
26323ae02089SMasatake YAMATO 	 * the issue for all types.
26333ae02089SMasatake YAMATO 	 */
26343ae02089SMasatake YAMATO 
2635ce990805SThomas Braun 	findCmdTerm (token, false);
26363ae02089SMasatake YAMATO }
26373ae02089SMasatake YAMATO 
parseVariable(tokenInfo * const token)26383ae02089SMasatake YAMATO static void parseVariable (tokenInfo *const token)
26393ae02089SMasatake YAMATO {
26403ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
26413ae02089SMasatake YAMATO 
26423ae02089SMasatake YAMATO 	/*
26433ae02089SMasatake YAMATO 	 * This deals with these formats
26443ae02089SMasatake YAMATO 	 *	   create variable varname1 integer;
26453ae02089SMasatake YAMATO 	 *	   create variable @varname2 integer;
26463ae02089SMasatake YAMATO 	 *	   create variable "varname3" integer;
26473ae02089SMasatake YAMATO 	 *	   drop   variable @varname3;
26483ae02089SMasatake YAMATO 	 */
26493ae02089SMasatake YAMATO 
26503ae02089SMasatake YAMATO 	readIdentifier (name);
26513ae02089SMasatake YAMATO 	readToken (token);
26523ae02089SMasatake YAMATO 	if (! isType (token, TOKEN_SEMICOLON) &&
26533ae02089SMasatake YAMATO 		(isType (name, TOKEN_IDENTIFIER) ||
26543ae02089SMasatake YAMATO 		 isType (name, TOKEN_STRING)))
26553ae02089SMasatake YAMATO 	{
26563ae02089SMasatake YAMATO 		makeSqlTag (name, SQLTAG_VARIABLE);
26573ae02089SMasatake YAMATO 	}
2658ce990805SThomas Braun 	findCmdTerm (token, true);
26593ae02089SMasatake YAMATO 
26603ae02089SMasatake YAMATO 	deleteToken (name);
26613ae02089SMasatake YAMATO }
26623ae02089SMasatake YAMATO 
parseSynonym(tokenInfo * const token)26633ae02089SMasatake YAMATO static void parseSynonym (tokenInfo *const token)
26643ae02089SMasatake YAMATO {
26653ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
26663ae02089SMasatake YAMATO 
26673ae02089SMasatake YAMATO 	/*
26683ae02089SMasatake YAMATO 	 * This deals with these formats
26693ae02089SMasatake YAMATO 	 *	   create variable varname1 integer;
26703ae02089SMasatake YAMATO 	 *	   create variable @varname2 integer;
26713ae02089SMasatake YAMATO 	 *	   create variable "varname3" integer;
26723ae02089SMasatake YAMATO 	 *	   drop   variable @varname3;
26733ae02089SMasatake YAMATO 	 */
26743ae02089SMasatake YAMATO 
26753ae02089SMasatake YAMATO 	readIdentifier (name);
26763ae02089SMasatake YAMATO 	readToken (token);
26773ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_for) &&
26783ae02089SMasatake YAMATO 		(isType (name, TOKEN_IDENTIFIER) ||
26793ae02089SMasatake YAMATO 		 isType (name, TOKEN_STRING)))
26803ae02089SMasatake YAMATO 	{
26813ae02089SMasatake YAMATO 		makeSqlTag (name, SQLTAG_SYNONYM);
26823ae02089SMasatake YAMATO 	}
2683ce990805SThomas Braun 	findCmdTerm (token, true);
26843ae02089SMasatake YAMATO 
26853ae02089SMasatake YAMATO 	deleteToken (name);
26863ae02089SMasatake YAMATO }
26873ae02089SMasatake YAMATO 
parseView(tokenInfo * const token)26883ae02089SMasatake YAMATO static void parseView (tokenInfo *const token)
26893ae02089SMasatake YAMATO {
26903ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
26913ae02089SMasatake YAMATO 
26923ae02089SMasatake YAMATO 	/*
26933ae02089SMasatake YAMATO 	 * This deals with these formats
26949742d29eSMasatake YAMATO 	 *     create view VIEW;
26959742d29eSMasatake YAMATO 	 *     create view VIEW as ...;
26969742d29eSMasatake YAMATO 	 *     create view VIEW (...) as ...;
26973ae02089SMasatake YAMATO 	 */
26983ae02089SMasatake YAMATO 
26993ae02089SMasatake YAMATO 	readIdentifier (name);
27003ae02089SMasatake YAMATO 	readToken (token);
27013ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
27023ae02089SMasatake YAMATO 	{
27033ae02089SMasatake YAMATO 		readIdentifier (name);
27043ae02089SMasatake YAMATO 		readToken (token);
27053ae02089SMasatake YAMATO 	}
27063ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
27073ae02089SMasatake YAMATO 	{
27083ae02089SMasatake YAMATO 		skipArgumentList(token);
27093ae02089SMasatake YAMATO 	}
27103ae02089SMasatake YAMATO 
27113ae02089SMasatake YAMATO 	while (! isKeyword (token, KEYWORD_is) &&
27123ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_SEMICOLON) &&
27133ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF))
27143ae02089SMasatake YAMATO 	{
27153ae02089SMasatake YAMATO 		readToken (token);
27163ae02089SMasatake YAMATO 	}
27173ae02089SMasatake YAMATO 
27183ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_is) &&
27193ae02089SMasatake YAMATO 		(isType (name, TOKEN_IDENTIFIER) ||
27203ae02089SMasatake YAMATO 		 isType (name, TOKEN_STRING)))
27213ae02089SMasatake YAMATO 	{
27223ae02089SMasatake YAMATO 		makeSqlTag (name, SQLTAG_VIEW);
27233ae02089SMasatake YAMATO 	}
27243ae02089SMasatake YAMATO 
2725ce990805SThomas Braun 	findCmdTerm (token, true);
27263ae02089SMasatake YAMATO 
27273ae02089SMasatake YAMATO 	deleteToken (name);
27283ae02089SMasatake YAMATO }
27293ae02089SMasatake YAMATO 
parseMLTable(tokenInfo * const token)27303ae02089SMasatake YAMATO static void parseMLTable (tokenInfo *const token)
27313ae02089SMasatake YAMATO {
27323ae02089SMasatake YAMATO 	tokenInfo *const version = newToken ();
27333ae02089SMasatake YAMATO 	tokenInfo *const table	 = newToken ();
27343ae02089SMasatake YAMATO 	tokenInfo *const event	 = newToken ();
27353ae02089SMasatake YAMATO 
27363ae02089SMasatake YAMATO 	/*
27373ae02089SMasatake YAMATO 	 * This deals with these formats
27383ae02089SMasatake YAMATO 	 *	  call dbo.ml_add_table_script( 'version', 'table_name', 'event',
27393ae02089SMasatake YAMATO 	 *		   'some SQL statement'
27403ae02089SMasatake YAMATO 	 *		   );
27413ae02089SMasatake YAMATO 	 */
27423ae02089SMasatake YAMATO 
27433ae02089SMasatake YAMATO 	readToken (token);
27443ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
27453ae02089SMasatake YAMATO 	{
27463ae02089SMasatake YAMATO 		readToken (version);
27473ae02089SMasatake YAMATO 		readToken (token);
27483ae02089SMasatake YAMATO 		while (! isType (token, TOKEN_COMMA) &&
27493ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_CLOSE_PAREN) &&
27503ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF))
27513ae02089SMasatake YAMATO 		{
27523ae02089SMasatake YAMATO 			readToken (token);
27533ae02089SMasatake YAMATO 		}
27543ae02089SMasatake YAMATO 
27553ae02089SMasatake YAMATO 		if (isType (token, TOKEN_COMMA))
27563ae02089SMasatake YAMATO 		{
27573ae02089SMasatake YAMATO 			readToken (table);
27583ae02089SMasatake YAMATO 			readToken (token);
27593ae02089SMasatake YAMATO 			while (! isType (token, TOKEN_COMMA) &&
27603ae02089SMasatake YAMATO 				   ! isType (token, TOKEN_CLOSE_PAREN) &&
27613ae02089SMasatake YAMATO 				   ! isType (token, TOKEN_EOF))
27623ae02089SMasatake YAMATO 			{
27633ae02089SMasatake YAMATO 				readToken (token);
27643ae02089SMasatake YAMATO 			}
27653ae02089SMasatake YAMATO 
27663ae02089SMasatake YAMATO 			if (isType (token, TOKEN_COMMA))
27673ae02089SMasatake YAMATO 			{
27683ae02089SMasatake YAMATO 				readToken (event);
27693ae02089SMasatake YAMATO 
27703ae02089SMasatake YAMATO 				if (isType (version, TOKEN_STRING) &&
27713ae02089SMasatake YAMATO 					isType (table, TOKEN_STRING) &&
27723ae02089SMasatake YAMATO 					isType (event, TOKEN_STRING))
27733ae02089SMasatake YAMATO 				{
27743ae02089SMasatake YAMATO 					addToScope(version, table->string, SQLTAG_TABLE);
27753ae02089SMasatake YAMATO 					addToScope(version, event->string, SQLTAG_EVENT);
27763ae02089SMasatake YAMATO 					makeSqlTag (version, SQLTAG_MLTABLE);
27773ae02089SMasatake YAMATO 				}
27783ae02089SMasatake YAMATO 			}
27793ae02089SMasatake YAMATO 			if (! isType (token, TOKEN_CLOSE_PAREN))
27803ae02089SMasatake YAMATO 				findToken (token, TOKEN_CLOSE_PAREN);
27813ae02089SMasatake YAMATO 		}
27823ae02089SMasatake YAMATO 	}
27833ae02089SMasatake YAMATO 
2784ce990805SThomas Braun 	findCmdTerm (token, true);
27853ae02089SMasatake YAMATO 
27863ae02089SMasatake YAMATO 	deleteToken (version);
27873ae02089SMasatake YAMATO 	deleteToken (table);
27883ae02089SMasatake YAMATO 	deleteToken (event);
27893ae02089SMasatake YAMATO }
27903ae02089SMasatake YAMATO 
parseMLConn(tokenInfo * const token)27913ae02089SMasatake YAMATO static void parseMLConn (tokenInfo *const token)
27923ae02089SMasatake YAMATO {
27933ae02089SMasatake YAMATO 	tokenInfo *const version = newToken ();
27943ae02089SMasatake YAMATO 	tokenInfo *const event	 = newToken ();
27953ae02089SMasatake YAMATO 
27963ae02089SMasatake YAMATO 	/*
27973ae02089SMasatake YAMATO 	 * This deals with these formats
27983ae02089SMasatake YAMATO 	 *	  call ml_add_connection_script( 'version', 'event',
27993ae02089SMasatake YAMATO 	 *		   'some SQL statement'
28003ae02089SMasatake YAMATO 	 *		   );
28013ae02089SMasatake YAMATO 	 */
28023ae02089SMasatake YAMATO 
28033ae02089SMasatake YAMATO 	readToken (token);
28043ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
28053ae02089SMasatake YAMATO 	{
28063ae02089SMasatake YAMATO 		readToken (version);
28073ae02089SMasatake YAMATO 		readToken (token);
28083ae02089SMasatake YAMATO 		while (! isType (token, TOKEN_COMMA) &&
28093ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_CLOSE_PAREN) &&
28103ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF))
28113ae02089SMasatake YAMATO 		{
28123ae02089SMasatake YAMATO 			readToken (token);
28133ae02089SMasatake YAMATO 		}
28143ae02089SMasatake YAMATO 
28153ae02089SMasatake YAMATO 		if (isType (token, TOKEN_COMMA))
28163ae02089SMasatake YAMATO 		{
28173ae02089SMasatake YAMATO 			readToken (event);
28183ae02089SMasatake YAMATO 
28193ae02089SMasatake YAMATO 			if (isType (version, TOKEN_STRING) &&
28203ae02089SMasatake YAMATO 				isType (event, TOKEN_STRING))
28213ae02089SMasatake YAMATO 			{
28223ae02089SMasatake YAMATO 				addToScope(version, event->string, SQLTAG_EVENT);
28233ae02089SMasatake YAMATO 				makeSqlTag (version, SQLTAG_MLCONN);
28243ae02089SMasatake YAMATO 			}
28253ae02089SMasatake YAMATO 		}
28263ae02089SMasatake YAMATO 		if (! isType (token, TOKEN_CLOSE_PAREN))
28273ae02089SMasatake YAMATO 			findToken (token, TOKEN_CLOSE_PAREN);
28283ae02089SMasatake YAMATO 
28293ae02089SMasatake YAMATO 	}
28303ae02089SMasatake YAMATO 
2831ce990805SThomas Braun 	findCmdTerm (token, true);
28323ae02089SMasatake YAMATO 
28333ae02089SMasatake YAMATO 	deleteToken (version);
28343ae02089SMasatake YAMATO 	deleteToken (event);
28353ae02089SMasatake YAMATO }
28363ae02089SMasatake YAMATO 
parseMLProp(tokenInfo * const token)28373ae02089SMasatake YAMATO static void parseMLProp (tokenInfo *const token)
28383ae02089SMasatake YAMATO {
28393ae02089SMasatake YAMATO 	tokenInfo *const component     = newToken ();
28403ae02089SMasatake YAMATO 	tokenInfo *const prop_set_name = newToken ();
28413ae02089SMasatake YAMATO 	tokenInfo *const prop_name     = newToken ();
28423ae02089SMasatake YAMATO 
28433ae02089SMasatake YAMATO 	/*
28443ae02089SMasatake YAMATO 	 * This deals with these formats
28453ae02089SMasatake YAMATO      *   ml_add_property (
28463ae02089SMasatake YAMATO      *       'comp_name',
28473ae02089SMasatake YAMATO      *       'prop_set_name',
28483ae02089SMasatake YAMATO      *       'prop_name',
28493ae02089SMasatake YAMATO      *       'prop_value'
28503ae02089SMasatake YAMATO      *   )
28513ae02089SMasatake YAMATO 	 */
28523ae02089SMasatake YAMATO 
28533ae02089SMasatake YAMATO 	readToken (token);
28543ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
28553ae02089SMasatake YAMATO 	{
28563ae02089SMasatake YAMATO 		readToken (component);
28573ae02089SMasatake YAMATO 		readToken (token);
28583ae02089SMasatake YAMATO 		while (! isType (token, TOKEN_COMMA) &&
28593ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_CLOSE_PAREN) &&
28603ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF))
28613ae02089SMasatake YAMATO 		{
28623ae02089SMasatake YAMATO 			readToken (token);
28633ae02089SMasatake YAMATO 		}
28643ae02089SMasatake YAMATO 
28653ae02089SMasatake YAMATO 		if (isType (token, TOKEN_COMMA))
28663ae02089SMasatake YAMATO 		{
28673ae02089SMasatake YAMATO 			readToken (prop_set_name);
28683ae02089SMasatake YAMATO 			readToken (token);
28693ae02089SMasatake YAMATO 			while (! isType (token, TOKEN_COMMA) &&
28703ae02089SMasatake YAMATO 				   ! isType (token, TOKEN_CLOSE_PAREN) &&
28713ae02089SMasatake YAMATO 				   ! isType (token, TOKEN_EOF))
28723ae02089SMasatake YAMATO 			{
28733ae02089SMasatake YAMATO 				readToken (token);
28743ae02089SMasatake YAMATO 			}
28753ae02089SMasatake YAMATO 
28763ae02089SMasatake YAMATO 			if (isType (token, TOKEN_COMMA))
28773ae02089SMasatake YAMATO 			{
28783ae02089SMasatake YAMATO 				readToken (prop_name);
28793ae02089SMasatake YAMATO 
28803ae02089SMasatake YAMATO 				if (isType (component, TOKEN_STRING) &&
28813ae02089SMasatake YAMATO 					isType (prop_set_name, TOKEN_STRING) &&
28823ae02089SMasatake YAMATO 					isType (prop_name, TOKEN_STRING))
28833ae02089SMasatake YAMATO 				{
28843ae02089SMasatake YAMATO 					addToScope(component, prop_set_name->string, SQLTAG_MLPROP /* FIXME */);
28853ae02089SMasatake YAMATO 					addToScope(component, prop_name->string, SQLTAG_MLPROP /* FIXME */);
28863ae02089SMasatake YAMATO 					makeSqlTag (component, SQLTAG_MLPROP);
28873ae02089SMasatake YAMATO 				}
28883ae02089SMasatake YAMATO 			}
28893ae02089SMasatake YAMATO 			if (! isType (token, TOKEN_CLOSE_PAREN))
28903ae02089SMasatake YAMATO 				findToken (token, TOKEN_CLOSE_PAREN);
28913ae02089SMasatake YAMATO 		}
28923ae02089SMasatake YAMATO 	}
28933ae02089SMasatake YAMATO 
2894ce990805SThomas Braun 	findCmdTerm (token, true);
28953ae02089SMasatake YAMATO 
28963ae02089SMasatake YAMATO 	deleteToken (component);
28973ae02089SMasatake YAMATO 	deleteToken (prop_set_name);
28983ae02089SMasatake YAMATO 	deleteToken (prop_name);
28993ae02089SMasatake YAMATO }
29003ae02089SMasatake YAMATO 
parseComment(tokenInfo * const token)29013ae02089SMasatake YAMATO static void parseComment (tokenInfo *const token)
29023ae02089SMasatake YAMATO {
29033ae02089SMasatake YAMATO 	/*
29043ae02089SMasatake YAMATO 	 * This deals with this statement:
29053ae02089SMasatake YAMATO 	 *	   COMMENT TO PRESERVE FORMAT ON PROCEDURE "DBA"."test" IS
29063ae02089SMasatake YAMATO 	 *	   {create PROCEDURE DBA."test"()
29073ae02089SMasatake YAMATO 	 *	   BEGIN
29083ae02089SMasatake YAMATO 	 *		signal dave;
29093ae02089SMasatake YAMATO 	 *	   END
29103ae02089SMasatake YAMATO 	 *	   }
29113ae02089SMasatake YAMATO 	 *	   ;
29123ae02089SMasatake YAMATO 	 * The comment can contain anything between the CURLY
29133ae02089SMasatake YAMATO 	 * braces
29143ae02089SMasatake YAMATO 	 *	   COMMENT ON USER "admin" IS
29153ae02089SMasatake YAMATO 	 *			'Administration Group'
29163ae02089SMasatake YAMATO 	 *			;
29173ae02089SMasatake YAMATO 	 * Or it could be a simple string with no curly braces
29183ae02089SMasatake YAMATO 	 */
29193ae02089SMasatake YAMATO 	while (! isKeyword (token, KEYWORD_is) &&
29203ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF))
29213ae02089SMasatake YAMATO 	{
29223ae02089SMasatake YAMATO 		readToken (token);
29233ae02089SMasatake YAMATO 	}
29243ae02089SMasatake YAMATO 	readToken (token);
29253ae02089SMasatake YAMATO 	if (isType(token, TOKEN_OPEN_CURLY))
29263ae02089SMasatake YAMATO 	{
29273ae02089SMasatake YAMATO 		findToken (token, TOKEN_CLOSE_CURLY);
29283ae02089SMasatake YAMATO 	}
29293ae02089SMasatake YAMATO 
2930ce990805SThomas Braun 	findCmdTerm (token, true);
29313ae02089SMasatake YAMATO }
29323ae02089SMasatake YAMATO 
parseCCFLAGS(tokenInfo * const token)293356b419e9SMasatake YAMATO static void parseCCFLAGS (tokenInfo *const token)
293456b419e9SMasatake YAMATO {
293556b419e9SMasatake YAMATO 	readToken(token);
293656b419e9SMasatake YAMATO 	if (!isType (token, TOKEN_EQUAL))
293756b419e9SMasatake YAMATO 	{
293856b419e9SMasatake YAMATO 		findCmdTerm (token, true);
293956b419e9SMasatake YAMATO 		return;
294056b419e9SMasatake YAMATO 	}
294156b419e9SMasatake YAMATO 
294256b419e9SMasatake YAMATO 	readToken(token);
294356b419e9SMasatake YAMATO 	if (!isType (token, TOKEN_STRING))
294456b419e9SMasatake YAMATO 	{
294556b419e9SMasatake YAMATO 		findCmdTerm (token, true);
294656b419e9SMasatake YAMATO 		return;
294756b419e9SMasatake YAMATO 	}
294856b419e9SMasatake YAMATO 
294956b419e9SMasatake YAMATO 	bool in_var = true;
295056b419e9SMasatake YAMATO 	const char *s = vStringValue(token->string);
295156b419e9SMasatake YAMATO 	vString *ccflag = vStringNew();
295256b419e9SMasatake YAMATO 	/* http://web.deu.edu.tr/doc/oracle/B19306_01/server.102/b14237/initparams158.htm#REFRN10261 */
295356b419e9SMasatake YAMATO 	while (*s)
295456b419e9SMasatake YAMATO 	{
295556b419e9SMasatake YAMATO 		if (in_var && isIdentChar1((int)*s))
295656b419e9SMasatake YAMATO 			vStringPut(ccflag, *s);
295756b419e9SMasatake YAMATO 		else if (*s == ':' && !vStringIsEmpty(ccflag))
295856b419e9SMasatake YAMATO 		{
295956b419e9SMasatake YAMATO 			if (lookupCaseKeyword(vStringValue(ccflag), Lang_sql)
296056b419e9SMasatake YAMATO 				!= KEYWORD_inquiry_directive)
296156b419e9SMasatake YAMATO 			{
2962293050e3SMasatake YAMATO 				int index = makeSimpleTag(ccflag, SQLTAG_PLSQL_CCFLAGS);
2963293050e3SMasatake YAMATO 				registerEntry(index);
296456b419e9SMasatake YAMATO 				vStringClear(ccflag);
296556b419e9SMasatake YAMATO 				in_var = false;
296656b419e9SMasatake YAMATO 			}
296756b419e9SMasatake YAMATO 		}
296856b419e9SMasatake YAMATO 		else if (*s == ',')
296956b419e9SMasatake YAMATO 			in_var = true;
297056b419e9SMasatake YAMATO 		s++;
297156b419e9SMasatake YAMATO 	}
297256b419e9SMasatake YAMATO 	vStringDelete(ccflag);
297356b419e9SMasatake YAMATO 
297456b419e9SMasatake YAMATO }
29753ae02089SMasatake YAMATO 
parseDatabase(tokenInfo * const token,enum eKeywordId keyword)2976dd3d1aaeSMasatake YAMATO static void parseDatabase (tokenInfo *const token, enum eKeywordId keyword)
2977dd3d1aaeSMasatake YAMATO {
2978dd3d1aaeSMasatake YAMATO 	tokenInfo * name;
2979dd3d1aaeSMasatake YAMATO 
2980dd3d1aaeSMasatake YAMATO 	/*
2981dd3d1aaeSMasatake YAMATO 	 * In MySQL and HPL/SQL, "CREATE DATABASE" and "CREATE SCHEMA"
2982dd3d1aaeSMasatake YAMATO 	 * are the same. However, In PostgreSQL, they are different.
2983dd3d1aaeSMasatake YAMATO 	 * Too support PostgreSQL, we prepare different kinds for them.
2984dd3d1aaeSMasatake YAMATO 	 *
2985dd3d1aaeSMasatake YAMATO 	 * MySQL
2986dd3d1aaeSMasatake YAMATO 	 * A. CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name ...;
2987dd3d1aaeSMasatake YAMATO 	 *
2988dd3d1aaeSMasatake YAMATO 	 * PostgreSQL
2989dd3d1aaeSMasatake YAMATO 	 *
2990dd3d1aaeSMasatake YAMATO 	 * B. CREATE DATABASE name ...;
2991dd3d1aaeSMasatake YAMATO 	 *
2992dd3d1aaeSMasatake YAMATO 	 * C. CREATE SCHEMA schema_name [ AUTHORIZATION role_specification ] [ schema_element [ ... ] ]
2993dd3d1aaeSMasatake YAMATO 	 * D. CREATE SCHEMA AUTHORIZATION role_specification [ schema_element [ ... ] ]
2994dd3d1aaeSMasatake YAMATO 	 * E. CREATE SCHEMA IF NOT EXISTS schema_name [ AUTHORIZATION role_specification ]
2995dd3d1aaeSMasatake YAMATO 	 * F. CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification
2996dd3d1aaeSMasatake YAMATO 	 *
2997dd3d1aaeSMasatake YAMATO 	 * HPL/SQL
2998dd3d1aaeSMasatake YAMATO 	 * G. CREATE DATABASE | SCHEMA [IF NOT EXISTS] dbname_expr...;
2999dd3d1aaeSMasatake YAMATO 	 */
3000dd3d1aaeSMasatake YAMATO 	readIdentifier (token);
3001dd3d1aaeSMasatake YAMATO 	if (keyword == KEYWORD_schema
3002dd3d1aaeSMasatake YAMATO 		&& isType (token, TOKEN_IDENTIFIER)
3003dd3d1aaeSMasatake YAMATO 		&& vStringLength (token->string) == 13
3004dd3d1aaeSMasatake YAMATO 		&& strcasecmp("authorization", vStringValue(token->string)) == 0)
3005dd3d1aaeSMasatake YAMATO 	{
3006dd3d1aaeSMasatake YAMATO 		/* D. */
3007dd3d1aaeSMasatake YAMATO 		readIdentifier (token);
3008dd3d1aaeSMasatake YAMATO 		makeSqlTag (token, SQLTAG_SCHEMA);
3009dd3d1aaeSMasatake YAMATO 		findCmdTerm (token, false);
3010dd3d1aaeSMasatake YAMATO 		return;
3011dd3d1aaeSMasatake YAMATO 	}
3012dd3d1aaeSMasatake YAMATO 
3013dd3d1aaeSMasatake YAMATO 	name = newToken ();
3014dd3d1aaeSMasatake YAMATO 	copyToken (name, token);
3015dd3d1aaeSMasatake YAMATO 	readIdentifier (token);
3016dd3d1aaeSMasatake YAMATO 	parseIdAfterIfNotExists (name, token, true);
3017dd3d1aaeSMasatake YAMATO 
3018dd3d1aaeSMasatake YAMATO 	makeSqlTag (name,
3019dd3d1aaeSMasatake YAMATO 				keyword == KEYWORD_database
3020dd3d1aaeSMasatake YAMATO 				? SQLTAG_DATABASE: SQLTAG_SCHEMA);
3021dd3d1aaeSMasatake YAMATO 	deleteToken (name);
3022dd3d1aaeSMasatake YAMATO 
3023dd3d1aaeSMasatake YAMATO 	/* TODO:
3024dd3d1aaeSMasatake YAMATO 	 *
3025dd3d1aaeSMasatake YAMATO 	 * In PostgreSQL, CREATE FOO can follow to CREATE SCHEMA like:
3026dd3d1aaeSMasatake YAMATO 	 *
3027dd3d1aaeSMasatake YAMATO 	 * -- https://www.postgresql.org/docs/current/sql-createschema.html
3028dd3d1aaeSMasatake YAMATO 	 *
3029dd3d1aaeSMasatake YAMATO 	 *     CREATE SCHEMA hollywood
3030dd3d1aaeSMasatake YAMATO 	 *         CREATE TABLE films (title text, release date, awards text[])
3031dd3d1aaeSMasatake YAMATO 	 *         CREATE VIEW winners AS
3032dd3d1aaeSMasatake YAMATO 	 *             SELECT title, release FROM films WHERE awards IS NOT NULL;
3033dd3d1aaeSMasatake YAMATO 	 *
3034dd3d1aaeSMasatake YAMATO 	 * In above example, "hollywood.films" and "hollywood.winners" should be
3035dd3d1aaeSMasatake YAMATO 	 * tagged.
3036dd3d1aaeSMasatake YAMATO 	 */
3037dd3d1aaeSMasatake YAMATO 	findCmdTerm (token, true);
3038dd3d1aaeSMasatake YAMATO }
3039dd3d1aaeSMasatake YAMATO 
parseKeywords(tokenInfo * const token)30403ae02089SMasatake YAMATO static void parseKeywords (tokenInfo *const token)
30413ae02089SMasatake YAMATO {
30423ae02089SMasatake YAMATO 		switch (token->keyword)
30433ae02089SMasatake YAMATO 		{
3044ce990805SThomas Braun 			case KEYWORD_begin:			parseBlock (token, false); break;
304556b419e9SMasatake YAMATO 			case KEYWORD_inquiry_directive:
304656b419e9SMasatake YAMATO 				if (strcasecmp(vStringValue(token->string), "PLSQL_CCFLAGS") == 0)
304756b419e9SMasatake YAMATO 					parseCCFLAGS (token);
304856b419e9SMasatake YAMATO 				break;
30493ae02089SMasatake YAMATO 			case KEYWORD_comment:		parseComment (token); break;
30503ae02089SMasatake YAMATO 			case KEYWORD_cursor:		parseSimple (token, SQLTAG_CURSOR); break;
3051dd3d1aaeSMasatake YAMATO 			case KEYWORD_database:		parseDatabase (token, KEYWORD_database); break;
30523ae02089SMasatake YAMATO 			case KEYWORD_datatype:		parseDomain (token); break;
3053ce990805SThomas Braun 			case KEYWORD_declare:		parseBlock (token, false); break;
30543ae02089SMasatake YAMATO 			case KEYWORD_domain:		parseDomain (token); break;
30553ae02089SMasatake YAMATO 			case KEYWORD_drop:			parseDrop (token); break;
30563ae02089SMasatake YAMATO 			case KEYWORD_event:			parseEvent (token); break;
30577831b8dcSMasatake YAMATO 			case KEYWORD_extension:		findCmdTerm (token, false); break;
30583ae02089SMasatake YAMATO 			case KEYWORD_function:		parseSubProgram (token); break;
3059ce990805SThomas Braun 			case KEYWORD_if:			parseStatements (token, false); break;
30603ae02089SMasatake YAMATO 			case KEYWORD_index:			parseIndex (token); break;
30613ae02089SMasatake YAMATO 			case KEYWORD_ml_table:		parseMLTable (token); break;
30623ae02089SMasatake YAMATO 			case KEYWORD_ml_table_lang: parseMLTable (token); break;
30633ae02089SMasatake YAMATO 			case KEYWORD_ml_table_dnet: parseMLTable (token); break;
30643ae02089SMasatake YAMATO 			case KEYWORD_ml_table_java: parseMLTable (token); break;
30653ae02089SMasatake YAMATO 			case KEYWORD_ml_table_chk:  parseMLTable (token); break;
30663ae02089SMasatake YAMATO 			case KEYWORD_ml_conn:		parseMLConn (token); break;
30673ae02089SMasatake YAMATO 			case KEYWORD_ml_conn_lang:	parseMLConn (token); break;
30683ae02089SMasatake YAMATO 			case KEYWORD_ml_conn_dnet:	parseMLConn (token); break;
30693ae02089SMasatake YAMATO 			case KEYWORD_ml_conn_java:	parseMLConn (token); break;
30703ae02089SMasatake YAMATO 			case KEYWORD_ml_conn_chk:	parseMLConn (token); break;
30713ae02089SMasatake YAMATO 			case KEYWORD_ml_prop:		parseMLProp (token); break;
30723ae02089SMasatake YAMATO 			case KEYWORD_package:		parsePackage (token); break;
30733ae02089SMasatake YAMATO 			case KEYWORD_procedure:		parseSubProgram (token); break;
30743ae02089SMasatake YAMATO 			case KEYWORD_publication:	parsePublication (token); break;
3075dd3d1aaeSMasatake YAMATO 			case KEYWORD_schema:		parseDatabase (token, KEYWORD_schema); break;
30763ae02089SMasatake YAMATO 			case KEYWORD_service:		parseService (token); break;
30773ae02089SMasatake YAMATO 			case KEYWORD_subtype:		parseSimple (token, SQLTAG_SUBTYPE); break;
30783ae02089SMasatake YAMATO 			case KEYWORD_synonym:		parseSynonym (token); break;
30793ae02089SMasatake YAMATO 			case KEYWORD_table:			parseTable (token); break;
30803ae02089SMasatake YAMATO 			case KEYWORD_trigger:		parseTrigger (token); break;
30813ae02089SMasatake YAMATO 			case KEYWORD_type:			parseType (token); break;
30823ae02089SMasatake YAMATO 			case KEYWORD_variable:		parseVariable (token); break;
30833ae02089SMasatake YAMATO 			case KEYWORD_view:			parseView (token); break;
3084b36b4b38SColomban Wendling 			case KEYWORD_with:			readToken (token); break; /* skip next token */
3085b36b4b38SColomban Wendling 			case KEYWORD_without:		readToken (token); break; /* skip next token */
30863ae02089SMasatake YAMATO 			default:				    break;
30873ae02089SMasatake YAMATO 		}
30883ae02089SMasatake YAMATO }
30893ae02089SMasatake YAMATO 
parseSqlFile(tokenInfo * const token)30903ae02089SMasatake YAMATO static tokenType parseSqlFile (tokenInfo *const token)
30913ae02089SMasatake YAMATO {
30923ae02089SMasatake YAMATO 	do
30933ae02089SMasatake YAMATO 	{
30943ae02089SMasatake YAMATO 		readToken (token);
30953ae02089SMasatake YAMATO 
30963ae02089SMasatake YAMATO 		if (isType (token, TOKEN_BLOCK_LABEL_BEGIN))
30973ae02089SMasatake YAMATO 			parseLabel (token);
30983ae02089SMasatake YAMATO 		else
30993ae02089SMasatake YAMATO 			parseKeywords (token);
31003ae02089SMasatake YAMATO 	} while (! isKeyword (token, KEYWORD_end) &&
31013ae02089SMasatake YAMATO 			 ! isType (token, TOKEN_EOF));
31023ae02089SMasatake YAMATO 
31033ae02089SMasatake YAMATO 	return token->type;
31043ae02089SMasatake YAMATO }
31053ae02089SMasatake YAMATO 
initialize(const langType language)31063ae02089SMasatake YAMATO static void initialize (const langType language)
31073ae02089SMasatake YAMATO {
3108158a3387SMasatake YAMATO 	Assert (ARRAY_SIZE (SqlKinds) == SQLTAG_COUNT);
31093ae02089SMasatake YAMATO 	Lang_sql = language;
31104dbda622SMasatake YAMATO 	addKeywordGroup (&predefinedInquiryDirective, language);
31113ae02089SMasatake YAMATO }
31123ae02089SMasatake YAMATO 
findSqlTags(void)31133ae02089SMasatake YAMATO static void findSqlTags (void)
31143ae02089SMasatake YAMATO {
31153ae02089SMasatake YAMATO 	tokenInfo *const token = newToken ();
31163ae02089SMasatake YAMATO 
31173ae02089SMasatake YAMATO 	while (parseSqlFile (token) != TOKEN_EOF);
31183ae02089SMasatake YAMATO 
31193ae02089SMasatake YAMATO 	deleteToken (token);
31203ae02089SMasatake YAMATO }
31213ae02089SMasatake YAMATO 
SqlParser(void)31223ae02089SMasatake YAMATO extern parserDefinition* SqlParser (void)
31233ae02089SMasatake YAMATO {
31243ae02089SMasatake YAMATO 	static const char *const extensions [] = { "sql", NULL };
3125a9b9ded9SMasatake YAMATO 	static const char *const aliases [] = {"pgsql", NULL };
3126b29ae60fSMasatake YAMATO 	parserDefinition* def = parserNew ("SQL");
312709ae690fSMasatake YAMATO 	def->kindTable	= SqlKinds;
31283db72c21SMasatake YAMATO 	def->kindCount	= ARRAY_SIZE (SqlKinds);
31293ae02089SMasatake YAMATO 	def->extensions = extensions;
3130a9b9ded9SMasatake YAMATO 	def->aliases    = aliases;
31313ae02089SMasatake YAMATO 	def->parser		= findSqlTags;
31323ae02089SMasatake YAMATO 	def->initialize = initialize;
3133c379c5d2SMasatake YAMATO 	def->keywordTable = SqlKeywordTable;
31343db72c21SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (SqlKeywordTable);
3135293050e3SMasatake YAMATO 	def->useCork = CORK_QUEUE | CORK_SYMTAB;
31363ae02089SMasatake YAMATO 	return def;
31373ae02089SMasatake YAMATO }
3138