@@ -78,6 +78,7 @@ enum eKeywordId {
7878 KEYWORD_constraint ,
7979 KEYWORD_create ,
8080 KEYWORD_cursor ,
81+ KEYWORD_database ,
8182 KEYWORD_datatype ,
8283 KEYWORD_declare ,
8384 KEYWORD_do ,
@@ -130,6 +131,7 @@ enum eKeywordId {
130131 KEYWORD_result ,
131132 KEYWORD_return ,
132133 KEYWORD_returns ,
134+ KEYWORD_schema ,
133135 KEYWORD_select ,
134136 KEYWORD_service ,
135137 KEYWORD_subtype ,
@@ -217,9 +219,11 @@ typedef enum {
217219 SQLTAG_BLOCK_LABEL ,
218220 SQLTAG_PACKAGE ,
219221 SQLTAG_SERVICE ,
222+ SQLTAG_SCHEMA ,
220223 SQLTAG_TRIGGER ,
221224 SQLTAG_PUBLICATION ,
222225 SQLTAG_VIEW ,
226+ SQLTAG_DATABASE ,
223227 SQLTAG_CURSOR ,
224228 SQLTAG_PROTOTYPE ,
225229 SQLTAG_EVENT ,
@@ -245,9 +249,11 @@ static kindDefinition SqlKinds [] = {
245249 { true, 'L' , "label" , "block label" },
246250 { true, 'P' , "package" , "packages" },
247251 { true, 'R' , "service" , "services" },
252+ { true, 'S' , "schema" , "schemas" },
248253 { true, 'T' , "trigger" , "triggers" },
249254 { true, 'U' , "publication" , "publications" },
250255 { true, 'V' , "view" , "views" },
256+ { true, 'b' , "database" , "database" },
251257 { true, 'c' , "cursor" , "cursors" },
252258 { false, 'd' , "prototype" , "prototypes" },
253259 { true, 'e' , "event" , "events" },
@@ -278,6 +284,7 @@ static const keywordTable SqlKeywordTable [] = {
278284 { "constraint" , KEYWORD_constraint },
279285 { "create" , KEYWORD_create },
280286 { "cursor" , KEYWORD_cursor },
287+ { "database" , KEYWORD_database },
281288 { "datatype" , KEYWORD_datatype },
282289 { "declare" , KEYWORD_declare },
283290 { "do" , KEYWORD_do },
@@ -329,6 +336,7 @@ static const keywordTable SqlKeywordTable [] = {
329336 { "result" , KEYWORD_result },
330337 { "return" , KEYWORD_return },
331338 { "returns" , KEYWORD_returns },
339+ { "schema" , KEYWORD_schema },
332340 { "select" , KEYWORD_select },
333341 { "service" , KEYWORD_service },
334342 { "subtype" , KEYWORD_subtype },
@@ -399,6 +407,8 @@ static bool SqlReservedWordPredicatorForIsOrAs (tokenInfo *const token);
399407static struct SqlReservedWord SqlReservedWord [SQLKEYWORD_COUNT ] = {
400408 /*
401409 * RESERVED_BIT: MYSQL & POSTGRESQL&SQL2016&SQL2011&SQL92 & ORACLE11g&PLSQL & SQLANYWERE
410+ *
411+ * { 0 } means we have not inspect whether the keyword is reserved or not.
402412 */
403413 [KEYWORD_at ] = {0 & 0 & 1 & 1 & 1 & 0 & 1 & 0 },
404414 [KEYWORD_begin ] = {0 & 0 & 1 & 1 & 1 & 0 & 1 & 1 },
@@ -410,6 +420,7 @@ static struct SqlReservedWord SqlReservedWord [SQLKEYWORD_COUNT] = {
410420 [KEYWORD_constraint ] = {1 & 1 & 1 & 1 & 1 & 0 & 1 & 1 },
411421 [KEYWORD_create ] = {1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 },
412422 [KEYWORD_cursor ] = {1 & 0 & 1 & 1 & 1 & 0 & 1 & 1 },
423+ [KEYWORD_database ] = { 0 },
413424 [KEYWORD_datatype ] = {0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 },
414425 [KEYWORD_declare ] = {1 & 0 & 1 & 1 & 1 & 0 & 1 & 1 },
415426 [KEYWORD_do ] = {0 & 1 & 0 & 0 & 0 & 0 & 1 & 1 },
@@ -462,6 +473,7 @@ static struct SqlReservedWord SqlReservedWord [SQLKEYWORD_COUNT] = {
462473 [KEYWORD_result ] = {0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 },
463474 [KEYWORD_return ] = {1 & 0 & 1 & 1 & 0 & 0 & 1 & 1 },
464475 [KEYWORD_returns ] = {0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 },
476+ [KEYWORD_schema ] = {0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 },
465477 [KEYWORD_select ] = {1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 },
466478 [KEYWORD_service ] = {0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 },
467479 [KEYWORD_subtype ] = {0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 },
@@ -2169,6 +2181,44 @@ static void parseColumnsAndAliases (tokenInfo *const token)
21692181 deleteToken (lastId );
21702182}
21712183
2184+ /* Skip "IF NOT EXISTS"
2185+ * https://dev.mysql.com/doc/refman/8.0/en/create-table.html
2186+ * https://www.postgresql.org/docs/current/sql-createtable.html
2187+ * https://sqlite.org/lang_createtable.html
2188+ */
2189+ static bool parseIdAfterIfNotExists (tokenInfo * const name ,
2190+ tokenInfo * const token ,
2191+ bool authorization_following )
2192+ {
2193+ if (isKeyword (name , KEYWORD_if )
2194+ && (isType (token , TOKEN_IDENTIFIER )
2195+ && vStringLength (token -> string ) == 3
2196+ && strcasecmp ("not" , vStringValue (token -> string )) == 0 ))
2197+ {
2198+ readToken (token );
2199+ if (isType (token , TOKEN_IDENTIFIER )
2200+ && vStringLength (token -> string ) == 6
2201+ && strcasecmp ("exists" , vStringValue (token -> string )) == 0 )
2202+ {
2203+ readIdentifier (name );
2204+ if (authorization_following
2205+ && isType (name , TOKEN_IDENTIFIER )
2206+ && vStringLength (name -> string ) == 13
2207+ && strcasecmp ("authorization" , vStringValue (name -> string )) == 0 )
2208+ {
2209+ /*
2210+ * PostgreSQL:
2211+ * - CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification
2212+ */
2213+ readIdentifier (name );
2214+ }
2215+ readToken (token );
2216+ return true;
2217+ }
2218+ }
2219+ return false;
2220+ }
2221+
21722222static void parseTable (tokenInfo * const token )
21732223{
21742224 tokenInfo * const name = newToken ();
@@ -2207,25 +2257,7 @@ static void parseTable (tokenInfo *const token)
22072257 readIdentifier (name );
22082258 readToken (token );
22092259
2210- /* Skip "IF NOT EXISTS"
2211- * https://dev.mysql.com/doc/refman/8.0/en/create-table.html
2212- * https://www.postgresql.org/docs/current/sql-createtable.html
2213- * https://sqlite.org/lang_createtable.html
2214- */
2215- if (isKeyword (name , KEYWORD_if )
2216- && (isType (token , TOKEN_IDENTIFIER )
2217- && vStringLength (token -> string ) == 3
2218- && strcasecmp ("not" , vStringValue (token -> string )) == 0 ))
2219- {
2220- readToken (token );
2221- if (isType (token , TOKEN_IDENTIFIER )
2222- && vStringLength (token -> string ) == 6
2223- && strcasecmp ("exists" , vStringValue (token -> string )) == 0 )
2224- {
2225- readIdentifier (name );
2226- readToken (token );
2227- }
2228- }
2260+ parseIdAfterIfNotExists (name , token , false);
22292261
22302262 if (isType (token , TOKEN_PERIOD ))
22312263 {
@@ -2902,6 +2934,70 @@ static void parseCCFLAGS (tokenInfo *const token)
29022934
29032935}
29042936
2937+ static void parseDatabase (tokenInfo * const token , enum eKeywordId keyword )
2938+ {
2939+ tokenInfo * name ;
2940+
2941+ /*
2942+ * In MySQL and HPL/SQL, "CREATE DATABASE" and "CREATE SCHEMA"
2943+ * are the same. However, In PostgreSQL, they are different.
2944+ * Too support PostgreSQL, we prepare different kinds for them.
2945+ *
2946+ * MySQL
2947+ * A. CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name ...;
2948+ *
2949+ * PostgreSQL
2950+ *
2951+ * B. CREATE DATABASE name ...;
2952+ *
2953+ * C. CREATE SCHEMA schema_name [ AUTHORIZATION role_specification ] [ schema_element [ ... ] ]
2954+ * D. CREATE SCHEMA AUTHORIZATION role_specification [ schema_element [ ... ] ]
2955+ * E. CREATE SCHEMA IF NOT EXISTS schema_name [ AUTHORIZATION role_specification ]
2956+ * F. CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification
2957+ *
2958+ * HPL/SQL
2959+ * G. CREATE DATABASE | SCHEMA [IF NOT EXISTS] dbname_expr...;
2960+ */
2961+ readIdentifier (token );
2962+ if (keyword == KEYWORD_schema
2963+ && isType (token , TOKEN_IDENTIFIER )
2964+ && vStringLength (token -> string ) == 13
2965+ && strcasecmp ("authorization" , vStringValue (token -> string )) == 0 )
2966+ {
2967+ /* D. */
2968+ readIdentifier (token );
2969+ makeSqlTag (token , SQLTAG_SCHEMA );
2970+ findCmdTerm (token , false);
2971+ return ;
2972+ }
2973+
2974+ name = newToken ();
2975+ copyToken (name , token );
2976+ readIdentifier (token );
2977+ parseIdAfterIfNotExists (name , token , true);
2978+
2979+ makeSqlTag (name ,
2980+ keyword == KEYWORD_database
2981+ ? SQLTAG_DATABASE : SQLTAG_SCHEMA );
2982+ deleteToken (name );
2983+
2984+ /* TODO:
2985+ *
2986+ * In PostgreSQL, CREATE FOO can follow to CREATE SCHEMA like:
2987+ *
2988+ * -- https://www.postgresql.org/docs/current/sql-createschema.html
2989+ *
2990+ * CREATE SCHEMA hollywood
2991+ * CREATE TABLE films (title text, release date, awards text[])
2992+ * CREATE VIEW winners AS
2993+ * SELECT title, release FROM films WHERE awards IS NOT NULL;
2994+ *
2995+ * In above example, "hollywood.films" and "hollywood.winners" should be
2996+ * tagged.
2997+ */
2998+ findCmdTerm (token , true);
2999+ }
3000+
29053001static void parseKeywords (tokenInfo * const token )
29063002{
29073003 switch (token -> keyword )
@@ -2913,6 +3009,7 @@ static void parseKeywords (tokenInfo *const token)
29133009 break ;
29143010 case KEYWORD_comment : parseComment (token ); break ;
29153011 case KEYWORD_cursor : parseSimple (token , SQLTAG_CURSOR ); break ;
3012+ case KEYWORD_database : parseDatabase (token , KEYWORD_database ); break ;
29163013 case KEYWORD_datatype : parseDomain (token ); break ;
29173014 case KEYWORD_declare : parseBlock (token , false); break ;
29183015 case KEYWORD_domain : parseDomain (token ); break ;
@@ -2936,6 +3033,7 @@ static void parseKeywords (tokenInfo *const token)
29363033 case KEYWORD_package : parsePackage (token ); break ;
29373034 case KEYWORD_procedure : parseSubProgram (token ); break ;
29383035 case KEYWORD_publication : parsePublication (token ); break ;
3036+ case KEYWORD_schema : parseDatabase (token , KEYWORD_schema ); break ;
29393037 case KEYWORD_service : parseService (token ); break ;
29403038 case KEYWORD_subtype : parseSimple (token , SQLTAG_SUBTYPE ); break ;
29413039 case KEYWORD_synonym : parseSynonym (token ); break ;
0 commit comments