001package gudusoft.gsqlparser.stmt; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.compiler.TFrame; 005import gudusoft.gsqlparser.compiler.TVariable; 006import gudusoft.gsqlparser.nodes.*; 007 008/** 009 * A LOOP statement executes a sequence of statements multiple times. PL/SQL provides 010 * these loop statements: 011 * <ul> 012 * <li>Basic loop</li> 013 * <li>WHILE loop</li> 014 * <li>FOR loop 015 * <p>FOR indexName IN lower_bound .. upper_bound LOOP statements END LOOP 016 * </li> 017 * <li>Cursor FOR loop</li> 018 * </ul> 019 * 020 * @see TBlockSqlStatement#bodyStatements 021 */ 022 023public class TLoopStmt extends TBlockSqlStatement { 024 025 public final static int basic_loop = 1; 026 public final static int while_loop = 2; 027 public final static int for_loop = 3; 028 public final static int cursor_for_loop = 4; 029 030 private int kind = basic_loop; 031 032 public void setKind(int kind) { 033 this.kind = kind; 034 if (this.kind == cursor_for_loop){ 035 this.recordName = this.indexName; 036 } 037 } 038 039 /** 040 * 041 * @return What's kind of loop statement: simple, while or for. 042 043 */ 044 public int getKind() { 045 return kind; 046 } 047 048 public TLoopStmt(){ 049 this(EDbVendor.dbvoracle); 050 } 051 052 public TLoopStmt(EDbVendor dbvendor){ 053 super(dbvendor); 054 sqlstatementtype = ESqlStatementType.sst_loopstmt; 055 } 056 057 private TObjectNameList scalarVariables; 058 059 public TObjectNameList getScalarVariables() { 060 return scalarVariables; 061 } 062 063 /** 064 * An undeclared identifier that names the loop index. 065 * Or, it should be a record-name when kind is cursor_for_loop. 066 * @return Index name used in for-loop-statement. 067 */ 068 public TObjectName getIndexName() { 069 return indexName; 070 } 071 072 private TObjectName indexName = null; 073 074 /** 075 * Oracle 26 PAIRS OF second iterand (value iterand). 076 * Example: FOR i, j IN PAIRS OF collection LOOP ... END LOOP; 077 * where i is the index/key and j is the value. 078 */ 079 private TObjectName secondIndexName = null; 080 081 public void setSecondIndexName(TObjectName secondIndexName) { 082 this.secondIndexName = secondIndexName; 083 } 084 085 /** 086 * @return The second iterand name for PAIRS OF iteration, or null if not applicable. 087 */ 088 public TObjectName getSecondIndexName() { 089 return secondIndexName; 090 } 091 092 /** 093 * Oracle 26 typed iterand declaration in FOR LOOP. 094 * Example: FOR i NUMBER(5,1) IN 1.0..3.0 LOOP ... END LOOP; 095 */ 096 private TTypeName iterandType = null; 097 098 public void setIterandType(TTypeName iterandType) { 099 this.iterandType = iterandType; 100 } 101 102 /** 103 * @return The explicit type declaration for the iterand, or null if not specified. 104 */ 105 public TTypeName getIterandType() { 106 return iterandType; 107 } 108 109 public TObjectName getRecordName() { 110 return recordName; 111 } 112 113 private TObjectName recordName = null; 114 115 private TStatementListSqlNode stmts = null; 116 117 private TExpression lower_bound = null; 118 private TExpression upper_bound = null; 119 120 private boolean isReverse = false; 121 122 public void setReverse(boolean reverse) { 123 isReverse = reverse; 124 } 125 126 public boolean isReverse() { 127 128 return isReverse; 129 } 130 131 /** 132 * Used in for-loop-statement. 133 * @return 134 */ 135 public TExpression getUpper_bound() { 136 137 return upper_bound; 138 } 139 140 /** 141 * Used in for-loop-statement. 142 * @return 143 */ 144 public TExpression getLower_bound() { 145 146 return lower_bound; 147 } 148 149 150 151 public void setSubquery(TSelectSqlStatement subquery) { 152 this.subquery = subquery; 153 } 154 155 /** 156 * 157 * @return Select statement when {@link #kind} is cursor_for_loop. 158 */ 159 public TSelectSqlStatement getSubquery() { 160 return subquery; 161 } 162 163 private TSelectSqlStatement subquery = null; 164 private TSelectSqlNode selectSqlNode = null; 165 166 public void setSelectSqlNode(TSelectSqlNode selectSqlNode) { 167 this.selectSqlNode = selectSqlNode; 168 } 169 170 private TExpressionList cursorParameterNames = null; 171 172 public void setCursorParameterNames(TExpressionList cursorParameterNames) { 173 this.cursorParameterNames = cursorParameterNames; 174 } 175 176 /** 177 * 178 * @return Cursor parameter names when {@link #kind} is cursor_for_loop if any. 179 */ 180 public TExpressionList getCursorParameterNames() { 181 182 return cursorParameterNames; 183 } 184 185 void buildsql() { 186 } 187 188 void clear() { 189 } 190 191 String getasprettytext() { 192 return ""; 193 } 194 195 void iterate(TVisitorAbs pvisitor) { 196 } 197 198 public void init(Object arg1) 199 { 200 stmts = (TStatementListSqlNode)arg1; 201 } 202 203 public void init(Object arg1,Object arg2) 204 { 205 stmts = (TStatementListSqlNode)arg1; 206 if (arg2 instanceof TExpression){ 207 this.condition = (TExpression)arg2; 208 }else if (arg2 instanceof TObjectNameList){ 209 this.scalarVariables = (TObjectNameList) arg2; 210 this.indexName = this.scalarVariables.getObjectName(0); 211 }else{ 212 this.indexName = (TObjectName)arg2; 213 } 214 } 215 216 public void init(Object arg1,Object arg2,Object arg3) 217 { 218 init(arg1,arg2); 219 cursorName = (TObjectName)arg3; 220 } 221 222 public void init(Object arg1,Object arg2,Object arg3,Object arg4) 223 { 224 init(arg1,arg2); 225 226 lower_bound = (TExpression)arg3; 227 upper_bound = (TExpression)arg4; 228 } 229 230 /** 231 * 232 * @return Cursor name when {@link #kind} is cursor_for_loop. 233 */ 234 public TObjectName getCursorName() { 235 return cursorName; 236 } 237 238 private TObjectName cursorName = null; 239 240 241 /** 242 * Used in while-loop-statement 243 * @return If and only if the value of this expression is TRUE, 244 * the statements in while will execute. 245 */ 246 public TExpression getCondition() { 247 return condition; 248 } 249 250 private TExpression condition = null; 251 252 private TExpression executeExpr; 253 private TExpressionList executeUsingVars; 254 255 public void setExecuteExpr(TExpression executeExpr) { 256 this.executeExpr = executeExpr; 257 } 258 259 public void setExecuteUsingVars(TExpressionList executeUsingVars) { 260 this.executeUsingVars = executeUsingVars; 261 } 262 263 public TExpression getExecuteExpr() { 264 265 return executeExpr; 266 } 267 268 public TExpressionList getExecuteUsingVars() { 269 return executeUsingVars; 270 } 271 272 /** 273 * Oracle 26 WHILE predicate for FOR LOOP iteration control. 274 * Example: FOR i IN 1..10 WHILE i < 5 LOOP ... END LOOP; 275 */ 276 private TExpression whilePredicate; 277 278 public void setWhilePredicate(TExpression whilePredicate) { 279 this.whilePredicate = whilePredicate; 280 } 281 282 /** 283 * @return The WHILE predicate expression in FOR LOOP, or null if not specified. 284 */ 285 public TExpression getWhilePredicate() { 286 return whilePredicate; 287 } 288 289 /** 290 * Oracle 26 WHEN predicate for FOR LOOP iteration control. 291 * Example: FOR i IN 1..10 WHEN MOD(i,2)=0 LOOP ... END LOOP; 292 */ 293 private TExpression whenPredicate; 294 295 public void setWhenPredicate(TExpression whenPredicate) { 296 this.whenPredicate = whenPredicate; 297 } 298 299 /** 300 * @return The WHEN predicate expression in FOR LOOP, or null if not specified. 301 */ 302 public TExpression getWhenPredicate() { 303 return whenPredicate; 304 } 305 306 /** 307 * Oracle 26 BY step clause for FOR LOOP iteration control. 308 * Example: FOR i IN 1..10 BY 2 LOOP ... END LOOP; 309 */ 310 private TExpression stepExpression; 311 312 public void setStepExpression(TExpression stepExpression) { 313 this.stepExpression = stepExpression; 314 } 315 316 /** 317 * @return The BY step expression in FOR LOOP, or null if not specified. 318 */ 319 public TExpression getStepExpression() { 320 return stepExpression; 321 } 322 323 /** 324 * Oracle 26 multiple iteration controls for FOR LOOP. 325 * Example: FOR i IN 1..3, REVERSE i+1..i+10, 51..55 LOOP ... END LOOP; 326 */ 327 private TIterationControlList iterationControls; 328 329 public void setIterationControls(TIterationControlList iterationControls) { 330 this.iterationControls = iterationControls; 331 } 332 333 /** 334 * @return The list of iteration controls in FOR LOOP, or null if using legacy single iteration. 335 */ 336 public TIterationControlList getIterationControls() { 337 return iterationControls; 338 } 339 340 /** 341 * @return True if this FOR LOOP has multiple iteration controls. 342 */ 343 public boolean hasMultipleIterationControls() { 344 return iterationControls != null && iterationControls.size() > 1; 345 } 346 347 public int doParseStatement(TCustomSqlStatement psql) { 348 super.doParseStatement(psql); 349 this.stmtScope.setValidToDeclareVariable(true); 350 351 TFrame currentFrame = new TFrame(this.stmtScope); 352 currentFrame.pushMeToStack(getFrameStack()); 353 354 switch (dbvendor){ 355 case dbvmysql: 356 case dbvteradata: 357 case dbvbigquery: 358 case dbvsparksql: 359 if (rootNode == null) return -1; 360 TLoopSqlNode loopSqlNode = (TLoopSqlNode)rootNode; 361 setLabelName(loopSqlNode.getLabelName()); 362 363 loopSqlNode.getStmts().doParse(this,ESqlClause.unknown); 364 for(int i=0;i<loopSqlNode.getStmts().size();i++){ 365 this.getBodyStatements().add(loopSqlNode.getStmts().getStatementSqlNode(i).getStmt()); 366 } 367 break; 368 default: 369 //super.doParseStatement(psql); 370 371 if (indexName != null){ 372 this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjParameter,this, indexName)); 373 TVariable variable = new TVariable(indexName); 374 this.stmtScope.addSymbol(variable); 375 } 376 // Second iterand for PAIRS OF iteration (Oracle 26) 377 if (secondIndexName != null){ 378 this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjParameter,this, secondIndexName)); 379 TVariable variable2 = new TVariable(secondIndexName); 380 this.stmtScope.addSymbol(variable2); 381 } 382 if (this.condition != null){ 383 this.condition.doParse(this,ESqlClause.unknown); 384 } 385 if (this.whilePredicate != null){ 386 this.whilePredicate.doParse(this,ESqlClause.unknown); 387 } 388 if (this.whenPredicate != null){ 389 this.whenPredicate.doParse(this,ESqlClause.unknown); 390 } 391 if (this.stepExpression != null){ 392 this.stepExpression.doParse(this,ESqlClause.unknown); 393 } 394 // Parse iterand type if present (Oracle 26) 395 if (this.iterandType != null){ 396 this.iterandType.doParse(this,ESqlClause.unknown); 397 } 398 // Parse multiple iteration controls if present 399 if (this.iterationControls != null){ 400 for(int i=0;i<this.iterationControls.size();i++){ 401 TIterationControl ic = this.iterationControls.getIterationControl(i); 402 if (ic.getLowerBound() != null){ 403 ic.getLowerBound().doParse(this,ESqlClause.unknown); 404 } 405 if (ic.getUpperBound() != null){ 406 ic.getUpperBound().doParse(this,ESqlClause.unknown); 407 } 408 if (ic.getStepExpression() != null){ 409 ic.getStepExpression().doParse(this,ESqlClause.unknown); 410 } 411 if (ic.getWhilePredicate() != null){ 412 ic.getWhilePredicate().doParse(this,ESqlClause.unknown); 413 } 414 if (ic.getWhenPredicate() != null){ 415 ic.getWhenPredicate().doParse(this,ESqlClause.unknown); 416 } 417 } 418 } 419 if (this.executeExpr != null){ 420 this.executeExpr.doParse(this,ESqlClause.unknown); 421 } 422 if (this.executeUsingVars != null){ 423 for(int i=0;i<this.executeUsingVars.size();i++){ 424 this.executeUsingVars.getExpression(i).doParse(this,ESqlClause.unknown); 425 } 426 } 427 if (subquery != null){ 428 subquery.parsestatement(this,false); 429 }else if (selectSqlNode != null){ 430 //postgresql 431 subquery = new TSelectSqlStatement(this.dbvendor); 432 subquery.rootNode = selectSqlNode; 433 subquery.doParseStatement(this); 434 } 435 436 stmts.doParse(this,ESqlClause.unknown); 437 for(int i=0;i<stmts.size();i++){ 438 this.getBodyStatements().add(stmts.getStatementSqlNode(i).getStmt()); 439 } 440 if (secondIndexName != null) { 441 this.getTopStatement().getSymbolTable().pop(); 442 } 443 if (indexName != null) { 444 this.getTopStatement().getSymbolTable().pop(); 445 } 446 447 break; 448 } 449 450 currentFrame.popMeFromStack(getFrameStack()); 451 452 return 0; 453 } 454 455 public void accept(TParseTreeVisitor v){ 456 v.preVisit(this); 457 v.postVisit(this); 458 } 459 460 public void acceptChildren(TParseTreeVisitor v){ 461 v.preVisit(this); 462 if (this.condition != null) condition.acceptChildren(v); 463 if (this.whilePredicate != null) whilePredicate.acceptChildren(v); 464 if (this.whenPredicate != null) whenPredicate.acceptChildren(v); 465 if (this.stepExpression != null) stepExpression.acceptChildren(v); 466 if (this.iterandType != null) iterandType.acceptChildren(v); 467 if (this.iterationControls != null) iterationControls.acceptChildren(v); 468 if (this.executeExpr != null) executeExpr.acceptChildren(v); 469 if (this.executeUsingVars != null) executeUsingVars.acceptChildren(v); 470 if (subquery != null) subquery.acceptChildren(v); 471 getBodyStatements().acceptChildren(v); 472 v.postVisit(this); 473 } 474 475 public void setIndexName(TObjectName indexName) { 476 this.indexName = indexName; 477 } 478 479 public void setRecordName(TObjectName recordName) { 480 this.recordName = recordName; 481 } 482 483 public void setLower_bound(TExpression lower_bound) { 484 this.lower_bound = lower_bound; 485 } 486 487 public void setUpper_bound(TExpression upper_bound) { 488 this.upper_bound = upper_bound; 489 } 490 491 public void setCursorName(TObjectName cursorName) { 492 this.cursorName = cursorName; 493 } 494 495 public void setCondition(TExpression condition) { 496 this.condition = condition; 497 } 498}