1 /* Copyright (c) 2001-2016, The HSQL Development Group 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of the HSQL Development Group nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, 22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32 package org.hsqldb; 33 34 import org.hsqldb.HsqlNameManager.HsqlName; 35 import org.hsqldb.HsqlNameManager.SimpleName; 36 import org.hsqldb.error.Error; 37 import org.hsqldb.error.ErrorCode; 38 import org.hsqldb.lib.ArrayUtil; 39 import org.hsqldb.lib.HsqlArrayList; 40 import org.hsqldb.lib.HsqlList; 41 import org.hsqldb.lib.LongDeque; 42 import org.hsqldb.lib.OrderedHashSet; 43 import org.hsqldb.lib.OrderedIntHashSet; 44 import org.hsqldb.result.ResultProperties; 45 import org.hsqldb.types.ArrayType; 46 import org.hsqldb.types.RowType; 47 import org.hsqldb.types.Type; 48 import org.hsqldb.types.Types; 49 50 /** 51 * Parser for SQL stored procedures and functions - PSM 52 * 53 * @author Fred Toussi (fredt@users dot sourceforge.net) 54 * @version 2.3.4 55 * @since 1.9.0 56 */ 57 public class ParserRoutine extends ParserTable { 58 ParserRoutine(Session session, Scanner t)59 ParserRoutine(Session session, Scanner t) { 60 super(session, t); 61 } 62 compileOpenCursorStatement(StatementCompound context)63 Statement compileOpenCursorStatement(StatementCompound context) { 64 65 readThis(Tokens.OPEN); 66 checkIsSimpleName(); 67 68 String tokenString = token.tokenString; 69 70 read(); 71 72 for (int i = 0; i < context.cursors.length; i++) { 73 if (context.cursors[i].getCursorName().name.equals(tokenString)) { 74 return context.cursors[i]; 75 } 76 } 77 78 throw Error.parseError(ErrorCode.X_34000, null, 79 scanner.getLineNumber()); 80 } 81 compileSelectSingleRowStatement(RangeGroup[] rangeGroups)82 Statement compileSelectSingleRowStatement(RangeGroup[] rangeGroups) { 83 84 OrderedHashSet variableNames = new OrderedHashSet(); 85 Type[] targetTypes; 86 LongDeque colIndexList = new LongDeque(); 87 QuerySpecification select; 88 89 compileContext.setOuterRanges(rangeGroups); 90 91 select = XreadSelect(); 92 93 readThis(Tokens.INTO); 94 95 RangeVariable[] ranges = rangeGroups[0].getRangeVariables(); 96 97 readTargetSpecificationList(variableNames, ranges, colIndexList); 98 XreadTableExpression(select); 99 select.setReturningResult(); 100 101 int[] columnMap = new int[colIndexList.size()]; 102 103 colIndexList.toArray(columnMap); 104 105 Expression[] variables = new Expression[variableNames.size()]; 106 107 variableNames.toArray(variables); 108 109 targetTypes = new Type[variables.length]; 110 111 for (int i = 0; i < variables.length; i++) { 112 if (variables[i].getColumn().getParameterMode() 113 == SchemaObject.ParameterModes.PARAM_IN) { 114 115 // todo - use more specific error message 116 throw Error.parseError(ErrorCode.X_0U000, null, 117 scanner.getLineNumber()); 118 } 119 120 targetTypes[i] = variables[i].getDataType(); 121 } 122 123 select.setReturningResult(); 124 select.resolve(session, rangeGroups, targetTypes); 125 126 if (select.getColumnCount() != variables.length) { 127 throw Error.error(ErrorCode.X_42564, Tokens.T_INTO); 128 } 129 130 Statement statement = new StatementSet(session, variables, select, 131 columnMap, compileContext); 132 133 return statement; 134 } 135 136 /** 137 * Creates GET DIAGNOSTICS. 138 */ compileGetStatement(RangeGroup[] rangeGroups)139 Statement compileGetStatement(RangeGroup[] rangeGroups) { 140 141 read(); 142 readThis(Tokens.DIAGNOSTICS); 143 144 OrderedHashSet targetSet = new OrderedHashSet(); 145 HsqlArrayList exprList = new HsqlArrayList(); 146 LongDeque colIndexList = new LongDeque(); 147 RangeVariable[] rangeVars = rangeGroups[0].getRangeVariables(); 148 149 readGetClauseList(rangeVars, targetSet, colIndexList, exprList); 150 151 if (exprList.size() > 1) { 152 throw Error.parseError(ErrorCode.X_42602, null, 153 scanner.getLineNumber()); 154 } 155 156 Expression expression = (Expression) exprList.get(0); 157 158 if (expression.getDegree() != targetSet.size()) { 159 throw Error.error(ErrorCode.X_42546, Tokens.T_SET); 160 } 161 162 int[] columnMap = new int[colIndexList.size()]; 163 164 colIndexList.toArray(columnMap); 165 166 Expression[] targets = new Expression[targetSet.size()]; 167 168 targetSet.toArray(targets); 169 170 for (int i = 0; i < targets.length; i++) { 171 resolveOuterReferencesAndTypes(rangeGroups, targets[i]); 172 } 173 174 resolveOuterReferencesAndTypes(rangeGroups, expression); 175 176 for (int i = 0; i < targets.length; i++) { 177 if (targets[i].getColumn().getParameterMode() 178 == SchemaObject.ParameterModes.PARAM_IN) { 179 180 // todo - use more specific error message 181 throw Error.parseError(ErrorCode.X_0U000, null, 182 scanner.getLineNumber()); 183 } 184 185 if (!targets[i].getDataType().canBeAssignedFrom( 186 expression.getNodeDataType(i))) { 187 throw Error.parseError(ErrorCode.X_42561, null, 188 scanner.getLineNumber()); 189 } 190 } 191 192 StatementSet cs = new StatementSet(session, targets, expression, 193 columnMap, compileContext); 194 195 return cs; 196 } 197 198 /** 199 * Creates SET Statement for PSM or session variables from this parse context. 200 */ compileSetStatement(RangeGroup[] rangeGroups, RangeVariable[] rangeVars)201 StatementSet compileSetStatement(RangeGroup[] rangeGroups, 202 RangeVariable[] rangeVars) { 203 204 OrderedHashSet targetSet = new OrderedHashSet(); 205 HsqlArrayList exprList = new HsqlArrayList(); 206 LongDeque colIndexList = new LongDeque(); 207 208 readSetClauseList(rangeVars, targetSet, colIndexList, exprList); 209 210 if (exprList.size() > 1) { 211 throw Error.parseError(ErrorCode.X_42602, null, 212 scanner.getLineNumber()); 213 } 214 215 Expression expression = (Expression) exprList.get(0); 216 217 if (expression.getDegree() != targetSet.size()) { 218 throw Error.error(ErrorCode.X_42546, Tokens.T_SET); 219 } 220 221 int[] columnMap = new int[colIndexList.size()]; 222 223 colIndexList.toArray(columnMap); 224 225 Expression[] targets = new Expression[targetSet.size()]; 226 227 targetSet.toArray(targets); 228 229 for (int i = 0; i < targets.length; i++) { 230 resolveOuterReferencesAndTypes(rangeGroups, targets[i]); 231 } 232 233 resolveOuterReferencesAndTypes(rangeGroups, expression); 234 235 for (int i = 0; i < targets.length; i++) { 236 ColumnSchema col = targets[i].getColumn(); 237 238 if (col.getParameterMode() 239 == SchemaObject.ParameterModes.PARAM_IN) { 240 241 // todo - use more specific error message 242 throw Error.error(ErrorCode.X_0U000, 243 col.getName().statementName); 244 } 245 246 if (!targets[i].getDataType().canBeAssignedFrom( 247 expression.getNodeDataType(i))) { 248 throw Error.parseError(ErrorCode.X_42561, null, 249 scanner.getLineNumber()); 250 } 251 } 252 253 StatementSet cs = new StatementSet(session, targets, expression, 254 columnMap, compileContext); 255 256 return cs; 257 } 258 259 /** 260 * Creates SET Statement for a trigger row from this parse context. 261 */ compileTriggerSetStatement(Table table, RangeGroup[] rangeGroups)262 StatementDMQL compileTriggerSetStatement(Table table, 263 RangeGroup[] rangeGroups) { 264 265 Expression[] updateExpressions; 266 int[] columnMap; 267 OrderedHashSet targetSet = new OrderedHashSet(); 268 HsqlArrayList exprList = new HsqlArrayList(); 269 RangeVariable[] targetRangeVars = new RangeVariable[]{ 270 rangeGroups[0].getRangeVariables()[TriggerDef.NEW_ROW] }; 271 LongDeque colIndexList = new LongDeque(); 272 273 readSetClauseList(targetRangeVars, targetSet, colIndexList, exprList); 274 275 columnMap = new int[colIndexList.size()]; 276 277 colIndexList.toArray(columnMap); 278 279 Expression[] targets = new Expression[targetSet.size()]; 280 281 targetSet.toArray(targets); 282 283 for (int i = 0; i < targets.length; i++) { 284 resolveOuterReferencesAndTypes(RangeGroup.emptyArray, targets[i]); 285 } 286 287 updateExpressions = new Expression[exprList.size()]; 288 289 exprList.toArray(updateExpressions); 290 resolveUpdateExpressions(table, RangeGroup.emptyGroup, columnMap, 291 updateExpressions, rangeGroups); 292 293 StatementDMQL cs = new StatementSet(session, targets, table, 294 rangeGroups[0].getRangeVariables(), 295 columnMap, updateExpressions, 296 compileContext); 297 298 return cs; 299 } 300 compileAlterSpecificRoutine()301 StatementSchema compileAlterSpecificRoutine() { 302 303 boolean restrict = false; 304 305 readThis(Tokens.SPECIFIC); 306 readThis(Tokens.ROUTINE); 307 308 Routine routine = 309 (Routine) readSchemaObjectName(SchemaObject.SPECIFIC_ROUTINE); 310 311 routine = routine.duplicate(); 312 313 readRoutineCharacteristics(routine); 314 315 restrict = readIfThis(Tokens.RESTRICT); 316 317 if (restrict) { 318 OrderedHashSet set = database.schemaManager.getReferencesTo( 319 routine.getSpecificName()); 320 321 if (!set.isEmpty()) { 322 throw Error.parseError(ErrorCode.X_42502, null, 323 scanner.getLineNumber()); 324 } 325 } 326 327 if (token.tokenType == Tokens.BODY) { 328 read(); 329 } else if (token.tokenType == Tokens.NAME) { 330 read(); 331 } 332 333 readRoutineBody(routine); 334 routine.resetAlteredRoutineSettings(); 335 routine.resolve(session); 336 337 Object[] args = new Object[]{ routine }; 338 String sql = getLastPart(); 339 StatementSchema cs = new StatementSchema(sql, 340 StatementTypes.ALTER_ROUTINE, args, null, 341 database.schemaManager.getCatalogNameArray()); 342 343 return cs; 344 } 345 346 // SQL-invoked routine compileCreateProcedureOrFunction(boolean orReplace)347 StatementSchema compileCreateProcedureOrFunction(boolean orReplace) { 348 349 Routine routine = readCreateProcedureOrFunction(); 350 Object[] args = new Object[]{ routine }; 351 String sql = getLastPart(); 352 StatementSchema cs = new StatementSchema(sql, 353 StatementTypes.CREATE_ROUTINE, args, null, 354 database.schemaManager.getCatalogNameArray()); 355 356 return cs; 357 } 358 readCreateProcedureOrFunction()359 Routine readCreateProcedureOrFunction() { 360 361 Routine routine = readProcedureOrFunctionDeclaration(); 362 363 readRoutineBody(routine); 364 365 return routine; 366 } 367 readProcedureOrFunctionDeclaration()368 Routine readProcedureOrFunctionDeclaration() { 369 370 int routineType; 371 boolean isAggregate = false; 372 373 if (token.tokenType == Tokens.AGGREGATE) { 374 isAggregate = true; 375 376 read(); 377 378 if (token.tokenType == Tokens.PROCEDURE) { 379 throw unexpectedToken(); 380 } 381 } 382 383 routineType = token.tokenType == Tokens.PROCEDURE 384 ? SchemaObject.PROCEDURE 385 : SchemaObject.FUNCTION; 386 387 HsqlName name; 388 389 read(); 390 391 name = readNewSchemaObjectName(routineType, true); 392 393 name.setSchemaIfNull(session.getCurrentSchemaHsqlName()); 394 395 Routine routine = new Routine(routineType); 396 397 routine.setName(name); 398 routine.setAggregate(isAggregate); 399 readRoutineArguments(routine); 400 401 if (routineType != SchemaObject.PROCEDURE) { 402 readThis(Tokens.RETURNS); 403 404 if (token.tokenType == Tokens.TABLE) { 405 read(); 406 407 TableDerived table = 408 new TableDerived(database, SqlInvariants.MODULE_HSQLNAME, 409 TableBase.FUNCTION_TABLE); 410 411 readTableDefinition(routine, table); 412 routine.setReturnTable(table); 413 } else { 414 Type type = readTypeDefinition(false, true); 415 416 routine.setReturnType(type); 417 } 418 } 419 420 readRoutineCharacteristics(routine); 421 422 return routine; 423 } 424 readRoutineArguments(Routine routine)425 void readRoutineArguments(Routine routine) { 426 427 readThis(Tokens.OPENBRACKET); 428 429 if (token.tokenType == Tokens.CLOSEBRACKET) { 430 read(); 431 } else { 432 while (true) { 433 ColumnSchema newcolumn = readRoutineParameter(routine, true); 434 435 routine.addParameter(newcolumn); 436 437 if (token.tokenType == Tokens.COMMA) { 438 read(); 439 } else { 440 readThis(Tokens.CLOSEBRACKET); 441 442 break; 443 } 444 } 445 } 446 } 447 readCreatePasswordCheckFunction()448 Routine readCreatePasswordCheckFunction() { 449 450 Routine routine = new Routine(SchemaObject.FUNCTION); 451 452 if (token.tokenType == Tokens.NONE) { 453 read(); 454 455 return null; 456 } else if (token.tokenType == Tokens.EXTERNAL) { 457 routine.setLanguage(Routine.LANGUAGE_JAVA); 458 routine.setDataImpact(Routine.NO_SQL); 459 } else { 460 routine.setLanguage(Routine.LANGUAGE_SQL); 461 routine.setDataImpact(Routine.CONTAINS_SQL); 462 } 463 464 HsqlName hsqlName = database.nameManager.newHsqlName(Tokens.T_PASSWORD, 465 false, SchemaObject.FUNCTION); 466 467 hsqlName.setSchemaIfNull(SqlInvariants.SYSTEM_SCHEMA_HSQLNAME); 468 routine.setName(hsqlName); 469 470 hsqlName = database.nameManager.newHsqlName(Tokens.T_PASSWORD, false, 471 SchemaObject.PARAMETER); 472 473 ColumnSchema column = new ColumnSchema(hsqlName, Type.SQL_VARCHAR, 474 false, false, null); 475 476 routine.addParameter(column); 477 routine.setReturnType(Type.SQL_BOOLEAN); 478 readRoutineBody(routine); 479 routine.resolve(session); 480 481 return routine; 482 } 483 readCreateDatabaseAuthenticationFunction()484 Routine readCreateDatabaseAuthenticationFunction() { 485 486 Routine routine = new Routine(SchemaObject.FUNCTION); 487 488 if (token.tokenType == Tokens.NONE) { 489 read(); 490 491 return null; 492 } 493 494 checkIsThis(Tokens.EXTERNAL); 495 routine.setLanguage(Routine.LANGUAGE_JAVA); 496 routine.setDataImpact(Routine.NO_SQL); 497 routine.setName( 498 database.nameManager.newHsqlName( 499 Tokens.T_AUTHENTICATION, false, SchemaObject.FUNCTION)); 500 501 for (int i = 0; i < 3; i++) { 502 ColumnSchema column = new ColumnSchema(null, Type.SQL_VARCHAR, 503 false, false, null); 504 505 routine.addParameter(column); 506 } 507 508 routine.setReturnType( 509 new ArrayType( 510 Type.SQL_VARCHAR_DEFAULT, ArrayType.defaultArrayCardinality)); 511 readRoutineBody(routine); 512 routine.resolve(session); 513 514 return routine; 515 } 516 readTableDefinition(Routine routine, Table table)517 private void readTableDefinition(Routine routine, Table table) { 518 519 readThis(Tokens.OPENBRACKET); 520 521 for (int i = 0; ; i++) { 522 ColumnSchema newcolumn = readRoutineParameter(routine, false); 523 524 if (newcolumn.getName() == null) { 525 throw unexpectedToken(); 526 } 527 528 table.addColumn(newcolumn); 529 530 if (token.tokenType == Tokens.COMMA) { 531 read(); 532 } else { 533 readThis(Tokens.CLOSEBRACKET); 534 535 break; 536 } 537 } 538 539 table.createPrimaryKey(); 540 } 541 readRoutineCharacteristics(Routine routine)542 private void readRoutineCharacteristics(Routine routine) { 543 544 OrderedIntHashSet set = new OrderedIntHashSet(); 545 boolean end = false; 546 547 while (!end) { 548 switch (token.tokenType) { 549 550 case Tokens.LANGUAGE : { 551 if (!set.add(Tokens.LANGUAGE)) { 552 throw unexpectedToken(); 553 } 554 555 read(); 556 557 if (token.tokenType == Tokens.JAVA) { 558 read(); 559 routine.setLanguage(Routine.LANGUAGE_JAVA); 560 } else if (token.tokenType == Tokens.SQL) { 561 read(); 562 routine.setLanguage(Routine.LANGUAGE_SQL); 563 } else { 564 throw unexpectedToken(); 565 } 566 567 break; 568 } 569 case Tokens.PARAMETER : { 570 if (!set.add(Tokens.PARAMETER)) { 571 throw unexpectedToken(); 572 } 573 574 read(); 575 readThis(Tokens.STYLE); 576 577 if (token.tokenType == Tokens.JAVA) { 578 read(); 579 routine.setParameterStyle(Routine.PARAM_STYLE_JAVA); 580 } else { 581 readThis(Tokens.SQL); 582 routine.setParameterStyle(Routine.PARAM_STYLE_SQL); 583 } 584 585 break; 586 } 587 case Tokens.SPECIFIC : { 588 if (!set.add(Tokens.SPECIFIC)) { 589 throw unexpectedToken(); 590 } 591 592 read(); 593 594 HsqlName name = 595 readNewSchemaObjectName(SchemaObject.SPECIFIC_ROUTINE, 596 false); 597 598 routine.setSpecificName(name); 599 600 break; 601 } 602 case Tokens.DETERMINISTIC : { 603 if (!set.add(Tokens.DETERMINISTIC)) { 604 throw unexpectedToken(); 605 } 606 607 read(); 608 routine.setDeterministic(true); 609 610 break; 611 } 612 case Tokens.NOT : { 613 if (!set.add(Tokens.DETERMINISTIC)) { 614 throw unexpectedToken(); 615 } 616 617 read(); 618 readThis(Tokens.DETERMINISTIC); 619 routine.setDeterministic(false); 620 621 break; 622 } 623 case Tokens.MODIFIES : { 624 if (!set.add(Tokens.SQL)) { 625 throw unexpectedToken(); 626 } 627 628 if (routine.getType() == SchemaObject.FUNCTION) { 629 throw unexpectedToken(); 630 } 631 632 read(); 633 readThis(Tokens.SQL); 634 readThis(Tokens.DATA); 635 routine.setDataImpact(Routine.MODIFIES_SQL); 636 637 break; 638 } 639 case Tokens.NO : { 640 if (!set.add(Tokens.SQL)) { 641 throw unexpectedToken(); 642 } 643 644 read(); 645 readThis(Tokens.SQL); 646 routine.setDataImpact(Routine.NO_SQL); 647 648 break; 649 } 650 case Tokens.READS : { 651 if (!set.add(Tokens.SQL)) { 652 throw unexpectedToken(); 653 } 654 655 read(); 656 readThis(Tokens.SQL); 657 readThis(Tokens.DATA); 658 routine.setDataImpact(Routine.READS_SQL); 659 660 break; 661 } 662 case Tokens.CONTAINS : { 663 if (!set.add(Tokens.SQL)) { 664 throw unexpectedToken(); 665 } 666 667 read(); 668 readThis(Tokens.SQL); 669 routine.setDataImpact(Routine.CONTAINS_SQL); 670 671 break; 672 } 673 case Tokens.RETURNS : { 674 if (!set.add(Tokens.NULL) || routine.isProcedure()) { 675 throw unexpectedToken(); 676 } 677 678 if (routine.isAggregate()) { 679 throw Error.error(ErrorCode.X_42604, 680 token.tokenString); 681 } 682 683 read(); 684 readThis(Tokens.NULL); 685 readThis(Tokens.ON); 686 readThis(Tokens.NULL); 687 readThis(Tokens.INPUT); 688 routine.setNullInputOutput(true); 689 690 break; 691 } 692 case Tokens.CALLED : { 693 if (!set.add(Tokens.NULL) || routine.isProcedure()) { 694 throw unexpectedToken(); 695 } 696 697 read(); 698 readThis(Tokens.ON); 699 readThis(Tokens.NULL); 700 readThis(Tokens.INPUT); 701 routine.setNullInputOutput(false); 702 703 break; 704 } 705 case Tokens.DYNAMIC : { 706 if (!set.add(Tokens.RESULT) || routine.isFunction()) { 707 throw unexpectedToken(); 708 } 709 710 read(); 711 readThis(Tokens.RESULT); 712 readThis(Tokens.SETS); 713 714 int results = readInteger(); 715 716 if (results < 0 || results > 16) { 717 throw Error.error(ErrorCode.X_42604, 718 String.valueOf(results)); 719 } 720 721 routine.setMaxDynamicResults(results); 722 723 break; 724 } 725 case Tokens.NEW : { 726 if (routine.getType() == SchemaObject.FUNCTION 727 || !set.add(Tokens.SAVEPOINT)) { 728 throw unexpectedToken(); 729 } 730 731 read(); 732 readThis(Tokens.SAVEPOINT); 733 readThis(Tokens.LEVEL); 734 routine.setNewSavepointLevel(true); 735 736 break; 737 } 738 case Tokens.OLD : { 739 if (routine.getType() == SchemaObject.FUNCTION 740 || !set.add(Tokens.SAVEPOINT)) { 741 throw unexpectedToken(); 742 } 743 744 read(); 745 readThis(Tokens.SAVEPOINT); 746 readThis(Tokens.LEVEL); 747 routine.setNewSavepointLevel(false); 748 749 throw unsupportedFeature(Tokens.T_OLD); 750 751 // break; 752 } 753 default : 754 end = true; 755 break; 756 } 757 } 758 } 759 readRoutineBody(Routine routine)760 void readRoutineBody(Routine routine) { 761 762 if (token.tokenType == Tokens.EXTERNAL) { 763 readRoutineJavaBody(routine); 764 } else { 765 readRoutineSQLBody(routine); 766 } 767 } 768 readRoutineSQLBody(Routine routine)769 void readRoutineSQLBody(Routine routine) { 770 771 startRecording(); 772 session.sessionContext.pushRoutineTables(); 773 774 try { 775 Statement statement = compileSQLProcedureStatementOrNull(routine, 776 null); 777 778 if (statement == null) { 779 throw unexpectedToken(); 780 } 781 782 Token[] tokenisedStatement = getRecordedStatement(); 783 String sql = Token.getSQL(tokenisedStatement); 784 785 statement.setSQL(sql); 786 routine.setProcedure(statement); 787 } finally { 788 session.sessionContext.popRoutineTables(); 789 } 790 } 791 readRoutineJavaBody(Routine routine)792 void readRoutineJavaBody(Routine routine) { 793 794 if (routine.getLanguage() != Routine.LANGUAGE_JAVA) { 795 throw unexpectedToken(); 796 } 797 798 read(); 799 readThis(Tokens.NAME); 800 checkIsQuotedString(); 801 routine.setMethodURL((String) token.tokenValue); 802 read(); 803 804 if (token.tokenType == Tokens.PARAMETER) { 805 read(); 806 readThis(Tokens.STYLE); 807 readThis(Tokens.JAVA); 808 } 809 } 810 811 /* 812 <SQL control statement> ::= 813 <call statement> 814 | <return statement> 815 816 <compound statement> 817 <case statement> 818 <if statement> 819 <iterate statement> 820 <leave statement> 821 <loop statement> 822 <while statement> 823 <repeat statement> 824 <for statement> 825 <assignment statement> SET (,,,) = (,,,) or SET a = b 826 827 828 */ readLocalDeclarationList(Routine routine, StatementCompound context)829 Object[] readLocalDeclarationList(Routine routine, 830 StatementCompound context) { 831 832 HsqlArrayList list = new HsqlArrayList(); 833 final int table = 0; 834 final int variableOrCondition = 1; 835 final int cursor = 2; 836 final int handler = 3; 837 int objectType = table; 838 RangeGroup[] rangeGroups = new RangeGroup[1]; 839 840 rangeGroups[0] = context == null ? routine 841 : context; 842 843 compileContext.setOuterRanges(rangeGroups); 844 845 while (token.tokenType == Tokens.DECLARE) { 846 Object var = null; 847 848 if (objectType == table) { 849 var = readLocalTableVariableDeclarationOrNull(routine); 850 851 if (var == null) { 852 objectType = variableOrCondition; 853 } else { 854 list.add(var); 855 readThis(Tokens.SEMICOLON); 856 } 857 } else if (objectType == variableOrCondition) { 858 var = readLocalVariableDeclarationOrNull(); 859 860 if (var == null) { 861 objectType = cursor; 862 } else { 863 list.addAll((Object[]) var); 864 } 865 } else if (objectType == cursor) { 866 var = compileDeclareCursorOrNull(rangeGroups, true); 867 868 if (var == null) { 869 objectType = handler; 870 } else { 871 list.add(var); 872 readThis(Tokens.SEMICOLON); 873 } 874 } else if (objectType == handler) { 875 var = compileLocalHandlerDeclaration(routine, context); 876 877 list.add(var); 878 } 879 } 880 881 Object[] declarations = new Object[list.size()]; 882 883 list.toArray(declarations); 884 885 return declarations; 886 } 887 readLocalTableVariableDeclarationOrNull(Routine routine)888 Table readLocalTableVariableDeclarationOrNull(Routine routine) { 889 890 int position = getPosition(); 891 892 readThis(Tokens.DECLARE); 893 894 if (token.tokenType == Tokens.TABLE) { 895 read(); 896 897 HsqlName name = readNewSchemaObjectName(SchemaObject.TABLE, false); 898 899 name.schema = SqlInvariants.MODULE_HSQLNAME; 900 901 Table table = new Table(database, name, TableBase.TEMP_TABLE); 902 903 table.persistenceScope = TableBase.SCOPE_ROUTINE; 904 905 readTableDefinition(routine, table); 906 session.sessionContext.addSessionTable(table); 907 908 return table; 909 } else { 910 rewind(position); 911 912 return null; 913 } 914 } 915 readLocalVariableDeclarationOrNull()916 ColumnSchema[] readLocalVariableDeclarationOrNull() { 917 918 int position = getPosition(); 919 Type type; 920 HsqlArrayList names = new HsqlArrayList(); 921 922 try { 923 readThis(Tokens.DECLARE); 924 925 if (isReservedKey()) { 926 rewind(position); 927 928 return null; 929 } 930 931 while (true) { 932 HsqlName name = readNewSchemaObjectName(SchemaObject.VARIABLE, 933 false); 934 935 if (token.tokenType == Tokens.CONDITION) { 936 rewind(position); 937 938 return null; 939 } 940 941 names.add(name); 942 943 if (token.tokenType == Tokens.COMMA) { 944 read(); 945 } else { 946 break; 947 } 948 } 949 950 type = readTypeDefinition(false, true); 951 } catch (HsqlException e) { 952 953 // may be cursor 954 rewind(position); 955 956 return null; 957 } 958 959 Expression def = null; 960 961 if (token.tokenType == Tokens.DEFAULT) { 962 read(); 963 964 def = readDefaultClause(type); 965 } 966 967 ColumnSchema[] variable = new ColumnSchema[names.size()]; 968 969 for (int i = 0; i < names.size(); i++) { 970 variable[i] = new ColumnSchema((HsqlName) names.get(i), type, 971 true, false, def); 972 973 variable[i].setParameterMode( 974 SchemaObject.ParameterModes.PARAM_INOUT); 975 } 976 977 readThis(Tokens.SEMICOLON); 978 979 return variable; 980 } 981 compileLocalHandlerDeclaration(Routine routine, StatementCompound context)982 private StatementHandler compileLocalHandlerDeclaration(Routine routine, 983 StatementCompound context) { 984 985 int handlerType; 986 987 readThis(Tokens.DECLARE); 988 989 switch (token.tokenType) { 990 991 case Tokens.CONTINUE : 992 read(); 993 994 handlerType = StatementHandler.CONTINUE; 995 break; 996 997 case Tokens.EXIT : 998 read(); 999 1000 handlerType = StatementHandler.EXIT; 1001 break; 1002 1003 case Tokens.UNDO : 1004 read(); 1005 1006 handlerType = StatementHandler.UNDO; 1007 break; 1008 1009 default : 1010 throw unexpectedToken(); 1011 } 1012 1013 readThis(Tokens.HANDLER); 1014 readThis(Tokens.FOR); 1015 1016 StatementHandler handler = new StatementHandler(handlerType); 1017 boolean end = false; 1018 boolean start = true; 1019 1020 while (!end) { 1021 int conditionType = StatementHandler.NONE; 1022 1023 switch (token.tokenType) { 1024 1025 case Tokens.COMMA : 1026 if (start) { 1027 throw unexpectedToken(); 1028 } 1029 1030 read(); 1031 1032 start = true; 1033 break; 1034 1035 case Tokens.SQLSTATE : 1036 conditionType = StatementHandler.SQL_STATE; 1037 1038 // fall through 1039 case Tokens.SQLEXCEPTION : 1040 if (conditionType == StatementHandler.NONE) { 1041 conditionType = StatementHandler.SQL_EXCEPTION; 1042 } 1043 1044 // fall through 1045 case Tokens.SQLWARNING : 1046 if (conditionType == StatementHandler.NONE) { 1047 conditionType = StatementHandler.SQL_WARNING; 1048 } 1049 1050 // fall through 1051 case Tokens.NOT : 1052 if (conditionType == StatementHandler.NONE) { 1053 conditionType = StatementHandler.SQL_NOT_FOUND; 1054 } 1055 1056 if (!start) { 1057 throw unexpectedToken(); 1058 } 1059 1060 start = false; 1061 1062 read(); 1063 1064 if (conditionType == StatementHandler.SQL_NOT_FOUND) { 1065 readThis(Tokens.FOUND); 1066 } else if (conditionType == StatementHandler.SQL_STATE) { 1067 String sqlState = parseSQLStateValue(); 1068 1069 handler.addConditionState(sqlState); 1070 1071 break; 1072 } 1073 1074 handler.addConditionType(conditionType); 1075 break; 1076 1077 default : 1078 if (start) { 1079 throw unexpectedToken(); 1080 } 1081 1082 end = true; 1083 break; 1084 } 1085 } 1086 1087 if (token.tokenType == Tokens.SEMICOLON) { 1088 read(); 1089 } else { 1090 Statement e = compileSQLProcedureStatementOrNull(routine, context); 1091 1092 if (e == null) { 1093 throw unexpectedToken(); 1094 } 1095 1096 readThis(Tokens.SEMICOLON); 1097 handler.addStatement(e); 1098 } 1099 1100 return handler; 1101 } 1102 parseSQLStateValue()1103 String parseSQLStateValue() { 1104 1105 readIfThis(Tokens.VALUE); 1106 checkIsQuotedString(); 1107 1108 String sqlState = token.tokenString; 1109 1110 if (sqlState.length() != 5) { 1111 throw Error.parseError(ErrorCode.X_42607, null, 1112 scanner.getLineNumber()); 1113 } 1114 1115 read(); 1116 1117 return sqlState; 1118 } 1119 1120 static String[] featureStrings = new String[]{ "H901_03" }; 1121 parseSQLFeatureValue()1122 String parseSQLFeatureValue() { 1123 1124 if (!isUndelimitedSimpleName()) { 1125 throw Error.parseError(ErrorCode.X_42555, token.tokenString, 1126 scanner.getLineNumber()); 1127 } 1128 1129 String sqlFeature = token.tokenString; 1130 int index = ArrayUtil.find(featureStrings, sqlFeature); 1131 1132 if (index < 0) { 1133 throw Error.parseError(ErrorCode.X_42555, token.tokenString, 1134 scanner.getLineNumber()); 1135 } 1136 1137 read(); 1138 1139 return sqlFeature; 1140 } 1141 compileCompoundStatement(Routine routine, StatementCompound context, HsqlName label)1142 Statement compileCompoundStatement(Routine routine, 1143 StatementCompound context, 1144 HsqlName label) { 1145 1146 final boolean atomic = true; 1147 1148 readThis(Tokens.BEGIN); 1149 readThis(Tokens.ATOMIC); 1150 1151 label = createLabelIfNull(context, label); 1152 1153 StatementCompound statement = 1154 new StatementCompound(StatementTypes.BEGIN_END, label, context); 1155 1156 statement.setAtomic(atomic); 1157 statement.setRoot(routine); 1158 1159 Object[] declarations = readLocalDeclarationList(routine, context); 1160 1161 statement.setLocalDeclarations(declarations); 1162 1163 Statement[] statements = compileSQLProcedureStatementList(routine, 1164 statement); 1165 1166 statement.setStatements(statements); 1167 readThis(Tokens.END); 1168 1169 if (isSimpleName() && !isReservedKey()) { 1170 if (label == null) { 1171 throw unexpectedToken(); 1172 } 1173 1174 if (!label.name.equals(token.tokenString)) { 1175 throw Error.error(ErrorCode.X_42508, token.tokenString); 1176 } 1177 1178 read(); 1179 } 1180 1181 return statement; 1182 } 1183 createLabelIfNull(StatementCompound context, HsqlName label)1184 HsqlName createLabelIfNull(StatementCompound context, HsqlName label) { 1185 1186 if (label != null) { 1187 return label; 1188 } 1189 1190 String labelString; 1191 StatementCompound parent = context; 1192 int level = 0; 1193 1194 while (parent != null) { 1195 level++; 1196 1197 parent = parent.parent; 1198 } 1199 1200 labelString = "_" + level; 1201 label = session.database.nameManager.newHsqlName(labelString, false, 1202 SchemaObject.LABEL); 1203 1204 return label; 1205 } 1206 compileSQLProcedureStatementList(Routine routine, StatementCompound context)1207 Statement[] compileSQLProcedureStatementList(Routine routine, 1208 StatementCompound context) { 1209 1210 Statement e; 1211 HsqlArrayList list = new HsqlArrayList(); 1212 1213 while (true) { 1214 e = compileSQLProcedureStatementOrNull(routine, context); 1215 1216 if (e == null) { 1217 break; 1218 } 1219 1220 readThis(Tokens.SEMICOLON); 1221 list.add(e); 1222 } 1223 1224 if (list.size() == 0) { 1225 throw unexpectedToken(); 1226 } 1227 1228 Statement[] statements = new Statement[list.size()]; 1229 1230 list.toArray(statements); 1231 1232 return statements; 1233 } 1234 compileSQLProcedureStatementOrNull(Routine routine, StatementCompound context)1235 Statement compileSQLProcedureStatementOrNull(Routine routine, 1236 StatementCompound context) { 1237 1238 Statement cs = null; 1239 HsqlName label = null; 1240 RangeGroup rangeGroup = context == null ? routine 1241 : context; 1242 RangeGroup[] rangeGroups = new RangeGroup[]{ rangeGroup }; 1243 1244 if (!routine.isTrigger() && isSimpleName() && !isReservedKey()) { 1245 label = readLabel(); 1246 } 1247 1248 compileContext.reset(); 1249 1250 HsqlName oldSchema = session.getCurrentSchemaHsqlName(); 1251 1252 session.setCurrentSchemaHsqlName(routine.getSchemaName()); 1253 1254 try { 1255 switch (token.tokenType) { 1256 1257 // data 1258 case Tokens.OPEN : { 1259 if (routine.dataImpact == Routine.CONTAINS_SQL) { 1260 throw Error.error(ErrorCode.X_42602, 1261 routine.getDataImpactString()); 1262 } 1263 1264 if (label != null) { 1265 throw unexpectedToken(); 1266 } 1267 1268 cs = compileOpenCursorStatement(context); 1269 1270 break; 1271 } 1272 case Tokens.SELECT : { 1273 if (label != null) { 1274 throw unexpectedToken(); 1275 } 1276 1277 cs = compileSelectSingleRowStatement(rangeGroups); 1278 1279 break; 1280 } 1281 1282 // data change 1283 case Tokens.INSERT : 1284 if (label != null) { 1285 throw unexpectedToken(); 1286 } 1287 1288 cs = compileInsertStatement(rangeGroups); 1289 break; 1290 1291 case Tokens.UPDATE : 1292 if (label != null) { 1293 throw unexpectedToken(); 1294 } 1295 1296 cs = compileUpdateStatement(rangeGroups); 1297 break; 1298 1299 case Tokens.DELETE : 1300 if (label != null) { 1301 throw unexpectedToken(); 1302 } 1303 1304 cs = compileDeleteStatement(rangeGroups); 1305 break; 1306 1307 case Tokens.TRUNCATE : 1308 if (label != null) { 1309 throw unexpectedToken(); 1310 } 1311 1312 cs = compileTruncateStatement(); 1313 break; 1314 1315 case Tokens.MERGE : 1316 if (label != null) { 1317 throw unexpectedToken(); 1318 } 1319 1320 cs = compileMergeStatement(rangeGroups); 1321 break; 1322 1323 case Tokens.SET : 1324 if (label != null) { 1325 throw unexpectedToken(); 1326 } 1327 1328 read(); 1329 1330 if (routine.isTrigger()) { 1331 if (routine.triggerType == TriggerDef.BEFORE 1332 && routine.triggerOperation 1333 != StatementTypes.DELETE_WHERE) { 1334 int position = getPosition(); 1335 1336 try { 1337 cs = compileTriggerSetStatement( 1338 routine.triggerTable, rangeGroups); 1339 1340 break; 1341 } catch (HsqlException e) { 1342 rewind(position); 1343 1344 cs = compileSetStatement( 1345 rangeGroups, 1346 rangeGroup.getRangeVariables()); 1347 } 1348 } else { 1349 cs = compileSetStatement( 1350 rangeGroups, rangeGroup.getRangeVariables()); 1351 } 1352 1353 ((StatementSet) cs).checkIsNotColumnTarget(); 1354 } else { 1355 cs = compileSetStatement( 1356 rangeGroups, rangeGroup.getRangeVariables()); 1357 } 1358 break; 1359 1360 case Tokens.GET : 1361 if (label != null) { 1362 throw unexpectedToken(); 1363 } 1364 1365 cs = compileGetStatement(rangeGroups); 1366 break; 1367 1368 // control 1369 case Tokens.CALL : { 1370 if (label != null) { 1371 throw unexpectedToken(); 1372 } 1373 1374 cs = compileCallStatement(rangeGroups, true); 1375 1376 Routine proc = ((StatementProcedure) cs).procedure; 1377 1378 if (proc != null) { 1379 switch (routine.dataImpact) { 1380 1381 case Routine.CONTAINS_SQL : { 1382 if (proc.dataImpact == Routine.READS_SQL 1383 || proc.dataImpact 1384 == Routine.MODIFIES_SQL) { 1385 throw Error.error( 1386 ErrorCode.X_42602, 1387 routine.getDataImpactString()); 1388 } 1389 1390 break; 1391 } 1392 case Routine.READS_SQL : { 1393 if (proc.dataImpact == Routine.MODIFIES_SQL) { 1394 throw Error.error( 1395 ErrorCode.X_42602, 1396 routine.getDataImpactString()); 1397 } 1398 1399 break; 1400 } 1401 } 1402 } 1403 1404 break; 1405 } 1406 case Tokens.RETURN : { 1407 if (routine.isTrigger() || label != null) { 1408 throw unexpectedToken(); 1409 } 1410 1411 read(); 1412 1413 cs = compileReturnValue(routine, context); 1414 1415 break; 1416 } 1417 case Tokens.BEGIN : { 1418 cs = compileCompoundStatement(routine, context, label); 1419 1420 break; 1421 } 1422 case Tokens.WHILE : { 1423 if (routine.isTrigger()) { 1424 throw unexpectedToken(); 1425 } 1426 1427 cs = compileWhile(routine, context, label); 1428 1429 break; 1430 } 1431 case Tokens.REPEAT : { 1432 cs = compileRepeat(routine, context, label); 1433 1434 break; 1435 } 1436 case Tokens.LOOP : { 1437 cs = compileLoop(routine, context, label); 1438 1439 break; 1440 } 1441 case Tokens.FOR : { 1442 cs = compileFor(routine, context, label); 1443 1444 break; 1445 } 1446 case Tokens.ITERATE : { 1447 if (label != null) { 1448 throw unexpectedToken(); 1449 } 1450 1451 cs = compileIterate(); 1452 1453 break; 1454 } 1455 case Tokens.LEAVE : { 1456 if (label != null) { 1457 throw unexpectedToken(); 1458 } 1459 1460 cs = compileLeave(routine, context); 1461 1462 break; 1463 } 1464 case Tokens.IF : { 1465 cs = compileIf(routine, context); 1466 1467 break; 1468 } 1469 case Tokens.CASE : { 1470 cs = compileCase(routine, context); 1471 1472 break; 1473 } 1474 case Tokens.SIGNAL : { 1475 cs = compileSignal(routine, context, label); 1476 1477 break; 1478 } 1479 case Tokens.RESIGNAL : { 1480 cs = compileResignal(routine, context, label); 1481 1482 break; 1483 } 1484 default : 1485 return null; 1486 } 1487 1488 cs.setRoot(routine); 1489 cs.setParent(context); 1490 1491 return cs; 1492 } finally { 1493 session.setCurrentSchemaHsqlName(oldSchema); 1494 } 1495 } 1496 readLabel()1497 HsqlName readLabel() { 1498 1499 HsqlName label = readNewSchemaObjectName(SchemaObject.LABEL, false); 1500 1501 if (token.tokenType != Tokens.COLON) { 1502 throw unexpectedToken(label.getNameString()); 1503 } 1504 1505 readThis(Tokens.COLON); 1506 1507 return label; 1508 } 1509 compileReturnValue(Routine routine, StatementCompound context)1510 Statement compileReturnValue(Routine routine, StatementCompound context) { 1511 1512 RangeGroup[] rangeGroups = new RangeGroup[1]; 1513 1514 rangeGroups[0] = context == null ? routine 1515 : context; 1516 1517 compileContext.setOuterRanges(rangeGroups); 1518 1519 Expression e = XreadValueExpressionOrNull(); 1520 1521 if (e == null) { 1522 throw unexpectedToken(); 1523 } 1524 1525 resolveOuterReferencesAndTypes(routine, context, e); 1526 1527 if (routine.isProcedure()) { 1528 throw Error.parseError(ErrorCode.X_42602, null, 1529 scanner.getLineNumber()); 1530 } 1531 1532 if (routine.returnsTable()) { 1533 if (e.getType() != OpTypes.TABLE_SUBQUERY) { 1534 throw Error.parseError(ErrorCode.X_42611, null, 1535 scanner.getLineNumber()); 1536 } 1537 } 1538 1539 Type returnType = new RowType(e.getNodeDataTypes()); 1540 Type declaredType = routine.getReturnType(); 1541 1542 if (!declaredType.isRowType()) { 1543 declaredType = new RowType(new Type[]{ routine.getReturnType() }); 1544 } 1545 1546 if (declaredType.getDegree() != returnType.getDegree()) { 1547 throw Error.parseError(ErrorCode.X_42564, null, 1548 scanner.getLineNumber()); 1549 } 1550 1551 if (!declaredType.canBeAssignedFrom(returnType)) { 1552 throw Error.parseError(ErrorCode.X_42611, null, 1553 scanner.getLineNumber()); 1554 } 1555 1556 return new StatementExpression(session, compileContext, 1557 StatementTypes.RETURN, e); 1558 } 1559 compileIterate()1560 Statement compileIterate() { 1561 1562 readThis(Tokens.ITERATE); 1563 1564 HsqlName label = readNewSchemaObjectName(SchemaObject.LABEL, false); 1565 1566 return new StatementSimple(StatementTypes.ITERATE, label); 1567 } 1568 compileLeave(Routine routine, StatementCompound context)1569 Statement compileLeave(Routine routine, StatementCompound context) { 1570 1571 readThis(Tokens.LEAVE); 1572 1573 HsqlName label = readNewSchemaObjectName(SchemaObject.LABEL, false); 1574 1575 return new StatementSimple(StatementTypes.LEAVE, label); 1576 } 1577 compileWhile(Routine routine, StatementCompound context, HsqlName label)1578 Statement compileWhile(Routine routine, StatementCompound context, 1579 HsqlName label) { 1580 1581 readThis(Tokens.WHILE); 1582 1583 Expression e = XreadBooleanValueExpression(); 1584 1585 resolveOuterReferencesAndTypes(routine, context, e); 1586 1587 StatementExpression condition = new StatementExpression(session, 1588 compileContext, StatementTypes.CONDITION, e); 1589 1590 readThis(Tokens.DO); 1591 1592 Statement[] statements = compileSQLProcedureStatementList(routine, 1593 context); 1594 1595 readThis(Tokens.END); 1596 readThis(Tokens.WHILE); 1597 1598 if (isSimpleName() && !isReservedKey()) { 1599 if (label == null) { 1600 throw unexpectedToken(); 1601 } 1602 1603 if (!label.name.equals(token.tokenString)) { 1604 throw Error.error(ErrorCode.X_42508, token.tokenString); 1605 } 1606 1607 read(); 1608 } 1609 1610 StatementCompound statement = 1611 new StatementCompound(StatementTypes.WHILE, label, context); 1612 1613 statement.setStatements(statements); 1614 statement.setCondition(condition); 1615 1616 return statement; 1617 } 1618 compileRepeat(Routine routine, StatementCompound context, HsqlName label)1619 Statement compileRepeat(Routine routine, StatementCompound context, 1620 HsqlName label) { 1621 1622 readThis(Tokens.REPEAT); 1623 1624 Statement[] statements = compileSQLProcedureStatementList(routine, 1625 context); 1626 1627 readThis(Tokens.UNTIL); 1628 1629 Expression e = XreadBooleanValueExpression(); 1630 1631 resolveOuterReferencesAndTypes(routine, context, e); 1632 1633 StatementExpression condition = new StatementExpression(session, 1634 compileContext, StatementTypes.CONDITION, e); 1635 1636 readThis(Tokens.END); 1637 readThis(Tokens.REPEAT); 1638 1639 if (isSimpleName() && !isReservedKey()) { 1640 if (label == null) { 1641 throw unexpectedToken(); 1642 } 1643 1644 if (!label.name.equals(token.tokenString)) { 1645 throw Error.error(ErrorCode.X_42508, token.tokenString); 1646 } 1647 1648 read(); 1649 } 1650 1651 StatementCompound statement = 1652 new StatementCompound(StatementTypes.REPEAT, label, context); 1653 1654 statement.setStatements(statements); 1655 statement.setCondition(condition); 1656 1657 return statement; 1658 } 1659 compileLoop(Routine routine, StatementCompound context, HsqlName label)1660 Statement compileLoop(Routine routine, StatementCompound context, 1661 HsqlName label) { 1662 1663 readThis(Tokens.LOOP); 1664 1665 Statement[] statements = compileSQLProcedureStatementList(routine, 1666 context); 1667 1668 readThis(Tokens.END); 1669 readThis(Tokens.LOOP); 1670 1671 if (isSimpleName() && !isReservedKey()) { 1672 if (label == null) { 1673 throw unexpectedToken(); 1674 } 1675 1676 if (!label.name.equals(token.tokenString)) { 1677 throw Error.error(ErrorCode.X_42508, token.tokenString); 1678 } 1679 1680 read(); 1681 } 1682 1683 StatementCompound result = new StatementCompound(StatementTypes.LOOP, 1684 label, context); 1685 1686 result.setStatements(statements); 1687 1688 return result; 1689 } 1690 compileFor(Routine routine, StatementCompound context, HsqlName label)1691 Statement compileFor(Routine routine, StatementCompound context, 1692 HsqlName label) { 1693 1694 RangeGroup[] rangeGroups = new RangeGroup[1]; 1695 1696 rangeGroups[0] = context == null ? routine 1697 : context; 1698 1699 compileContext.setOuterRanges(rangeGroups); 1700 readThis(Tokens.FOR); 1701 1702 StatementQuery cursorStatement = 1703 compileCursorSpecification(rangeGroups, 1704 ResultProperties.defaultPropsValue, 1705 false); 1706 1707 readThis(Tokens.DO); 1708 1709 StatementCompound forStatement = 1710 new StatementCompound(StatementTypes.FOR, label, context); 1711 1712 forStatement.setAtomic(true); 1713 forStatement.setRoot(routine); 1714 forStatement.setLoopStatement(null, cursorStatement); 1715 1716 Statement[] statements = compileSQLProcedureStatementList(routine, 1717 forStatement); 1718 1719 readThis(Tokens.END); 1720 readThis(Tokens.FOR); 1721 1722 if (isSimpleName() && !isReservedKey()) { 1723 if (label == null) { 1724 throw unexpectedToken(); 1725 } 1726 1727 if (!label.name.equals(token.tokenString)) { 1728 throw Error.error(ErrorCode.X_42508, token.tokenString); 1729 } 1730 1731 read(); 1732 } 1733 1734 forStatement.setStatements(statements); 1735 1736 return forStatement; 1737 } 1738 compileIf(Routine routine, StatementCompound context)1739 Statement compileIf(Routine routine, StatementCompound context) { 1740 1741 HsqlArrayList list = new HsqlArrayList(); 1742 1743 readThis(Tokens.IF); 1744 1745 Expression e = XreadBooleanValueExpression(); 1746 1747 resolveOuterReferencesAndTypes(routine, context, e); 1748 1749 Statement statement = new StatementExpression(session, compileContext, 1750 StatementTypes.CONDITION, e); 1751 1752 list.add(statement); 1753 readThis(Tokens.THEN); 1754 1755 Statement[] statements = compileSQLProcedureStatementList(routine, 1756 context); 1757 1758 for (int i = 0; i < statements.length; i++) { 1759 list.add(statements[i]); 1760 } 1761 1762 while (token.tokenType == Tokens.ELSEIF) { 1763 read(); 1764 1765 e = XreadBooleanValueExpression(); 1766 1767 resolveOuterReferencesAndTypes(routine, context, e); 1768 1769 statement = new StatementExpression(session, compileContext, 1770 StatementTypes.CONDITION, e); 1771 1772 list.add(statement); 1773 readThis(Tokens.THEN); 1774 1775 statements = compileSQLProcedureStatementList(routine, context); 1776 1777 for (int i = 0; i < statements.length; i++) { 1778 list.add(statements[i]); 1779 } 1780 } 1781 1782 if (token.tokenType == Tokens.ELSE) { 1783 read(); 1784 1785 e = Expression.EXPR_TRUE; 1786 statement = new StatementExpression(session, compileContext, 1787 StatementTypes.CONDITION, e); 1788 1789 list.add(statement); 1790 1791 statements = compileSQLProcedureStatementList(routine, context); 1792 1793 for (int i = 0; i < statements.length; i++) { 1794 list.add(statements[i]); 1795 } 1796 } 1797 1798 readThis(Tokens.END); 1799 readThis(Tokens.IF); 1800 1801 statements = new Statement[list.size()]; 1802 1803 list.toArray(statements); 1804 1805 StatementCompound result = new StatementCompound(StatementTypes.IF, 1806 null, context); 1807 1808 result.setStatements(statements); 1809 1810 return result; 1811 } 1812 compileCase(Routine routine, StatementCompound context)1813 Statement compileCase(Routine routine, StatementCompound context) { 1814 1815 HsqlArrayList list = new HsqlArrayList(); 1816 Expression condition = null; 1817 Statement statement; 1818 Statement[] statements; 1819 1820 readThis(Tokens.CASE); 1821 1822 if (token.tokenType == Tokens.WHEN) { 1823 list = readCaseWhen(routine, context); 1824 } else { 1825 list = readSimpleCaseWhen(routine, context); 1826 } 1827 1828 if (token.tokenType == Tokens.ELSE) { 1829 read(); 1830 1831 condition = Expression.EXPR_TRUE; 1832 statement = new StatementExpression(session, compileContext, 1833 StatementTypes.CONDITION, 1834 condition); 1835 1836 list.add(statement); 1837 1838 statements = compileSQLProcedureStatementList(routine, context); 1839 1840 for (int i = 0; i < statements.length; i++) { 1841 list.add(statements[i]); 1842 } 1843 } 1844 1845 readThis(Tokens.END); 1846 readThis(Tokens.CASE); 1847 1848 statements = new Statement[list.size()]; 1849 1850 list.toArray(statements); 1851 1852 StatementCompound result = new StatementCompound(StatementTypes.IF, 1853 null, context); 1854 1855 result.setStatements(statements); 1856 1857 return result; 1858 } 1859 readSimpleCaseWhen(Routine routine, StatementCompound context)1860 HsqlArrayList readSimpleCaseWhen(Routine routine, 1861 StatementCompound context) { 1862 1863 HsqlArrayList list = new HsqlArrayList(); 1864 Expression condition = null; 1865 Statement statement; 1866 Statement[] statements; 1867 Expression predicand = XreadRowValuePredicand(); 1868 1869 do { 1870 readThis(Tokens.WHEN); 1871 1872 do { 1873 Expression newCondition = XreadPredicateRightPart(predicand); 1874 1875 if (predicand == newCondition) { 1876 newCondition = 1877 new ExpressionLogical(predicand, 1878 XreadRowValuePredicand()); 1879 } 1880 1881 resolveOuterReferencesAndTypes(routine, context, newCondition); 1882 1883 if (condition == null) { 1884 condition = newCondition; 1885 } else { 1886 condition = new ExpressionLogical(OpTypes.OR, condition, 1887 newCondition); 1888 } 1889 1890 if (token.tokenType == Tokens.COMMA) { 1891 read(); 1892 } else { 1893 break; 1894 } 1895 } while (true); 1896 1897 statement = new StatementExpression(session, compileContext, 1898 StatementTypes.CONDITION, 1899 condition); 1900 1901 list.add(statement); 1902 readThis(Tokens.THEN); 1903 1904 statements = compileSQLProcedureStatementList(routine, context); 1905 1906 for (int i = 0; i < statements.length; i++) { 1907 list.add(statements[i]); 1908 } 1909 1910 if (token.tokenType != Tokens.WHEN) { 1911 break; 1912 } 1913 } while (true); 1914 1915 return list; 1916 } 1917 readCaseWhen(Routine routine, StatementCompound context)1918 HsqlArrayList readCaseWhen(Routine routine, StatementCompound context) { 1919 1920 HsqlArrayList list = new HsqlArrayList(); 1921 Expression condition = null; 1922 Statement statement; 1923 Statement[] statements; 1924 1925 do { 1926 readThis(Tokens.WHEN); 1927 1928 condition = XreadBooleanValueExpression(); 1929 1930 resolveOuterReferencesAndTypes(routine, context, condition); 1931 1932 statement = new StatementExpression(session, compileContext, 1933 StatementTypes.CONDITION, 1934 condition); 1935 1936 list.add(statement); 1937 readThis(Tokens.THEN); 1938 1939 statements = compileSQLProcedureStatementList(routine, context); 1940 1941 for (int i = 0; i < statements.length; i++) { 1942 list.add(statements[i]); 1943 } 1944 1945 if (token.tokenType != Tokens.WHEN) { 1946 break; 1947 } 1948 } while (true); 1949 1950 return list; 1951 } 1952 compileSignal(Routine routine, StatementCompound context, HsqlName label)1953 Statement compileSignal(Routine routine, StatementCompound context, 1954 HsqlName label) { 1955 1956 String sqlState; 1957 Expression message = null; 1958 1959 readThis(Tokens.SIGNAL); 1960 readThis(Tokens.SQLSTATE); 1961 1962 sqlState = parseSQLStateValue(); 1963 1964 if (readIfThis(Tokens.SET)) { 1965 readThis(Tokens.MESSAGE_TEXT); 1966 readThis(Tokens.EQUALS_OP); 1967 1968 message = XreadSimpleValueSpecificationOrNull(); 1969 1970 if (message == null) { 1971 throw unexpectedToken(); 1972 } 1973 1974 resolveOuterReferencesAndTypes(routine, context, message); 1975 } 1976 1977 StatementSignal cs = new StatementSignal(StatementTypes.SIGNAL, 1978 sqlState, message); 1979 1980 return cs; 1981 } 1982 compileResignal(Routine routine, StatementCompound context, HsqlName label)1983 private Statement compileResignal(Routine routine, 1984 StatementCompound context, 1985 HsqlName label) { 1986 1987 String sqlState = null; 1988 Expression message = null; 1989 1990 readThis(Tokens.RESIGNAL); 1991 1992 if (readIfThis(Tokens.SQLSTATE)) { 1993 sqlState = parseSQLStateValue(); 1994 1995 if (readIfThis(Tokens.SET)) { 1996 readThis(Tokens.MESSAGE_TEXT); 1997 readThis(Tokens.EQUALS_OP); 1998 1999 message = XreadSimpleValueSpecificationOrNull(); 2000 2001 if (message == null) { 2002 throw unexpectedToken(); 2003 } 2004 2005 resolveOuterReferencesAndTypes(routine, context, message); 2006 } 2007 } 2008 2009 StatementSignal cs = new StatementSignal(StatementTypes.RESIGNAL, 2010 sqlState, message); 2011 2012 return cs; 2013 } 2014 readRoutineParameter(Routine routine, boolean isParam)2015 ColumnSchema readRoutineParameter(Routine routine, boolean isParam) { 2016 2017 HsqlName hsqlName = null; 2018 int parameterMode = readRoutineParameterMode(routine.routineType, 2019 routine.isAggregate); 2020 2021 if (!isReservedKey()) { 2022 hsqlName = readNewDependentSchemaObjectName(routine.getName(), 2023 SchemaObject.PARAMETER); 2024 } 2025 2026 Type typeObject = readTypeDefinition(false, true); 2027 ColumnSchema column = new ColumnSchema(hsqlName, typeObject, true, 2028 false, null); 2029 2030 if (isParam) { 2031 column.setParameterMode((byte) parameterMode); 2032 } 2033 2034 return column; 2035 } 2036 readRoutineParameterMode(int routineType, boolean isAggregate)2037 int readRoutineParameterMode(int routineType, boolean isAggregate) { 2038 2039 int parameterMode = SchemaObject.ParameterModes.PARAM_IN; 2040 2041 switch (token.tokenType) { 2042 2043 case Tokens.IN : 2044 read(); 2045 break; 2046 2047 case Tokens.OUT : 2048 if (routineType != SchemaObject.PROCEDURE) { 2049 throw unexpectedToken(); 2050 } 2051 2052 read(); 2053 2054 parameterMode = SchemaObject.ParameterModes.PARAM_OUT; 2055 break; 2056 2057 case Tokens.INOUT : 2058 if (routineType != SchemaObject.PROCEDURE) { 2059 if (!isAggregate) { 2060 throw unexpectedToken(); 2061 } 2062 } 2063 2064 read(); 2065 2066 parameterMode = SchemaObject.ParameterModes.PARAM_INOUT; 2067 break; 2068 2069 default : 2070 } 2071 2072 return parameterMode; 2073 } 2074 resolveOuterReferencesAndTypes(Routine routine, StatementCompound context, Expression e)2075 void resolveOuterReferencesAndTypes(Routine routine, 2076 StatementCompound context, 2077 Expression e) { 2078 2079 RangeGroup rangeGroup = context == null ? routine 2080 : context; 2081 2082 resolveOuterReferencesAndTypes(new RangeGroup[]{ rangeGroup }, e); 2083 } 2084 compileCreateTrigger(boolean orReplace)2085 StatementSchema compileCreateTrigger(boolean orReplace) { 2086 2087 Table table; 2088 Boolean isForEachRow = null; 2089 boolean isNowait = false; 2090 boolean hasQueueSize = false; 2091 int queueSize = 0; 2092 int beforeOrAfterType; 2093 int operationType; 2094 String className; 2095 TriggerDef td; 2096 HsqlName name; 2097 HsqlName otherName = null; 2098 OrderedHashSet columns = null; 2099 int[] updateColumnIndexes = null; 2100 2101 read(); 2102 2103 name = readNewSchemaObjectName(SchemaObject.TRIGGER, true); 2104 2105 switch (token.tokenType) { 2106 2107 case Tokens.INSTEAD : 2108 beforeOrAfterType = TriggerDef.getTiming(Tokens.INSTEAD); 2109 2110 read(); 2111 readThis(Tokens.OF); 2112 break; 2113 2114 case Tokens.BEFORE : 2115 case Tokens.AFTER : 2116 beforeOrAfterType = TriggerDef.getTiming(token.tokenType); 2117 2118 read(); 2119 break; 2120 2121 default : 2122 throw unexpectedToken(); 2123 } 2124 2125 switch (token.tokenType) { 2126 2127 case Tokens.INSERT : 2128 case Tokens.DELETE : 2129 operationType = TriggerDef.getOperationType(token.tokenType); 2130 2131 read(); 2132 break; 2133 2134 case Tokens.UPDATE : 2135 operationType = TriggerDef.getOperationType(token.tokenType); 2136 2137 read(); 2138 2139 if (token.tokenType == Tokens.OF 2140 && beforeOrAfterType != TriggerDef.INSTEAD) { 2141 read(); 2142 2143 columns = new OrderedHashSet(); 2144 2145 readColumnNameList(columns, null, false); 2146 } 2147 break; 2148 2149 default : 2150 throw unexpectedToken(); 2151 } 2152 2153 readThis(Tokens.ON); 2154 2155 table = readTableName(); 2156 2157 if (token.tokenType == Tokens.BEFORE) { 2158 read(); 2159 checkIsSimpleName(); 2160 2161 otherName = readNewSchemaObjectName(SchemaObject.TRIGGER, true); 2162 } 2163 2164 name.setSchemaIfNull(table.getSchemaName()); 2165 checkSchemaUpdateAuthorisation(name.schema); 2166 2167 if (beforeOrAfterType == TriggerDef.INSTEAD) { 2168 if (!table.isView() 2169 || ((View) table).getCheckOption() 2170 == SchemaObject.ViewCheckModes.CHECK_CASCADE) { 2171 throw Error.error(ErrorCode.X_42538, name.schema.name); 2172 } 2173 } else { 2174 if (table.isView()) { 2175 throw Error.error(ErrorCode.X_42538, name.schema.name); 2176 } 2177 } 2178 2179 if (name.schema != table.getSchemaName()) { 2180 throw Error.error(ErrorCode.X_42505, name.schema.name); 2181 } 2182 2183 name.parent = table.getName(); 2184 2185 database.schemaManager.checkSchemaObjectNotExists(name); 2186 2187 if (columns != null) { 2188 updateColumnIndexes = table.getColumnIndexes(columns); 2189 2190 for (int i = 0; i < updateColumnIndexes.length; i++) { 2191 if (updateColumnIndexes[i] == -1) { 2192 throw Error.error(ErrorCode.X_42544, 2193 (String) columns.get(i)); 2194 } 2195 } 2196 } 2197 2198 Expression condition = null; 2199 SimpleName oldTableName = null; 2200 SimpleName newTableName = null; 2201 SimpleName oldRowName = null; 2202 SimpleName newRowName = null; 2203 Table[] transitions = new Table[4]; 2204 RangeVariable[] rangeVars = new RangeVariable[4]; 2205 String conditionSQL = null; 2206 RangeGroup[] rangeGroups = new RangeGroup[]{ 2207 new RangeGroup.RangeGroupSimple(rangeVars, false) }; 2208 2209 if (token.tokenType == Tokens.REFERENCING) { 2210 read(); 2211 2212 if (token.tokenType != Tokens.OLD 2213 && token.tokenType != Tokens.NEW) { 2214 throw unexpectedToken(); 2215 } 2216 2217 while (true) { 2218 if (token.tokenType == Tokens.OLD) { 2219 if (operationType == StatementTypes.INSERT) { 2220 throw unexpectedToken(); 2221 } 2222 2223 read(); 2224 2225 if (token.tokenType == Tokens.TABLE) { 2226 if (Boolean.TRUE.equals(isForEachRow) 2227 || oldTableName != null 2228 || beforeOrAfterType == TriggerDef.BEFORE) { 2229 throw unexpectedToken(); 2230 } 2231 2232 read(); 2233 readIfThis(Tokens.AS); 2234 checkIsSimpleName(); 2235 read(); 2236 2237 oldTableName = HsqlNameManager.getSimpleName( 2238 token.tokenString, token.isDelimitedIdentifier); 2239 2240 SimpleName n = oldTableName; 2241 2242 if (n.equals(newTableName) || n.equals(oldRowName) 2243 || n.equals(newRowName)) { 2244 throw unexpectedToken(); 2245 } 2246 2247 isForEachRow = Boolean.FALSE; 2248 2249 HsqlName hsqlName = database.nameManager.newHsqlName( 2250 table.getSchemaName(), n.name, 2251 isDelimitedIdentifier(), SchemaObject.TRANSITION); 2252 Table transition = new Table(table, hsqlName); 2253 RangeVariable range = new RangeVariable(transition, 2254 null, null, null, compileContext); 2255 2256 transitions[TriggerDef.OLD_TABLE] = transition; 2257 rangeVars[TriggerDef.OLD_TABLE] = range; 2258 } else { 2259 if (Boolean.FALSE.equals(isForEachRow) 2260 || oldRowName != null) { 2261 throw unexpectedToken(); 2262 } 2263 2264 readIfThis(Tokens.ROW); 2265 readIfThis(Tokens.AS); 2266 checkIsSimpleName(); 2267 2268 oldRowName = HsqlNameManager.getSimpleName( 2269 token.tokenString, token.isDelimitedIdentifier); 2270 2271 read(); 2272 2273 SimpleName n = oldRowName; 2274 2275 if (n.equals(newTableName) || n.equals(oldTableName) 2276 || n.equals(newRowName)) { 2277 throw unexpectedToken(); 2278 } 2279 2280 isForEachRow = Boolean.TRUE; 2281 2282 RangeVariable range = 2283 new RangeVariable(table.columnList, oldRowName, 2284 false, 2285 RangeVariable.TRANSITION_RANGE); 2286 2287 range.rangePosition = TriggerDef.OLD_ROW; 2288 transitions[TriggerDef.OLD_ROW] = null; 2289 rangeVars[TriggerDef.OLD_ROW] = range; 2290 } 2291 } else if (token.tokenType == Tokens.NEW) { 2292 if (operationType == StatementTypes.DELETE_WHERE) { 2293 throw unexpectedToken(); 2294 } 2295 2296 read(); 2297 2298 if (token.tokenType == Tokens.TABLE) { 2299 if (Boolean.TRUE.equals(isForEachRow) 2300 || newTableName != null 2301 || beforeOrAfterType == TriggerDef.BEFORE) { 2302 throw unexpectedToken(); 2303 } 2304 2305 read(); 2306 readIfThis(Tokens.AS); 2307 checkIsSimpleName(); 2308 2309 newTableName = HsqlNameManager.getSimpleName( 2310 token.tokenString, token.isDelimitedIdentifier); 2311 2312 read(); 2313 2314 isForEachRow = Boolean.FALSE; 2315 2316 SimpleName n = newTableName; 2317 2318 if (n.equals(oldTableName) || n.equals(oldRowName) 2319 || n.equals(newRowName)) { 2320 throw unexpectedToken(); 2321 } 2322 2323 HsqlName hsqlName = database.nameManager.newHsqlName( 2324 table.getSchemaName(), n.name, 2325 isDelimitedIdentifier(), SchemaObject.TRANSITION); 2326 Table transition = new Table(table, hsqlName); 2327 RangeVariable range = new RangeVariable(transition, 2328 null, null, null, compileContext); 2329 2330 transitions[TriggerDef.NEW_TABLE] = transition; 2331 rangeVars[TriggerDef.NEW_TABLE] = range; 2332 } else { 2333 if (Boolean.FALSE.equals(isForEachRow) 2334 || newRowName != null) { 2335 throw unexpectedToken(); 2336 } 2337 2338 readIfThis(Tokens.ROW); 2339 readIfThis(Tokens.AS); 2340 checkIsSimpleName(); 2341 2342 newRowName = HsqlNameManager.getSimpleName( 2343 token.tokenString, token.isDelimitedIdentifier); 2344 2345 read(); 2346 2347 SimpleName n = newRowName; 2348 2349 if (n.equals(oldTableName) || n.equals(newTableName) 2350 || n.equals(oldRowName)) { 2351 throw unexpectedToken(); 2352 } 2353 2354 isForEachRow = Boolean.TRUE; 2355 2356 RangeVariable range = 2357 new RangeVariable(table.columnList, newRowName, 2358 false, 2359 RangeVariable.TRANSITION_RANGE); 2360 2361 range.rangePosition = TriggerDef.NEW_ROW; 2362 transitions[TriggerDef.NEW_ROW] = null; 2363 rangeVars[TriggerDef.NEW_ROW] = range; 2364 } 2365 } else { 2366 break; 2367 } 2368 } 2369 } 2370 2371 if (Boolean.TRUE.equals(isForEachRow) 2372 && token.tokenType != Tokens.FOR) { 2373 throw unexpectedTokenRequire(Tokens.T_FOR); 2374 } 2375 2376 if (token.tokenType == Tokens.FOR) { 2377 read(); 2378 readThis(Tokens.EACH); 2379 2380 if (token.tokenType == Tokens.ROW) { 2381 if (Boolean.FALSE.equals(isForEachRow)) { 2382 throw unexpectedToken(); 2383 } 2384 2385 isForEachRow = Boolean.TRUE; 2386 } else if (token.tokenType == Tokens.STATEMENT) { 2387 if (Boolean.TRUE.equals(isForEachRow) 2388 || beforeOrAfterType == TriggerDef.BEFORE) { 2389 throw unexpectedToken(); 2390 } 2391 2392 isForEachRow = Boolean.FALSE; 2393 } else { 2394 throw unexpectedToken(); 2395 } 2396 2397 read(); 2398 } 2399 2400 // 2401 if (rangeVars[TriggerDef.OLD_TABLE] != null) {} 2402 2403 if (rangeVars[TriggerDef.NEW_TABLE] != null) {} 2404 2405 // 2406 if (Tokens.T_QUEUE.equals(token.tokenString)) { 2407 read(); 2408 2409 queueSize = readInteger(); 2410 hasQueueSize = true; 2411 } 2412 2413 if (Tokens.T_NOWAIT.equals(token.tokenString)) { 2414 read(); 2415 2416 isNowait = true; 2417 } 2418 2419 if (token.tokenType == Tokens.WHEN 2420 && beforeOrAfterType != TriggerDef.INSTEAD) { 2421 read(); 2422 readThis(Tokens.OPENBRACKET); 2423 2424 int position = getPosition(); 2425 2426 isCheckOrTriggerCondition = true; 2427 condition = XreadBooleanValueExpression(); 2428 conditionSQL = getLastPart(position); 2429 isCheckOrTriggerCondition = false; 2430 2431 readThis(Tokens.CLOSEBRACKET); 2432 2433 HsqlList unresolved = condition.resolveColumnReferences(session, 2434 rangeGroups[0], rangeGroups, null); 2435 2436 ExpressionColumn.checkColumnsResolved(unresolved); 2437 condition.resolveTypes(session, null); 2438 2439 if (condition.getDataType() != Type.SQL_BOOLEAN) { 2440 throw Error.error(ErrorCode.X_42568); 2441 } 2442 } 2443 2444 if (isForEachRow == null) { 2445 isForEachRow = Boolean.FALSE; 2446 } 2447 2448 if (token.tokenType == Tokens.CALL) { 2449 int position = getPosition(); 2450 2451 try { 2452 read(); 2453 checkIsSimpleName(); 2454 checkIsDelimitedIdentifier(); 2455 2456 className = token.tokenString; 2457 2458 read(); 2459 2460 if (token.tokenType == Tokens.OPENBRACKET) { 2461 throw unexpectedToken(); 2462 } 2463 2464 td = new TriggerDef(name, beforeOrAfterType, operationType, 2465 isForEachRow.booleanValue(), table, 2466 transitions, rangeVars, condition, 2467 conditionSQL, updateColumnIndexes, 2468 className, isNowait, queueSize); 2469 2470 String sql = getLastPart(); 2471 Object[] args = new Object[] { 2472 td, otherName 2473 }; 2474 HsqlName[] writeLockNames = new HsqlName[] { 2475 database.getCatalogName(), table.getName() 2476 }; 2477 2478 return new StatementSchema(sql, StatementTypes.CREATE_TRIGGER, 2479 args, null, writeLockNames); 2480 } catch (HsqlException e) { 2481 rewind(position); 2482 } 2483 } 2484 2485 // 2486 if (hasQueueSize) { 2487 throw unexpectedToken(Tokens.T_QUEUE); 2488 } 2489 2490 if (isNowait) { 2491 throw unexpectedToken(Tokens.T_NOWAIT); 2492 } 2493 2494 Routine routine = compileTriggerRoutine(table, rangeVars, 2495 beforeOrAfterType, operationType); 2496 2497 td = new TriggerDefSQL(name, beforeOrAfterType, operationType, 2498 isForEachRow.booleanValue(), table, 2499 transitions, rangeVars, condition, 2500 conditionSQL, updateColumnIndexes, routine); 2501 2502 String sql = getLastPart(); 2503 Object[] args = new Object[] { 2504 td, otherName 2505 }; 2506 2507 return new StatementSchema(sql, StatementTypes.CREATE_TRIGGER, args, 2508 null, new HsqlName[] { 2509 database.getCatalogName(), table.getName() 2510 }); 2511 } 2512 compileTriggerRoutine(Table table, RangeVariable[] ranges, int beforeOrAfter, int operation)2513 Routine compileTriggerRoutine(Table table, RangeVariable[] ranges, 2514 int beforeOrAfter, int operation) { 2515 2516 int impact = (beforeOrAfter == TriggerDef.BEFORE) ? Routine.READS_SQL 2517 : Routine 2518 .MODIFIES_SQL; 2519 Routine routine = new Routine(table, ranges, impact, beforeOrAfter, 2520 operation); 2521 2522 session.sessionContext.pushRoutineTables(); 2523 2524 try { 2525 startRecording(); 2526 2527 StatementCompound parent = 2528 new StatementCompound(StatementTypes.BEGIN_END, null, null); 2529 2530 parent.rangeVariables = ranges; 2531 2532 Statement statement = compileSQLProcedureStatementOrNull(routine, 2533 null); 2534 2535 if (statement == null) { 2536 throw unexpectedToken(); 2537 } 2538 2539 Token[] tokenisedStatement = getRecordedStatement(); 2540 String sql = Token.getSQL(tokenisedStatement); 2541 2542 statement.setSQL(sql); 2543 routine.setProcedure(statement); 2544 routine.resolve(session); 2545 } finally { 2546 session.sessionContext.popRoutineTables(); 2547 } 2548 2549 return routine; 2550 } 2551 checkSchemaUpdateAuthorisation(HsqlName schema)2552 void checkSchemaUpdateAuthorisation(HsqlName schema) { 2553 2554 if (session.isProcessingLog()) { 2555 return; 2556 } 2557 2558 SqlInvariants.checkSchemaNameNotSystem(schema.name); 2559 2560 if (isSchemaDefinition) { 2561 if (schema != session.getCurrentSchemaHsqlName()) { 2562 throw Error.error(ErrorCode.X_42505); 2563 } 2564 } else { 2565 session.getGrantee().checkSchemaUpdateOrGrantRights(schema.name); 2566 } 2567 2568 session.checkDDLWrite(); 2569 } 2570 } 2571