001/* 002 * Decompiled with CFR 0.152. 003 */ 004package gudusoft.gsqlparser.parser; 005 006import gudusoft.gsqlparser.EDataType; 007import gudusoft.gsqlparser.EDbVendor; 008import gudusoft.gsqlparser.EErrorType; 009import gudusoft.gsqlparser.EFindSqlStateType; 010import gudusoft.gsqlparser.ESqlStatementType; 011import gudusoft.gsqlparser.ETokenType; 012import gudusoft.gsqlparser.TBaseType; 013import gudusoft.gsqlparser.TCustomLexer; 014import gudusoft.gsqlparser.TCustomParser; 015import gudusoft.gsqlparser.TCustomSqlStatement; 016import gudusoft.gsqlparser.TLexerTeradata; 017import gudusoft.gsqlparser.TParserTeradata; 018import gudusoft.gsqlparser.TSourceToken; 019import gudusoft.gsqlparser.TSourceTokenList; 020import gudusoft.gsqlparser.TStatementList; 021import gudusoft.gsqlparser.TSyntaxError; 022import gudusoft.gsqlparser.nodes.TDatatypeAttribute; 023import gudusoft.gsqlparser.nodes.TFunctionCall; 024import gudusoft.gsqlparser.nodes.TTypeName; 025import gudusoft.gsqlparser.nodes.teradata.TTeradataHelper; 026import gudusoft.gsqlparser.parser.AbstractSqlParser; 027import gudusoft.gsqlparser.parser.ParserContext; 028import gudusoft.gsqlparser.parser.SqlParseResult; 029import gudusoft.gsqlparser.resolver.TSQLResolver; 030import gudusoft.gsqlparser.sqlcmds.SqlCmdsFactory; 031import gudusoft.gsqlparser.stmt.TUnknownSqlStatement; 032import gudusoft.gsqlparser.stmt.teradata.TTeradataBTEQCmd; 033import gudusoft.gsqlparser.stmt.teradata.TTeradataFastExportCmd; 034import gudusoft.gsqlparser.stmt.teradata.TTeradataFastLoadCmd; 035import gudusoft.gsqlparser.stmt.teradata.TTeradataMultiLoadCmd; 036import gudusoft.gsqlparser.stmt.teradata.utilities.BteqCmdType; 037import java.util.ArrayList; 038 039public class TeradataSqlParser 040extends AbstractSqlParser { 041 public TLexerTeradata flexer; 042 private TParserTeradata fparser; 043 private TCustomSqlStatement gcurrentsqlstatement; 044 private char curdelimiterchar = (char)59; 045 046 // BTEQ state tracking - must persist across token processing 047 private boolean inBTEQComment = false; 048 private boolean isContinueBTEQCmd = false; 049 // Track when we're collecting a SQL statement after .IF/.ELSEIF THEN 050 private boolean isInIfThenStatement = false; 051 052 public TeradataSqlParser() { 053 super(EDbVendor.dbvteradata); 054 this.delimiterChar = '/'; // Teradata uses forward slash as delimiter for stored procedures 055 this.defaultDelimiterStr = ";"; // Match TGSqlParser default 056 this.flexer = new TLexerTeradata(); 057 this.flexer.delimiterchar = '/'; // Must match TGSqlParser: delimiterchar = '/' 058 this.flexer.defaultDelimiterStr = ";"; // Match TGSqlParser default 059 this.lexer = this.flexer; 060 this.fparser = new TParserTeradata(null); 061 this.fparser.lexer = this.flexer; 062 } 063 064 @Override 065 protected TCustomLexer getLexer(ParserContext context) { 066 // Transfer Teradata utility type from context to lexer 067 if (context.getTeradataUtilityType() != null) { 068 this.flexer.setTeradataUtilityType(context.getTeradataUtilityType()); 069 } 070 return this.flexer; 071 } 072 073 @Override 074 protected TCustomParser getParser(ParserContext context, TSourceTokenList tokens) { 075 this.fparser.sourcetokenlist = tokens; 076 return this.fparser; 077 } 078 079 @Override 080 protected TCustomParser getSecondaryParser(ParserContext context, TSourceTokenList tokens) { 081 return null; 082 } 083 084 @Override 085 protected void tokenizeVendorSql() { 086 this.doteradatatexttotokenlist(); 087 } 088 089 @Override 090 protected void setupVendorParsersForExtraction() { 091 this.fparser.sqlcmds = this.sqlcmds; 092 this.fparser.sourcetokenlist = this.sourcetokenlist; 093 } 094 095 @Override 096 protected void extractVendorRawStatements(SqlParseResult.Builder builder) { 097 this.doteradatagetrawsqlstatements(builder); 098 } 099 100 private void doteradatatexttotokenlist() { 101 TSourceToken asourcetoken, lcprevst; 102 int yychar; 103 104 asourcetoken = this.getanewsourcetoken(); 105 if (asourcetoken == null) { 106 return; 107 } 108 yychar = asourcetoken.tokencode; 109 110 while (yychar > 0) { 111 this.sourcetokenlist.add(asourcetoken); 112 asourcetoken = this.getanewsourcetoken(); 113 if (asourcetoken == null) break; 114 115 if ((asourcetoken.tokencode == TBaseType.rrw_casespecific) 116 || (asourcetoken.tokencode == TBaseType.rrw_teradata_cs)) { 117 // change not to not1 to make "not null column constraints" work correctly 118 // |RW_NOT1 RW_CASESPECIFIC 119 lcprevst = this.getprevsolidtoken(asourcetoken); 120 if (lcprevst != null) { 121 if (lcprevst.tokencode == TBaseType.rrw_not) { 122 lcprevst.tokencode = TBaseType.rw_not1; 123 } 124 } 125 } else if (asourcetoken.tokencode == ';') { 126 lcprevst = this.getprevsolidtoken(asourcetoken); 127 if (lcprevst != null) { 128 if (lcprevst.tokencode == ';') { 129 asourcetoken.tokencode = TBaseType.sqlpluscmd; 130 } 131 } 132 } else if (asourcetoken.tokencode == TBaseType.variable) { // mantisbt/view.php?id=972 133 if (asourcetoken.toString().toLowerCase().endsWith("begin")) { // MYPROC :BEGIN 134 asourcetoken.tokencode = TBaseType.rrw_begin; 135 asourcetoken.tokentype = ETokenType.ttkeyword; 136 137 lcprevst = this.getprevsolidtoken(asourcetoken); 138 if (lcprevst != null) { 139 lcprevst.tokencode = TBaseType.mslabel; 140 } 141 } 142 } else if (asourcetoken.tokencode == TCustomLexer.UNICODE_ENCODE_ID) { 143 if (asourcetoken.toString().endsWith("008D")) { // REVERSE LINE FEED, https://codepoints.net/U+008D?lang=en 144 asourcetoken.tokencode = TBaseType.lexspace; 145 } else { 146 asourcetoken.tokencode = TBaseType.ident; 147 } 148 } 149 150 yychar = asourcetoken.tokencode; 151 } 152 } 153 154 private TSourceToken getprevsolidtoken(TSourceToken ptoken) { 155 TSourceToken ret = null; 156 TSourceTokenList lctokenlist = ptoken.container; 157 if (lctokenlist != null && ptoken.posinlist > 0 && lctokenlist.size() > ptoken.posinlist - 1) { 158 ret = lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttwhitespace && lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttreturn && lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttsimplecomment && lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttbracketedcomment ? lctokenlist.get(ptoken.posinlist - 1) : lctokenlist.nextsolidtoken(ptoken.posinlist - 1, -1, false); 159 } 160 return ret; 161 } 162 163 private int doteradatagetrawsqlstatements(SqlParseResult.Builder builder) { 164 this.gcurrentsqlstatement = null; 165 EFindSqlStateType gst = EFindSqlStateType.stnormal; 166 int lcNestedParens = 0; 167 int lcNestedBeginEnd = 0; 168 int lcNestedCase = 0; 169 int lcNestedSample = 0; 170 Object lcprevst = null; 171 Object lcnextst = null; 172 Object lcnextst2 = null; 173 Object lcnextst3 = null; 174 TSourceToken lcprevsolidtoken = null; 175 TSourceToken ast = null; 176 int errorcount = 0; 177 // Note: inBTEQComment, isContinueBTEQCmd, isInIfThenStatement are instance fields 178 this.inBTEQComment = false; 179 this.isContinueBTEQCmd = false; 180 this.isInIfThenStatement = false; 181 char ch; 182 String lcstr; 183 block10: for (int i = 0; i < this.sourcetokenlist.size(); ++i) { 184 if (ast != null && ast.issolidtoken()) { 185 lcprevsolidtoken = ast; 186 } 187 ast = this.sourcetokenlist.get(i); 188 this.sourcetokenlist.curpos = i; 189 if (ast.tokencode != TBaseType.rrw_time && ast.tokencode != TBaseType.rrw_date && ast.tokencode != TBaseType.rrw_timestamp) { 190 if (ast.tokencode == '(') { 191 this.handleLeftParenthesisToken(ast, i); 192 } else if (ast.tokencode == TBaseType.rrw_for) { 193 this.handleForToken(ast); 194 } else if (ast.tokencode == TBaseType.rrw_teradata_last) { 195 this.handleLastToken(ast); 196 } else if (ast.tokencode == TBaseType.rrw_teradata_pivot) { 197 this.handlePivotToken(ast); 198 } else if (ast.tokencode == TBaseType.rrw_teradata_period) { 199 this.handlePeriodToken(ast); 200 } else if (ast.tokencode == TBaseType.rrw_teradata_transaction) { 201 this.handleTransactionToken(ast); 202 } else if (ast.tokencode == TBaseType.rrw_replace) { 203 this.handleReplaceToken(ast); 204 } else if (ast.tokencode == TBaseType.rrw_between) { 205 this.handleBetweenToken(ast); 206 } else if (ast.tokencode == TBaseType.rrw_declare) { 207 this.handleDeclareToken(ast); 208 } else if (ast.tokencode == TBaseType.rrw_case && ast.tag == 0 && ast.posinlist + 1 < this.sourcetokenlist.size()) { 209 this.handleCaseToken(ast); 210 } else if (ast.tokencode == TBaseType.rrw_grant) { 211 this.handleGrantToken(ast); 212 } else if (ast.tokencode == TBaseType.variable) { 213 this.handleVariableToken(ast); 214 } else if (ast.tokencode == TBaseType.rrw_teradata_sequenced || ast.tokencode == TBaseType.rrw_teradata_nonsequenced) { 215 this.handleSequencedToken(ast); 216 } 217 } 218 switch (gst) { 219 case sterror: { 220 if (ast.tokentype == ETokenType.ttsemicolon) { 221 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 222 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 223 gst = EFindSqlStateType.stnormal; 224 continue block10; 225 } 226 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 227 continue block10; 228 } 229 case stMultiLoadCmd: { 230 gst = this.handleMultiLoadCmdState(ast, gst, builder); 231 continue block10; 232 } 233 case stFastExportCmd: { 234 gst = this.handleFastExportCmdState(ast, gst, builder); 235 continue block10; 236 } 237 case stFastLoadCmd: { 238 gst = this.handleFastLoadCmdState(ast, gst, builder); 239 continue block10; 240 } 241 case stBTEQCmd: { 242 gst = this.handleBTEQCmdState(ast, builder); 243 continue block10; 244 } 245 case stnormal: { 246 gst = this.handleNormalState(ast, gst, lcprevsolidtoken, builder); 247 if (gst != EFindSqlStateType.ststoredprocedure) continue block10; 248 lcNestedParens = 0; 249 continue block10; 250 } 251 case stsql: { 252 boolean readyToEnd = true; 253 if (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstteradatacreatemacro) { 254 if (ast.tokencode == '(' || ast.tokencode == TBaseType.left_parenthesis_2) { 255 ++lcNestedParens; 256 } 257 if (ast.tokencode == ')') { 258 --lcNestedParens; 259 if (lcNestedParens < 0) { 260 lcNestedParens = 0; 261 } 262 } 263 readyToEnd = lcNestedParens == 0; 264 } 265 if (ast.tokentype == ETokenType.ttsemicolon && readyToEnd) { 266 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 267 this.gcurrentsqlstatement.semicolonended = ast; 268 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 269 gst = EFindSqlStateType.stnormal; 270 continue block10; 271 } 272 if (ast.tokencode == TBaseType.cmtdoublehyphen && ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)) { 273 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 274 gst = EFindSqlStateType.stnormal; 275 continue block10; 276 } 277 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 278 continue block10; 279 } 280 case ststoredprocedure: { 281 boolean readyToEnd = true; 282 if (ast.tokencode == ';') { 283 // don't count case..end, sample ... end after ; 284 lcNestedSample = 0; 285 lcNestedCase = 0; 286 } else if (ast.tokencode == TBaseType.rrw_case) { // case ... end 287 ++lcNestedCase; 288 TSourceToken prevst = ast.prevSolidToken(); 289 if (prevst != null && prevst.tokencode == TBaseType.rrw_end) { 290 // don't count: end case 291 --lcNestedCase; 292 } 293 } else if (ast.tokencode == TBaseType.rrw_teradata_sample) { // sample ... end 294 ++lcNestedSample; 295 } 296 if (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatetrigger 297 || this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreateprocedure 298 || this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatefunction) { 299 if (ast.tokencode == '(' || ast.tokencode == TBaseType.left_parenthesis_2) { 300 ++lcNestedParens; 301 } 302 if (ast.tokencode == ')' && --lcNestedParens < 0) { 303 lcNestedParens = 0; 304 } 305 if (ast.tokencode == TBaseType.rrw_begin) { 306 ++lcNestedBeginEnd; 307 } 308 if (ast.tokencode == TBaseType.rrw_end) { 309 boolean countThisEnd = true; 310 if (lcNestedSample > 0) { 311 // don't count sample...end 312 --lcNestedSample; 313 countThisEnd = false; 314 } else if (lcNestedCase > 0) { 315 // don't count case...end 316 --lcNestedCase; 317 countThisEnd = false; 318 } 319 if (countThisEnd) { 320 // don't count end while/if/case/loop/for/repeat 321 TSourceToken nt = ast.nextSolidToken(); 322 if (nt != null) { 323 countThisEnd = nt.tokencode != TBaseType.rrw_while 324 && nt.tokencode != TBaseType.rrw_if 325 && nt.tokencode != TBaseType.rrw_case 326 && nt.tokencode != TBaseType.rrw_loop 327 && nt.tokencode != TBaseType.rrw_for 328 && nt.tokencode != TBaseType.rrw_repeat; 329 } 330 } 331 if (countThisEnd && --lcNestedBeginEnd < 0) { 332 lcNestedBeginEnd = 0; 333 } 334 } 335 readyToEnd = lcNestedParens == 0 && lcNestedBeginEnd == 0; 336 } 337 // single stmt in function/procedure/trigger may use ; as terminate char 338 // so default terminate char is ;, if begin is found, then 339 // set terminate char to DelimiterChar 340 if (this.curdelimiterchar != this.delimiterChar) { 341 if (ast.tokencode == TBaseType.rrw_begin) { 342 this.curdelimiterchar = this.delimiterChar; 343 } else if (ast.tokencode == TBaseType.mslabel && ast.container.nextsolidtoken(ast, 1, false).tokencode == TBaseType.rrw_begin) { 344 this.curdelimiterchar = this.delimiterChar; 345 } 346 } 347 if (this.curdelimiterchar == ';') { 348 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 349 if (ast.tokentype == ETokenType.ttsemicolon 350 && (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatetrigger 351 || this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 352 && readyToEnd) { 353 gst = EFindSqlStateType.stnormal; 354 this.gcurrentsqlstatement.semicolonended = ast; 355 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 356 continue block10; 357 } 358 } else { 359 if (ast.getAstext().length() == 1) { 360 ch = ast.getAstext().charAt(0); 361 } else if (ast.getAstext().length() > 1) { 362 ch = ast.getAstext().charAt(ast.getAstext().length() - 1); 363 } else { 364 ch = ' '; 365 } 366 if (ast.tokencode != TBaseType.cmtslashstar && ast.tokencode != TBaseType.cmtdoublehyphen 367 && ch == this.curdelimiterchar && ast.isFirstTokenOfLine() && readyToEnd) { 368 if (ast.getAstext().length() > 1) { 369 lcstr = ast.getAstext().substring(0, ast.getAstext().length() - 1); 370 int c2 = this.flexer.getkeywordvalue(lcstr); 371 if (c2 > 0) { 372 ast.tokencode = c2; 373 } 374 } else { 375 this.gcurrentsqlstatement.semicolonended = ast; 376 } 377 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 378 gst = EFindSqlStateType.stnormal; 379 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 380 } else if (ast.searchToken(TBaseType.rrw_create, 1) != null && ast.searchToken(TBaseType.rrw_procedure, 4) != null && readyToEnd) { 381 gst = EFindSqlStateType.stnormal; 382 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 383 } else if (ast.tokencode == ';') { 384 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 385 boolean startNewStatement = false; 386 if (readyToEnd) { 387 startNewStatement = this.sqlcmds.issql(ast.nextSolidToken(), gst, this.gcurrentsqlstatement) != null; 388 } 389 if (startNewStatement) { 390 gst = EFindSqlStateType.stnormal; 391 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 392 } 393 } else { 394 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 395 } 396 } 397 if (gst == EFindSqlStateType.ststoredprocedure && ast.tokencode == TBaseType.cmtdoublehyphen && ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)) { 398 gst = EFindSqlStateType.stnormal; 399 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 400 } 401 } 402 } 403 } 404 if (TBaseType.assigned(this.gcurrentsqlstatement) && (gst == EFindSqlStateType.stsql || gst == EFindSqlStateType.stBTEQCmd || gst == EFindSqlStateType.ststoredprocedure || gst == EFindSqlStateType.sterror 405 || gst == EFindSqlStateType.stFastExportCmd || gst == EFindSqlStateType.stFastLoadCmd || gst == EFindSqlStateType.stMultiLoadCmd)) { 406 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, true, builder); 407 } 408 builder.sqlStatements(this.sqlstatements); 409 builder.syntaxErrors(this.syntaxErrors instanceof ArrayList ? (ArrayList)this.syntaxErrors : new ArrayList(this.syntaxErrors)); 410 builder.errorCode(this.syntaxErrors.isEmpty() ? 0 : this.syntaxErrors.size()); 411 return errorcount; 412 } 413 414 private void handleLeftParenthesisToken(TSourceToken ast, int i) { 415 TSourceToken lcnextst = this.sourcetokenlist.nextsolidtoken(i, 1, false); 416 TSourceToken lcprevst = this.getprevsolidtoken(ast); 417 if ((lcprevst != null) && ( 418 (lcprevst.tokencode == TBaseType.rrw_teradata_cast) 419 || (lcprevst.tokencode == TBaseType.rrw_year) // sample sql: select year(date) - 1 mantisbt/view.php?id=3049 420 )) { 421 lcnextst = null; // don't check next token if prev token is cast. sample: cast(DATETIME as BIGINT) 422 } 423 if ((lcprevst != null) && (TFunctionCall.isBuiltIn(lcprevst.toString(), EDbVendor.dbvteradata))) { 424 if (((lcprevst.tokencode == TBaseType.rrw_end) 425 || (lcprevst.tokencode == TBaseType.rrw_time) 426 || (lcprevst.tokencode == TBaseType.rrw_date) 427 || (lcprevst.tokencode == TBaseType.rrw_timestamp) 428 || (lcprevst.tokencode == TBaseType.rrw_teradata_type) 429 || (lcprevst.toString().equalsIgnoreCase("current_date")) 430 || (lcprevst.toString().equalsIgnoreCase("current_time")) 431 || (lcprevst.toString().equalsIgnoreCase("current_timestamp")) 432 || (lcprevst.toString().equalsIgnoreCase("user")) 433 || (lcprevst.toString().equalsIgnoreCase("current_user")) 434 )) { 435 // Keep lcnextst as is 436 } else { 437 lcnextst = null; 438 } 439 } 440 if (lcnextst != null) { 441 EDataType dataType = TTypeName.searchTeradataTypeByName(lcnextst.toString()); 442 if ((dataType != null) && (lcprevst != null) && (lcprevst.tokencode != TBaseType.rrw_teradata_period)) { 443 ast.tokencode = TBaseType.rrw_teradata_start_data_conversion; 444 // lcnextst2 is the token 2 steps after ( 445 TSourceToken lcnextst2 = this.sourcetokenlist.nextsolidtoken(i, 2, false); 446 // lcnextst3 is the token 3 steps after ( 447 TSourceToken lcnextst3 = this.sourcetokenlist.nextsolidtoken(i, 3, false); 448 if (lcnextst2.tokencode == ',') { 449 // this is data conversion: (date,format '$xxx'), 450 // this is not data conversion: trunc(date,'yy') 451 TSourceToken st1 = lcnextst3; 452 TSourceToken st2 = this.sourcetokenlist.nextsolidtoken(i, 4, false); 453 if (TDatatypeAttribute.searchDataTypeAttributeByName(st1, st2) == null) { 454 // this is not data conversion, such as :trunc(date,'yy') 455 ast.tokencode = '('; 456 } 457 } else if (lcnextst2 != null) { 458 // lcnextst3 may be null when (date) is at end of query 459 this.handleDataTypeConversion(ast, dataType, lcnextst2, lcnextst3, lcprevst); 460 } 461 } else { 462 TSourceToken st1 = lcnextst; 463 TSourceToken st2 = this.sourcetokenlist.nextsolidtoken(i, 2, false); 464 if (TDatatypeAttribute.searchDataTypeAttributeByName(st1, st2) != null) { 465 ast.tokencode = TBaseType.rrw_teradata_start_data_conversion; 466 } 467 } 468 } 469 } 470 471 private void handleDataTypeConversion(TSourceToken ast, EDataType dataType, TSourceToken lcnextst2, TSourceToken lcnextst3, TSourceToken lcprevst) { 472 switch (dataType) { 473 case date_t: 474 case time_t: 475 // next token is: ) or comma or data attribute token 476 if ((lcnextst2.tokencode == ')') 477 || ((lcnextst2.tokencode == '(') && (lcnextst3 != null) && (lcnextst3.tokencode == TBaseType.iconst))) { // hire_date (time(6)) 478 // (date) 479 // select (date) from t, here (date) is a function, not a data conversion, 480 // But if prev token is identifier like TD_WEDNESDAY (no space before parenthesis), treat as function call 481 // mantisbt/view.php?id=4023 482 // f3 (date) - with space - is data conversion 483 // TD_WEDNESDAY(date) - no space - is function call 484 if ((lcprevst != null) && (lcprevst.tokencode == TBaseType.ident) && (lcnextst2.tokencode == ')')) { 485 // Check if there's whitespace between identifier and '(' 486 // If identifier ends at column X and '(' starts at column X+1, there's no space 487 long identEndCol = lcprevst.columnNo + lcprevst.toString().length(); 488 if (identEndCol == ast.columnNo) { 489 // No space between identifier and '(' - treat as function call 490 ast.tokencode = '('; 491 } 492 // If there's a space, keep as DATA_CONVERSION for data conversion pattern 493 } 494 } else { 495 ast.tokencode = '('; 496 } 497 break; 498 case timestamp_t: 499 case interval_t: 500 if (lcnextst2.tokencode == TBaseType.sconst) { // INSERT t1 (TIME '10:44:25.123-08:00',TIMESTAMP '2000-09-20 10:44:25.1234') 501 ast.tokencode = '('; 502 } 503 break; 504 case period_t: 505 if (lcnextst2.tokencode == '(') { 506 // 只有 period() 才确保这里 period 是datatype,否则period不是datatype 507 } else { 508 ast.tokencode = '('; 509 } 510 break; 511 case char_t: 512 if (lcnextst2.tokencode == ')') { 513 // NULL (CHAR) AS B 514 } else if ((lcnextst3 == null) || (lcnextst3.tokencode != TBaseType.iconst)) { // INSERT t1 (TIME '10:44:25.123-08:00',TIMESTAMP '2000-09-20 10:44:25.1234') 515 ast.tokencode = '('; 516 } 517 break; 518 default: 519 break; 520 } 521 } 522 523 private void handleForToken(TSourceToken ast) { 524 TSourceToken nextToken = ast.searchTokenAfterObjectName(); 525 if (nextToken != null) { 526 if (nextToken.tokencode == TBaseType.rrw_as) { 527 ast.tokencode = TBaseType.rrw_teradata_for_loop; 528 } 529 } 530 } 531 532 private void handleLastToken(TSourceToken ast) { 533 TSourceToken nextToken = ast.searchToken('(', 1); 534 if (nextToken != null) { 535 ast.tokencode = TBaseType.rrw_last_function; 536 } 537 } 538 539 private void handlePivotToken(TSourceToken ast) { 540 TSourceToken nextToken = ast.searchToken('(', 1); 541 if (nextToken == null) { 542 ast.tokencode = TBaseType.ident; 543 } 544 } 545 546 private void handlePeriodToken(TSourceToken ast) { 547 TSourceToken nextToken = ast.nextSolidToken(); 548 if (nextToken == null) { 549 ast.tokencode = TBaseType.ident; 550 } else if (nextToken.tokencode == '(') { 551 // keep it as keyword 552 } else if (nextToken.tokencode == TBaseType.rrw_for) { 553 // keep it as keyword 554 } else if (nextToken.tokencode == TBaseType.sconst) { 555 // sample: DEFAULT PERIOD '(2005-02-03, 2006-02-03)' 556 // keep it as keyword 557 } else { 558 if (ast.prevSolidToken() == null) { 559 ast.tokencode = TBaseType.ident; 560 } else { 561 if (!ast.prevSolidToken().toString().equalsIgnoreCase("anchor")) { 562 ast.tokencode = TBaseType.ident; 563 } 564 } 565 } 566 } 567 568 private void handleTransactionToken(TSourceToken ast) { 569 TSourceToken lcprevst = this.getprevsolidtoken(ast); 570 if (lcprevst != null) { 571 if (lcprevst.tokencode == TBaseType.rrw_end) { 572 lcprevst.tokencode = TBaseType.rrw_teradata_end_t; 573 } 574 } 575 } 576 577 private void handleReplaceToken(TSourceToken ast) { 578 TSourceToken nextToken = ast.searchToken('(', 1); 579 if (nextToken != null) { 580 ast.tokencode = TBaseType.ident; 581 } 582 } 583 584 private void handleBetweenToken(TSourceToken ast) { 585 TSourceToken nextToken = ast.nextSolidToken(); 586 if (nextToken != null) { 587 if ((nextToken.tokencode == TBaseType.rrw_begin) || (nextToken.tokencode == TBaseType.rrw_end)) { 588 // BETWEEN begin(DODD_EFF_PERI) 589 nextToken.tokencode = TBaseType.ident; 590 } 591 } 592 } 593 594 private void handleDeclareToken(TSourceToken ast) { 595 TSourceToken nextToken = ast.nextSolidToken(); 596 if (nextToken != null) { 597 TSourceToken nextnextToken = nextToken.nextSolidToken(); 598 if (nextnextToken != null) { 599 if ((nextnextToken.toString().equalsIgnoreCase("cursor")) 600 || (nextnextToken.toString().equalsIgnoreCase("insensitive")) 601 || (nextnextToken.toString().equalsIgnoreCase("scroll")) 602 || (nextnextToken.toString().equalsIgnoreCase("no"))) { 603 nextToken.tokencode = TBaseType.rrw_teradata_cursor_name; 604 } else if ((nextnextToken.toString().equalsIgnoreCase("condition"))) { 605 nextToken.tokencode = TBaseType.rrw_teradata_condition_name; 606 } 607 } 608 } 609 } 610 611 private void handleCaseToken(TSourceToken ast) { 612 int lcNest = 1; 613 for (int m = ast.posinlist + 1; m < this.sourcetokenlist.size() - 1; m++) { 614 TSourceToken st = this.sourcetokenlist.get(m); 615 if (st.tokencode == TBaseType.rrw_case) { 616 st.tag = 1; // this is nested case keyword, don't check this token later 617 lcNest++; 618 } 619 if (st.tokencode == TBaseType.rrw_end) { 620 lcNest--; 621 if (lcNest == 0) { 622 TSourceToken caseToken = st.nextSolidToken(); 623 if (caseToken != null) { 624 if (caseToken.tokencode == TBaseType.rrw_case) { 625 ast.tokencode = TBaseType.rrw_teradata_case_stmt; 626 caseToken.tag = 1; // this is case after end, don't check this token later 627 } 628 } 629 // Always break after finding the matching END, whether it's followed by CASE or not 630 // This prevents CASE expressions from incorrectly matching with later "END CASE" constructs 631 break; 632 } 633 } 634 } 635 } 636 637 private void handleGrantToken(TSourceToken ast) { 638 TSourceToken prevSolidToken = ast.prevSolidToken(); 639 if (prevSolidToken != null) { 640 if (prevSolidToken.tokencode == TBaseType.rrw_with) { 641 prevSolidToken.tokencode = TBaseType.rrw_teradata_with_grant; 642 } 643 } 644 } 645 646 private void handleVariableToken(TSourceToken ast) { 647 // USING ( _spVV8 VARCHAR(1024) CHARACTER SET UNICODE ) SELECT INTO :_spVV8 ; 648 // variable after into keyword treat as identifier 649 TSourceToken prevSolidToken = ast.prevSolidToken(); 650 if (prevSolidToken != null) { 651 if (prevSolidToken.tokencode == TBaseType.rrw_into) { 652 ast.tokencode = TBaseType.ident; 653 } 654 } 655 } 656 657 private void handleSequencedToken(TSourceToken ast) { 658 TSourceToken nextSolidToken = ast.nextSolidToken(); 659 if (nextSolidToken != null) { 660 if ((nextSolidToken.tokencode == TBaseType.rrw_teradata_validtime)) { 661 TSourceToken nextToken2 = nextSolidToken.nextSolidToken(); 662 if (nextToken2 != null) { 663 if ((nextToken2.tokencode == TBaseType.rrw_select) 664 || (nextToken2.tokencode == TBaseType.rrw_insert) 665 || (nextToken2.tokencode == TBaseType.rrw_update) 666 || (nextToken2.tokencode == TBaseType.rrw_delete) 667 || (nextToken2.tokencode == TBaseType.rrw_merge)) { 668 // SEQUENCED VALIDTIME select/insert/update/delete/merge 669 ast.tokencode = TBaseType.lexspace; 670 nextSolidToken.tokencode = TBaseType.lexspace; 671 } 672 } 673 } 674 } 675 } 676 677 private EFindSqlStateType handleMultiLoadCmdState(TSourceToken ast, EFindSqlStateType gst, SqlParseResult.Builder builder) { 678 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 679 if ((ast.tokencode == ';') && (ast.isLastTokenOfLine())) { 680 TSourceToken nextToken = ast.nextSolidToken(); 681 TSourceToken nextToken2 = nextToken != null ? nextToken.nextSolidToken() : null; 682 if (nextToken != null && nextToken2 != null && 683 nextToken.tokencode == '.' && 684 nextToken2.toString().equalsIgnoreCase("FIELD") && 685 nextToken.isFirstTokenOfLine()) { 686 // Remain in stMultiLoadCmd state 687 } else { 688 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 689 gst = EFindSqlStateType.stnormal; 690 } 691 } else if (ast.isLastTokenOfLine()) { 692 // .IF ERRORCODE <> 0 THEN 693 // INSERT INTO Sou_EMP_Tab 694 // (1, 'bala'); 695 String cmdstr = this.gcurrentsqlstatement.sourcetokenlist.get(0).toString(); 696 if (this.gcurrentsqlstatement.sourcetokenlist.size() > 1) { 697 cmdstr = cmdstr + this.gcurrentsqlstatement.sourcetokenlist.get(1).toString(); 698 } 699 if ((cmdstr.toLowerCase().startsWith(".if")) || (cmdstr.toLowerCase().startsWith(".set")) || (cmdstr.toLowerCase().startsWith("set"))) { 700 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 701 gst = EFindSqlStateType.stnormal; 702 } 703 } 704 return gst; 705 } 706 707 private EFindSqlStateType handleFastExportCmdState(TSourceToken ast, EFindSqlStateType gst, SqlParseResult.Builder builder) { 708 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 709 if ((ast.tokencode == ';') && (ast.isLastTokenOfLine())) { 710 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 711 gst = EFindSqlStateType.stnormal; 712 } else { 713 boolean findSQL = false; 714 TSourceToken nextst = ast.nextToken(); 715 if (nextst != null) { 716 if (nextst.tokentype == ETokenType.ttreturn) { 717 findSQL = (this.sqlcmds.issql(ast.nextSolidToken(), gst, this.gcurrentsqlstatement) != null); 718 if (findSQL) { 719 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 720 gst = EFindSqlStateType.stnormal; 721 } 722 } 723 } 724 } 725 return gst; 726 } 727 728 private EFindSqlStateType handleFastLoadCmdState(TSourceToken ast, EFindSqlStateType gst, SqlParseResult.Builder builder) { 729 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 730 if ((ast.tokencode == ';') && (ast.isLastTokenOfLine())) { 731 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 732 gst = EFindSqlStateType.stnormal; 733 } else if (ast.tokencode == TBaseType.lexnewline) { 734 TSourceToken nextst = ast.nextSolidToken(); 735 if (nextst != null) { 736 if (nextst.tokencode == TBaseType.BTEQCMD) { 737 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 738 gst = EFindSqlStateType.stFastLoadCmd; 739 } else if (nextst.tokencode == '.') { 740 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 741 gst = EFindSqlStateType.stFastLoadCmd; 742 } else if (this.sqlcmds.issql(nextst, gst, this.gcurrentsqlstatement) != null) { 743 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 744 gst = EFindSqlStateType.stnormal; 745 } 746 } 747 } 748 return gst; 749 } 750 751 private EFindSqlStateType handleBTEQCmdState(TSourceToken ast, SqlParseResult.Builder builder) { 752 EFindSqlStateType gst = EFindSqlStateType.stBTEQCmd; 753 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 754 755 if (ast.tokencode == TBaseType.lexnewline) { 756 if (this.isContinueBTEQCmd) { 757 this.isContinueBTEQCmd = false; 758 } else if (this.isInIfThenStatement) { 759 // Continue collecting tokens for .IF/.ELSEIF THEN until semicolon 760 // Don't complete the statement on newline 761 } else { 762 if (((TTeradataBTEQCmd)this.gcurrentsqlstatement).getBteqCmdType() == BteqCmdType.LOGON) { 763 boolean findSQL = (this.sqlcmds.issql(ast.nextSolidToken(), gst, this.gcurrentsqlstatement) != null); 764 if (findSQL) { 765 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 766 gst = EFindSqlStateType.stnormal; 767 } 768 } else { 769 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 770 gst = EFindSqlStateType.stnormal; 771 } 772 } 773 } else if ((ast.tokencode == '-') && (ast.isLastTokenOfLine())) { 774 if (!this.inBTEQComment) { 775 this.isContinueBTEQCmd = true; 776 } 777 } else if (ast.tokencode == TBaseType.lexspace) { 778 // Do nothing 779 } else if (ast.tokencode == ';') { 780 // Reset IF THEN state when statement ends 781 this.isInIfThenStatement = false; 782 this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder); 783 boolean findNewCmdInSameLine = this.checkForNewBTEQCmdInSameLine(ast); 784 if (findNewCmdInSameLine) { 785 gst = EFindSqlStateType.stBTEQCmd; 786 } else { 787 gst = EFindSqlStateType.stnormal; 788 } 789 } else if (ast.tokencode == '*') { 790 this.isContinueBTEQCmd = false; 791 } else { // solid token 792 // Check if this is a THEN keyword at end of line for .IF/.ELSEIF commands 793 // In this case, the BTEQ command should continue to include the following SQL statement 794 BteqCmdType cmdType = ((TTeradataBTEQCmd)this.gcurrentsqlstatement).getBteqCmdType(); 795 if ((cmdType == BteqCmdType.IF || cmdType == BteqCmdType.ELSEIF) 796 && ast.tokencode == TBaseType.rrw_then 797 && ast.isLastTokenOfLine()) { 798 this.isContinueBTEQCmd = true; 799 this.isInIfThenStatement = true; 800 } else { 801 this.isContinueBTEQCmd = false; 802 } 803 } 804 return gst; 805 } 806 807 private boolean checkForNewBTEQCmdInSameLine(TSourceToken ast) { 808 boolean findNewCmdInSameLine = false; 809 if (!ast.isLastTokenOfLine()) { 810 // check if next cmd like below: 811 // .SET SIDETITLES ON; .SET FOLDLINE ON ALL 812 TSourceToken nextst = ast.nextSolidToken(); 813 if ((nextst != null) && (nextst.tokencode == '.')) { 814 TSourceToken nextst2 = nextst.nextSolidToken(); 815 TSourceToken searchToken = null; 816 if (nextst2 != null) { 817 if (nextst2.tokencode == TBaseType.rrw_set) { 818 TSourceToken nextst3 = nextst2.nextSolidToken(); 819 if (nextst3 != null) { 820 searchToken = nextst3; 821 } 822 } else { 823 searchToken = nextst2; 824 } 825 826 BteqCmdType bteqCmdType = BteqCmdType.searchBteqCmd(searchToken); 827 if (bteqCmdType != null) { 828 this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor); 829 ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setBteqCmdType(bteqCmdType); 830 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 831 findNewCmdInSameLine = true; 832 } 833 } 834 } 835 } 836 return findNewCmdInSameLine; 837 } 838 839 private EFindSqlStateType handleNormalState(TSourceToken ast, EFindSqlStateType gst, TSourceToken lcprevsolidtoken, SqlParseResult.Builder builder) { 840 if ((ast.tokencode == TBaseType.cmtdoublehyphen) 841 || (ast.tokencode == TBaseType.cmtslashstar) 842 || (ast.tokencode == TBaseType.lexspace) 843 || (ast.tokencode == TBaseType.lexnewline) 844 || (ast.tokentype == ETokenType.ttsemicolon)) { 845 if (TBaseType.assigned(this.gcurrentsqlstatement)) { 846 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 847 } 848 849 if ((lcprevsolidtoken != null) && (ast.tokentype == ETokenType.ttsemicolon)) { 850 if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) { 851 // ;;;; continuous semicolon, treat it as comment 852 ast.tokentype = ETokenType.ttsimplecomment; 853 ast.tokencode = TBaseType.cmtdoublehyphen; 854 } 855 } 856 857 return gst; 858 } 859 if ((gst = this.checkForBTEQOrUtilityCommand(ast, gst)) != EFindSqlStateType.stnormal) { 860 return gst; 861 } 862 863 // find a tokentext to start sql or stored procedure mode 864 this.gcurrentsqlstatement = this.sqlcmds.issql(ast, gst, this.gcurrentsqlstatement); 865 866 if (TBaseType.assigned(this.gcurrentsqlstatement)) { 867 ESqlStatementType[] ses = {ESqlStatementType.sstcreateprocedure, ESqlStatementType.sstteradatacreatefunction, ESqlStatementType.sstcreatetrigger}; 868 if (this.includesqlstatementtype(this.gcurrentsqlstatement.sqlstatementtype, ses)) { 869 gst = EFindSqlStateType.ststoredprocedure; 870 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 871 if ((this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 872 || (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstteradatacreatefunction) 873 || (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatetrigger)) { 874 this.curdelimiterchar = ';'; 875 } 876 } else { 877 gst = EFindSqlStateType.stsql; 878 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 879 } 880 } 881 882 if ((!TBaseType.assigned(this.gcurrentsqlstatement)) && (ast.isFirstTokenOfLine())) { 883 gst = this.flexer.cmdType(ast); 884 if ((gst == EFindSqlStateType.stMultiLoadCmd) || (gst == EFindSqlStateType.stFastLoadCmd) || (gst == EFindSqlStateType.stFastExportCmd)) { 885 this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor); 886 ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst); 887 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 888 return gst; 889 } 890 gst = EFindSqlStateType.stnormal; 891 } 892 893 if (!TBaseType.assigned(this.gcurrentsqlstatement)) { // error tokentext found 894 this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo), 895 "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist)); 896 897 ast.tokentype = ETokenType.tttokenlizererrortoken; 898 gst = EFindSqlStateType.sterror; 899 900 this.gcurrentsqlstatement = new TUnknownSqlStatement(this.vendor); 901 this.gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid; 902 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 903 } 904 return gst; 905 } 906 907 private EFindSqlStateType checkForBTEQOrUtilityCommand(TSourceToken ast, EFindSqlStateType gst) { 908 // Check for .bteq commands: either "." at start of line, or "." after ";" at start of line 909 boolean isDotAtStartOfLine = (ast.tokencode == '.') && (ast.isFirstTokenOfLine()); 910 boolean isDotAfterSemicolonAtStartOfLine = false; 911 if ((ast.tokencode == '.') && !isDotAtStartOfLine) { 912 TSourceToken prevToken = ast.prevSolidToken(); 913 if ((prevToken != null) && (prevToken.tokencode == ';') && (prevToken.isFirstTokenOfLine())) { 914 isDotAfterSemicolonAtStartOfLine = true; 915 } 916 } 917 918 if (isDotAtStartOfLine || isDotAfterSemicolonAtStartOfLine) { 919 // .bteq commands 920 TSourceToken nextst = ast.nextSolidToken(); 921 if (nextst != null) { 922 gst = this.flexer.cmdType(nextst); 923 boolean foundCmd = false; 924 switch (gst) { 925 case stMultiLoadCmd: 926 this.gcurrentsqlstatement = new TTeradataMultiLoadCmd(this.vendor); 927 gst = EFindSqlStateType.stMultiLoadCmd; 928 ((TTeradataMultiLoadCmd)this.gcurrentsqlstatement).setCmdType(TTeradataHelper.searchMultiLoadTypeByName(nextst.getAstext())); 929 foundCmd = true; 930 break; 931 case stFastExportCmd: 932 this.gcurrentsqlstatement = new TTeradataFastExportCmd(this.vendor); 933 gst = EFindSqlStateType.stFastExportCmd; 934 foundCmd = true; 935 break; 936 case stFastLoadCmd: 937 this.gcurrentsqlstatement = new TTeradataFastLoadCmd(this.vendor); 938 gst = EFindSqlStateType.stFastLoadCmd; 939 foundCmd = true; 940 break; 941 case stBTEQCmd: 942 this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor); 943 ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setBteqCmdType(BteqCmdType.searchBteqCmd(nextst)); 944 gst = EFindSqlStateType.stBTEQCmd; 945 foundCmd = true; 946 break; 947 default: 948 break; 949 } 950 if (foundCmd) { 951 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 952 return gst; 953 } 954 } 955 } else if ((ast.tokencode == '*') && (ast.isFirstTokenOfLine())) { 956 // BTEQ comment: * comment 957 gst = EFindSqlStateType.stBTEQCmd; 958 this.inBTEQComment = true; // Mark that we're in a BTEQ comment 959 this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor); 960 ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setBteqCmdType(BteqCmdType.COMMENT); 961 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 962 return gst; 963 } else if ((ast.tokencode == '=') && (ast.isFirstTokenOfLine())) { 964 // BTEQ command starting with = 965 TSourceToken st1 = ast.prevSolidToken(); 966 if ((st1 != null) && (st1.tokencode == ';')) { 967 gst = EFindSqlStateType.stBTEQCmd; 968 this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor); 969 ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst); 970 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 971 return gst; 972 } 973 } else if ((ast.isFirstTokenOfLine()) && (BteqCmdType.searchBteqCmd(ast) != null)) { 974 TSourceToken st1 = ast.prevSolidToken(); 975 if ((st1 != null) && (st1.tokencode == ';')) { 976 gst = EFindSqlStateType.stBTEQCmd; 977 this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor); 978 ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst); 979 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 980 return gst; 981 } 982 } else if ((ast.tokencode == '&') && (ast.isFirstTokenOfLine())) { 983 // Teradata macro/substitution variable: &VARIABLE_NAME at start of line 984 // Treat it as a BTEQ-like command that ends at end of line 985 TSourceToken nextst = ast.nextSolidToken(); 986 if (nextst != null && (nextst.tokencode == TBaseType.ident || nextst.tokentype == ETokenType.ttidentifier)) { 987 gst = EFindSqlStateType.stBTEQCmd; 988 this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor); 989 ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst); 990 this.gcurrentsqlstatement.sourcetokenlist.add(ast); 991 return gst; 992 } 993 } 994 return EFindSqlStateType.stnormal; 995 } 996 997 998 private boolean includesqlstatementtype(ESqlStatementType type, ESqlStatementType[] types) { 999 for (ESqlStatementType t : types) { 1000 if (type != t) continue; 1001 return true; 1002 } 1003 return false; 1004 } 1005 1006 @Override 1007 protected TStatementList performParsing(ParserContext context, TCustomParser parser, TCustomParser secondaryParser, TSourceTokenList tokens, TStatementList rawStatements) { 1008 this.fparser = (TParserTeradata)parser; 1009 this.sourcetokenlist = tokens; 1010 this.parserContext = context; 1011 this.sqlstatements = rawStatements; 1012 if (this.sqlstatements == null) { 1013 this.sqlstatements = new TStatementList(); 1014 return this.sqlstatements; 1015 } 1016 if (this.sqlcmds == null) { 1017 this.sqlcmds = SqlCmdsFactory.get(this.vendor); 1018 } 1019 this.fparser.sqlcmds = this.sqlcmds; 1020 1021 // Initialize global context for semantic analysis 1022 // CRITICAL: When delegated from TGSqlParser, use TGSqlParser's frameStack 1023 // so that variables set in SET statements can be found by EXECUTE statements 1024 if (context != null && context.getGsqlparser() != null) { 1025 gudusoft.gsqlparser.TGSqlParser gsqlparser = (gudusoft.gsqlparser.TGSqlParser) context.getGsqlparser(); 1026 this.frameStack = gsqlparser.getFrameStack(); 1027 1028 // CRITICAL: Set gsqlparser on the NodeFactory - matches TGSqlParser behavior 1029 // This is needed for proper AST node creation during parsing 1030 this.fparser.getNf().setGsqlParser(gsqlparser); 1031 1032 // Create global context if needed 1033 this.globalContext = new gudusoft.gsqlparser.compiler.TContext(); 1034 this.sqlEnv = new gudusoft.gsqlparser.sqlenv.TSQLEnv(this.vendor) { 1035 @Override 1036 public void initSQLEnv() { 1037 } 1038 }; 1039 this.globalContext.setSqlEnv(this.sqlEnv, this.sqlstatements); 1040 } else { 1041 this.initializeGlobalContext(); 1042 } 1043 1044 for (int i = 0; i < this.sqlstatements.size(); ++i) { 1045 TCustomSqlStatement stmt = this.sqlstatements.getRawSql(i); 1046 try { 1047 stmt.setFrameStack(this.frameStack); 1048 int parseResult = stmt.parsestatement(null, false, context.isOnlyNeedRawParseTree()); 1049 boolean doRecover = TBaseType.ENABLE_ERROR_RECOVER_IN_CREATE_TABLE; 1050 if (doRecover && (parseResult != 0 || stmt.getErrorCount() > 0)) { 1051 this.handleCreateTableErrorRecovery(stmt); 1052 } 1053 if (parseResult == 0 && stmt.getErrorCount() <= 0) continue; 1054 this.copyErrorsFromStatement(stmt); 1055 continue; 1056 } 1057 catch (Exception ex) { 1058 ex.printStackTrace(); 1059 this.handleStatementParsingException(stmt, i, ex); 1060 } 1061 } 1062 if (this.globalFrame != null) { 1063 this.globalFrame.popMeFromStack(this.frameStack); 1064 } 1065 return this.sqlstatements; 1066 } 1067 1068 private void handleCreateTableErrorRecovery(TCustomSqlStatement stmt) { 1069 if (!(stmt.sqlstatementtype != ESqlStatementType.sstcreatetable && stmt.sqlstatementtype != ESqlStatementType.sstcreateindex || TBaseType.c_createTableStrictParsing)) { 1070 int nested = 0; 1071 boolean isIgnore = false; 1072 boolean isFoundIgnoreToken = false; 1073 TSourceToken firstIgnoreToken = null; 1074 for (int k = 0; k < stmt.sourcetokenlist.size(); ++k) { 1075 TSourceToken st = stmt.sourcetokenlist.get(k); 1076 if (isIgnore) { 1077 if (st.issolidtoken() && st.tokencode != 59) { 1078 isFoundIgnoreToken = true; 1079 if (firstIgnoreToken == null) { 1080 firstIgnoreToken = st; 1081 } 1082 } 1083 if (st.tokencode == 59) continue; 1084 st.tokencode = 273; 1085 continue; 1086 } 1087 if (st.tokencode == 41 && --nested == 0) { 1088 isIgnore = true; 1089 } 1090 if (st.tokencode != 40) continue; 1091 ++nested; 1092 } 1093 if (isFoundIgnoreToken) { 1094 stmt.parsestatement(null, false, this.parserContext.isOnlyNeedRawParseTree()); 1095 } 1096 } 1097 } 1098 1099 @Override 1100 protected void performSemanticAnalysis(ParserContext context, TStatementList statements) { 1101 if (!TBaseType.isEnableResolver()) { 1102 return; 1103 } 1104 if (!this.getSyntaxErrors().isEmpty()) { 1105 return; 1106 } 1107 TSQLResolver resolver = new TSQLResolver(this.globalContext, statements); 1108 resolver.resolve(); 1109 } 1110 1111 @Override 1112 protected void performInterpreter(ParserContext context, TStatementList statements) { 1113 } 1114 1115 @Override 1116 public String toString() { 1117 return "TeradataSqlParser{vendor=" + (Object)((Object)this.vendor) + "}"; 1118 } 1119}