Token* SqlParser::GetNextNumberToken(Token *prev) { if(prev == NULL) return NULL; return GetNextNumberToken(); }
// Parse Oracle CREATE TABLE, CREATE INDEX, PARTITION definition storage clause bool SqlParser::ParseOracleStorageClause(int stmt_scope) { bool exists = false; while(true) { Token *next = GetNextToken(); if(next == NULL) break; // SEGMENT CREATION IMMEDIATE | DEFERRED if(next->Compare("SEGMENT", L"SEGMENT", 7) == true) { Token *creation = GetNextWordToken("CREATION", L"CREATION", 8); Token *value = GetNextToken(); if(_target != SQL_ORACLE && creation != NULL) Token::Remove(next, value); exists = true; continue; } else // PCTFREE num if(next->Compare("PCTFREE", L"PCTFREE", 7) == true) { Token *value = GetNextNumberToken(); if(_target != SQL_ORACLE && value != NULL) Token::Remove(next, value); exists = true; continue; } else // PCTUSED num if(next->Compare("PCTUSED", L"PCTUSED", 7) == true) { Token *value = GetNextNumberToken(); if(_target != SQL_ORACLE && value != NULL) Token::Remove(next, value); exists = true; continue; } else // INITRANS num if(next->Compare("INITRANS", L"INITRANS", 8) == true) { Token *value = GetNextNumberToken(); if(_target != SQL_ORACLE && value != NULL) Token::Remove(next, value); exists = true; continue; } else // MAXTRANS num if(next->Compare("MAXTRANS", L"MAXTRANS", 8) == true) { Token *value = GetNextNumberToken(); if(_target != SQL_ORACLE && value != NULL) Token::Remove(next, value); exists = true; continue; } else // COMPRESS [BASIC] or COMPRESS num (for index-orginized tables and indexes) if(next->Compare("COMPRESS", L"COMPRESS", 8) == true) { // Optional BASIC keyword Token *basic = GetNextWordToken("BASIC", L"BASIC", 5); Token *num = NULL; // Check for a number if(basic == NULL) num = GetNextNumberToken(); if(_target != SQL_ORACLE) { Token::Remove(next); Token::Remove(basic); Token::Remove(num); } exists = true; continue; } else // NOCOMPRESS if(next->Compare("NOCOMPRESS", L"NOCOMPRESS", 10) == true) { if(_target != SQL_ORACLE) Token::Remove(next); exists = true; continue; } else // NOCACHE if(next->Compare("NOCACHE", L"NOCACHE", 7) == true) { if(_target != SQL_ORACLE) Token::Remove(next); exists = true; continue; } else // LOGGING if(next->Compare("LOGGING", L"LOGGING", 7) == true) { if(_target != SQL_ORACLE) Token::Remove(next); exists = true; continue; } else // NOLOGGING if(next->Compare("NOLOGGING", L"NOLOGGING", 9) == true) { if(_target != SQL_ORACLE) Token::Remove(next); exists = true; continue; } else // NOPARALLEL if(next->Compare("NOPARALLEL", L"NOPARALLEL", 10) == true) { if(_target != SQL_ORACLE) Token::Remove(next); exists = true; continue; } else // PARALLEL num if(next->Compare("PARALLEL", L"PARALLEL", 8) == true) { Token *value = GetNextNumberToken(); if(_target != SQL_ORACLE && value != NULL) Token::Remove(next, value); exists = true; continue; } else // NOMONITORING if(next->Compare("NOMONITORING", L"NOMONITORING", 12) == true) { if(_target != SQL_ORACLE) Token::Remove(next); exists = true; continue; } else // TABLESPACE name if(next->Compare("TABLESPACE", L"TABLESPACE", 10) == true) { Token *name = GetNextIdentToken(); // ON name if(_target == SQL_SQL_SERVER) Token::Change(next, "ON", L"ON", 2); else // IN name if(_target == SQL_DB2) Token::Change(next, "IN", L"IN", 2); else Token::Remove(next, name); exists = true; continue; } else // STORAGE () clause if(next->Compare("STORAGE", L"STORAGE", 7) == true) { exists = ParseOracleStorageClause(next); continue; } else // LOB (column) STORE AS (params) if(next->Compare("LOB", L"LOB", 3) == true) { if(ParseOracleLobStorageClause(next) == true) { exists = true; continue; } } else // Oracle partitioning clauses if(ParseOraclePartitions(next, stmt_scope) == true) { exists = true; continue; } else // COMPUTE STATISTICS if(next->Compare("COMPUTE", L"COMPUTE", 7) == true) { Token *statistics = GetNextWordToken("STATISTICS", L"STATISTICS", 10); // Remove if not Oracle if(_target != SQL_ORACLE) Token::Remove(next, statistics); exists = true; continue; } else // ENABLE ROW MOVEMENT if(next->Compare("ENABLE", L"ENABLE", 6) == true) { Token *row = GetNextWordToken("ROW", L"ROW", 3); if(row != NULL) { Token *movement = GetNextWordToken("MOVEMENT", L"MOVEMENT", 8); // Remove if not Oracle if(_target != SQL_ORACLE) Token::Remove(next, movement); exists = true; continue; } } else // REVERSE index or primary key storage attribute if(next->Compare("REVERSE", L"REVERSE", 7) == true) { // Remove if not Oracle if(_target != SQL_ORACLE) Token::Remove(next); exists = true; continue; } // Not an Oracle storage clause PushBack(next); break; } return exists; }
// Parse MySQL CREATE TABLE storage clause bool SqlParser::ParseMysqlStorageClause(Token *table_name, Token **id_start, Token **comment_out) { bool exists = false; // Auto_increment start value Token *auto_start = NULL; while(true) { Token *next = GetNextToken(); if(next == NULL) break; // ENGINE = type if(next->Compare("ENGINE", L"ENGINE", 6) == true) { // Equal sign = is optional in the clause Token *equal = GetNextCharToken('=', L'='); Token *type = GetNextToken(); if(_target != SQL_MYSQL) { Token::Remove(next); Token::Remove(equal); Token::Remove(type); } exists = true; continue; } else // AUTO_INCREMENT = start table option if(next->Compare("AUTO_INCREMENT", L"AUTO_INCREMENT", 14) == true) { // Equal sign = is optional in the clause Token *equal = GetNextCharToken('=', L'='); auto_start = GetNextNumberToken(); if(_target != SQL_MYSQL) { Token::Remove(next); Token::Remove(equal); Token::Remove(auto_start); } exists = true; continue; } else // DEFAULT CHARSET if(next->Compare("DEFAULT", L"DEFAULT", 7) == true) { Token *option = GetNextToken(); if(option == NULL) break; // CHARSET if(option->Compare("CHARSET", L"CHARSET", 7) == true) { Token *equal = GetNextCharToken('=', L'='); Token *value = GetNextIdentToken(); if(_target != SQL_MYSQL) Token::Remove(next, value); } else // CHARACTER SET if(option->Compare("CHARACTER", L"CHARACTER", 9) == true) { Token *set = GetNextWordToken("SET", L"SET", 3); Token *equal = GetNextCharToken('=', L'='); Token *value = GetNextIdentToken(); if(_target != SQL_MYSQL) Token::Remove(next, value); } exists = true; continue; } else // COLLATE = value if(next->Compare("COLLATE", L"COLLATE", 7) == true) { Token *equal = GetNextCharToken('=', L'='); Token *value = GetNextIdentToken(); if(_target != SQL_MYSQL) Token::Remove(next, value); exists = true; continue; } else // COMMENT = 'table comment' if(next->Compare("COMMENT", L"COMMENT", 7) == true) { // Equal sign = is optional in the clause Token *equal = GetNextCharToken('=', L'='); Token *text = GetNextToken(); if(comment_out != NULL) *comment_out = text; // Remove from CREATE TABLE if(_target != SQL_MYSQL) Token::Remove(next, text); exists = true; continue; } else // PACK_KEYS = 0 | 1 | DEFAULT if(next->Compare("PACK_KEYS", L"PACK_KEYS", 9) == true) { // Optional = Token *equal = GetNextCharToken('=', L'='); Token *value = GetNextToken(); if(_target != SQL_MYSQL) Token::Remove(next, value); exists = true; continue; } else // ROW_FORMAT = type | DEFAULT if(next->Compare("ROW_FORMAT", L"ROW_FORMAT", 10) == true) { // Optional = Token *equal = GetNextCharToken('=', L'='); Token *value = GetNextToken(); if(_target != SQL_MYSQL) Token::Remove(next, value); exists = true; continue; } // Not a MySQL stoage clause PushBack(next); break; } if(id_start != NULL) *id_start = auto_start; // Restart sequence for PostgreSQL and Greenplum if(auto_start != NULL && (_target == SQL_POSTGRESQL || _target == SQL_GREENPLUM)) { // Try to get ; Token *semi = GetNextCharToken(';', L';'); Token *last = (semi != NULL) ? semi : GetLastToken(); // Append ALTER SEQUENCE command Append(last, "\n\nALTER SEQUENCE ", L"\n\nALTER SEQUENCE ", 17); // Add sequence name Token *seq_name = AppendIdentifier(table_name, "_seq", L"_seq", 4); Append(last, seq_name); Append(last, " RESTART WITH ", L" RESTART WITH ", 14); AppendCopy(last, auto_start); Append(last, ";", L";", 1); } return exists; }
// DB2 identity options in GENERATED ALWAYS or BY DEFAULT AS IDENTITY bool SqlParser::ParseDb2GeneratedClause(Token *create, Token *table_name, Token *column, Token *generated, Token **id_col, Token **id_start, Token **id_inc, bool *id_default) { if(generated == NULL) return false; Token *always = GetNextWordToken("ALWAYS", L"ALWAYS", 6); Token *by = NULL; Token *default_ = NULL; if(always == NULL) { by = GetNextWordToken("BY", L"BY", 2); default_ = GetNextWordToken("DEFAULT", L"DEFAULT", 7); if(id_default != NULL) *id_default = true; } else { if(id_default != NULL) *id_default = false; } Token *as = GetNextWordToken("AS", L"AS", 2); Token *identity = GetNextWordToken("IDENTITY", L"IDENTITY", 8); // Identity parameters are optional Token *open = GetNextCharToken('(', L'('); Token *close = NULL; Token *start_with = NULL; Token *increment_by = NULL; while(true) { bool exists = false; if(open == NULL) break; Token *option = GetNextToken(); if(option == NULL) break; // START WITH if(option->Compare("START", L"START", 5) == true) { /*Token *with */ (void) GetNextWordToken("WITH", L"WITH", 4); start_with = GetNextNumberToken(); exists = true; continue; } else // INCREMENT BY if(option->Compare("INCREMENT", L"INCREMENT", 9) == true) { /*Token *by */ (void) GetNextWordToken("BY", L"BY", 2); increment_by = GetNextNumberToken(); exists = true; continue; } else // MINVALUE if(option->Compare("MINVALUE", L"MINVALUE", 8) == true) { /*Token *value */ (void) GetNextNumberToken(); exists = true; continue; } else // MAXVALUE if(option->Compare("MAXVALUE", L"MAXVALUE", 8) == true) { /*Token *value */ (void) GetNextNumberToken(); exists = true; continue; } else // NO CYCLE and NO ORDER if(option->Compare("NO", L"NO", 2) == true) { /*Token *attr */ (void) GetNextToken(); exists = true; continue; } else // CACHE if(option->Compare("CACHE", L"CACHE", 5) == true) { /*Token *value */ (void) GetNextNumberToken(); exists = true; continue; } else // CYCLE if(option->Compare("CYCLE", L"CYCLE", 5) == true) { exists = true; continue; } else // Looks like comma is optional if(option->Compare(',', L',') == true) { exists = true; continue; } PushBack(option); break; } if(open != NULL) close = GetNextCharToken(')', L')'); // IDENTITY(start, inc) in SQL Server if(_target == SQL_SQL_SERVER) { Token::Change(generated, "IDENTITY(", L"IDENTITY(", 9); AppendCopy(generated, start_with); if(increment_by != NULL) { Append(generated, ", ", L", ", 2); AppendCopy(generated, increment_by); } Append(generated, ")", L")", 1); if(always != NULL) Token::Remove(always, close); else Token::Remove(by, close); } else // Use a sequence and DEFAULT nextval for PostgreSQL and Greenplum if(_target == SQL_POSTGRESQL || _target == SQL_GREENPLUM) { TokenStr seq_name(table_name); AppendIdentifier(seq_name, "_seq", L"_seq", 4); // Generate CREATE SEQUENCE before CREATE TABLE Prepend(create, "CREATE SEQUENCE ", L"CREATE SEQUENCE ", 16); PrependNoFormat(create, &seq_name); if(start_with != NULL) { Prepend(create, " START WITH ", L" START WITH ", 12); PrependCopy(create, start_with); } if(increment_by != NULL) { Prepend(create, " INCREMENT BY ", L" INCREMENT BY ", 14); PrependCopy(create, increment_by); } Prepend(create, ";\n\n", L";\n\n", 3); // Generate DEFAULT nextval('tablename_seq') clause Token::Change(generated, "DEFAULT ", L"DEFAULT ", 8); Append(generated, "nextval ('", L"nextval ('", 10); AppendNoFormat(generated, &seq_name); Append(generated, "')", L"')", 2); if(always != NULL) Token::Remove(always, close); else Token::Remove(by, close); } else // Remove for other databases if(_target != SQL_DB2) { Token::Remove(generated); Token::Remove(always); Token::Remove(by, default_); Token::Remove(as, identity); Token::Remove(open, close); } if(id_col != NULL) *id_col = column; if(id_start != NULL) *id_start = start_with; if(id_inc != NULL) *id_inc = increment_by; return true; }