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