PageRenderTime 44ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 1ms

/h2/src/main/org/h2/command/Parser.java

http://h2database.googlecode.com/
Java | 5949 lines | 5553 code | 169 blank | 227 comment | 1681 complexity | a58dfe4f8c1c65b9913b805a6bc30771 MD5 | raw file
  1. /*
  2. * Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License,
  3. * Version 1.0, and under the Eclipse Public License, Version 1.0
  4. * (http://h2database.com/html/license.html).
  5. * Initial Developer: H2 Group
  6. *
  7. * Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888
  8. * Support for the operator "&&" as an alias for SPATIAL_INTERSECTS
  9. */
  10. package org.h2.command;
  11. import java.math.BigDecimal;
  12. import java.math.BigInteger;
  13. import java.nio.charset.Charset;
  14. import java.text.Collator;
  15. import java.util.ArrayList;
  16. import java.util.HashSet;
  17. import org.h2.api.ErrorCode;
  18. import org.h2.api.Trigger;
  19. import org.h2.command.ddl.AlterIndexRename;
  20. import org.h2.command.ddl.AlterSchemaRename;
  21. import org.h2.command.ddl.AlterTableAddConstraint;
  22. import org.h2.command.ddl.AlterTableAlterColumn;
  23. import org.h2.command.ddl.AlterTableDropConstraint;
  24. import org.h2.command.ddl.AlterTableRename;
  25. import org.h2.command.ddl.AlterTableRenameColumn;
  26. import org.h2.command.ddl.AlterUser;
  27. import org.h2.command.ddl.AlterView;
  28. import org.h2.command.ddl.Analyze;
  29. import org.h2.command.ddl.CreateAggregate;
  30. import org.h2.command.ddl.CreateConstant;
  31. import org.h2.command.ddl.CreateFunctionAlias;
  32. import org.h2.command.ddl.CreateIndex;
  33. import org.h2.command.ddl.CreateLinkedTable;
  34. import org.h2.command.ddl.CreateRole;
  35. import org.h2.command.ddl.CreateSchema;
  36. import org.h2.command.ddl.CreateSequence;
  37. import org.h2.command.ddl.CreateTable;
  38. import org.h2.command.ddl.CreateTableData;
  39. import org.h2.command.ddl.CreateTrigger;
  40. import org.h2.command.ddl.CreateUser;
  41. import org.h2.command.ddl.CreateUserDataType;
  42. import org.h2.command.ddl.CreateView;
  43. import org.h2.command.ddl.DeallocateProcedure;
  44. import org.h2.command.ddl.DefineCommand;
  45. import org.h2.command.ddl.DropAggregate;
  46. import org.h2.command.ddl.DropConstant;
  47. import org.h2.command.ddl.DropDatabase;
  48. import org.h2.command.ddl.DropFunctionAlias;
  49. import org.h2.command.ddl.DropIndex;
  50. import org.h2.command.ddl.DropRole;
  51. import org.h2.command.ddl.DropSchema;
  52. import org.h2.command.ddl.DropSequence;
  53. import org.h2.command.ddl.DropTable;
  54. import org.h2.command.ddl.DropTrigger;
  55. import org.h2.command.ddl.DropUser;
  56. import org.h2.command.ddl.DropUserDataType;
  57. import org.h2.command.ddl.DropView;
  58. import org.h2.command.ddl.GrantRevoke;
  59. import org.h2.command.ddl.PrepareProcedure;
  60. import org.h2.command.ddl.SetComment;
  61. import org.h2.command.ddl.TruncateTable;
  62. import org.h2.command.dml.AlterSequence;
  63. import org.h2.command.dml.AlterTableSet;
  64. import org.h2.command.dml.BackupCommand;
  65. import org.h2.command.dml.Call;
  66. import org.h2.command.dml.Delete;
  67. import org.h2.command.dml.ExecuteProcedure;
  68. import org.h2.command.dml.Explain;
  69. import org.h2.command.dml.Insert;
  70. import org.h2.command.dml.Merge;
  71. import org.h2.command.dml.NoOperation;
  72. import org.h2.command.dml.Query;
  73. import org.h2.command.dml.Replace;
  74. import org.h2.command.dml.RunScriptCommand;
  75. import org.h2.command.dml.ScriptCommand;
  76. import org.h2.command.dml.Select;
  77. import org.h2.command.dml.SelectOrderBy;
  78. import org.h2.command.dml.SelectUnion;
  79. import org.h2.command.dml.Set;
  80. import org.h2.command.dml.SetTypes;
  81. import org.h2.command.dml.TransactionCommand;
  82. import org.h2.command.dml.Update;
  83. import org.h2.constraint.ConstraintReferential;
  84. import org.h2.engine.Constants;
  85. import org.h2.engine.Database;
  86. import org.h2.engine.DbObject;
  87. import org.h2.engine.FunctionAlias;
  88. import org.h2.engine.Procedure;
  89. import org.h2.engine.Right;
  90. import org.h2.engine.Session;
  91. import org.h2.engine.SysProperties;
  92. import org.h2.engine.User;
  93. import org.h2.engine.UserAggregate;
  94. import org.h2.engine.UserDataType;
  95. import org.h2.expression.Aggregate;
  96. import org.h2.expression.Alias;
  97. import org.h2.expression.CompareLike;
  98. import org.h2.expression.Comparison;
  99. import org.h2.expression.ConditionAndOr;
  100. import org.h2.expression.ConditionExists;
  101. import org.h2.expression.ConditionIn;
  102. import org.h2.expression.ConditionInSelect;
  103. import org.h2.expression.ConditionNot;
  104. import org.h2.expression.Expression;
  105. import org.h2.expression.ExpressionColumn;
  106. import org.h2.expression.ExpressionList;
  107. import org.h2.expression.Function;
  108. import org.h2.expression.FunctionCall;
  109. import org.h2.expression.JavaAggregate;
  110. import org.h2.expression.JavaFunction;
  111. import org.h2.expression.Operation;
  112. import org.h2.expression.Parameter;
  113. import org.h2.expression.Rownum;
  114. import org.h2.expression.SequenceValue;
  115. import org.h2.expression.Subquery;
  116. import org.h2.expression.TableFunction;
  117. import org.h2.expression.ValueExpression;
  118. import org.h2.expression.Variable;
  119. import org.h2.expression.Wildcard;
  120. import org.h2.index.Index;
  121. import org.h2.message.DbException;
  122. import org.h2.result.SortOrder;
  123. import org.h2.schema.Schema;
  124. import org.h2.schema.Sequence;
  125. import org.h2.table.Column;
  126. import org.h2.table.FunctionTable;
  127. import org.h2.table.IndexColumn;
  128. import org.h2.table.RangeTable;
  129. import org.h2.table.Table;
  130. import org.h2.table.TableFilter;
  131. import org.h2.table.TableView;
  132. import org.h2.table.TableFilter.TableFilterVisitor;
  133. import org.h2.util.MathUtils;
  134. import org.h2.util.New;
  135. import org.h2.util.StatementBuilder;
  136. import org.h2.util.StringUtils;
  137. import org.h2.value.CompareMode;
  138. import org.h2.value.DataType;
  139. import org.h2.value.Value;
  140. import org.h2.value.ValueBoolean;
  141. import org.h2.value.ValueBytes;
  142. import org.h2.value.ValueDate;
  143. import org.h2.value.ValueDecimal;
  144. import org.h2.value.ValueInt;
  145. import org.h2.value.ValueLong;
  146. import org.h2.value.ValueNull;
  147. import org.h2.value.ValueString;
  148. import org.h2.value.ValueTime;
  149. import org.h2.value.ValueTimestamp;
  150. /**
  151. * The parser is used to convert a SQL statement string to an command object.
  152. *
  153. * @author Thomas Mueller
  154. * @author Noel Grandin
  155. * @author Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888
  156. */
  157. public class Parser {
  158. // used during the tokenizer phase
  159. private static final int CHAR_END = 1, CHAR_VALUE = 2, CHAR_QUOTED = 3;
  160. private static final int CHAR_NAME = 4, CHAR_SPECIAL_1 = 5,
  161. CHAR_SPECIAL_2 = 6;
  162. private static final int CHAR_STRING = 7, CHAR_DOT = 8,
  163. CHAR_DOLLAR_QUOTED_STRING = 9;
  164. // this are token types
  165. private static final int KEYWORD = 1, IDENTIFIER = 2, PARAMETER = 3,
  166. END = 4, VALUE = 5;
  167. private static final int EQUAL = 6, BIGGER_EQUAL = 7, BIGGER = 8;
  168. private static final int SMALLER = 9, SMALLER_EQUAL = 10, NOT_EQUAL = 11,
  169. AT = 12;
  170. private static final int MINUS = 13, PLUS = 14, STRING_CONCAT = 15;
  171. private static final int OPEN = 16, CLOSE = 17, NULL = 18, TRUE = 19,
  172. FALSE = 20;
  173. private static final int CURRENT_TIMESTAMP = 21, CURRENT_DATE = 22,
  174. CURRENT_TIME = 23, ROWNUM = 24;
  175. private static final int SPATIAL_INTERSECTS = 25;
  176. private final Database database;
  177. private final Session session;
  178. /**
  179. * @see org.h2.engine.DbSettings#databaseToUpper
  180. */
  181. private final boolean identifiersToUpper;
  182. /** indicates character-type for each char in sqlCommand */
  183. private int[] characterTypes;
  184. private int currentTokenType;
  185. private String currentToken;
  186. private boolean currentTokenQuoted;
  187. private Value currentValue;
  188. private String originalSQL;
  189. /** copy of originalSQL, with comments blanked out */
  190. private String sqlCommand;
  191. /** cached array if chars from sqlCommand */
  192. private char[] sqlCommandChars;
  193. /** index into sqlCommand of previous token */
  194. private int lastParseIndex;
  195. /** index into sqlCommand of current token */
  196. private int parseIndex;
  197. private CreateView createView;
  198. private Prepared currentPrepared;
  199. private Select currentSelect;
  200. private ArrayList<Parameter> parameters;
  201. private String schemaName;
  202. private ArrayList<String> expectedList;
  203. private boolean rightsChecked;
  204. private boolean recompileAlways;
  205. private ArrayList<Parameter> indexedParameterList;
  206. public Parser(Session session) {
  207. this.database = session.getDatabase();
  208. this.identifiersToUpper = database.getSettings().databaseToUpper;
  209. this.session = session;
  210. }
  211. /**
  212. * Parse the statement and prepare it for execution.
  213. *
  214. * @param sql the SQL statement to parse
  215. * @return the prepared object
  216. */
  217. public Prepared prepare(String sql) {
  218. Prepared p = parse(sql);
  219. p.prepare();
  220. if (currentTokenType != END) {
  221. throw getSyntaxError();
  222. }
  223. return p;
  224. }
  225. /**
  226. * Parse a statement or a list of statements, and prepare it for execution.
  227. *
  228. * @param sql the SQL statement to parse
  229. * @return the command object
  230. */
  231. public Command prepareCommand(String sql) {
  232. try {
  233. Prepared p = parse(sql);
  234. boolean hasMore = isToken(";");
  235. if (!hasMore && currentTokenType != END) {
  236. throw getSyntaxError();
  237. }
  238. p.prepare();
  239. Command c = new CommandContainer(this, sql, p);
  240. if (hasMore) {
  241. String remaining = originalSQL.substring(parseIndex);
  242. if (remaining.trim().length() != 0) {
  243. CommandList list = new CommandList(this, sql, c, remaining);
  244. // list.addCommand(c);
  245. // do {
  246. // c = parseCommand();
  247. // list.addCommand(c);
  248. // } while (currentToken.equals(";"));
  249. c = list;
  250. }
  251. }
  252. return c;
  253. } catch (DbException e) {
  254. throw e.addSQL(originalSQL);
  255. }
  256. }
  257. /**
  258. * Parse the statement, but don't prepare it for execution.
  259. *
  260. * @param sql the SQL statement to parse
  261. * @return the prepared object
  262. */
  263. Prepared parse(String sql) {
  264. Prepared p;
  265. try {
  266. // first, try the fast variant
  267. p = parse(sql, false);
  268. } catch (DbException e) {
  269. if (e.getErrorCode() == ErrorCode.SYNTAX_ERROR_1) {
  270. // now, get the detailed exception
  271. p = parse(sql, true);
  272. } else {
  273. throw e.addSQL(sql);
  274. }
  275. }
  276. p.setPrepareAlways(recompileAlways);
  277. p.setParameterList(parameters);
  278. return p;
  279. }
  280. private Prepared parse(String sql, boolean withExpectedList) {
  281. initialize(sql);
  282. if (withExpectedList) {
  283. expectedList = New.arrayList();
  284. } else {
  285. expectedList = null;
  286. }
  287. parameters = New.arrayList();
  288. currentSelect = null;
  289. currentPrepared = null;
  290. createView = null;
  291. recompileAlways = false;
  292. indexedParameterList = null;
  293. read();
  294. return parsePrepared();
  295. }
  296. private Prepared parsePrepared() {
  297. int start = lastParseIndex;
  298. Prepared c = null;
  299. String token = currentToken;
  300. if (token.length() == 0) {
  301. c = new NoOperation(session);
  302. } else {
  303. char first = token.charAt(0);
  304. switch (first) {
  305. case '?':
  306. // read the ? as a parameter
  307. readTerm();
  308. // this is an 'out' parameter - set a dummy value
  309. parameters.get(0).setValue(ValueNull.INSTANCE);
  310. read("=");
  311. read("CALL");
  312. c = parseCall();
  313. break;
  314. case '(':
  315. c = parseSelect();
  316. break;
  317. case 'a':
  318. case 'A':
  319. if (readIf("ALTER")) {
  320. c = parseAlter();
  321. } else if (readIf("ANALYZE")) {
  322. c = parseAnalyze();
  323. }
  324. break;
  325. case 'b':
  326. case 'B':
  327. if (readIf("BACKUP")) {
  328. c = parseBackup();
  329. } else if (readIf("BEGIN")) {
  330. c = parseBegin();
  331. }
  332. break;
  333. case 'c':
  334. case 'C':
  335. if (readIf("COMMIT")) {
  336. c = parseCommit();
  337. } else if (readIf("CREATE")) {
  338. c = parseCreate();
  339. } else if (readIf("CALL")) {
  340. c = parseCall();
  341. } else if (readIf("CHECKPOINT")) {
  342. c = parseCheckpoint();
  343. } else if (readIf("COMMENT")) {
  344. c = parseComment();
  345. }
  346. break;
  347. case 'd':
  348. case 'D':
  349. if (readIf("DELETE")) {
  350. c = parseDelete();
  351. } else if (readIf("DROP")) {
  352. c = parseDrop();
  353. } else if (readIf("DECLARE")) {
  354. // support for DECLARE GLOBAL TEMPORARY TABLE...
  355. c = parseCreate();
  356. } else if (readIf("DEALLOCATE")) {
  357. c = parseDeallocate();
  358. }
  359. break;
  360. case 'e':
  361. case 'E':
  362. if (readIf("EXPLAIN")) {
  363. c = parseExplain();
  364. } else if (readIf("EXECUTE")) {
  365. c = parseExecute();
  366. }
  367. break;
  368. case 'f':
  369. case 'F':
  370. if (isToken("FROM")) {
  371. c = parseSelect();
  372. }
  373. break;
  374. case 'g':
  375. case 'G':
  376. if (readIf("GRANT")) {
  377. c = parseGrantRevoke(CommandInterface.GRANT);
  378. }
  379. break;
  380. case 'h':
  381. case 'H':
  382. if (readIf("HELP")) {
  383. c = parseHelp();
  384. }
  385. break;
  386. case 'i':
  387. case 'I':
  388. if (readIf("INSERT")) {
  389. c = parseInsert();
  390. }
  391. break;
  392. case 'm':
  393. case 'M':
  394. if (readIf("MERGE")) {
  395. c = parseMerge();
  396. }
  397. break;
  398. case 'p':
  399. case 'P':
  400. if (readIf("PREPARE")) {
  401. c = parsePrepare();
  402. }
  403. break;
  404. case 'r':
  405. case 'R':
  406. if (readIf("ROLLBACK")) {
  407. c = parseRollback();
  408. } else if (readIf("REVOKE")) {
  409. c = parseGrantRevoke(CommandInterface.REVOKE);
  410. } else if (readIf("RUNSCRIPT")) {
  411. c = parseRunScript();
  412. } else if (readIf("RELEASE")) {
  413. c = parseReleaseSavepoint();
  414. } else if (readIf("REPLACE")) {
  415. c = parseReplace();
  416. }
  417. break;
  418. case 's':
  419. case 'S':
  420. if (isToken("SELECT")) {
  421. c = parseSelect();
  422. } else if (readIf("SET")) {
  423. c = parseSet();
  424. } else if (readIf("SAVEPOINT")) {
  425. c = parseSavepoint();
  426. } else if (readIf("SCRIPT")) {
  427. c = parseScript();
  428. } else if (readIf("SHUTDOWN")) {
  429. c = parseShutdown();
  430. } else if (readIf("SHOW")) {
  431. c = parseShow();
  432. }
  433. break;
  434. case 't':
  435. case 'T':
  436. if (readIf("TRUNCATE")) {
  437. c = parseTruncate();
  438. }
  439. break;
  440. case 'u':
  441. case 'U':
  442. if (readIf("UPDATE")) {
  443. c = parseUpdate();
  444. }
  445. break;
  446. case 'v':
  447. case 'V':
  448. if (readIf("VALUES")) {
  449. c = parseValues();
  450. }
  451. break;
  452. case 'w':
  453. case 'W':
  454. if (readIf("WITH")) {
  455. c = parseWith();
  456. }
  457. break;
  458. case ';':
  459. c = new NoOperation(session);
  460. break;
  461. default:
  462. throw getSyntaxError();
  463. }
  464. if (indexedParameterList != null) {
  465. for (int i = 0, size = indexedParameterList.size();
  466. i < size; i++) {
  467. if (indexedParameterList.get(i) == null) {
  468. indexedParameterList.set(i, new Parameter(i));
  469. }
  470. }
  471. parameters = indexedParameterList;
  472. }
  473. if (readIf("{")) {
  474. do {
  475. int index = (int) readLong() - 1;
  476. if (index < 0 || index >= parameters.size()) {
  477. throw getSyntaxError();
  478. }
  479. Parameter p = parameters.get(index);
  480. if (p == null) {
  481. throw getSyntaxError();
  482. }
  483. read(":");
  484. Expression expr = readExpression();
  485. expr = expr.optimize(session);
  486. p.setValue(expr.getValue(session));
  487. } while (readIf(","));
  488. read("}");
  489. for (Parameter p : parameters) {
  490. p.checkSet();
  491. }
  492. parameters.clear();
  493. }
  494. }
  495. if (c == null) {
  496. throw getSyntaxError();
  497. }
  498. setSQL(c, null, start);
  499. return c;
  500. }
  501. private DbException getSyntaxError() {
  502. if (expectedList == null || expectedList.size() == 0) {
  503. return DbException.getSyntaxError(sqlCommand, parseIndex);
  504. }
  505. StatementBuilder buff = new StatementBuilder();
  506. for (String e : expectedList) {
  507. buff.appendExceptFirst(", ");
  508. buff.append(e);
  509. }
  510. return DbException.getSyntaxError(sqlCommand, parseIndex,
  511. buff.toString());
  512. }
  513. private Prepared parseBackup() {
  514. BackupCommand command = new BackupCommand(session);
  515. read("TO");
  516. command.setFileName(readExpression());
  517. return command;
  518. }
  519. private Prepared parseAnalyze() {
  520. Analyze command = new Analyze(session);
  521. if (readIf("SAMPLE_SIZE")) {
  522. command.setTop(getPositiveInt());
  523. }
  524. return command;
  525. }
  526. private TransactionCommand parseBegin() {
  527. TransactionCommand command;
  528. if (!readIf("WORK")) {
  529. readIf("TRANSACTION");
  530. }
  531. command = new TransactionCommand(session, CommandInterface.BEGIN);
  532. return command;
  533. }
  534. private TransactionCommand parseCommit() {
  535. TransactionCommand command;
  536. if (readIf("TRANSACTION")) {
  537. command = new TransactionCommand(session,
  538. CommandInterface.COMMIT_TRANSACTION);
  539. command.setTransactionName(readUniqueIdentifier());
  540. return command;
  541. }
  542. command = new TransactionCommand(session,
  543. CommandInterface.COMMIT);
  544. readIf("WORK");
  545. return command;
  546. }
  547. private TransactionCommand parseShutdown() {
  548. int type = CommandInterface.SHUTDOWN;
  549. if (readIf("IMMEDIATELY")) {
  550. type = CommandInterface.SHUTDOWN_IMMEDIATELY;
  551. } else if (readIf("COMPACT")) {
  552. type = CommandInterface.SHUTDOWN_COMPACT;
  553. } else if (readIf("DEFRAG")) {
  554. type = CommandInterface.SHUTDOWN_DEFRAG;
  555. } else {
  556. readIf("SCRIPT");
  557. }
  558. return new TransactionCommand(session, type);
  559. }
  560. private TransactionCommand parseRollback() {
  561. TransactionCommand command;
  562. if (readIf("TRANSACTION")) {
  563. command = new TransactionCommand(session,
  564. CommandInterface.ROLLBACK_TRANSACTION);
  565. command.setTransactionName(readUniqueIdentifier());
  566. return command;
  567. }
  568. if (readIf("TO")) {
  569. read("SAVEPOINT");
  570. command = new TransactionCommand(session,
  571. CommandInterface.ROLLBACK_TO_SAVEPOINT);
  572. command.setSavepointName(readUniqueIdentifier());
  573. } else {
  574. readIf("WORK");
  575. command = new TransactionCommand(session,
  576. CommandInterface.ROLLBACK);
  577. }
  578. return command;
  579. }
  580. private Prepared parsePrepare() {
  581. if (readIf("COMMIT")) {
  582. TransactionCommand command = new TransactionCommand(session,
  583. CommandInterface.PREPARE_COMMIT);
  584. command.setTransactionName(readUniqueIdentifier());
  585. return command;
  586. }
  587. String procedureName = readAliasIdentifier();
  588. if (readIf("(")) {
  589. ArrayList<Column> list = New.arrayList();
  590. for (int i = 0;; i++) {
  591. Column column = parseColumnForTable("C" + i, true);
  592. list.add(column);
  593. if (readIf(")")) {
  594. break;
  595. }
  596. read(",");
  597. }
  598. }
  599. read("AS");
  600. Prepared prep = parsePrepared();
  601. PrepareProcedure command = new PrepareProcedure(session);
  602. command.setProcedureName(procedureName);
  603. command.setPrepared(prep);
  604. return command;
  605. }
  606. private TransactionCommand parseSavepoint() {
  607. TransactionCommand command = new TransactionCommand(session,
  608. CommandInterface.SAVEPOINT);
  609. command.setSavepointName(readUniqueIdentifier());
  610. return command;
  611. }
  612. private Prepared parseReleaseSavepoint() {
  613. Prepared command = new NoOperation(session);
  614. readIf("SAVEPOINT");
  615. readUniqueIdentifier();
  616. return command;
  617. }
  618. private Schema getSchema(String schemaName) {
  619. if (schemaName == null) {
  620. return null;
  621. }
  622. Schema schema = database.findSchema(schemaName);
  623. if (schema == null) {
  624. if (equalsToken("SESSION", schemaName)) {
  625. // for local temporary tables
  626. schema = database.getSchema(session.getCurrentSchemaName());
  627. } else if (database.getMode().sysDummy1 &&
  628. "SYSIBM".equals(schemaName)) {
  629. // IBM DB2 and Apache Derby compatibility: SYSIBM.SYSDUMMY1
  630. } else {
  631. throw DbException.get(ErrorCode.SCHEMA_NOT_FOUND_1, schemaName);
  632. }
  633. }
  634. return schema;
  635. }
  636. private Schema getSchema() {
  637. return getSchema(schemaName);
  638. }
  639. private Column readTableColumn(TableFilter filter) {
  640. String tableAlias = null;
  641. String columnName = readColumnIdentifier();
  642. if (readIf(".")) {
  643. tableAlias = columnName;
  644. columnName = readColumnIdentifier();
  645. if (readIf(".")) {
  646. String schema = tableAlias;
  647. tableAlias = columnName;
  648. columnName = readColumnIdentifier();
  649. if (readIf(".")) {
  650. String catalogName = schema;
  651. schema = tableAlias;
  652. tableAlias = columnName;
  653. columnName = readColumnIdentifier();
  654. if (!equalsToken(catalogName, database.getShortName())) {
  655. throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1,
  656. catalogName);
  657. }
  658. }
  659. if (!equalsToken(schema, filter.getTable().getSchema()
  660. .getName())) {
  661. throw DbException.get(ErrorCode.SCHEMA_NOT_FOUND_1, schema);
  662. }
  663. }
  664. if (!equalsToken(tableAlias, filter.getTableAlias())) {
  665. throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1,
  666. tableAlias);
  667. }
  668. }
  669. if (database.getSettings().rowId) {
  670. if (Column.ROWID.equals(columnName)) {
  671. return filter.getRowIdColumn();
  672. }
  673. }
  674. return filter.getTable().getColumn(columnName);
  675. }
  676. private Update parseUpdate() {
  677. Update command = new Update(session);
  678. currentPrepared = command;
  679. int start = lastParseIndex;
  680. TableFilter filter = readSimpleTableFilter();
  681. command.setTableFilter(filter);
  682. read("SET");
  683. if (readIf("(")) {
  684. ArrayList<Column> columns = New.arrayList();
  685. do {
  686. Column column = readTableColumn(filter);
  687. columns.add(column);
  688. } while (readIf(","));
  689. read(")");
  690. read("=");
  691. Expression expression = readExpression();
  692. if (columns.size() == 1) {
  693. // the expression is parsed as a simple value
  694. command.setAssignment(columns.get(0), expression);
  695. } else {
  696. for (int i = 0, size = columns.size(); i < size; i++) {
  697. Column column = columns.get(i);
  698. Function f = Function.getFunction(database, "ARRAY_GET");
  699. f.setParameter(0, expression);
  700. f.setParameter(1, ValueExpression.get(ValueInt.get(i + 1)));
  701. f.doneWithParameters();
  702. command.setAssignment(column, f);
  703. }
  704. }
  705. } else {
  706. do {
  707. Column column = readTableColumn(filter);
  708. read("=");
  709. Expression expression;
  710. if (readIf("DEFAULT")) {
  711. expression = ValueExpression.getDefault();
  712. } else {
  713. expression = readExpression();
  714. }
  715. command.setAssignment(column, expression);
  716. } while (readIf(","));
  717. }
  718. if (readIf("WHERE")) {
  719. Expression condition = readExpression();
  720. command.setCondition(condition);
  721. }
  722. if (readIf("LIMIT")) {
  723. Expression limit = readTerm().optimize(session);
  724. command.setLimit(limit);
  725. }
  726. setSQL(command, "UPDATE", start);
  727. return command;
  728. }
  729. private TableFilter readSimpleTableFilter() {
  730. Table table = readTableOrView();
  731. String alias = null;
  732. if (readIf("AS")) {
  733. alias = readAliasIdentifier();
  734. } else if (currentTokenType == IDENTIFIER) {
  735. if (!equalsToken("SET", currentToken)) {
  736. // SET is not a keyword (PostgreSQL supports it as a table name)
  737. alias = readAliasIdentifier();
  738. }
  739. }
  740. return new TableFilter(session, table, alias, rightsChecked,
  741. currentSelect);
  742. }
  743. private Delete parseDelete() {
  744. Delete command = new Delete(session);
  745. Expression limit = null;
  746. if (readIf("TOP")) {
  747. limit = readTerm().optimize(session);
  748. }
  749. currentPrepared = command;
  750. int start = lastParseIndex;
  751. readIf("FROM");
  752. TableFilter filter = readSimpleTableFilter();
  753. command.setTableFilter(filter);
  754. if (readIf("WHERE")) {
  755. Expression condition = readExpression();
  756. command.setCondition(condition);
  757. }
  758. if (readIf("LIMIT") && limit == null) {
  759. limit = readTerm().optimize(session);
  760. }
  761. command.setLimit(limit);
  762. setSQL(command, "DELETE", start);
  763. return command;
  764. }
  765. private IndexColumn[] parseIndexColumnList() {
  766. ArrayList<IndexColumn> columns = New.arrayList();
  767. do {
  768. IndexColumn column = new IndexColumn();
  769. column.columnName = readColumnIdentifier();
  770. columns.add(column);
  771. if (readIf("ASC")) {
  772. // ignore
  773. } else if (readIf("DESC")) {
  774. column.sortType = SortOrder.DESCENDING;
  775. }
  776. if (readIf("NULLS")) {
  777. if (readIf("FIRST")) {
  778. column.sortType |= SortOrder.NULLS_FIRST;
  779. } else {
  780. read("LAST");
  781. column.sortType |= SortOrder.NULLS_LAST;
  782. }
  783. }
  784. } while (readIf(","));
  785. read(")");
  786. return columns.toArray(new IndexColumn[columns.size()]);
  787. }
  788. private String[] parseColumnList() {
  789. ArrayList<String> columns = New.arrayList();
  790. do {
  791. String columnName = readColumnIdentifier();
  792. columns.add(columnName);
  793. } while (readIfMore());
  794. return columns.toArray(new String[columns.size()]);
  795. }
  796. private Column[] parseColumnList(Table table) {
  797. ArrayList<Column> columns = New.arrayList();
  798. HashSet<Column> set = New.hashSet();
  799. if (!readIf(")")) {
  800. do {
  801. Column column = parseColumn(table);
  802. if (!set.add(column)) {
  803. throw DbException.get(ErrorCode.DUPLICATE_COLUMN_NAME_1,
  804. column.getSQL());
  805. }
  806. columns.add(column);
  807. } while (readIfMore());
  808. }
  809. return columns.toArray(new Column[columns.size()]);
  810. }
  811. private Column parseColumn(Table table) {
  812. String id = readColumnIdentifier();
  813. if (database.getSettings().rowId && Column.ROWID.equals(id)) {
  814. return table.getRowIdColumn();
  815. }
  816. return table.getColumn(id);
  817. }
  818. private boolean readIfMore() {
  819. if (readIf(",")) {
  820. return !readIf(")");
  821. }
  822. read(")");
  823. return false;
  824. }
  825. private Prepared parseHelp() {
  826. StringBuilder buff = new StringBuilder(
  827. "SELECT * FROM INFORMATION_SCHEMA.HELP");
  828. int i = 0;
  829. ArrayList<Value> paramValues = New.arrayList();
  830. while (currentTokenType != END) {
  831. String s = currentToken;
  832. read();
  833. if (i == 0) {
  834. buff.append(" WHERE ");
  835. } else {
  836. buff.append(" AND ");
  837. }
  838. i++;
  839. buff.append("UPPER(TOPIC) LIKE ?");
  840. paramValues.add(ValueString.get("%" + s + "%"));
  841. }
  842. return prepare(session, buff.toString(), paramValues);
  843. }
  844. private Prepared parseShow() {
  845. ArrayList<Value> paramValues = New.arrayList();
  846. StringBuilder buff = new StringBuilder("SELECT ");
  847. if (readIf("CLIENT_ENCODING")) {
  848. // for PostgreSQL compatibility
  849. buff.append("'UNICODE' AS CLIENT_ENCODING FROM DUAL");
  850. } else if (readIf("DEFAULT_TRANSACTION_ISOLATION")) {
  851. // for PostgreSQL compatibility
  852. buff.append("'read committed' AS DEFAULT_TRANSACTION_ISOLATION " +
  853. "FROM DUAL");
  854. } else if (readIf("TRANSACTION")) {
  855. // for PostgreSQL compatibility
  856. read("ISOLATION");
  857. read("LEVEL");
  858. buff.append("'read committed' AS TRANSACTION_ISOLATION " +
  859. "FROM DUAL");
  860. } else if (readIf("DATESTYLE")) {
  861. // for PostgreSQL compatibility
  862. buff.append("'ISO' AS DATESTYLE FROM DUAL");
  863. } else if (readIf("SERVER_VERSION")) {
  864. // for PostgreSQL compatibility
  865. buff.append("'8.1.4' AS SERVER_VERSION FROM DUAL");
  866. } else if (readIf("SERVER_ENCODING")) {
  867. // for PostgreSQL compatibility
  868. buff.append("'UTF8' AS SERVER_ENCODING FROM DUAL");
  869. } else if (readIf("TABLES")) {
  870. // for MySQL compatibility
  871. String schema = Constants.SCHEMA_MAIN;
  872. if (readIf("FROM")) {
  873. schema = readUniqueIdentifier();
  874. }
  875. buff.append("TABLE_NAME, TABLE_SCHEMA FROM "
  876. + "INFORMATION_SCHEMA.TABLES "
  877. + "WHERE TABLE_SCHEMA=? ORDER BY TABLE_NAME");
  878. paramValues.add(ValueString.get(schema));
  879. } else if (readIf("COLUMNS")) {
  880. // for MySQL compatibility
  881. read("FROM");
  882. String tableName = readIdentifierWithSchema();
  883. String schemaName = getSchema().getName();
  884. paramValues.add(ValueString.get(tableName));
  885. if (readIf("FROM")) {
  886. schemaName = readUniqueIdentifier();
  887. }
  888. buff.append("C.COLUMN_NAME FIELD, "
  889. + "C.TYPE_NAME || '(' || C.NUMERIC_PRECISION || ')' TYPE, "
  890. + "C.IS_NULLABLE \"NULL\", "
  891. + "CASE (SELECT MAX(I.INDEX_TYPE_NAME) FROM "
  892. + "INFORMATION_SCHEMA.INDEXES I "
  893. + "WHERE I.TABLE_SCHEMA=C.TABLE_SCHEMA "
  894. + "AND I.TABLE_NAME=C.TABLE_NAME "
  895. + "AND I.COLUMN_NAME=C.COLUMN_NAME)"
  896. + "WHEN 'PRIMARY KEY' THEN 'PRI' "
  897. + "WHEN 'UNIQUE INDEX' THEN 'UNI' ELSE '' END KEY, "
  898. + "IFNULL(COLUMN_DEFAULT, 'NULL') DEFAULT "
  899. + "FROM INFORMATION_SCHEMA.COLUMNS C "
  900. + "WHERE C.TABLE_NAME=? AND C.TABLE_SCHEMA=? "
  901. + "ORDER BY C.ORDINAL_POSITION");
  902. paramValues.add(ValueString.get(schemaName));
  903. } else if (readIf("DATABASES") || readIf("SCHEMAS")) {
  904. // for MySQL compatibility
  905. buff.append("SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA");
  906. }
  907. boolean b = session.getAllowLiterals();
  908. try {
  909. // need to temporarily enable it, in case we are in
  910. // ALLOW_LITERALS_NUMBERS mode
  911. session.setAllowLiterals(true);
  912. return prepare(session, buff.toString(), paramValues);
  913. } finally {
  914. session.setAllowLiterals(b);
  915. }
  916. }
  917. private static Prepared prepare(Session s, String sql,
  918. ArrayList<Value> paramValues) {
  919. Prepared prep = s.prepare(sql);
  920. ArrayList<Parameter> params = prep.getParameters();
  921. if (params != null) {
  922. for (int i = 0, size = params.size(); i < size; i++) {
  923. Parameter p = params.get(i);
  924. p.setValue(paramValues.get(i));
  925. }
  926. }
  927. return prep;
  928. }
  929. private boolean isSelect() {
  930. int start = lastParseIndex;
  931. while (readIf("(")) {
  932. // need to read ahead, it could be a nested union:
  933. // ((select 1) union (select 1))
  934. }
  935. boolean select = isToken("SELECT") || isToken("FROM");
  936. parseIndex = start;
  937. read();
  938. return select;
  939. }
  940. private Merge parseMerge() {
  941. Merge command = new Merge(session);
  942. currentPrepared = command;
  943. read("INTO");
  944. Table table = readTableOrView();
  945. command.setTable(table);
  946. if (readIf("(")) {
  947. if (isSelect()) {
  948. command.setQuery(parseSelect());
  949. read(")");
  950. return command;
  951. }
  952. Column[] columns = parseColumnList(table);
  953. command.setColumns(columns);
  954. }
  955. if (readIf("KEY")) {
  956. read("(");
  957. Column[] keys = parseColumnList(table);
  958. command.setKeys(keys);
  959. }
  960. if (readIf("VALUES")) {
  961. do {
  962. ArrayList<Expression> values = New.arrayList();
  963. read("(");
  964. if (!readIf(")")) {
  965. do {
  966. if (readIf("DEFAULT")) {
  967. values.add(null);
  968. } else {
  969. values.add(readExpression());
  970. }
  971. } while (readIfMore());
  972. }
  973. command.addRow(values.toArray(new Expression[values.size()]));
  974. } while (readIf(","));
  975. } else {
  976. command.setQuery(parseSelect());
  977. }
  978. return command;
  979. }
  980. private Insert parseInsert() {
  981. Insert command = new Insert(session);
  982. currentPrepared = command;
  983. read("INTO");
  984. Table table = readTableOrView();
  985. command.setTable(table);
  986. Column[] columns = null;
  987. if (readIf("(")) {
  988. if (isSelect()) {
  989. command.setQuery(parseSelect());
  990. read(")");
  991. return command;
  992. }
  993. columns = parseColumnList(table);
  994. command.setColumns(columns);
  995. }
  996. if (readIf("DIRECT")) {
  997. command.setInsertFromSelect(true);
  998. }
  999. if (readIf("SORTED")) {
  1000. command.setSortedInsertMode(true);
  1001. }
  1002. if (readIf("DEFAULT")) {
  1003. read("VALUES");
  1004. Expression[] expr = {};
  1005. command.addRow(expr);
  1006. } else if (readIf("VALUES")) {
  1007. read("(");
  1008. do {
  1009. ArrayList<Expression> values = New.arrayList();
  1010. if (!readIf(")")) {
  1011. do {
  1012. if (readIf("DEFAULT")) {
  1013. values.add(null);
  1014. } else {
  1015. values.add(readExpression());
  1016. }
  1017. } while (readIfMore());
  1018. }
  1019. command.addRow(values.toArray(new Expression[values.size()]));
  1020. // the following condition will allow (..),; and (..);
  1021. } while (readIf(",") && readIf("("));
  1022. } else if (readIf("SET")) {
  1023. if (columns != null) {
  1024. throw getSyntaxError();
  1025. }
  1026. ArrayList<Column> columnList = New.arrayList();
  1027. ArrayList<Expression> values = New.arrayList();
  1028. do {
  1029. columnList.add(parseColumn(table));
  1030. read("=");
  1031. Expression expression;
  1032. if (readIf("DEFAULT")) {
  1033. expression = ValueExpression.getDefault();
  1034. } else {
  1035. expression = readExpression();
  1036. }
  1037. values.add(expression);
  1038. } while (readIf(","));
  1039. command.setColumns(columnList.toArray(new Column[columnList.size()]));
  1040. command.addRow(values.toArray(new Expression[values.size()]));
  1041. } else {
  1042. command.setQuery(parseSelect());
  1043. }
  1044. if (database.getMode().onDuplicateKeyUpdate) {
  1045. if (readIf("ON")) {
  1046. read("DUPLICATE");
  1047. read("KEY");
  1048. read("UPDATE");
  1049. do {
  1050. Column column = parseColumn(table);
  1051. read("=");
  1052. Expression expression;
  1053. if (readIf("DEFAULT")) {
  1054. expression = ValueExpression.getDefault();
  1055. } else {
  1056. expression = readExpression();
  1057. }
  1058. command.addAssignmentForDuplicate(column, expression);
  1059. } while (readIf(","));
  1060. }
  1061. }
  1062. if (database.getMode().isolationLevelInSelectOrInsertStatement) {
  1063. parseIsolationClause();
  1064. }
  1065. return command;
  1066. }
  1067. /**
  1068. * MySQL compatibility. REPLACE is similar to MERGE.
  1069. */
  1070. private Replace parseReplace() {
  1071. Replace command = new Replace(session);
  1072. currentPrepared = command;
  1073. read("INTO");
  1074. Table table = readTableOrView();
  1075. command.setTable(table);
  1076. if (readIf("(")) {
  1077. if (isSelect()) {
  1078. command.setQuery(parseSelect());
  1079. read(")");
  1080. return command;
  1081. }
  1082. Column[] columns = parseColumnList(table);
  1083. command.setColumns(columns);
  1084. }
  1085. if (readIf("VALUES")) {
  1086. do {
  1087. ArrayList<Expression> values = New.arrayList();
  1088. read("(");
  1089. if (!readIf(")")) {
  1090. do {
  1091. if (readIf("DEFAULT")) {
  1092. values.add(null);
  1093. } else {
  1094. values.add(readExpression());
  1095. }
  1096. } while (readIfMore());
  1097. }
  1098. command.addRow(values.toArray(new Expression[values.size()]));
  1099. } while (readIf(","));
  1100. } else {
  1101. command.setQuery(parseSelect());
  1102. }
  1103. return command;
  1104. }
  1105. private TableFilter readTableFilter(boolean fromOuter) {
  1106. Table table;
  1107. String alias = null;
  1108. if (readIf("(")) {
  1109. if (isSelect()) {
  1110. Query query = parseSelectUnion();
  1111. read(")");
  1112. query.setParameterList(New.arrayList(parameters));
  1113. query.init();
  1114. Session s;
  1115. if (createView != null) {
  1116. s = database.getSystemSession();
  1117. } else {
  1118. s = session;
  1119. }
  1120. alias = session.getNextSystemIdentifier(sqlCommand);
  1121. table = TableView.createTempView(s, session.getUser(), alias,
  1122. query, currentSelect);
  1123. } else {
  1124. TableFilter top;
  1125. if (database.getSettings().nestedJoins) {
  1126. top = readTableFilter(false);
  1127. top = readJoin(top, currentSelect, false, false);
  1128. top = getNested(top);
  1129. } else {
  1130. top = readTableFilter(fromOuter);
  1131. top = readJoin(top, currentSelect, false, fromOuter);
  1132. }
  1133. read(")");
  1134. alias = readFromAlias(null);
  1135. if (alias != null) {
  1136. top.setAlias(alias);
  1137. }
  1138. return top;
  1139. }
  1140. } else if (readIf("VALUES")) {
  1141. table = parseValuesTable().getTable();
  1142. } else {
  1143. String tableName = readIdentifierWithSchema(null);
  1144. Schema schema = getSchema();
  1145. boolean foundLeftBracket = readIf("(");
  1146. if (foundLeftBracket && readIf("INDEX")) {
  1147. // Sybase compatibility with
  1148. // "select * from test (index table1_index)"
  1149. readIdentifierWithSchema(null);
  1150. read(")");
  1151. foundLeftBracket = false;
  1152. }
  1153. if (foundLeftBracket) {
  1154. Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
  1155. if (equalsToken(tableName, RangeTable.NAME)) {
  1156. Expression min = readExpression();
  1157. read(",");
  1158. Expression max = readExpression();
  1159. read(")");
  1160. table = new RangeTable(mainSchema, min, max, false);
  1161. } else {
  1162. Expression expr = readFunction(schema, tableName);
  1163. if (!(expr instanceof FunctionCall)) {
  1164. throw getSyntaxError();
  1165. }
  1166. FunctionCall call = (FunctionCall) expr;
  1167. if (!call.isDeterministic()) {
  1168. recompileAlways = true;
  1169. }
  1170. table = new FunctionTable(mainSchema, session, expr, call);
  1171. }
  1172. } else if (equalsToken("DUAL", tableName)) {
  1173. table = getDualTable(false);
  1174. } else if (database.getMode().sysDummy1 &&
  1175. equalsToken("SYSDUMMY1", tableName)) {
  1176. table = getDualTable(false);
  1177. } else {
  1178. table = readTableOrView(tableName);
  1179. }
  1180. }
  1181. alias = readFromAlias(alias);
  1182. return new TableFilter(session, table, alias, rightsChecked,
  1183. currentSelect);
  1184. }
  1185. private String readFromAlias(String alias) {
  1186. if (readIf("AS")) {
  1187. alias = readAliasIdentifier();
  1188. } else if (currentTokenType == IDENTIFIER) {
  1189. // left and right are not keywords (because they are functions as
  1190. // well)
  1191. if (!isToken("LEFT") && !isToken("RIGHT") && !isToken("FULL")) {
  1192. alias = readAliasIdentifier();
  1193. }
  1194. }
  1195. return alias;
  1196. }
  1197. private Prepared parseTruncate() {
  1198. read("TABLE");
  1199. Table table = readTableOrView();
  1200. TruncateTable command = new TruncateTable(session);
  1201. command.setTable(table);
  1202. return command;
  1203. }
  1204. private boolean readIfExists(boolean ifExists) {
  1205. if (readIf("IF")) {
  1206. read("EXISTS");
  1207. ifExists = true;
  1208. }
  1209. return ifExists;
  1210. }
  1211. private Prepared parseComment() {
  1212. int type = 0;
  1213. read("ON");
  1214. boolean column = false;
  1215. if (readIf("TABLE") || readIf("VIEW")) {
  1216. type = DbObject.TABLE_OR_VIEW;
  1217. } else if (readIf("COLUMN")) {
  1218. column = true;
  1219. type = DbObject.TABLE_OR_VIEW;
  1220. } else if (readIf("CONSTANT")) {
  1221. type = DbObject.CONSTANT;
  1222. } else if (readIf("CONSTRAINT")) {
  1223. type = DbObject.CONSTRAINT;
  1224. } else if (readIf("ALIAS")) {
  1225. type = DbObject.FUNCTION_ALIAS;
  1226. } else if (readIf("INDEX")) {
  1227. type = DbObject.INDEX;
  1228. } else if (readIf("ROLE")) {
  1229. type = DbObject.ROLE;
  1230. } else if (readIf("SCHEMA")) {
  1231. type = DbObject.SCHEMA;
  1232. } else if (readIf("SEQUENCE")) {
  1233. type = DbObject.SEQUENCE;
  1234. } else if (readIf("TRIGGER")) {
  1235. type = DbObject.TRIGGER;
  1236. } else if (readIf("USER")) {
  1237. type = DbObject.USER;
  1238. } else if (readIf("DOMAIN")) {
  1239. type = DbObject.USER_DATATYPE;
  1240. } else {
  1241. throw getSyntaxError();
  1242. }
  1243. SetComment command = new SetComment(session);
  1244. String objectName;
  1245. if (column) {
  1246. // can't use readIdentifierWithSchema() because
  1247. // it would not read schema.table.column correctly
  1248. // if the db name is equal to the schema name
  1249. ArrayList<String> list = New.arrayList();
  1250. do {
  1251. list.add(readUniqueIdentifier());
  1252. } while (readIf("."));
  1253. schemaName = session.getCurrentSchemaName();
  1254. if (list.size() == 4) {
  1255. if (!equalsToken(database.getShortName(), list.get(0))) {
  1256. throw DbException.getSyntaxError(sqlCommand, parseIndex,
  1257. "database name");
  1258. }
  1259. list.remove(0);
  1260. }
  1261. if (list.size() == 3) {
  1262. schemaName = list.get(0);
  1263. list.remove(0);
  1264. }
  1265. if (list.size() != 2) {
  1266. throw DbException.getSyntaxError(sqlCommand, parseIndex,
  1267. "table.column");
  1268. }
  1269. objectName = list.get(0);
  1270. command.setColumn(true);
  1271. command.setColumnName(list.get(1));
  1272. } else {
  1273. objectName = readIdentifierWithSchema();
  1274. }
  1275. command.setSchemaName(schemaName);
  1276. command.setObjectName(objectName);
  1277. command.setObjectType(type);
  1278. read("IS");
  1279. command.setCommentExpression(readExpression());
  1280. return command;
  1281. }
  1282. private Prepared parseDrop() {
  1283. if (readIf("TABLE")) {
  1284. boolean ifExists = readIfExists(false);
  1285. String tableName = readIdentifierWithSchema();
  1286. DropTable command = new DropTable(session, getSchema());
  1287. command.setTableName(tableName);
  1288. while (readIf(",")) {
  1289. tableName = readIdentifierWithSchema();
  1290. DropTable next = new DropTable(session, getSchema());
  1291. next.setTableName(tableName);
  1292. command.addNextDropTable(next);
  1293. }
  1294. ifExists = readIfExists(ifExists);
  1295. command.setIfExists(ifExists);
  1296. if (readIf("CASCADE")) {
  1297. command.setDropAction(ConstraintReferential.CASCADE);
  1298. readIf("CONSTRAINTS");
  1299. } else if (readIf("RESTRICT")) {
  1300. command.setDropAction(ConstraintReferential.RESTRICT);
  1301. } else if (readIf("IGNORE")) {
  1302. command.setDropAction(ConstraintReferential.SET_DEFAULT);
  1303. }
  1304. return command;
  1305. } else if (readIf("INDEX")) {
  1306. boolean ifExists = readIfExists(false);
  1307. String indexName = readIdentifierWithSchema();
  1308. DropIndex command = new DropIndex(session, getSchema());
  1309. command.setIndexName(indexName);
  1310. ifExists = readIfExists(ifExists);
  1311. command.setIfExists(ifExists);
  1312. return command;
  1313. } else if (readIf("USER")) {
  1314. boolean ifExists = readIfExists(false);
  1315. DropUser command = new DropUser(session);
  1316. command.setUserName(readUniqueIdentifier());
  1317. ifExists = readIfExists(ifExists);
  1318. readIf("CASCADE");
  1319. command.setIfExists(ifExists);
  1320. return command;
  1321. } else if (readIf("SEQUENCE")) {
  1322. boolean ifExists = readIfExists(false);
  1323. String sequenceName = readIdentifierWithSchema();
  1324. DropSequence command = new DropSequence(session, getSchema());
  1325. command.setSequenceName(sequenceName);
  1326. ifExists = readIfExists(ifExists);
  1327. command.setIfExists(ifExists);
  1328. return command;
  1329. } else if (readIf("CONSTANT")) {
  1330. boolean ifExists = readIfExists(false);
  1331. String constantName = readIdentifierWithSchema();
  1332. DropConstant command = new DropConstant(session, getSchema());
  1333. command.setConstantName(constantName);
  1334. ifExists = readIfExists(ifExists);
  1335. command.setIfExists(ifExists);
  1336. return command;
  1337. } else if (readIf("TRIGGER")) {
  1338. boolean ifExists = readIfExists(false);
  1339. String triggerName = readIdentifierWithSchema();
  1340. DropTrigger command = new DropTrigger(session, getSchema());
  1341. command.setTriggerName(triggerName);
  1342. ifExists = readIfExists(ifExists);
  1343. command.setIfExists(ifExists);
  1344. return command;
  1345. } else if (readIf("VIEW")) {
  1346. boolean ifExists = readIfExists(false);
  1347. String viewName = readIdentifierWithSchema();
  1348. DropView command = new DropView(session, getSchema());
  1349. command.setViewName(viewName);
  1350. ifExists = readIfExists(ifExists);
  1351. command.setIfExists(ifExists);
  1352. Integer dropAction = parseCascadeOrRestrict();
  1353. if (dropAction != null) {
  1354. command.setDropAction(dropAction);
  1355. }
  1356. return command;
  1357. } else if (readIf("ROLE")) {
  1358. boolean ifExists = readIfExists(false);
  1359. DropRole command = new DropRole(session);
  1360. command.setRoleName(readUniqueIdentifier());
  1361. ifExists = readIfExists(ifExists);
  1362. command.setIfExists(ifExists);
  1363. return command;
  1364. } else if (readIf("ALIAS")) {
  1365. boolean ifExists = readIfExists(false);
  1366. String aliasName = readIdentifierWithSchema();
  1367. DropFunctionAlias command = new DropFunctionAlias(session,
  1368. getSchema());
  1369. command.setAliasName(aliasName);
  1370. ifExists = readIfExists(ifExists);
  1371. command.setIfExists(ifExists);
  1372. return command;
  1373. } else if (readIf("SCHEMA")) {
  1374. boolean ifExists = readIfExists(false);
  1375. DropSchema command = new DropSchema(session);
  1376. command.setSchemaName(readUniqueIdentifier());
  1377. ifExists = readIfExists(ifExists);
  1378. command.setIfExists(ifExists);
  1379. return command;
  1380. } else if (readIf("ALL")) {
  1381. read("OBJECTS");
  1382. DropDatabase command = new DropDatabase(session);
  1383. command.setDropAllObjects(true);
  1384. if (readIf("DELETE")) {
  1385. read("FILES");
  1386. command.setDeleteFiles(true);
  1387. }
  1388. return command;
  1389. } else if (readIf("DOMAIN")) {
  1390. return parseDropUserDataType();
  1391. } else if (readIf("TYPE")) {
  1392. return parseDropUserDataType();
  1393. } else if (readIf("DATATYPE")) {
  1394. return parseDropUserDataType();
  1395. } else if (readIf("AGGREGATE")) {
  1396. return parseDropAggregate();
  1397. }
  1398. throw getSyntaxError();
  1399. }
  1400. private DropUserDataType parseDropUserDataType() {
  1401. boolean ifExists = readIfExists(false);
  1402. DropUserDataType command = new DropUserDataType(session);
  1403. command.setTypeName(readUniqueIdentifier());
  1404. ifExists = readIfExists(ifExists);
  1405. command.setIfExists(ifExists);
  1406. return command;
  1407. }
  1408. private DropAggregate parseDropAggregate() {
  1409. boolean ifExists = readIfExists(false);
  1410. DropAggregate command = new DropAggregate(session);
  1411. command.setName(readUniqueIdentifier());
  1412. ifExists = readIfExists(ifExists);
  1413. command.setIfExists(ifExists);
  1414. return command;
  1415. }
  1416. private TableFilter readJoin(TableFilter top, Select command,
  1417. boolean nested, boolean fromOuter) {
  1418. boolean joined = false;
  1419. TableFilter last = top;
  1420. boolean nestedJoins = database.getSettings().nestedJoins;
  1421. while (true) {
  1422. if (readIf("RIGHT")) {
  1423. readIf("OUTER");
  1424. read("JOIN");
  1425. joined = true;
  1426. // the right hand side is the 'inner' table usually
  1427. TableFilter newTop = readTableFilter(fromOuter);
  1428. newTop = readJoin(newTop, command, nested, true);
  1429. Expression on = null;
  1430. if (readIf("ON")) {
  1431. on = readExpression();
  1432. }
  1433. if (nestedJoins) {
  1434. top = getNested(top);
  1435. newTop.addJoin(top, true, false, on);
  1436. } else {
  1437. newTop.addJoin(top, true, false, on);
  1438. }
  1439. top = newTop;
  1440. last = newTop;
  1441. } else if (readIf("LEFT")) {
  1442. readIf("OUTER");
  1443. read("JOIN");
  1444. joined = true;
  1445. TableFilter join = readTableFilter(true);
  1446. if (nestedJoins) {
  1447. join = readJoin(join, command, true, true);
  1448. } else {
  1449. top = readJoin(top, command, false, true);
  1450. }
  1451. Expression on = null;
  1452. if (readIf("ON")) {
  1453. on = readExpression();
  1454. }
  1455. top.addJoin(join, true, false, on);
  1456. last = join;
  1457. } else if (readIf("FULL")) {
  1458. throw getSyntaxError();
  1459. } else if (readIf("INNER")) {
  1460. read("JOIN");
  1461. joined = true;
  1462. TableFilter join = readTableFilter(fromOuter);
  1463. top = readJoin(top, command, false, false);
  1464. Expression on = null;
  1465. if (readIf("ON")) {
  1466. on = readExpression();
  1467. }
  1468. if (nestedJoins) {
  1469. top.addJoin(join, false, false, on);
  1470. } else {
  1471. top.addJoin(join, fromOuter, false, on);
  1472. }
  1473. last = join;
  1474. } else if (readIf("JOIN")) {
  1475. joined = true;
  1476. TableFilter join = readTableFilter(fromOuter);
  1477. top = readJoin(top, command, false, false);
  1478. Expression on = null;
  1479. if (readIf("ON")) {
  1480. on = readExpression();
  1481. }
  1482. if (nestedJoins) {
  1483. top.addJoin(join, false, false, on);
  1484. } else {
  1485. top.addJoin(join, fromOuter, false, on);
  1486. }
  1487. last = join;
  1488. } else if (readIf("CROSS")) {
  1489. read("JOIN");
  1490. joined = true;
  1491. TableFilter join = readTableFilter(fromOuter);
  1492. if (nestedJoins) {
  1493. top.addJoin(join, false, false, null);
  1494. } else {
  1495. top.addJoin(join, fromOuter, false, null);
  1496. }
  1497. last = join;
  1498. } else if (readIf("NATURAL")) {
  1499. read("JOIN");
  1500. joined = true;
  1501. TableFilter join = readTableFilter(fromOuter);
  1502. Column[] tableCols = last.getTable().getColumns();
  1503. Column[] joinCols = join.getTable().getColumns();
  1504. String tableSchema = last.getTable().getSchema().getName();
  1505. String joinSchema = join.getTable().getSchema().getName();
  1506. Expression on = null;
  1507. for (Column tc : tableCols) {
  1508. String tableColumnName = tc.getName();
  1509. for (Column c : joinCols) {
  1510. String joinColumnName = c.getName();
  1511. if (equalsToken(tableColumnName, joinColumnName)) {
  1512. join.addNaturalJoinColumn(c);
  1513. Expression tableExpr = new ExpressionColumn(
  1514. database, tableSchema,
  1515. last.getTableAlias(), tableColumnName);
  1516. Expression joinExpr = new ExpressionColumn(
  1517. database, joinSchema, join.getTableAlias(),
  1518. joinColumnName);
  1519. Expression equal = new Comparison(session,
  1520. Comparison.EQUAL, tableExpr, joinExpr);
  1521. if (on == null) {
  1522. on = equal;
  1523. } else {
  1524. on = new ConditionAndOr(ConditionAndOr.AND, on,
  1525. equal);
  1526. }
  1527. }
  1528. }
  1529. }
  1530. if (nestedJoins) {
  1531. top.addJoin(join, false, nested, on);
  1532. } else {
  1533. top.addJoin(join, fromOuter, false, on);
  1534. }
  1535. last = join;
  1536. } else {
  1537. break;
  1538. }
  1539. }
  1540. if (nested && joined) {
  1541. top = getNested(top);
  1542. }
  1543. return top;
  1544. }
  1545. private TableFilter getNested(TableFilter n) {
  1546. String joinTable = Constants.PREFIX_JOIN + parseIndex;
  1547. TableFilter top = new TableFilter(session, getDualTable(true),
  1548. joinTable, rightsChecked, currentSelect);
  1549. top.addJoin(n, false, true, null);
  1550. return top;
  1551. }
  1552. private Prepared parseExecute() {
  1553. ExecuteProcedure command = new ExecuteProcedure(session);
  1554. String procedureName = readAliasIdentifier();
  1555. Procedure p = session.getProcedure(procedureName);
  1556. if (p == null) {
  1557. throw DbException.get(ErrorCode.FUNCTION_ALIAS_NOT_FOUND_1,
  1558. procedureName);
  1559. }
  1560. command.setProcedure(p);
  1561. if (readIf("(")) {
  1562. for (int i = 0;; i++) {
  1563. command.setExpression(i, readExpression());
  1564. if (readIf(")")) {
  1565. break;
  1566. }
  1567. read(",");
  1568. }
  1569. }
  1570. return command;
  1571. }
  1572. private DeallocateProcedure parseDeallocate() {
  1573. readIf("PLAN");
  1574. String procedureName = readAliasIdentifier();
  1575. DeallocateProcedure command = new DeallocateProcedure(session);
  1576. command.setProcedureName(procedureName);
  1577. return command;
  1578. }
  1579. private Explain parseExplain() {
  1580. Explain command = new Explain(session);
  1581. if (readIf("ANALYZE")) {
  1582. command.setExecuteCommand(true);
  1583. } else {
  1584. if (readIf("PLAN")) {
  1585. readIf("FOR");
  1586. }
  1587. }
  1588. if (isToken("SELECT") || isToken("FROM") || isToken("(")) {
  1589. command.setCommand(parseSelect());
  1590. } else if (readIf("DELETE")) {
  1591. command.setCommand(parseDelete());
  1592. } else if (readIf("UPDATE")) {
  1593. command.setCommand(parseUpdate());
  1594. } else if (readIf("INSERT")) {
  1595. command.setCommand(parseInsert());
  1596. } else if (readIf("MERGE")) {
  1597. command.setCommand(parseMerge());
  1598. } else if (readIf("WITH")) {
  1599. command.setCommand(parseWith());
  1600. } else {
  1601. throw getSyntaxError();
  1602. }
  1603. return command;
  1604. }
  1605. private Query parseSelect() {
  1606. int paramIndex = parameters.size();
  1607. Query command = parseSelectUnion();
  1608. ArrayList<Parameter> params = New.arrayList();
  1609. for (int i = paramIndex, size = parameters.size(); i < size; i++) {
  1610. params.add(parameters.get(i));
  1611. }
  1612. command.setParameterList(params);
  1613. command.init();
  1614. return command;
  1615. }
  1616. private Query parseSelectUnion() {
  1617. int start = lastParseIndex;
  1618. Query command = parseSelectSub();
  1619. return parseSelectUnionExtension(command, start, false);
  1620. }
  1621. private Query parseSelectUnionExtension(Query command, int start,
  1622. boolean unionOnly) {
  1623. while (true) {
  1624. if (readIf("UNION")) {
  1625. SelectUnion union = new SelectUnion(session, command);
  1626. if (readIf("ALL")) {
  1627. union.setUnionType(SelectUnion.UNION_ALL);
  1628. } else {
  1629. readIf("DISTINCT");
  1630. union.setUnionType(SelectUnion.UNION);
  1631. }
  1632. union.setRight(parseSelectSub());
  1633. command = union;
  1634. } else if (readIf("MINUS") || readIf("EXCEPT")) {
  1635. SelectUnion union = new SelectUnion(session, command);
  1636. union.setUnionType(SelectUnion.EXCEPT);
  1637. union.setRight(parseSelectSub());
  1638. command = union;
  1639. } else if (readIf("INTERSECT")) {
  1640. SelectUnion union = new SelectUnion(session, command);
  1641. union.setUnionType(SelectUnion.INTERSECT);
  1642. union.setRight(parseSelectSub());
  1643. command = union;
  1644. } else {
  1645. break;
  1646. }
  1647. }
  1648. if (!unionOnly) {
  1649. parseEndOfQuery(command);
  1650. }
  1651. setSQL(command, null, start);
  1652. return command;
  1653. }
  1654. private void parseEndOfQuery(Query command) {
  1655. if (readIf("ORDER")) {
  1656. read("BY");
  1657. Select oldSelect = currentSelect;
  1658. if (command instanceof Select) {
  1659. currentSelect = (Select) command;
  1660. }
  1661. ArrayList<SelectOrderBy> orderList = New.arrayList();
  1662. do {
  1663. boolean canBeNumber = true;
  1664. if (readIf("=")) {
  1665. canBeNumber = false;
  1666. }
  1667. SelectOrderBy order = new SelectOrderBy();
  1668. Expression expr = readExpression();
  1669. if (canBeNumber && expr instanceof ValueExpression &&
  1670. expr.getType() == Value.INT) {
  1671. order.columnIndexExpr = expr;
  1672. } else if (expr instanceof Parameter) {
  1673. recompileAlways = true;
  1674. order.columnIndexExpr = expr;
  1675. } else {
  1676. order.expression = expr;
  1677. }
  1678. if (readIf("DESC")) {
  1679. order.descending = true;
  1680. } else {
  1681. readIf("ASC");
  1682. }
  1683. if (readIf("NULLS")) {
  1684. if (readIf("FIRST")) {
  1685. order.nullsFirst = true;
  1686. } else {
  1687. read("LAST");
  1688. order.nullsLast = true;
  1689. }
  1690. }
  1691. orderList.add(order);
  1692. } while (readIf(","));
  1693. command.setOrder(orderList);
  1694. currentSelect = oldSelect;
  1695. }
  1696. if (database.getMode().supportOffsetFetch) {
  1697. // make sure aggregate functions will not work here
  1698. Select temp = currentSelect;
  1699. currentSelect = null;
  1700. // http://sqlpro.developpez.com/SQL2008/
  1701. if (readIf("OFFSET")) {
  1702. command.setOffset(readExpression().optimize(session));
  1703. if (!readIf("ROW")) {
  1704. read("ROWS");
  1705. }
  1706. }
  1707. if (readIf("FETCH")) {
  1708. if (!readIf("FIRST")) {
  1709. read("NEXT");
  1710. }
  1711. if (readIf("ROW")) {
  1712. command.setLimit(ValueExpression.get(ValueInt.get(1)));
  1713. } else {
  1714. Expression limit = readExpression().optimize(session);
  1715. command.setLimit(limit);
  1716. if (!readIf("ROW")) {
  1717. read("ROWS");
  1718. }
  1719. }
  1720. read("ONLY");
  1721. }
  1722. currentSelect = temp;
  1723. }
  1724. if (readIf("LIMIT")) {
  1725. Select temp = currentSelect;
  1726. // make sure aggregate functions will not work here
  1727. currentSelect = null;
  1728. Expression limit = readExpression().optimize(session);
  1729. command.setLimit(limit);
  1730. if (readIf("OFFSET")) {
  1731. Expression offset = readExpression().optimize(session);
  1732. command.setOffset(offset);
  1733. } else if (readIf(",")) {
  1734. // MySQL: [offset, ] rowcount
  1735. Expression offset = limit;
  1736. limit = readExpression().optimize(session);
  1737. command.setOffset(offset);
  1738. command.setLimit(limit);
  1739. }
  1740. if (readIf("SAMPLE_SIZE")) {
  1741. Expression sampleSize = readExpression().optimize(session);
  1742. command.setSampleSize(sampleSize);
  1743. }
  1744. currentSelect = temp;
  1745. }
  1746. if (readIf("FOR")) {
  1747. if (readIf("UPDATE")) {
  1748. if (readIf("OF")) {
  1749. do {
  1750. readIdentifierWithSchema();
  1751. } while (readIf(","));
  1752. } else if (readIf("NOWAIT")) {
  1753. // TODO parser: select for update nowait: should not wait
  1754. }
  1755. command.setForUpdate(true);
  1756. } else if (readIf("READ") || readIf("FETCH")) {
  1757. read("ONLY");
  1758. }
  1759. }
  1760. if (database.getMode().isolationLevelInSelectOrInsertStatement) {
  1761. parseIsolationClause();
  1762. }
  1763. }
  1764. /**
  1765. * DB2 isolation clause
  1766. */
  1767. private void parseIsolationClause() {
  1768. if (readIf("WITH")) {
  1769. if (readIf("RR") || readIf("RS")) {
  1770. // concurrent-access-resolution clause
  1771. if (readIf("USE")) {
  1772. read("AND");
  1773. read("KEEP");
  1774. if (readIf("SHARE") || readIf("UPDATE") ||
  1775. readIf("EXCLUSIVE")) {
  1776. // ignore
  1777. }
  1778. read("LOCKS");
  1779. }
  1780. } else if (readIf("CS") || readIf("UR")) {
  1781. // ignore
  1782. }
  1783. }
  1784. }
  1785. private Query parseSelectSub() {
  1786. if (readIf("(")) {
  1787. Query command = parseSelectUnion();
  1788. read(")");
  1789. return command;
  1790. }
  1791. Select select = parseSelectSimple();
  1792. return select;
  1793. }
  1794. private void parseSelectSimpleFromPart(Select command) {
  1795. do {
  1796. TableFilter filter = readTableFilter(false);
  1797. parseJoinTableFilter(filter, command);
  1798. } while (readIf(","));
  1799. }
  1800. private void parseJoinTableFilter(TableFilter top, final Select command) {
  1801. top = readJoin(top, command, false, top.isJoinOuter());
  1802. command.addTableFilter(top, true);
  1803. boolean isOuter = false;
  1804. while (true) {
  1805. TableFilter n = top.getNestedJoin();
  1806. if (n != null) {
  1807. n.visit(new TableFilterVisitor() {
  1808. @Override
  1809. public void accept(TableFilter f) {
  1810. command.addTableFilter(f, false);
  1811. }
  1812. });
  1813. }
  1814. TableFilter join = top.getJoin();
  1815. if (join == null) {
  1816. break;
  1817. }
  1818. isOuter = isOuter | join.isJoinOuter();
  1819. if (isOuter) {
  1820. command.addTableFilter(join, false);
  1821. } else {
  1822. // make flat so the optimizer can work better
  1823. Expression on = join.getJoinCondition();
  1824. if (on != null) {
  1825. command.addCondition(on);
  1826. }
  1827. join.removeJoinCondition();
  1828. top.removeJoin();
  1829. command.addTableFilter(join, true);
  1830. }
  1831. top = join;
  1832. }
  1833. }
  1834. private void parseSelectSimpleSelectPart(Select command) {
  1835. Select temp = currentSelect;
  1836. // make sure aggregate functions will not work in TOP and LIMIT
  1837. currentSelect = null;
  1838. if (readIf("TOP")) {
  1839. // can't read more complex expressions here because
  1840. // SELECT TOP 1 +? A FROM TEST could mean
  1841. // SELECT TOP (1+?) A FROM TEST or
  1842. // SELECT TOP 1 (+?) AS A FROM TEST
  1843. Expression limit = readTerm().optimize(session);
  1844. command.setLimit(limit);
  1845. } else if (readIf("LIMIT")) {
  1846. Expression offset = readTerm().optimize(session);
  1847. command.setOffset(offset);
  1848. Expression limit = readTerm().optimize(session);
  1849. command.setLimit(limit);
  1850. }
  1851. currentSelect = temp;
  1852. if (readIf("DISTINCT")) {
  1853. command.setDistinct(true);
  1854. } else {
  1855. readIf("ALL");
  1856. }
  1857. ArrayList<Expression> expressions = New.arrayList();
  1858. do {
  1859. if (readIf("*")) {
  1860. expressions.add(new Wildcard(null, null));
  1861. } else {
  1862. Expression expr = readExpression();
  1863. if (readIf("AS") || currentTokenType == IDENTIFIER) {
  1864. String alias = readAliasIdentifier();
  1865. boolean aliasColumnName = database.getSettings().aliasColumnName;
  1866. aliasColumnName |= database.getMode().aliasColumnName;
  1867. expr = new Alias(expr, alias, aliasColumnName);
  1868. }
  1869. expressions.add(expr);
  1870. }
  1871. } while (readIf(","));
  1872. command.setExpressions(expressions);
  1873. }
  1874. private Select parseSelectSimple() {
  1875. boolean fromFirst;
  1876. if (readIf("SELECT")) {
  1877. fromFirst = false;
  1878. } else if (readIf("FROM")) {
  1879. fromFirst = true;
  1880. } else {
  1881. throw getSyntaxError();
  1882. }
  1883. Select command = new Select(session);
  1884. int start = lastParseIndex;
  1885. Select oldSelect = currentSelect;
  1886. currentSelect = command;
  1887. currentPrepared = command;
  1888. if (fromFirst) {
  1889. parseSelectSimpleFromPart(command);
  1890. read("SELECT");
  1891. parseSelectSimpleSelectPart(command);
  1892. } else {
  1893. parseSelectSimpleSelectPart(command);
  1894. if (!readIf("FROM")) {
  1895. // select without FROM: convert to SELECT ... FROM
  1896. // SYSTEM_RANGE(1,1)
  1897. Table dual = getDualTable(false);
  1898. TableFilter filter = new TableFilter(session, dual, null,
  1899. rightsChecked, currentSelect);
  1900. command.addTableFilter(filter, true);
  1901. } else {
  1902. parseSelectSimpleFromPart(command);
  1903. }
  1904. }
  1905. if (readIf("WHERE")) {
  1906. Expression condition = readExpression();
  1907. command.addCondition(condition);
  1908. }
  1909. // the group by is read for the outer select (or not a select)
  1910. // so that columns that are not grouped can be used
  1911. currentSelect = oldSelect;
  1912. if (readIf("GROUP")) {
  1913. read("BY");
  1914. command.setGroupQuery();
  1915. ArrayList<Expression> list = New.arrayList();
  1916. do {
  1917. Expression expr = readExpression();
  1918. list.add(expr);
  1919. } while (readIf(","));
  1920. command.setGroupBy(list);
  1921. }
  1922. currentSelect = command;
  1923. if (readIf("HAVING")) {
  1924. command.setGroupQuery();
  1925. Expression condition = readExpression();
  1926. command.setHaving(condition);
  1927. }
  1928. command.setParameterList(parameters);
  1929. currentSelect = oldSelect;
  1930. setSQL(command, "SELECT", start);
  1931. return command;
  1932. }
  1933. private Table getDualTable(boolean noColumns) {
  1934. Schema main = database.findSchema(Constants.SCHEMA_MAIN);
  1935. Expression one = ValueExpression.get(ValueLong.get(1));
  1936. return new RangeTable(main, one, one, noColumns);
  1937. }
  1938. private void setSQL(Prepared command, String start, int startIndex) {
  1939. String sql = originalSQL.substring(startIndex, lastParseIndex).trim();
  1940. if (start != null) {
  1941. sql = start + " " + sql;
  1942. }
  1943. command.setSQL(sql);
  1944. }
  1945. private Expression readExpression() {
  1946. Expression r = readAnd();
  1947. while (readIf("OR")) {
  1948. r = new ConditionAndOr(ConditionAndOr.OR, r, readAnd());
  1949. }
  1950. return r;
  1951. }
  1952. private Expression readAnd() {
  1953. Expression r = readCondition();
  1954. while (readIf("AND")) {
  1955. r = new ConditionAndOr(ConditionAndOr.AND, r, readCondition());
  1956. }
  1957. return r;
  1958. }
  1959. private Expression readCondition() {
  1960. if (readIf("NOT")) {
  1961. return new ConditionNot(readCondition());
  1962. }
  1963. if (readIf("EXISTS")) {
  1964. read("(");
  1965. Query query = parseSelect();
  1966. // can not reduce expression because it might be a union except
  1967. // query with distinct
  1968. read(")");
  1969. return new ConditionExists(query);
  1970. }
  1971. if (readIf("INTERSECTS")) {
  1972. read("(");
  1973. Expression r1 = readConcat();
  1974. read(",");
  1975. Expression r2 = readConcat();
  1976. read(")");
  1977. return new Comparison(session, Comparison.SPATIAL_INTERSECTS, r1,
  1978. r2);
  1979. }
  1980. Expression r = readConcat();
  1981. while (true) {
  1982. // special case: NOT NULL is not part of an expression (as in CREATE
  1983. // TABLE TEST(ID INT DEFAULT 0 NOT NULL))
  1984. int backup = parseIndex;
  1985. boolean not = false;
  1986. if (readIf("NOT")) {
  1987. not = true;
  1988. if (isToken("NULL")) {
  1989. // this really only works for NOT NULL!
  1990. parseIndex = backup;
  1991. currentToken = "NOT";
  1992. break;
  1993. }
  1994. }
  1995. if (readIf("LIKE")) {
  1996. Expression b = readConcat();
  1997. Expression esc = null;
  1998. if (readIf("ESCAPE")) {
  1999. esc = readConcat();
  2000. }
  2001. recompileAlways = true;
  2002. r = new CompareLike(database, r, b, esc, false);
  2003. } else if (readIf("REGEXP")) {
  2004. Expression b = readConcat();
  2005. r = new CompareLike(database, r, b, null, true);
  2006. } else if (readIf("IS")) {
  2007. if (readIf("NOT")) {
  2008. if (readIf("NULL")) {
  2009. r = new Comparison(session, Comparison.IS_NOT_NULL, r,
  2010. null);
  2011. } else if (readIf("DISTINCT")) {
  2012. read("FROM");
  2013. r = new Comparison(session, Comparison.EQUAL_NULL_SAFE,
  2014. r, readConcat());
  2015. } else {
  2016. r = new Comparison(session,
  2017. Comparison.NOT_EQUAL_NULL_SAFE, r, readConcat());
  2018. }
  2019. } else if (readIf("NULL")) {
  2020. r = new Comparison(session, Comparison.IS_NULL, r, null);
  2021. } else if (readIf("DISTINCT")) {
  2022. read("FROM");
  2023. r = new Comparison(session, Comparison.NOT_EQUAL_NULL_SAFE,
  2024. r, readConcat());
  2025. } else {
  2026. r = new Comparison(session, Comparison.EQUAL_NULL_SAFE, r,
  2027. readConcat());
  2028. }
  2029. } else if (readIf("IN")) {
  2030. read("(");
  2031. if (readIf(")")) {
  2032. r = ValueExpression.get(ValueBoolean.get(false));
  2033. } else {
  2034. if (isSelect()) {
  2035. Query query = parseSelect();
  2036. r = new ConditionInSelect(database, r, query, false,
  2037. Comparison.EQUAL);
  2038. } else {
  2039. ArrayList<Expression> v = New.arrayList();
  2040. Expression last;
  2041. do {
  2042. last = readExpression();
  2043. v.add(last);
  2044. } while (readIf(","));
  2045. if (v.size() == 1 && (last instanceof Subquery)) {
  2046. Subquery s = (Subquery) last;
  2047. Query q = s.getQuery();
  2048. r = new ConditionInSelect(database, r, q, false,
  2049. Comparison.EQUAL);
  2050. } else {
  2051. r = new ConditionIn(database, r, v);
  2052. }
  2053. }
  2054. read(")");
  2055. }
  2056. } else if (readIf("BETWEEN")) {
  2057. Expression low = readConcat();
  2058. read("AND");
  2059. Expression high = readConcat();
  2060. Expression condLow = new Comparison(session,
  2061. Comparison.SMALLER_EQUAL, low, r);
  2062. Expression condHigh = new Comparison(session,
  2063. Comparison.BIGGER_EQUAL, high, r);
  2064. r = new ConditionAndOr(ConditionAndOr.AND, condLow, condHigh);
  2065. } else {
  2066. int compareType = getCompareType(currentTokenType);
  2067. if (compareType < 0) {
  2068. break;
  2069. }
  2070. read();
  2071. if (readIf("ALL")) {
  2072. read("(");
  2073. Query query = parseSelect();
  2074. r = new ConditionInSelect(database, r, query, true,
  2075. compareType);
  2076. read(")");
  2077. } else if (readIf("ANY") || readIf("SOME")) {
  2078. read("(");
  2079. Query query = parseSelect();
  2080. r = new ConditionInSelect(database, r, query, false,
  2081. compareType);
  2082. read(")");
  2083. } else {
  2084. Expression right = readConcat();
  2085. if (SysProperties.OLD_STYLE_OUTER_JOIN &&
  2086. readIf("(") && readIf("+") && readIf(")")) {
  2087. // support for a subset of old-fashioned Oracle outer
  2088. // join with (+)
  2089. if (r instanceof ExpressionColumn &&
  2090. right instanceof ExpressionColumn) {
  2091. ExpressionColumn leftCol = (ExpressionColumn) r;
  2092. ExpressionColumn rightCol = (ExpressionColumn) right;
  2093. ArrayList<TableFilter> filters = currentSelect
  2094. .getTopFilters();
  2095. for (TableFilter f : filters) {
  2096. while (f != null) {
  2097. leftCol.mapColumns(f, 0);
  2098. rightCol.mapColumns(f, 0);
  2099. f = f.getJoin();
  2100. }
  2101. }
  2102. TableFilter leftFilter = leftCol.getTableFilter();
  2103. TableFilter rightFilter = rightCol.getTableFilter();
  2104. r = new Comparison(session, compareType, r, right);
  2105. if (leftFilter != null && rightFilter != null) {
  2106. int idx = filters.indexOf(rightFilter);
  2107. if (idx >= 0) {
  2108. filters.remove(idx);
  2109. leftFilter.addJoin(rightFilter, true,
  2110. false, r);
  2111. } else {
  2112. rightFilter.mapAndAddFilter(r);
  2113. }
  2114. r = ValueExpression.get(ValueBoolean.get(true));
  2115. }
  2116. }
  2117. } else {
  2118. r = new Comparison(session, compareType, r, right);
  2119. }
  2120. }
  2121. }
  2122. if (not) {
  2123. r = new ConditionNot(r);
  2124. }
  2125. }
  2126. return r;
  2127. }
  2128. private Expression readConcat() {
  2129. Expression r = readSum();
  2130. while (true) {
  2131. if (readIf("||")) {
  2132. r = new Operation(Operation.CONCAT, r, readSum());
  2133. } else if (readIf("~")) {
  2134. if (readIf("*")) {
  2135. Function function = Function.getFunction(database, "CAST");
  2136. function.setDataType(new Column("X",
  2137. Value.STRING_IGNORECASE));
  2138. function.setParameter(0, r);
  2139. r = function;
  2140. }
  2141. r = new CompareLike(database, r, readSum(), null, true);
  2142. } else if (readIf("!~")) {
  2143. if (readIf("*")) {
  2144. Function function = Function.getFunction(database, "CAST");
  2145. function.setDataType(new Column("X",
  2146. Value.STRING_IGNORECASE));
  2147. function.setParameter(0, r);
  2148. r = function;
  2149. }
  2150. r = new ConditionNot(new CompareLike(database, r, readSum(),
  2151. null, true));
  2152. } else {
  2153. return r;
  2154. }
  2155. }
  2156. }
  2157. private Expression readSum() {
  2158. Expression r = readFactor();
  2159. while (true) {
  2160. if (readIf("+")) {
  2161. r = new Operation(Operation.PLUS, r, readFactor());
  2162. } else if (readIf("-")) {
  2163. r = new Operation(Operation.MINUS, r, readFactor());
  2164. } else {
  2165. return r;
  2166. }
  2167. }
  2168. }
  2169. private Expression readFactor() {
  2170. Expression r = readTerm();
  2171. while (true) {
  2172. if (readIf("*")) {
  2173. r = new Operation(Operation.MULTIPLY, r, readTerm());
  2174. } else if (readIf("/")) {
  2175. r = new Operation(Operation.DIVIDE, r, readTerm());
  2176. } else if (readIf("%")) {
  2177. r = new Operation(Operation.MODULUS, r, readTerm());
  2178. } else {
  2179. return r;
  2180. }
  2181. }
  2182. }
  2183. private Expression readAggregate(int aggregateType) {
  2184. if (currentSelect == null) {
  2185. throw getSyntaxError();
  2186. }
  2187. currentSelect.setGroupQuery();
  2188. Expression r;
  2189. if (aggregateType == Aggregate.COUNT) {
  2190. if (readIf("*")) {
  2191. r = new Aggregate(Aggregate.COUNT_ALL, null, currentSelect,
  2192. false);
  2193. } else {
  2194. boolean distinct = readIf("DISTINCT");
  2195. Expression on = readExpression();
  2196. if (on instanceof Wildcard && !distinct) {
  2197. // PostgreSQL compatibility: count(t.*)
  2198. r = new Aggregate(Aggregate.COUNT_ALL, null, currentSelect,
  2199. false);
  2200. } else {
  2201. r = new Aggregate(Aggregate.COUNT, on, currentSelect,
  2202. distinct);
  2203. }
  2204. }
  2205. } else if (aggregateType == Aggregate.GROUP_CONCAT) {
  2206. boolean distinct = readIf("DISTINCT");
  2207. Aggregate agg = new Aggregate(Aggregate.GROUP_CONCAT,
  2208. readExpression(), currentSelect, distinct);
  2209. if (readIf("ORDER")) {
  2210. read("BY");
  2211. agg.setGroupConcatOrder(parseSimpleOrderList());
  2212. }
  2213. if (readIf("SEPARATOR")) {
  2214. agg.setGroupConcatSeparator(readExpression());
  2215. }
  2216. r = agg;
  2217. } else {
  2218. boolean distinct = readIf("DISTINCT");
  2219. r = new Aggregate(aggregateType, readExpression(), currentSelect,
  2220. distinct);
  2221. }
  2222. read(")");
  2223. return r;
  2224. }
  2225. private ArrayList<SelectOrderBy> parseSimpleOrderList() {
  2226. ArrayList<SelectOrderBy> orderList = New.arrayList();
  2227. do {
  2228. SelectOrderBy order = new SelectOrderBy();
  2229. Expression expr = readExpression();
  2230. order.expression = expr;
  2231. if (readIf("DESC")) {
  2232. order.descending = true;
  2233. } else {
  2234. readIf("ASC");
  2235. }
  2236. orderList.add(order);
  2237. } while (readIf(","));
  2238. return orderList;
  2239. }
  2240. private JavaFunction readJavaFunction(Schema schema, String functionName) {
  2241. FunctionAlias functionAlias = null;
  2242. if (schema != null) {
  2243. functionAlias = schema.findFunction(functionName);
  2244. } else {
  2245. functionAlias = findFunctionAlias(session.getCurrentSchemaName(),
  2246. functionName);
  2247. }
  2248. if (functionAlias == null) {
  2249. throw DbException.get(ErrorCode.FUNCTION_NOT_FOUND_1, functionName);
  2250. }
  2251. Expression[] args;
  2252. ArrayList<Expression> argList = New.arrayList();
  2253. int numArgs = 0;
  2254. while (!readIf(")")) {
  2255. if (numArgs++ > 0) {
  2256. read(",");
  2257. }
  2258. argList.add(readExpression());
  2259. }
  2260. args = new Expression[numArgs];
  2261. argList.toArray(args);
  2262. JavaFunction func = new JavaFunction(functionAlias, args);
  2263. return func;
  2264. }
  2265. private JavaAggregate readJavaAggregate(UserAggregate aggregate) {
  2266. ArrayList<Expression> params = New.arrayList();
  2267. do {
  2268. params.add(readExpression());
  2269. } while (readIf(","));
  2270. read(")");
  2271. Expression[] list = new Expression[params.size()];
  2272. params.toArray(list);
  2273. JavaAggregate agg = new JavaAggregate(aggregate, list, currentSelect);
  2274. currentSelect.setGroupQuery();
  2275. return agg;
  2276. }
  2277. private int getAggregateType(String name) {
  2278. if (!identifiersToUpper) {
  2279. // if not yet converted to uppercase, do it now
  2280. name = StringUtils.toUpperEnglish(name);
  2281. }
  2282. return Aggregate.getAggregateType(name);
  2283. }
  2284. private Expression readFunction(Schema schema, String name) {
  2285. if (schema != null) {
  2286. return readJavaFunction(schema, name);
  2287. }
  2288. int agg = getAggregateType(name);
  2289. if (agg >= 0) {
  2290. return readAggregate(agg);
  2291. }
  2292. Function function = Function.getFunction(database, name);
  2293. if (function == null) {
  2294. UserAggregate aggregate = database.findAggregate(name);
  2295. if (aggregate != null) {
  2296. return readJavaAggregate(aggregate);
  2297. }
  2298. return readJavaFunction(null, name);
  2299. }
  2300. switch (function.getFunctionType()) {
  2301. case Function.CAST: {
  2302. function.setParameter(0, readExpression());
  2303. read("AS");
  2304. Column type = parseColumnWithType(null);
  2305. function.setDataType(type);
  2306. read(")");
  2307. break;
  2308. }
  2309. case Function.CONVERT: {
  2310. if (database.getMode().swapConvertFunctionParameters) {
  2311. Column type = parseColumnWithType(null);
  2312. function.setDataType(type);
  2313. read(",");
  2314. function.setParameter(0, readExpression());
  2315. read(")");
  2316. } else {
  2317. function.setParameter(0, readExpression());
  2318. read(",");
  2319. Column type = parseColumnWithType(null);
  2320. function.setDataType(type);
  2321. read(")");
  2322. }
  2323. break;
  2324. }
  2325. case Function.EXTRACT: {
  2326. function.setParameter(0,
  2327. ValueExpression.get(ValueString.get(currentToken)));
  2328. read();
  2329. read("FROM");
  2330. function.setParameter(1, readExpression());
  2331. read(")");
  2332. break;
  2333. }
  2334. case Function.DATE_ADD:
  2335. case Function.DATE_DIFF: {
  2336. if (Function.isDatePart(currentToken)) {
  2337. function.setParameter(0,
  2338. ValueExpression.get(ValueString.get(currentToken)));
  2339. read();
  2340. } else {
  2341. function.setParameter(0, readExpression());
  2342. }
  2343. read(",");
  2344. function.setParameter(1, readExpression());
  2345. read(",");
  2346. function.setParameter(2, readExpression());
  2347. read(")");
  2348. break;
  2349. }
  2350. case Function.SUBSTRING: {
  2351. // Different variants include:
  2352. // SUBSTRING(X,1)
  2353. // SUBSTRING(X,1,1)
  2354. // SUBSTRING(X FROM 1 FOR 1) -- Postgres
  2355. // SUBSTRING(X FROM 1) -- Postgres
  2356. // SUBSTRING(X FOR 1) -- Postgres
  2357. function.setParameter(0, readExpression());
  2358. if (readIf("FROM")) {
  2359. function.setParameter(1, readExpression());
  2360. if (readIf("FOR")) {
  2361. function.setParameter(2, readExpression());
  2362. }
  2363. } else if (readIf("FOR")) {
  2364. function.setParameter(1, ValueExpression.get(ValueInt.get(0)));
  2365. function.setParameter(2, readExpression());
  2366. } else {
  2367. read(",");
  2368. function.setParameter(1, readExpression());
  2369. if (readIf(",")) {
  2370. function.setParameter(2, readExpression());
  2371. }
  2372. }
  2373. read(")");
  2374. break;
  2375. }
  2376. case Function.POSITION: {
  2377. // can't read expression because IN would be read too early
  2378. function.setParameter(0, readConcat());
  2379. if (!readIf(",")) {
  2380. read("IN");
  2381. }
  2382. function.setParameter(1, readExpression());
  2383. read(")");
  2384. break;
  2385. }
  2386. case Function.TRIM: {
  2387. Expression space = null;
  2388. if (readIf("LEADING")) {
  2389. function = Function.getFunction(database, "LTRIM");
  2390. if (!readIf("FROM")) {
  2391. space = readExpression();
  2392. read("FROM");
  2393. }
  2394. } else if (readIf("TRAILING")) {
  2395. function = Function.getFunction(database, "RTRIM");
  2396. if (!readIf("FROM")) {
  2397. space = readExpression();
  2398. read("FROM");
  2399. }
  2400. } else if (readIf("BOTH")) {
  2401. if (!readIf("FROM")) {
  2402. space = readExpression();
  2403. read("FROM");
  2404. }
  2405. }
  2406. Expression p0 = readExpression();
  2407. if (readIf(",")) {
  2408. space = readExpression();
  2409. } else if (readIf("FROM")) {
  2410. space = p0;
  2411. p0 = readExpression();
  2412. }
  2413. function.setParameter(0, p0);
  2414. if (space != null) {
  2415. function.setParameter(1, space);
  2416. }
  2417. read(")");
  2418. break;
  2419. }
  2420. case Function.TABLE:
  2421. case Function.TABLE_DISTINCT: {
  2422. int i = 0;
  2423. ArrayList<Column> columns = New.arrayList();
  2424. do {
  2425. String columnName = readAliasIdentifier();
  2426. Column column = parseColumnWithType(columnName);
  2427. columns.add(column);
  2428. read("=");
  2429. function.setParameter(i, readExpression());
  2430. i++;
  2431. } while (readIf(","));
  2432. read(")");
  2433. TableFunction tf = (TableFunction) function;
  2434. tf.setColumns(columns);
  2435. break;
  2436. }
  2437. case Function.ROW_NUMBER:
  2438. read(")");
  2439. read("OVER");
  2440. read("(");
  2441. read(")");
  2442. return new Rownum(currentSelect == null ? currentPrepared
  2443. : currentSelect);
  2444. default:
  2445. if (!readIf(")")) {
  2446. int i = 0;
  2447. do {
  2448. function.setParameter(i++, readExpression());
  2449. } while (readIf(","));
  2450. read(")");
  2451. }
  2452. }
  2453. function.doneWithParameters();
  2454. return function;
  2455. }
  2456. private Function readFunctionWithoutParameters(String name) {
  2457. if (readIf("(")) {
  2458. read(")");
  2459. }
  2460. Function function = Function.getFunction(database, name);
  2461. function.doneWithParameters();
  2462. return function;
  2463. }
  2464. private Expression readWildcardOrSequenceValue(String schema,
  2465. String objectName) {
  2466. if (readIf("*")) {
  2467. return new Wildcard(schema, objectName);
  2468. }
  2469. if (schema == null) {
  2470. schema = session.getCurrentSchemaName();
  2471. }
  2472. if (readIf("NEXTVAL")) {
  2473. Sequence sequence = findSequence(schema, objectName);
  2474. if (sequence != null) {
  2475. return new SequenceValue(sequence);
  2476. }
  2477. } else if (readIf("CURRVAL")) {
  2478. Sequence sequence = findSequence(schema, objectName);
  2479. if (sequence != null) {
  2480. Function function = Function.getFunction(database, "CURRVAL");
  2481. function.setParameter(0, ValueExpression.get(ValueString
  2482. .get(sequence.getSchema().getName())));
  2483. function.setParameter(1, ValueExpression.get(ValueString
  2484. .get(sequence.getName())));
  2485. function.doneWithParameters();
  2486. return function;
  2487. }
  2488. }
  2489. return null;
  2490. }
  2491. private Expression readTermObjectDot(String objectName) {
  2492. Expression expr = readWildcardOrSequenceValue(null, objectName);
  2493. if (expr != null) {
  2494. return expr;
  2495. }
  2496. String name = readColumnIdentifier();
  2497. Schema s = database.findSchema(objectName);
  2498. if ((!SysProperties.OLD_STYLE_OUTER_JOIN || s != null) && readIf("(")) {
  2499. // only if the token before the dot is a valid schema name,
  2500. // otherwise the old style Oracle outer join doesn't work:
  2501. // t.x = t2.x(+)
  2502. // this additional check is not required
  2503. // if the old style outer joins are not supported
  2504. return readFunction(s, name);
  2505. } else if (readIf(".")) {
  2506. String schema = objectName;
  2507. objectName = name;
  2508. expr = readWildcardOrSequenceValue(schema, objectName);
  2509. if (expr != null) {
  2510. return expr;
  2511. }
  2512. name = readColumnIdentifier();
  2513. if (readIf("(")) {
  2514. String databaseName = schema;
  2515. if (!equalsToken(database.getShortName(), databaseName)) {
  2516. throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1,
  2517. databaseName);
  2518. }
  2519. schema = objectName;
  2520. return readFunction(database.getSchema(schema), name);
  2521. } else if (readIf(".")) {
  2522. String databaseName = schema;
  2523. if (!equalsToken(database.getShortName(), databaseName)) {
  2524. throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1,
  2525. databaseName);
  2526. }
  2527. schema = objectName;
  2528. objectName = name;
  2529. expr = readWildcardOrSequenceValue(schema, objectName);
  2530. if (expr != null) {
  2531. return expr;
  2532. }
  2533. name = readColumnIdentifier();
  2534. return new ExpressionColumn(database, schema, objectName, name);
  2535. }
  2536. return new ExpressionColumn(database, schema, objectName, name);
  2537. }
  2538. return new ExpressionColumn(database, null, objectName, name);
  2539. }
  2540. private Expression readTerm() {
  2541. Expression r;
  2542. switch (currentTokenType) {
  2543. case AT:
  2544. read();
  2545. r = new Variable(session, readAliasIdentifier());
  2546. if (readIf(":=")) {
  2547. Expression value = readExpression();
  2548. Function function = Function.getFunction(database, "SET");
  2549. function.setParameter(0, r);
  2550. function.setParameter(1, value);
  2551. r = function;
  2552. }
  2553. break;
  2554. case PARAMETER:
  2555. // there must be no space between ? and the number
  2556. boolean indexed = Character.isDigit(sqlCommandChars[parseIndex]);
  2557. read();
  2558. Parameter p;
  2559. if (indexed && currentTokenType == VALUE &&
  2560. currentValue.getType() == Value.INT) {
  2561. if (indexedParameterList == null) {
  2562. if (parameters == null) {
  2563. // this can occur when parsing expressions only (for
  2564. // example check constraints)
  2565. throw getSyntaxError();
  2566. } else if (parameters.size() > 0) {
  2567. throw DbException
  2568. .get(ErrorCode.CANNOT_MIX_INDEXED_AND_UNINDEXED_PARAMS);
  2569. }
  2570. indexedParameterList = New.arrayList();
  2571. }
  2572. int index = currentValue.getInt() - 1;
  2573. if (index < 0 || index >= Constants.MAX_PARAMETER_INDEX) {
  2574. throw DbException.getInvalidValueException(
  2575. "parameter index", index);
  2576. }
  2577. if (indexedParameterList.size() <= index) {
  2578. indexedParameterList.ensureCapacity(index + 1);
  2579. while (indexedParameterList.size() <= index) {
  2580. indexedParameterList.add(null);
  2581. }
  2582. }
  2583. p = indexedParameterList.get(index);
  2584. if (p == null) {
  2585. p = new Parameter(index);
  2586. indexedParameterList.set(index, p);
  2587. }
  2588. read();
  2589. } else {
  2590. if (indexedParameterList != null) {
  2591. throw DbException
  2592. .get(ErrorCode.CANNOT_MIX_INDEXED_AND_UNINDEXED_PARAMS);
  2593. }
  2594. p = new Parameter(parameters.size());
  2595. }
  2596. parameters.add(p);
  2597. r = p;
  2598. break;
  2599. case KEYWORD:
  2600. if (isToken("SELECT") || isToken("FROM")) {
  2601. Query query = parseSelect();
  2602. r = new Subquery(query);
  2603. } else {
  2604. throw getSyntaxError();
  2605. }
  2606. break;
  2607. case IDENTIFIER:
  2608. String name = currentToken;
  2609. if (currentTokenQuoted) {
  2610. read();
  2611. if (readIf("(")) {
  2612. r = readFunction(null, name);
  2613. } else if (readIf(".")) {
  2614. r = readTermObjectDot(name);
  2615. } else {
  2616. r = new ExpressionColumn(database, null, null, name);
  2617. }
  2618. } else {
  2619. read();
  2620. if (readIf(".")) {
  2621. r = readTermObjectDot(name);
  2622. } else if (equalsToken("CASE", name)) {
  2623. // CASE must be processed before (,
  2624. // otherwise CASE(3) would be a function call, which it is
  2625. // not
  2626. r = readCase();
  2627. } else if (readIf("(")) {
  2628. r = readFunction(null, name);
  2629. } else if (equalsToken("CURRENT_USER", name)) {
  2630. r = readFunctionWithoutParameters("USER");
  2631. } else if (equalsToken("CURRENT", name)) {
  2632. if (readIf("TIMESTAMP")) {
  2633. r = readFunctionWithoutParameters("CURRENT_TIMESTAMP");
  2634. } else if (readIf("TIME")) {
  2635. r = readFunctionWithoutParameters("CURRENT_TIME");
  2636. } else if (readIf("DATE")) {
  2637. r = readFunctionWithoutParameters("CURRENT_DATE");
  2638. } else {
  2639. r = new ExpressionColumn(database, null, null, name);
  2640. }
  2641. } else if (equalsToken("NEXT", name) && readIf("VALUE")) {
  2642. read("FOR");
  2643. Sequence sequence = readSequence();
  2644. r = new SequenceValue(sequence);
  2645. } else if (currentTokenType == VALUE &&
  2646. currentValue.getType() == Value.STRING) {
  2647. if (equalsToken("DATE", name)) {
  2648. String date = currentValue.getString();
  2649. read();
  2650. r = ValueExpression.get(ValueDate.parse(date));
  2651. } else if (equalsToken("TIME", name)) {
  2652. String time = currentValue.getString();
  2653. read();
  2654. r = ValueExpression.get(ValueTime.parse(time));
  2655. } else if (equalsToken("TIMESTAMP", name)) {
  2656. String timestamp = currentValue.getString();
  2657. read();
  2658. r = ValueExpression
  2659. .get(ValueTimestamp.parse(timestamp));
  2660. } else if (equalsToken("X", name)) {
  2661. read();
  2662. byte[] buffer = StringUtils
  2663. .convertHexToBytes(currentValue.getString());
  2664. r = ValueExpression.get(ValueBytes.getNoCopy(buffer));
  2665. } else if (equalsToken("E", name)) {
  2666. String text = currentValue.getString();
  2667. // the PostgreSQL ODBC driver uses
  2668. // LIKE E'PROJECT\\_DATA' instead of LIKE
  2669. // 'PROJECT\_DATA'
  2670. // N: SQL-92 "National Language" strings
  2671. text = StringUtils.replaceAll(text, "\\\\", "\\");
  2672. read();
  2673. r = ValueExpression.get(ValueString.get(text));
  2674. } else if (equalsToken("N", name)) {
  2675. // SQL-92 "National Language" strings
  2676. String text = currentValue.getString();
  2677. read();
  2678. r = ValueExpression.get(ValueString.get(text));
  2679. } else {
  2680. r = new ExpressionColumn(database, null, null, name);
  2681. }
  2682. } else {
  2683. r = new ExpressionColumn(database, null, null, name);
  2684. }
  2685. }
  2686. break;
  2687. case MINUS:
  2688. read();
  2689. if (currentTokenType == VALUE) {
  2690. r = ValueExpression.get(currentValue.negate());
  2691. if (r.getType() == Value.LONG &&
  2692. r.getValue(session).getLong() == Integer.MIN_VALUE) {
  2693. // convert Integer.MIN_VALUE to type 'int'
  2694. // (Integer.MAX_VALUE+1 is of type 'long')
  2695. r = ValueExpression.get(ValueInt.get(Integer.MIN_VALUE));
  2696. } else if (r.getType() == Value.DECIMAL &&
  2697. r.getValue(session).getBigDecimal()
  2698. .compareTo(ValueLong.MIN_BD) == 0) {
  2699. // convert Long.MIN_VALUE to type 'long'
  2700. // (Long.MAX_VALUE+1 is of type 'decimal')
  2701. r = ValueExpression.get(ValueLong.get(Long.MIN_VALUE));
  2702. }
  2703. read();
  2704. } else {
  2705. r = new Operation(Operation.NEGATE, readTerm(), null);
  2706. }
  2707. break;
  2708. case PLUS:
  2709. read();
  2710. r = readTerm();
  2711. break;
  2712. case OPEN:
  2713. read();
  2714. if (readIf(")")) {
  2715. r = new ExpressionList(new Expression[0]);
  2716. } else {
  2717. r = readExpression();
  2718. if (readIf(",")) {
  2719. ArrayList<Expression> list = New.arrayList();
  2720. list.add(r);
  2721. while (!readIf(")")) {
  2722. r = readExpression();
  2723. list.add(r);
  2724. if (!readIf(",")) {
  2725. read(")");
  2726. break;
  2727. }
  2728. }
  2729. Expression[] array = new Expression[list.size()];
  2730. list.toArray(array);
  2731. r = new ExpressionList(array);
  2732. } else {
  2733. read(")");
  2734. }
  2735. }
  2736. break;
  2737. case TRUE:
  2738. read();
  2739. r = ValueExpression.get(ValueBoolean.get(true));
  2740. break;
  2741. case FALSE:
  2742. read();
  2743. r = ValueExpression.get(ValueBoolean.get(false));
  2744. break;
  2745. case CURRENT_TIME:
  2746. read();
  2747. r = readFunctionWithoutParameters("CURRENT_TIME");
  2748. break;
  2749. case CURRENT_DATE:
  2750. read();
  2751. r = readFunctionWithoutParameters("CURRENT_DATE");
  2752. break;
  2753. case CURRENT_TIMESTAMP: {
  2754. Function function = Function.getFunction(database,
  2755. "CURRENT_TIMESTAMP");
  2756. read();
  2757. if (readIf("(")) {
  2758. if (!readIf(")")) {
  2759. function.setParameter(0, readExpression());
  2760. read(")");
  2761. }
  2762. }
  2763. function.doneWithParameters();
  2764. r = function;
  2765. break;
  2766. }
  2767. case ROWNUM:
  2768. read();
  2769. if (readIf("(")) {
  2770. read(")");
  2771. }
  2772. r = new Rownum(currentSelect == null ? currentPrepared
  2773. : currentSelect);
  2774. break;
  2775. case NULL:
  2776. read();
  2777. r = ValueExpression.getNull();
  2778. break;
  2779. case VALUE:
  2780. r = ValueExpression.get(currentValue);
  2781. read();
  2782. break;
  2783. default:
  2784. throw getSyntaxError();
  2785. }
  2786. if (readIf("[")) {
  2787. Function function = Function.getFunction(database, "ARRAY_GET");
  2788. function.setParameter(0, r);
  2789. r = readExpression();
  2790. r = new Operation(Operation.PLUS, r, ValueExpression.get(ValueInt
  2791. .get(1)));
  2792. function.setParameter(1, r);
  2793. r = function;
  2794. read("]");
  2795. }
  2796. if (readIf("::")) {
  2797. // PostgreSQL compatibility
  2798. if (isToken("PG_CATALOG")) {
  2799. read("PG_CATALOG");
  2800. read(".");
  2801. }
  2802. if (readIf("REGCLASS")) {
  2803. FunctionAlias f = findFunctionAlias(Constants.SCHEMA_MAIN,
  2804. "PG_GET_OID");
  2805. if (f == null) {
  2806. throw getSyntaxError();
  2807. }
  2808. Expression[] args = { r };
  2809. JavaFunction func = new JavaFunction(f, args);
  2810. r = func;
  2811. } else {
  2812. Column col = parseColumnWithType(null);
  2813. Function function = Function.getFunction(database, "CAST");
  2814. function.setDataType(col);
  2815. function.setParameter(0, r);
  2816. r = function;
  2817. }
  2818. }
  2819. return r;
  2820. }
  2821. private Expression readCase() {
  2822. if (readIf("END")) {
  2823. readIf("CASE");
  2824. return ValueExpression.getNull();
  2825. }
  2826. if (readIf("ELSE")) {
  2827. Expression elsePart = readExpression().optimize(session);
  2828. read("END");
  2829. readIf("CASE");
  2830. return elsePart;
  2831. }
  2832. int i;
  2833. Function function;
  2834. if (readIf("WHEN")) {
  2835. function = Function.getFunction(database, "CASE");
  2836. function.setParameter(0, null);
  2837. i = 1;
  2838. do {
  2839. function.setParameter(i++, readExpression());
  2840. read("THEN");
  2841. function.setParameter(i++, readExpression());
  2842. } while (readIf("WHEN"));
  2843. } else {
  2844. Expression expr = readExpression();
  2845. if (readIf("END")) {
  2846. readIf("CASE");
  2847. return ValueExpression.getNull();
  2848. }
  2849. if (readIf("ELSE")) {
  2850. Expression elsePart = readExpression().optimize(session);
  2851. read("END");
  2852. readIf("CASE");
  2853. return elsePart;
  2854. }
  2855. function = Function.getFunction(database, "CASE");
  2856. function.setParameter(0, expr);
  2857. i = 1;
  2858. read("WHEN");
  2859. do {
  2860. function.setParameter(i++, readExpression());
  2861. read("THEN");
  2862. function.setParameter(i++, readExpression());
  2863. } while (readIf("WHEN"));
  2864. }
  2865. if (readIf("ELSE")) {
  2866. function.setParameter(i, readExpression());
  2867. }
  2868. read("END");
  2869. readIf("CASE");
  2870. function.doneWithParameters();
  2871. return function;
  2872. }
  2873. private int getPositiveInt() {
  2874. int v = getInt();
  2875. if (v < 0) {
  2876. throw DbException.getInvalidValueException("positive integer", v);
  2877. }
  2878. return v;
  2879. }
  2880. private int getInt() {
  2881. boolean minus = false;
  2882. if (currentTokenType == MINUS) {
  2883. minus = true;
  2884. read();
  2885. } else if (currentTokenType == PLUS) {
  2886. read();
  2887. }
  2888. if (currentTokenType != VALUE || currentValue.getType() != Value.INT) {
  2889. throw DbException.getSyntaxError(sqlCommand, parseIndex, "integer");
  2890. }
  2891. int i = currentValue.getInt();
  2892. read();
  2893. return minus ? -i : i;
  2894. }
  2895. private long readLong() {
  2896. boolean minus = false;
  2897. if (currentTokenType == MINUS) {
  2898. minus = true;
  2899. read();
  2900. }
  2901. if (currentTokenType != VALUE ||
  2902. (currentValue.getType() != Value.INT && currentValue.getType() != Value.LONG)) {
  2903. throw DbException.getSyntaxError(sqlCommand, parseIndex, "long");
  2904. }
  2905. long i = currentValue.getLong();
  2906. read();
  2907. return minus ? -i : i;
  2908. }
  2909. private boolean readBooleanSetting() {
  2910. if (currentTokenType == VALUE) {
  2911. boolean result = currentValue.getBoolean().booleanValue();
  2912. read();
  2913. return result;
  2914. }
  2915. if (readIf("TRUE") || readIf("ON")) {
  2916. return true;
  2917. } else if (readIf("FALSE") || readIf("OFF")) {
  2918. return false;
  2919. } else {
  2920. throw getSyntaxError();
  2921. }
  2922. }
  2923. private String readString() {
  2924. Expression expr = readExpression().optimize(session);
  2925. if (!(expr instanceof ValueExpression)) {
  2926. throw DbException.getSyntaxError(sqlCommand, parseIndex, "string");
  2927. }
  2928. String s = expr.getValue(session).getString();
  2929. return s;
  2930. }
  2931. private String readIdentifierWithSchema(String defaultSchemaName) {
  2932. if (currentTokenType != IDENTIFIER) {
  2933. throw DbException.getSyntaxError(sqlCommand, parseIndex,
  2934. "identifier");
  2935. }
  2936. String s = currentToken;
  2937. read();
  2938. schemaName = defaultSchemaName;
  2939. if (readIf(".")) {
  2940. schemaName = s;
  2941. if (currentTokenType != IDENTIFIER) {
  2942. throw DbException.getSyntaxError(sqlCommand, parseIndex,
  2943. "identifier");
  2944. }
  2945. s = currentToken;
  2946. read();
  2947. }
  2948. if (equalsToken(".", currentToken)) {
  2949. if (equalsToken(schemaName, database.getShortName())) {
  2950. read(".");
  2951. schemaName = s;
  2952. if (currentTokenType != IDENTIFIER) {
  2953. throw DbException.getSyntaxError(sqlCommand, parseIndex,
  2954. "identifier");
  2955. }
  2956. s = currentToken;
  2957. read();
  2958. }
  2959. }
  2960. return s;
  2961. }
  2962. private String readIdentifierWithSchema() {
  2963. return readIdentifierWithSchema(session.getCurrentSchemaName());
  2964. }
  2965. private String readAliasIdentifier() {
  2966. return readColumnIdentifier();
  2967. }
  2968. private String readUniqueIdentifier() {
  2969. return readColumnIdentifier();
  2970. }
  2971. private String readColumnIdentifier() {
  2972. if (currentTokenType != IDENTIFIER) {
  2973. throw DbException.getSyntaxError(sqlCommand, parseIndex,
  2974. "identifier");
  2975. }
  2976. String s = currentToken;
  2977. read();
  2978. return s;
  2979. }
  2980. private void read(String expected) {
  2981. if (currentTokenQuoted || !equalsToken(expected, currentToken)) {
  2982. addExpected(expected);
  2983. throw getSyntaxError();
  2984. }
  2985. read();
  2986. }
  2987. private boolean readIf(String token) {
  2988. if (!currentTokenQuoted && equalsToken(token, currentToken)) {
  2989. read();
  2990. return true;
  2991. }
  2992. addExpected(token);
  2993. return false;
  2994. }
  2995. private boolean isToken(String token) {
  2996. boolean result = equalsToken(token, currentToken) &&
  2997. !currentTokenQuoted;
  2998. if (result) {
  2999. return true;
  3000. }
  3001. addExpected(token);
  3002. return false;
  3003. }
  3004. private boolean equalsToken(String a, String b) {
  3005. if (a == null) {
  3006. return b == null;
  3007. } else if (a.equals(b)) {
  3008. return true;
  3009. } else if (!identifiersToUpper && a.equalsIgnoreCase(b)) {
  3010. return true;
  3011. }
  3012. return false;
  3013. }
  3014. private void addExpected(String token) {
  3015. if (expectedList != null) {
  3016. expectedList.add(token);
  3017. }
  3018. }
  3019. private void read() {
  3020. currentTokenQuoted = false;
  3021. if (expectedList != null) {
  3022. expectedList.clear();
  3023. }
  3024. int[] types = characterTypes;
  3025. lastParseIndex = parseIndex;
  3026. int i = parseIndex;
  3027. int type = types[i];
  3028. while (type == 0) {
  3029. type = types[++i];
  3030. }
  3031. int start = i;
  3032. char[] chars = sqlCommandChars;
  3033. char c = chars[i++];
  3034. currentToken = "";
  3035. switch (type) {
  3036. case CHAR_NAME:
  3037. while (true) {
  3038. type = types[i];
  3039. if (type != CHAR_NAME && type != CHAR_VALUE) {
  3040. break;
  3041. }
  3042. i++;
  3043. }
  3044. currentToken = StringUtils.fromCacheOrNew(sqlCommand.substring(
  3045. start, i));
  3046. currentTokenType = getTokenType(currentToken);
  3047. parseIndex = i;
  3048. return;
  3049. case CHAR_QUOTED: {
  3050. String result = null;
  3051. while (true) {
  3052. for (int begin = i;; i++) {
  3053. if (chars[i] == '\"') {
  3054. if (result == null) {
  3055. result = sqlCommand.substring(begin, i);
  3056. } else {
  3057. result += sqlCommand.substring(begin - 1, i);
  3058. }
  3059. break;
  3060. }
  3061. }
  3062. if (chars[++i] != '\"') {
  3063. break;
  3064. }
  3065. i++;
  3066. }
  3067. currentToken = StringUtils.fromCacheOrNew(result);
  3068. parseIndex = i;
  3069. currentTokenQuoted = true;
  3070. currentTokenType = IDENTIFIER;
  3071. return;
  3072. }
  3073. case CHAR_SPECIAL_2:
  3074. if (types[i] == CHAR_SPECIAL_2) {
  3075. i++;
  3076. }
  3077. currentToken = sqlCommand.substring(start, i);
  3078. currentTokenType = getSpecialType(currentToken);
  3079. parseIndex = i;
  3080. return;
  3081. case CHAR_SPECIAL_1:
  3082. currentToken = sqlCommand.substring(start, i);
  3083. currentTokenType = getSpecialType(currentToken);
  3084. parseIndex = i;
  3085. return;
  3086. case CHAR_VALUE:
  3087. if (c == '0' && chars[i] == 'X') {
  3088. // hex number
  3089. long number = 0;
  3090. start += 2;
  3091. i++;
  3092. while (true) {
  3093. c = chars[i];
  3094. if ((c < '0' || c > '9') && (c < 'A' || c > 'F')) {
  3095. checkLiterals(false);
  3096. currentValue = ValueInt.get((int) number);
  3097. currentTokenType = VALUE;
  3098. currentToken = "0";
  3099. parseIndex = i;
  3100. return;
  3101. }
  3102. number = (number << 4) + c -
  3103. (c >= 'A' ? ('A' - 0xa) : ('0'));
  3104. if (number > Integer.MAX_VALUE) {
  3105. readHexDecimal(start, i);
  3106. return;
  3107. }
  3108. i++;
  3109. }
  3110. }
  3111. long number = c - '0';
  3112. while (true) {
  3113. c = chars[i];
  3114. if (c < '0' || c > '9') {
  3115. if (c == '.' || c == 'E' || c == 'L') {
  3116. readDecimal(start, i);
  3117. break;
  3118. }
  3119. checkLiterals(false);
  3120. currentValue = ValueInt.get((int) number);
  3121. currentTokenType = VALUE;
  3122. currentToken = "0";
  3123. parseIndex = i;
  3124. break;
  3125. }
  3126. number = number * 10 + (c - '0');
  3127. if (number > Integer.MAX_VALUE) {
  3128. readDecimal(start, i);
  3129. break;
  3130. }
  3131. i++;
  3132. }
  3133. return;
  3134. case CHAR_DOT:
  3135. if (types[i] != CHAR_VALUE) {
  3136. currentTokenType = KEYWORD;
  3137. currentToken = ".";
  3138. parseIndex = i;
  3139. return;
  3140. }
  3141. readDecimal(i - 1, i);
  3142. return;
  3143. case CHAR_STRING: {
  3144. String result = null;
  3145. while (true) {
  3146. for (int begin = i;; i++) {
  3147. if (chars[i] == '\'') {
  3148. if (result == null) {
  3149. result = sqlCommand.substring(begin, i);
  3150. } else {
  3151. result += sqlCommand.substring(begin - 1, i);
  3152. }
  3153. break;
  3154. }
  3155. }
  3156. if (chars[++i] != '\'') {
  3157. break;
  3158. }
  3159. i++;
  3160. }
  3161. currentToken = "'";
  3162. checkLiterals(true);
  3163. currentValue = ValueString.get(StringUtils.fromCacheOrNew(result),
  3164. database.getMode().treatEmptyStringsAsNull);
  3165. parseIndex = i;
  3166. currentTokenType = VALUE;
  3167. return;
  3168. }
  3169. case CHAR_DOLLAR_QUOTED_STRING: {
  3170. String result = null;
  3171. int begin = i - 1;
  3172. while (types[i] == CHAR_DOLLAR_QUOTED_STRING) {
  3173. i++;
  3174. }
  3175. result = sqlCommand.substring(begin, i);
  3176. currentToken = "'";
  3177. checkLiterals(true);
  3178. currentValue = ValueString.get(StringUtils.fromCacheOrNew(result),
  3179. database.getMode().treatEmptyStringsAsNull);
  3180. parseIndex = i;
  3181. currentTokenType = VALUE;
  3182. return;
  3183. }
  3184. case CHAR_END:
  3185. currentToken = "";
  3186. currentTokenType = END;
  3187. parseIndex = i;
  3188. return;
  3189. default:
  3190. throw getSyntaxError();
  3191. }
  3192. }
  3193. private void checkLiterals(boolean text) {
  3194. if (!session.getAllowLiterals()) {
  3195. int allowed = database.getAllowLiterals();
  3196. if (allowed == Constants.ALLOW_LITERALS_NONE ||
  3197. (text && allowed != Constants.ALLOW_LITERALS_ALL)) {
  3198. throw DbException.get(ErrorCode.LITERALS_ARE_NOT_ALLOWED);
  3199. }
  3200. }
  3201. }
  3202. private void readHexDecimal(int start, int i) {
  3203. char[] chars = sqlCommandChars;
  3204. char c;
  3205. do {
  3206. c = chars[++i];
  3207. } while ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'));
  3208. parseIndex = i;
  3209. String sub = sqlCommand.substring(start, i);
  3210. BigDecimal bd = new BigDecimal(new BigInteger(sub, 16));
  3211. checkLiterals(false);
  3212. currentValue = ValueDecimal.get(bd);
  3213. currentTokenType = VALUE;
  3214. }
  3215. private void readDecimal(int start, int i) {
  3216. char[] chars = sqlCommandChars;
  3217. int[] types = characterTypes;
  3218. // go until the first non-number
  3219. while (true) {
  3220. int t = types[i];
  3221. if (t != CHAR_DOT && t != CHAR_VALUE) {
  3222. break;
  3223. }
  3224. i++;
  3225. }
  3226. boolean containsE = false;
  3227. if (chars[i] == 'E' || chars[i] == 'e') {
  3228. containsE = true;
  3229. i++;
  3230. if (chars[i] == '+' || chars[i] == '-') {
  3231. i++;
  3232. }
  3233. if (types[i] != CHAR_VALUE) {
  3234. throw getSyntaxError();
  3235. }
  3236. while (types[++i] == CHAR_VALUE) {
  3237. // go until the first non-number
  3238. }
  3239. }
  3240. parseIndex = i;
  3241. String sub = sqlCommand.substring(start, i);
  3242. checkLiterals(false);
  3243. if (!containsE && sub.indexOf('.') < 0) {
  3244. BigInteger bi = new BigInteger(sub);
  3245. if (bi.compareTo(ValueLong.MAX) <= 0) {
  3246. // parse constants like "10000000L"
  3247. if (chars[i] == 'L') {
  3248. parseIndex++;
  3249. }
  3250. currentValue = ValueLong.get(bi.longValue());
  3251. currentTokenType = VALUE;
  3252. return;
  3253. }
  3254. }
  3255. BigDecimal bd;
  3256. try {
  3257. bd = new BigDecimal(sub);
  3258. } catch (NumberFormatException e) {
  3259. throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, e, sub);
  3260. }
  3261. currentValue = ValueDecimal.get(bd);
  3262. currentTokenType = VALUE;
  3263. }
  3264. public Session getSession() {
  3265. return session;
  3266. }
  3267. private void initialize(String sql) {
  3268. if (sql == null) {
  3269. sql = "";
  3270. }
  3271. originalSQL = sql;
  3272. sqlCommand = sql;
  3273. int len = sql.length() + 1;
  3274. char[] command = new char[len];
  3275. int[] types = new int[len];
  3276. len--;
  3277. sql.getChars(0, len, command, 0);
  3278. boolean changed = false;
  3279. command[len] = ' ';
  3280. int startLoop = 0;
  3281. int lastType = 0;
  3282. for (int i = 0; i < len; i++) {
  3283. char c = command[i];
  3284. int type = 0;
  3285. switch (c) {
  3286. case '/':
  3287. if (command[i + 1] == '*') {
  3288. // block comment
  3289. changed = true;
  3290. command[i] = ' ';
  3291. command[i + 1] = ' ';
  3292. startLoop = i;
  3293. i += 2;
  3294. checkRunOver(i, len, startLoop);
  3295. while (command[i] != '*' || command[i + 1] != '/') {
  3296. command[i++] = ' ';
  3297. checkRunOver(i, len, startLoop);
  3298. }
  3299. command[i] = ' ';
  3300. command[i + 1] = ' ';
  3301. i++;
  3302. } else if (command[i + 1] == '/') {
  3303. // single line comment
  3304. changed = true;
  3305. startLoop = i;
  3306. while (true) {
  3307. c = command[i];
  3308. if (c == '\n' || c == '\r' || i >= len - 1) {
  3309. break;
  3310. }
  3311. command[i++] = ' ';
  3312. checkRunOver(i, len, startLoop);
  3313. }
  3314. } else {
  3315. type = CHAR_SPECIAL_1;
  3316. }
  3317. break;
  3318. case '-':
  3319. if (command[i + 1] == '-') {
  3320. // single line comment
  3321. changed = true;
  3322. startLoop = i;
  3323. while (true) {
  3324. c = command[i];
  3325. if (c == '\n' || c == '\r' || i >= len - 1) {
  3326. break;
  3327. }
  3328. command[i++] = ' ';
  3329. checkRunOver(i, len, startLoop);
  3330. }
  3331. } else {
  3332. type = CHAR_SPECIAL_1;
  3333. }
  3334. break;
  3335. case '$':
  3336. if (command[i + 1] == '$' && (i == 0 || command[i - 1] <= ' ')) {
  3337. // dollar quoted string
  3338. changed = true;
  3339. command[i] = ' ';
  3340. command[i + 1] = ' ';
  3341. startLoop = i;
  3342. i += 2;
  3343. checkRunOver(i, len, startLoop);
  3344. while (command[i] != '$' || command[i + 1] != '$') {
  3345. types[i++] = CHAR_DOLLAR_QUOTED_STRING;
  3346. checkRunOver(i, len, startLoop);
  3347. }
  3348. command[i] = ' ';
  3349. command[i + 1] = ' ';
  3350. i++;
  3351. } else {
  3352. if (lastType == CHAR_NAME || lastType == CHAR_VALUE) {
  3353. // $ inside an identifier is supported
  3354. type = CHAR_NAME;
  3355. } else {
  3356. // but not at the start, to support PostgreSQL $1
  3357. type = CHAR_SPECIAL_1;
  3358. }
  3359. }
  3360. break;
  3361. case '(':
  3362. case ')':
  3363. case '{':
  3364. case '}':
  3365. case '*':
  3366. case ',':
  3367. case ';':
  3368. case '+':
  3369. case '%':
  3370. case '?':
  3371. case '@':
  3372. case ']':
  3373. type = CHAR_SPECIAL_1;
  3374. break;
  3375. case '!':
  3376. case '<':
  3377. case '>':
  3378. case '|':
  3379. case '=':
  3380. case ':':
  3381. case '&':
  3382. case '~':
  3383. type = CHAR_SPECIAL_2;
  3384. break;
  3385. case '.':
  3386. type = CHAR_DOT;
  3387. break;
  3388. case '\'':
  3389. type = types[i] = CHAR_STRING;
  3390. startLoop = i;
  3391. while (command[++i] != '\'') {
  3392. checkRunOver(i, len, startLoop);
  3393. }
  3394. break;
  3395. case '[':
  3396. if (database.getMode().squareBracketQuotedNames) {
  3397. // SQL Server alias for "
  3398. command[i] = '"';
  3399. changed = true;
  3400. type = types[i] = CHAR_QUOTED;
  3401. startLoop = i;
  3402. while (command[++i] != ']') {
  3403. checkRunOver(i, len, startLoop);
  3404. }
  3405. command[i] = '"';
  3406. } else {
  3407. type = CHAR_SPECIAL_1;
  3408. }
  3409. break;
  3410. case '`':
  3411. // MySQL alias for ", but not case sensitive
  3412. command[i] = '"';
  3413. changed = true;
  3414. type = types[i] = CHAR_QUOTED;
  3415. startLoop = i;
  3416. while (command[++i] != '`') {
  3417. checkRunOver(i, len, startLoop);
  3418. c = command[i];
  3419. command[i] = Character.toUpperCase(c);
  3420. }
  3421. command[i] = '"';
  3422. break;
  3423. case '\"':
  3424. type = types[i] = CHAR_QUOTED;
  3425. startLoop = i;
  3426. while (command[++i] != '\"') {
  3427. checkRunOver(i, len, startLoop);
  3428. }
  3429. break;
  3430. case '_':
  3431. type = CHAR_NAME;
  3432. break;
  3433. default:
  3434. if (c >= 'a' && c <= 'z') {
  3435. if (identifiersToUpper) {
  3436. command[i] = (char) (c - ('a' - 'A'));
  3437. changed = true;
  3438. }
  3439. type = CHAR_NAME;
  3440. } else if (c >= 'A' && c <= 'Z') {
  3441. type = CHAR_NAME;
  3442. } else if (c >= '0' && c <= '9') {
  3443. type = CHAR_VALUE;
  3444. } else {
  3445. if (c <= ' ' || Character.isSpaceChar(c)) {
  3446. // whitespace
  3447. } else if (Character.isJavaIdentifierPart(c)) {
  3448. type = CHAR_NAME;
  3449. if (identifiersToUpper) {
  3450. char u = Character.toUpperCase(c);
  3451. if (u != c) {
  3452. command[i] = u;
  3453. changed = true;
  3454. }
  3455. }
  3456. } else {
  3457. type = CHAR_SPECIAL_1;
  3458. }
  3459. }
  3460. }
  3461. types[i] = type;
  3462. lastType = type;
  3463. }
  3464. sqlCommandChars = command;
  3465. types[len] = CHAR_END;
  3466. characterTypes = types;
  3467. if (changed) {
  3468. sqlCommand = new String(command);
  3469. }
  3470. parseIndex = 0;
  3471. }
  3472. private void checkRunOver(int i, int len, int startLoop) {
  3473. if (i >= len) {
  3474. parseIndex = startLoop;
  3475. throw getSyntaxError();
  3476. }
  3477. }
  3478. private int getSpecialType(String s) {
  3479. char c0 = s.charAt(0);
  3480. if (s.length() == 1) {
  3481. switch (c0) {
  3482. case '?':
  3483. case '$':
  3484. return PARAMETER;
  3485. case '@':
  3486. return AT;
  3487. case '+':
  3488. return PLUS;
  3489. case '-':
  3490. return MINUS;
  3491. case '{':
  3492. case '}':
  3493. case '*':
  3494. case '/':
  3495. case '%':
  3496. case ';':
  3497. case ',':
  3498. case ':':
  3499. case '[':
  3500. case ']':
  3501. case '~':
  3502. return KEYWORD;
  3503. case '(':
  3504. return OPEN;
  3505. case ')':
  3506. return CLOSE;
  3507. case '<':
  3508. return SMALLER;
  3509. case '>':
  3510. return BIGGER;
  3511. case '=':
  3512. return EQUAL;
  3513. default:
  3514. break;
  3515. }
  3516. } else if (s.length() == 2) {
  3517. switch (c0) {
  3518. case ':':
  3519. if ("::".equals(s)) {
  3520. return KEYWORD;
  3521. } else if (":=".equals(s)) {
  3522. return KEYWORD;
  3523. }
  3524. break;
  3525. case '>':
  3526. if (">=".equals(s)) {
  3527. return BIGGER_EQUAL;
  3528. }
  3529. break;
  3530. case '<':
  3531. if ("<=".equals(s)) {
  3532. return SMALLER_EQUAL;
  3533. } else if ("<>".equals(s)) {
  3534. return NOT_EQUAL;
  3535. }
  3536. break;
  3537. case '!':
  3538. if ("!=".equals(s)) {
  3539. return NOT_EQUAL;
  3540. } else if ("!~".equals(s)) {
  3541. return KEYWORD;
  3542. }
  3543. break;
  3544. case '|':
  3545. if ("||".equals(s)) {
  3546. return STRING_CONCAT;
  3547. }
  3548. break;
  3549. case '&':
  3550. if ("&&".equals(s)) {
  3551. return SPATIAL_INTERSECTS;
  3552. }
  3553. break;
  3554. }
  3555. }
  3556. throw getSyntaxError();
  3557. }
  3558. private int getTokenType(String s) {
  3559. int len = s.length();
  3560. if (len == 0) {
  3561. throw getSyntaxError();
  3562. }
  3563. if (!identifiersToUpper) {
  3564. // if not yet converted to uppercase, do it now
  3565. s = StringUtils.toUpperEnglish(s);
  3566. }
  3567. return getSaveTokenType(s, database.getMode().supportOffsetFetch);
  3568. }
  3569. private boolean isKeyword(String s) {
  3570. if (!identifiersToUpper) {
  3571. // if not yet converted to uppercase, do it now
  3572. s = StringUtils.toUpperEnglish(s);
  3573. }
  3574. return isKeyword(s, false);
  3575. }
  3576. /**
  3577. * Checks if this string is a SQL keyword.
  3578. *
  3579. * @param s the token to check
  3580. * @param supportOffsetFetch if OFFSET and FETCH are keywords
  3581. * @return true if it is a keyword
  3582. */
  3583. public static boolean isKeyword(String s, boolean supportOffsetFetch) {
  3584. if (s == null || s.length() == 0) {
  3585. return false;
  3586. }
  3587. return getSaveTokenType(s, supportOffsetFetch) != IDENTIFIER;
  3588. }
  3589. private static int getSaveTokenType(String s, boolean supportOffsetFetch) {
  3590. switch (s.charAt(0)) {
  3591. case 'C':
  3592. if (s.equals("CURRENT_TIMESTAMP")) {
  3593. return CURRENT_TIMESTAMP;
  3594. } else if (s.equals("CURRENT_TIME")) {
  3595. return CURRENT_TIME;
  3596. } else if (s.equals("CURRENT_DATE")) {
  3597. return CURRENT_DATE;
  3598. }
  3599. return getKeywordOrIdentifier(s, "CROSS", KEYWORD);
  3600. case 'D':
  3601. return getKeywordOrIdentifier(s, "DISTINCT", KEYWORD);
  3602. case 'E':
  3603. if ("EXCEPT".equals(s)) {
  3604. return KEYWORD;
  3605. }
  3606. return getKeywordOrIdentifier(s, "EXISTS", KEYWORD);
  3607. case 'F':
  3608. if ("FROM".equals(s)) {
  3609. return KEYWORD;
  3610. } else if ("FOR".equals(s)) {
  3611. return KEYWORD;
  3612. } else if ("FULL".equals(s)) {
  3613. return KEYWORD;
  3614. } else if (supportOffsetFetch && "FETCH".equals(s)) {
  3615. return KEYWORD;
  3616. }
  3617. return getKeywordOrIdentifier(s, "FALSE", FALSE);
  3618. case 'G':
  3619. return getKeywordOrIdentifier(s, "GROUP", KEYWORD);
  3620. case 'H':
  3621. return getKeywordOrIdentifier(s, "HAVING", KEYWORD);
  3622. case 'I':
  3623. if ("INNER".equals(s)) {
  3624. return KEYWORD;
  3625. } else if ("INTERSECT".equals(s)) {
  3626. return KEYWORD;
  3627. }
  3628. return getKeywordOrIdentifier(s, "IS", KEYWORD);
  3629. case 'J':
  3630. return getKeywordOrIdentifier(s, "JOIN", KEYWORD);
  3631. case 'L':
  3632. if ("LIMIT".equals(s)) {
  3633. return KEYWORD;
  3634. }
  3635. return getKeywordOrIdentifier(s, "LIKE", KEYWORD);
  3636. case 'M':
  3637. return getKeywordOrIdentifier(s, "MINUS", KEYWORD);
  3638. case 'N':
  3639. if ("NOT".equals(s)) {
  3640. return KEYWORD;
  3641. } else if ("NATURAL".equals(s)) {
  3642. return KEYWORD;
  3643. }
  3644. return getKeywordOrIdentifier(s, "NULL", NULL);
  3645. case 'O':
  3646. if ("ON".equals(s)) {
  3647. return KEYWORD;
  3648. } else if (supportOffsetFetch && "OFFSET".equals(s)) {
  3649. return KEYWORD;
  3650. }
  3651. return getKeywordOrIdentifier(s, "ORDER", KEYWORD);
  3652. case 'P':
  3653. return getKeywordOrIdentifier(s, "PRIMARY", KEYWORD);
  3654. case 'R':
  3655. return getKeywordOrIdentifier(s, "ROWNUM", ROWNUM);
  3656. case 'S':
  3657. if (s.equals("SYSTIMESTAMP")) {
  3658. return CURRENT_TIMESTAMP;
  3659. } else if (s.equals("SYSTIME")) {
  3660. return CURRENT_TIME;
  3661. } else if (s.equals("SYSDATE")) {
  3662. return CURRENT_TIMESTAMP;
  3663. }
  3664. return getKeywordOrIdentifier(s, "SELECT", KEYWORD);
  3665. case 'T':
  3666. if ("TODAY".equals(s)) {
  3667. return CURRENT_DATE;
  3668. }
  3669. return getKeywordOrIdentifier(s, "TRUE", TRUE);
  3670. case 'U':
  3671. if ("UNIQUE".equals(s)) {
  3672. return KEYWORD;
  3673. }
  3674. return getKeywordOrIdentifier(s, "UNION", KEYWORD);
  3675. case 'W':
  3676. if ("WITH".equals(s)) {
  3677. return KEYWORD;
  3678. }
  3679. return getKeywordOrIdentifier(s, "WHERE", KEYWORD);
  3680. default:
  3681. return IDENTIFIER;
  3682. }
  3683. }
  3684. private static int getKeywordOrIdentifier(String s1, String s2,
  3685. int keywordType) {
  3686. if (s1.equals(s2)) {
  3687. return keywordType;
  3688. }
  3689. return IDENTIFIER;
  3690. }
  3691. private Column parseColumnForTable(String columnName,
  3692. boolean defaultNullable) {
  3693. Column column;
  3694. boolean isIdentity = false;
  3695. if (readIf("IDENTITY") || readIf("BIGSERIAL")) {
  3696. column = new Column(columnName, Value.LONG);
  3697. column.setOriginalSQL("IDENTITY");
  3698. parseAutoIncrement(column);
  3699. // PostgreSQL compatibility
  3700. if (!database.getMode().serialColumnIsNotPK) {
  3701. column.setPrimaryKey(true);
  3702. }
  3703. } else if (readIf("SERIAL")) {
  3704. column = new Column(columnName, Value.INT);
  3705. column.setOriginalSQL("SERIAL");
  3706. parseAutoIncrement(column);
  3707. // PostgreSQL compatibility
  3708. if (!database.getMode().serialColumnIsNotPK) {
  3709. column.setPrimaryKey(true);
  3710. }
  3711. } else {
  3712. column = parseColumnWithType(columnName);
  3713. }
  3714. if (readIf("NOT")) {
  3715. read("NULL");
  3716. column.setNullable(false);
  3717. } else if (readIf("NULL")) {
  3718. column.setNullable(true);
  3719. } else {
  3720. // domains may be defined as not nullable
  3721. column.setNullable(defaultNullable & column.isNullable());
  3722. }
  3723. if (readIf("AS")) {
  3724. if (isIdentity) {
  3725. getSyntaxError();
  3726. }
  3727. Expression expr = readExpression();
  3728. column.setComputedExpression(expr);
  3729. } else if (readIf("DEFAULT")) {
  3730. Expression defaultExpression = readExpression();
  3731. column.setDefaultExpression(session, defaultExpression);
  3732. } else if (readIf("GENERATED")) {
  3733. if (!readIf("ALWAYS")) {
  3734. read("BY");
  3735. read("DEFAULT");
  3736. }
  3737. read("AS");
  3738. read("IDENTITY");
  3739. long start = 1, increment = 1;
  3740. if (readIf("(")) {
  3741. read("START");
  3742. readIf("WITH");
  3743. start = readLong();
  3744. readIf(",");
  3745. if (readIf("INCREMENT")) {
  3746. readIf("BY");
  3747. increment = readLong();
  3748. }
  3749. read(")");
  3750. }
  3751. column.setPrimaryKey(true);
  3752. column.setAutoIncrement(true, start, increment);
  3753. }
  3754. if (readIf("NOT")) {
  3755. read("NULL");
  3756. column.setNullable(false);
  3757. } else {
  3758. readIf("NULL");
  3759. }
  3760. if (readIf("AUTO_INCREMENT") || readIf("BIGSERIAL") || readIf("SERIAL")) {
  3761. parseAutoIncrement(column);
  3762. if (readIf("NOT")) {
  3763. read("NULL");
  3764. }
  3765. } else if (readIf("IDENTITY")) {
  3766. parseAutoIncrement(column);
  3767. column.setPrimaryKey(true);
  3768. if (readIf("NOT")) {
  3769. read("NULL");
  3770. }
  3771. }
  3772. if (readIf("NULL_TO_DEFAULT")) {
  3773. column.setConvertNullToDefault(true);
  3774. }
  3775. if (readIf("SEQUENCE")) {
  3776. Sequence sequence = readSequence();
  3777. column.setSequence(sequence);
  3778. }
  3779. if (readIf("SELECTIVITY")) {
  3780. int value = getPositiveInt();
  3781. column.setSelectivity(value);
  3782. }
  3783. String comment = readCommentIf();
  3784. if (comment != null) {
  3785. column.setComment(comment);
  3786. }
  3787. return column;
  3788. }
  3789. private void parseAutoIncrement(Column column) {
  3790. long start = 1, increment = 1;
  3791. if (readIf("(")) {
  3792. start = readLong();
  3793. if (readIf(",")) {
  3794. increment = readLong();
  3795. }
  3796. read(")");
  3797. }
  3798. column.setAutoIncrement(true, start, increment);
  3799. }
  3800. private String readCommentIf() {
  3801. if (readIf("COMMENT")) {
  3802. readIf("IS");
  3803. return readString();
  3804. }
  3805. return null;
  3806. }
  3807. private Column parseColumnWithType(String columnName) {
  3808. String original = currentToken;
  3809. boolean regular = false;
  3810. if (readIf("LONG")) {
  3811. if (readIf("RAW")) {
  3812. original += " RAW";
  3813. }
  3814. } else if (readIf("DOUBLE")) {
  3815. if (readIf("PRECISION")) {
  3816. original += " PRECISION";
  3817. }
  3818. } else if (readIf("CHARACTER")) {
  3819. if (readIf("VARYING")) {
  3820. original += " VARYING";
  3821. }
  3822. } else {
  3823. regular = true;
  3824. }
  3825. long precision = -1;
  3826. int displaySize = -1;
  3827. int scale = -1;
  3828. String comment = null;
  3829. Column templateColumn = null;
  3830. DataType dataType;
  3831. if (!identifiersToUpper) {
  3832. original = StringUtils.toUpperEnglish(original);
  3833. }
  3834. UserDataType userDataType = database.findUserDataType(original);
  3835. if (userDataType != null) {
  3836. templateColumn = userDataType.getColumn();
  3837. dataType = DataType.getDataType(templateColumn.getType());
  3838. comment = templateColumn.getComment();
  3839. original = templateColumn.getOriginalSQL();
  3840. precision = templateColumn.getPrecision();
  3841. displaySize = templateColumn.getDisplaySize();
  3842. scale = templateColumn.getScale();
  3843. } else {
  3844. dataType = DataType.getTypeByName(original);
  3845. if (dataType == null) {
  3846. throw DbException.get(ErrorCode.UNKNOWN_DATA_TYPE_1,
  3847. currentToken);
  3848. }
  3849. }
  3850. if (database.getIgnoreCase() && dataType.type == Value.STRING &&
  3851. !equalsToken("VARCHAR_CASESENSITIVE", original)) {
  3852. original = "VARCHAR_IGNORECASE";
  3853. dataType = DataType.getTypeByName(original);
  3854. }
  3855. if (regular) {
  3856. read();
  3857. }
  3858. precision = precision == -1 ? dataType.defaultPrecision : precision;
  3859. displaySize = displaySize == -1 ? dataType.defaultDisplaySize
  3860. : displaySize;
  3861. scale = scale == -1 ? dataType.defaultScale : scale;
  3862. if (dataType.supportsPrecision || dataType.supportsScale) {
  3863. if (readIf("(")) {
  3864. if (!readIf("MAX")) {
  3865. long p = readLong();
  3866. if (readIf("K")) {
  3867. p *= 1024;
  3868. } else if (readIf("M")) {
  3869. p *= 1024 * 1024;
  3870. } else if (readIf("G")) {
  3871. p *= 1024 * 1024 * 1024;
  3872. }
  3873. if (p > Long.MAX_VALUE) {
  3874. p = Long.MAX_VALUE;
  3875. }
  3876. original += "(" + p;
  3877. // Oracle syntax
  3878. readIf("CHAR");
  3879. if (dataType.supportsScale) {
  3880. if (readIf(",")) {
  3881. scale = getInt();
  3882. original += ", " + scale;
  3883. } else {
  3884. // special case: TIMESTAMP(5) actually means
  3885. // TIMESTAMP(23, 5)
  3886. if (dataType.type == Value.TIMESTAMP) {
  3887. scale = MathUtils.convertLongToInt(p);
  3888. p = precision;
  3889. } else {
  3890. scale = 0;
  3891. }
  3892. }
  3893. }
  3894. precision = p;
  3895. displaySize = MathUtils.convertLongToInt(precision);
  3896. original += ")";
  3897. }
  3898. read(")");
  3899. }
  3900. } else if (readIf("(")) {
  3901. // Support for MySQL: INT(11), MEDIUMINT(8) and so on.
  3902. // Just ignore the precision.
  3903. getPositiveInt();
  3904. read(")");
  3905. }
  3906. if (readIf("FOR")) {
  3907. read("BIT");
  3908. read("DATA");
  3909. if (dataType.type == Value.STRING) {
  3910. dataType = DataType.getTypeByName("BINARY");
  3911. }
  3912. }
  3913. // MySQL compatibility
  3914. readIf("UNSIGNED");
  3915. int type = dataType.type;
  3916. if (scale > precision) {
  3917. throw DbException.get(ErrorCode.INVALID_VALUE_2,
  3918. Integer.toString(scale), "scale (precision = " + precision +
  3919. ")");
  3920. }
  3921. Column column = new Column(columnName, type, precision, scale,
  3922. displaySize);
  3923. if (templateColumn != null) {
  3924. column.setNullable(templateColumn.isNullable());
  3925. column.setDefaultExpression(session,
  3926. templateColumn.getDefaultExpression());
  3927. int selectivity = templateColumn.getSelectivity();
  3928. if (selectivity != Constants.SELECTIVITY_DEFAULT) {
  3929. column.setSelectivity(selectivity);
  3930. }
  3931. Expression checkConstraint = templateColumn.getCheckConstraint(
  3932. session, columnName);
  3933. column.addCheckConstraint(session, checkConstraint);
  3934. }
  3935. column.setComment(comment);
  3936. column.setOriginalSQL(original);
  3937. return column;
  3938. }
  3939. private Prepared parseCreate() {
  3940. boolean orReplace = false;
  3941. if (readIf("OR")) {
  3942. read("REPLACE");
  3943. orReplace = true;
  3944. }
  3945. boolean force = readIf("FORCE");
  3946. if (readIf("VIEW")) {
  3947. return parseCreateView(force, orReplace);
  3948. } else if (readIf("ALIAS")) {
  3949. return parseCreateFunctionAlias(force);
  3950. } else if (readIf("SEQUENCE")) {
  3951. return parseCreateSequence();
  3952. } else if (readIf("USER")) {
  3953. return parseCreateUser();
  3954. } else if (readIf("TRIGGER")) {
  3955. return parseCreateTrigger(force);
  3956. } else if (readIf("ROLE")) {
  3957. return parseCreateRole();
  3958. } else if (readIf("SCHEMA")) {
  3959. return parseCreateSchema();
  3960. } else if (readIf("CONSTANT")) {
  3961. return parseCreateConstant();
  3962. } else if (readIf("DOMAIN")) {
  3963. return parseCreateUserDataType();
  3964. } else if (readIf("TYPE")) {
  3965. return parseCreateUserDataType();
  3966. } else if (readIf("DATATYPE")) {
  3967. return parseCreateUserDataType();
  3968. } else if (readIf("AGGREGATE")) {
  3969. return parseCreateAggregate(force);
  3970. } else if (readIf("LINKED")) {
  3971. return parseCreateLinkedTable(false, false, force);
  3972. }
  3973. // tables or linked tables
  3974. boolean memory = false, cached = false;
  3975. if (readIf("MEMORY")) {
  3976. memory = true;
  3977. } else if (readIf("CACHED")) {
  3978. cached = true;
  3979. }
  3980. if (readIf("LOCAL")) {
  3981. read("TEMPORARY");
  3982. if (readIf("LINKED")) {
  3983. return parseCreateLinkedTable(true, false, force);
  3984. }
  3985. read("TABLE");
  3986. return parseCreateTable(true, false, cached);
  3987. } else if (readIf("GLOBAL")) {
  3988. read("TEMPORARY");
  3989. if (readIf("LINKED")) {
  3990. return parseCreateLinkedTable(true, true, force);
  3991. }
  3992. read("TABLE");
  3993. return parseCreateTable(true, true, cached);
  3994. } else if (readIf("TEMP") || readIf("TEMPORARY")) {
  3995. if (readIf("LINKED")) {
  3996. return parseCreateLinkedTable(true, true, force);
  3997. }
  3998. read("TABLE");
  3999. return parseCreateTable(true, true, cached);
  4000. } else if (readIf("TABLE")) {
  4001. if (!cached && !memory) {
  4002. cached = database.getDefaultTableType() == Table.TYPE_CACHED;
  4003. }
  4004. return parseCreateTable(false, false, cached);
  4005. } else {
  4006. boolean hash = false, primaryKey = false;
  4007. boolean unique = false, spatial = false;
  4008. String indexName = null;
  4009. Schema oldSchema = null;
  4010. boolean ifNotExists = false;
  4011. if (readIf("PRIMARY")) {
  4012. read("KEY");
  4013. if (readIf("HASH")) {
  4014. hash = true;
  4015. }
  4016. primaryKey = true;
  4017. if (!isToken("ON")) {
  4018. ifNotExists = readIfNoExists();
  4019. indexName = readIdentifierWithSchema(null);
  4020. oldSchema = getSchema();
  4021. }
  4022. } else {
  4023. if (readIf("UNIQUE")) {
  4024. unique = true;
  4025. }
  4026. if (readIf("HASH")) {
  4027. hash = true;
  4028. }
  4029. if (readIf("SPATIAL")) {
  4030. spatial = true;
  4031. }
  4032. if (readIf("INDEX")) {
  4033. if (!isToken("ON")) {
  4034. ifNotExists = readIfNoExists();
  4035. indexName = readIdentifierWithSchema(null);
  4036. oldSchema = getSchema();
  4037. }
  4038. } else {
  4039. throw getSyntaxError();
  4040. }
  4041. }
  4042. read("ON");
  4043. String tableName = readIdentifierWithSchema();
  4044. checkSchema(oldSchema);
  4045. CreateIndex command = new CreateIndex(session, getSchema());
  4046. command.setIfNotExists(ifNotExists);
  4047. command.setHash(hash);
  4048. command.setSpatial(spatial);
  4049. command.setPrimaryKey(primaryKey);
  4050. command.setTableName(tableName);
  4051. command.setUnique(unique);
  4052. command.setIndexName(indexName);
  4053. command.setComment(readCommentIf());
  4054. read("(");
  4055. command.setIndexColumns(parseIndexColumnList());
  4056. return command;
  4057. }
  4058. }
  4059. /**
  4060. * @return true if we expect to see a TABLE clause
  4061. */
  4062. private boolean addRoleOrRight(GrantRevoke command) {
  4063. if (readIf("SELECT")) {
  4064. command.addRight(Right.SELECT);
  4065. return true;
  4066. } else if (readIf("DELETE")) {
  4067. command.addRight(Right.DELETE);
  4068. return true;
  4069. } else if (readIf("INSERT")) {
  4070. command.addRight(Right.INSERT);
  4071. return true;
  4072. } else if (readIf("UPDATE")) {
  4073. command.addRight(Right.UPDATE);
  4074. return true;
  4075. } else if (readIf("ALL")) {
  4076. command.addRight(Right.ALL);
  4077. return true;
  4078. } else if (readIf("ALTER")) {
  4079. read("ANY");
  4080. read("SCHEMA");
  4081. command.addRight(Right.ALTER_ANY_SCHEMA);
  4082. command.addTable(null);
  4083. return false;
  4084. } else if (readIf("CONNECT")) {
  4085. // ignore this right
  4086. return true;
  4087. } else if (readIf("RESOURCE")) {
  4088. // ignore this right
  4089. return true;
  4090. } else {
  4091. command.addRoleName(readUniqueIdentifier());
  4092. return false;
  4093. }
  4094. }
  4095. private GrantRevoke parseGrantRevoke(int operationType) {
  4096. GrantRevoke command = new GrantRevoke(session);
  4097. command.setOperationType(operationType);
  4098. boolean tableClauseExpected = addRoleOrRight(command);
  4099. while (readIf(",")) {
  4100. addRoleOrRight(command);
  4101. if (command.isRightMode() && command.isRoleMode()) {
  4102. throw DbException
  4103. .get(ErrorCode.ROLES_AND_RIGHT_CANNOT_BE_MIXED);
  4104. }
  4105. }
  4106. if (tableClauseExpected) {
  4107. if (readIf("ON")) {
  4108. do {
  4109. Table table = readTableOrView();
  4110. command.addTable(table);
  4111. } while (readIf(","));
  4112. }
  4113. }
  4114. if (operationType == CommandInterface.GRANT) {
  4115. read("TO");
  4116. } else {
  4117. read("FROM");
  4118. }
  4119. command.setGranteeName(readUniqueIdentifier());
  4120. return command;
  4121. }
  4122. private Select parseValues() {
  4123. Select command = new Select(session);
  4124. currentSelect = command;
  4125. TableFilter filter = parseValuesTable();
  4126. ArrayList<Expression> list = New.arrayList();
  4127. list.add(new Wildcard(null, null));
  4128. command.setExpressions(list);
  4129. command.addTableFilter(filter, true);
  4130. command.init();
  4131. return command;
  4132. }
  4133. private TableFilter parseValuesTable() {
  4134. Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
  4135. TableFunction tf = (TableFunction) Function.getFunction(database,
  4136. "TABLE");
  4137. ArrayList<Column> columns = New.arrayList();
  4138. ArrayList<ArrayList<Expression>> rows = New.arrayList();
  4139. do {
  4140. int i = 0;
  4141. ArrayList<Expression> row = New.arrayList();
  4142. boolean multiColumn = readIf("(");
  4143. do {
  4144. Expression expr = readExpression();
  4145. expr = expr.optimize(session);
  4146. int type = expr.getType();
  4147. long prec;
  4148. int scale, displaySize;
  4149. Column column;
  4150. String columnName = "C" + (i + 1);
  4151. if (rows.size() == 0) {
  4152. if (type == Value.UNKNOWN) {
  4153. type = Value.STRING;
  4154. }
  4155. DataType dt = DataType.getDataType(type);
  4156. prec = dt.defaultPrecision;
  4157. scale = dt.defaultScale;
  4158. displaySize = dt.defaultDisplaySize;
  4159. column = new Column(columnName, type, prec, scale,
  4160. displaySize);
  4161. columns.add(column);
  4162. }
  4163. prec = expr.getPrecision();
  4164. scale = expr.getScale();
  4165. displaySize = expr.getDisplaySize();
  4166. if (i >= columns.size()) {
  4167. throw DbException
  4168. .get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
  4169. }
  4170. Column c = columns.get(i);
  4171. type = Value.getHigherOrder(c.getType(), type);
  4172. prec = Math.max(c.getPrecision(), prec);
  4173. scale = Math.max(c.getScale(), scale);
  4174. displaySize = Math.max(c.getDisplaySize(), displaySize);
  4175. column = new Column(columnName, type, prec, scale, displaySize);
  4176. columns.set(i, column);
  4177. row.add(expr);
  4178. i++;
  4179. } while (multiColumn && readIf(","));
  4180. if (multiColumn) {
  4181. read(")");
  4182. }
  4183. rows.add(row);
  4184. } while (readIf(","));
  4185. int columnCount = columns.size();
  4186. int rowCount = rows.size();
  4187. for (int i = 0; i < rowCount; i++) {
  4188. if (rows.get(i).size() != columnCount) {
  4189. throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
  4190. }
  4191. }
  4192. for (int i = 0; i < columnCount; i++) {
  4193. Column c = columns.get(i);
  4194. if (c.getType() == Value.UNKNOWN) {
  4195. c = new Column(c.getName(), Value.STRING, 0, 0, 0);
  4196. columns.set(i, c);
  4197. }
  4198. Expression[] array = new Expression[rowCount];
  4199. for (int j = 0; j < rowCount; j++) {
  4200. array[j] = rows.get(j).get(i);
  4201. }
  4202. ExpressionList list = new ExpressionList(array);
  4203. tf.setParameter(i, list);
  4204. }
  4205. tf.setColumns(columns);
  4206. tf.doneWithParameters();
  4207. Table table = new FunctionTable(mainSchema, session, tf, tf);
  4208. TableFilter filter = new TableFilter(session, table, null,
  4209. rightsChecked, currentSelect);
  4210. return filter;
  4211. }
  4212. private Call parseCall() {
  4213. Call command = new Call(session);
  4214. currentPrepared = command;
  4215. command.setExpression(readExpression());
  4216. return command;
  4217. }
  4218. private CreateRole parseCreateRole() {
  4219. CreateRole command = new CreateRole(session);
  4220. command.setIfNotExists(readIfNoExists());
  4221. command.setRoleName(readUniqueIdentifier());
  4222. return command;
  4223. }
  4224. private CreateSchema parseCreateSchema() {
  4225. CreateSchema command = new CreateSchema(session);
  4226. command.setIfNotExists(readIfNoExists());
  4227. command.setSchemaName(readUniqueIdentifier());
  4228. if (readIf("AUTHORIZATION")) {
  4229. command.setAuthorization(readUniqueIdentifier());
  4230. } else {
  4231. command.setAuthorization(session.getUser().getName());
  4232. }
  4233. return command;
  4234. }
  4235. private CreateSequence parseCreateSequence() {
  4236. boolean ifNotExists = readIfNoExists();
  4237. String sequenceName = readIdentifierWithSchema();
  4238. CreateSequence command = new CreateSequence(session, getSchema());
  4239. command.setIfNotExists(ifNotExists);
  4240. command.setSequenceName(sequenceName);
  4241. while (true) {
  4242. if (readIf("START")) {
  4243. readIf("WITH");
  4244. command.setStartWith(readExpression());
  4245. } else if (readIf("INCREMENT")) {
  4246. readIf("BY");
  4247. command.setIncrement(readExpression());
  4248. } else if (readIf("MINVALUE")) {
  4249. command.setMinValue(readExpression());
  4250. } else if (readIf("NOMINVALUE")) {
  4251. command.setMinValue(null);
  4252. } else if (readIf("MAXVALUE")) {
  4253. command.setMaxValue(readExpression());
  4254. } else if (readIf("NOMAXVALUE")) {
  4255. command.setMaxValue(null);
  4256. } else if (readIf("CYCLE")) {
  4257. command.setCycle(true);
  4258. } else if (readIf("NOCYCLE")) {
  4259. command.setCycle(false);
  4260. } else if (readIf("NO")) {
  4261. if (readIf("MINVALUE")) {
  4262. command.setMinValue(null);
  4263. } else if (readIf("MAXVALUE")) {
  4264. command.setMaxValue(null);
  4265. } else if (readIf("CYCLE")) {
  4266. command.setCycle(false);
  4267. } else if (readIf("CACHE")) {
  4268. command.setCacheSize(ValueExpression.get(ValueLong.get(1)));
  4269. } else {
  4270. break;
  4271. }
  4272. } else if (readIf("CACHE")) {
  4273. command.setCacheSize(readExpression());
  4274. } else if (readIf("NOCACHE")) {
  4275. command.setCacheSize(ValueExpression.get(ValueLong.get(1)));
  4276. } else if (readIf("BELONGS_TO_TABLE")) {
  4277. command.setBelongsToTable(true);
  4278. } else {
  4279. break;
  4280. }
  4281. }
  4282. return command;
  4283. }
  4284. private boolean readIfNoExists() {
  4285. if (readIf("IF")) {
  4286. read("NOT");
  4287. read("EXISTS");
  4288. return true;
  4289. }
  4290. return false;
  4291. }
  4292. private CreateConstant parseCreateConstant() {
  4293. boolean ifNotExists = readIfNoExists();
  4294. String constantName = readIdentifierWithSchema();
  4295. Schema schema = getSchema();
  4296. if (isKeyword(constantName)) {
  4297. throw DbException.get(ErrorCode.CONSTANT_ALREADY_EXISTS_1,
  4298. constantName);
  4299. }
  4300. read("VALUE");
  4301. Expression expr = readExpression();
  4302. CreateConstant command = new CreateConstant(session, schema);
  4303. command.setConstantName(constantName);
  4304. command.setExpression(expr);
  4305. command.setIfNotExists(ifNotExists);
  4306. return command;
  4307. }
  4308. private CreateAggregate parseCreateAggregate(boolean force) {
  4309. boolean ifNotExists = readIfNoExists();
  4310. CreateAggregate command = new CreateAggregate(session);
  4311. command.setForce(force);
  4312. String name = readIdentifierWithSchema();
  4313. if (isKeyword(name) || Function.getFunction(database, name) != null ||
  4314. getAggregateType(name) >= 0) {
  4315. throw DbException.get(ErrorCode.FUNCTION_ALIAS_ALREADY_EXISTS_1,
  4316. name);
  4317. }
  4318. command.setName(name);
  4319. command.setSchema(getSchema());
  4320. command.setIfNotExists(ifNotExists);
  4321. read("FOR");
  4322. command.setJavaClassMethod(readUniqueIdentifier());
  4323. return command;
  4324. }
  4325. private CreateUserDataType parseCreateUserDataType() {
  4326. boolean ifNotExists = readIfNoExists();
  4327. CreateUserDataType command = new CreateUserDataType(session);
  4328. command.setTypeName(readUniqueIdentifier());
  4329. read("AS");
  4330. Column col = parseColumnForTable("VALUE", true);
  4331. if (readIf("CHECK")) {
  4332. Expression expr = readExpression();
  4333. col.addCheckConstraint(session, expr);
  4334. }
  4335. col.rename(null);
  4336. command.setColumn(col);
  4337. command.setIfNotExists(ifNotExists);
  4338. return command;
  4339. }
  4340. private CreateTrigger parseCreateTrigger(boolean force) {
  4341. boolean ifNotExists = readIfNoExists();
  4342. String triggerName = readIdentifierWithSchema(null);
  4343. Schema schema = getSchema();
  4344. boolean insteadOf, isBefore;
  4345. if (readIf("INSTEAD")) {
  4346. read("OF");
  4347. isBefore = true;
  4348. insteadOf = true;
  4349. } else if (readIf("BEFORE")) {
  4350. insteadOf = false;
  4351. isBefore = true;
  4352. } else {
  4353. read("AFTER");
  4354. insteadOf = false;
  4355. isBefore = false;
  4356. }
  4357. int typeMask = 0;
  4358. boolean onRollback = false;
  4359. do {
  4360. if (readIf("INSERT")) {
  4361. typeMask |= Trigger.INSERT;
  4362. } else if (readIf("UPDATE")) {
  4363. typeMask |= Trigger.UPDATE;
  4364. } else if (readIf("DELETE")) {
  4365. typeMask |= Trigger.DELETE;
  4366. } else if (readIf("SELECT")) {
  4367. typeMask |= Trigger.SELECT;
  4368. } else if (readIf("ROLLBACK")) {
  4369. onRollback = true;
  4370. } else {
  4371. throw getSyntaxError();
  4372. }
  4373. } while (readIf(","));
  4374. read("ON");
  4375. String tableName = readIdentifierWithSchema();
  4376. checkSchema(schema);
  4377. CreateTrigger command = new CreateTrigger(session, getSchema());
  4378. command.setForce(force);
  4379. command.setTriggerName(triggerName);
  4380. command.setIfNotExists(ifNotExists);
  4381. command.setInsteadOf(insteadOf);
  4382. command.setBefore(isBefore);
  4383. command.setOnRollback(onRollback);
  4384. command.setTypeMask(typeMask);
  4385. command.setTableName(tableName);
  4386. if (readIf("FOR")) {
  4387. read("EACH");
  4388. read("ROW");
  4389. command.setRowBased(true);
  4390. } else {
  4391. command.setRowBased(false);
  4392. }
  4393. if (readIf("QUEUE")) {
  4394. command.setQueueSize(getPositiveInt());
  4395. }
  4396. command.setNoWait(readIf("NOWAIT"));
  4397. read("CALL");
  4398. command.setTriggerClassName(readUniqueIdentifier());
  4399. return command;
  4400. }
  4401. private CreateUser parseCreateUser() {
  4402. CreateUser command = new CreateUser(session);
  4403. command.setIfNotExists(readIfNoExists());
  4404. command.setUserName(readUniqueIdentifier());
  4405. command.setComment(readCommentIf());
  4406. if (readIf("PASSWORD")) {
  4407. command.setPassword(readExpression());
  4408. } else if (readIf("SALT")) {
  4409. command.setSalt(readExpression());
  4410. read("HASH");
  4411. command.setHash(readExpression());
  4412. } else if (readIf("IDENTIFIED")) {
  4413. read("BY");
  4414. // uppercase if not quoted
  4415. command.setPassword(ValueExpression.get(ValueString
  4416. .get(readColumnIdentifier())));
  4417. } else {
  4418. throw getSyntaxError();
  4419. }
  4420. if (readIf("ADMIN")) {
  4421. command.setAdmin(true);
  4422. }
  4423. return command;
  4424. }
  4425. private CreateFunctionAlias parseCreateFunctionAlias(boolean force) {
  4426. boolean ifNotExists = readIfNoExists();
  4427. String aliasName = readIdentifierWithSchema();
  4428. if (isKeyword(aliasName) ||
  4429. Function.getFunction(database, aliasName) != null ||
  4430. getAggregateType(aliasName) >= 0) {
  4431. throw DbException.get(ErrorCode.FUNCTION_ALIAS_ALREADY_EXISTS_1,
  4432. aliasName);
  4433. }
  4434. CreateFunctionAlias command = new CreateFunctionAlias(session,
  4435. getSchema());
  4436. command.setForce(force);
  4437. command.setAliasName(aliasName);
  4438. command.setIfNotExists(ifNotExists);
  4439. command.setDeterministic(readIf("DETERMINISTIC"));
  4440. command.setBufferResultSetToLocalTemp(!readIf("NOBUFFER"));
  4441. if (readIf("AS")) {
  4442. command.setSource(readString());
  4443. } else {
  4444. read("FOR");
  4445. command.setJavaClassMethod(readUniqueIdentifier());
  4446. }
  4447. return command;
  4448. }
  4449. private Query parseWith() {
  4450. readIf("RECURSIVE");
  4451. String tempViewName = readIdentifierWithSchema();
  4452. Schema schema = getSchema();
  4453. Table recursiveTable;
  4454. read("(");
  4455. ArrayList<Column> columns = New.arrayList();
  4456. String[] cols = parseColumnList();
  4457. for (String c : cols) {
  4458. columns.add(new Column(c, Value.STRING));
  4459. }
  4460. Table old = session.findLocalTempTable(tempViewName);
  4461. if (old != null) {
  4462. if (!(old instanceof TableView)) {
  4463. throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
  4464. tempViewName);
  4465. }
  4466. TableView tv = (TableView) old;
  4467. if (!tv.isTableExpression()) {
  4468. throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
  4469. tempViewName);
  4470. }
  4471. session.removeLocalTempTable(old);
  4472. }
  4473. CreateTableData data = new CreateTableData();
  4474. data.id = database.allocateObjectId();
  4475. data.columns = columns;
  4476. data.tableName = tempViewName;
  4477. data.temporary = true;
  4478. data.persistData = true;
  4479. data.persistIndexes = false;
  4480. data.create = true;
  4481. data.session = session;
  4482. recursiveTable = schema.createTable(data);
  4483. session.addLocalTempTable(recursiveTable);
  4484. String querySQL;
  4485. try {
  4486. read("AS");
  4487. read("(");
  4488. Query withQuery = parseSelect();
  4489. read(")");
  4490. withQuery.prepare();
  4491. querySQL = StringUtils.fromCacheOrNew(withQuery.getPlanSQL());
  4492. } finally {
  4493. session.removeLocalTempTable(recursiveTable);
  4494. }
  4495. int id = database.allocateObjectId();
  4496. TableView view = new TableView(schema, id, tempViewName, querySQL,
  4497. null, cols, session, true);
  4498. view.setTableExpression(true);
  4499. view.setTemporary(true);
  4500. session.addLocalTempTable(view);
  4501. view.setOnCommitDrop(true);
  4502. Query q = parseSelect();
  4503. q.setPrepareAlways(true);
  4504. return q;
  4505. }
  4506. private CreateView parseCreateView(boolean force, boolean orReplace) {
  4507. boolean ifNotExists = readIfNoExists();
  4508. String viewName = readIdentifierWithSchema();
  4509. CreateView command = new CreateView(session, getSchema());
  4510. this.createView = command;
  4511. command.setViewName(viewName);
  4512. command.setIfNotExists(ifNotExists);
  4513. command.setComment(readCommentIf());
  4514. command.setOrReplace(orReplace);
  4515. command.setForce(force);
  4516. if (readIf("(")) {
  4517. String[] cols = parseColumnList();
  4518. command.setColumnNames(cols);
  4519. }
  4520. String select = StringUtils.fromCacheOrNew(sqlCommand
  4521. .substring(parseIndex));
  4522. read("AS");
  4523. try {
  4524. Query query = parseSelect();
  4525. query.prepare();
  4526. command.setSelect(query);
  4527. } catch (DbException e) {
  4528. if (force) {
  4529. command.setSelectSQL(select);
  4530. while (currentTokenType != END) {
  4531. read();
  4532. }
  4533. } else {
  4534. throw e;
  4535. }
  4536. }
  4537. return command;
  4538. }
  4539. private TransactionCommand parseCheckpoint() {
  4540. TransactionCommand command;
  4541. if (readIf("SYNC")) {
  4542. command = new TransactionCommand(session,
  4543. CommandInterface.CHECKPOINT_SYNC);
  4544. } else {
  4545. command = new TransactionCommand(session,
  4546. CommandInterface.CHECKPOINT);
  4547. }
  4548. return command;
  4549. }
  4550. private Prepared parseAlter() {
  4551. if (readIf("TABLE")) {
  4552. return parseAlterTable();
  4553. } else if (readIf("USER")) {
  4554. return parseAlterUser();
  4555. } else if (readIf("INDEX")) {
  4556. return parseAlterIndex();
  4557. } else if (readIf("SCHEMA")) {
  4558. return parseAlterSchema();
  4559. } else if (readIf("SEQUENCE")) {
  4560. return parseAlterSequence();
  4561. } else if (readIf("VIEW")) {
  4562. return parseAlterView();
  4563. }
  4564. throw getSyntaxError();
  4565. }
  4566. private void checkSchema(Schema old) {
  4567. if (old != null && getSchema() != old) {
  4568. throw DbException.get(ErrorCode.SCHEMA_NAME_MUST_MATCH);
  4569. }
  4570. }
  4571. private AlterIndexRename parseAlterIndex() {
  4572. String indexName = readIdentifierWithSchema();
  4573. Schema old = getSchema();
  4574. AlterIndexRename command = new AlterIndexRename(session);
  4575. command.setOldIndex(getSchema().getIndex(indexName));
  4576. read("RENAME");
  4577. read("TO");
  4578. String newName = readIdentifierWithSchema(old.getName());
  4579. checkSchema(old);
  4580. command.setNewName(newName);
  4581. return command;
  4582. }
  4583. private AlterView parseAlterView() {
  4584. AlterView command = new AlterView(session);
  4585. String viewName = readIdentifierWithSchema();
  4586. Table tableView = getSchema().findTableOrView(session, viewName);
  4587. if (!(tableView instanceof TableView)) {
  4588. throw DbException.get(ErrorCode.VIEW_NOT_FOUND_1, viewName);
  4589. }
  4590. TableView view = (TableView) tableView;
  4591. command.setView(view);
  4592. read("RECOMPILE");
  4593. return command;
  4594. }
  4595. private AlterSchemaRename parseAlterSchema() {
  4596. String schemaName = readIdentifierWithSchema();
  4597. Schema old = getSchema();
  4598. AlterSchemaRename command = new AlterSchemaRename(session);
  4599. command.setOldSchema(getSchema(schemaName));
  4600. read("RENAME");
  4601. read("TO");
  4602. String newName = readIdentifierWithSchema(old.getName());
  4603. checkSchema(old);
  4604. command.setNewName(newName);
  4605. return command;
  4606. }
  4607. private AlterSequence parseAlterSequence() {
  4608. String sequenceName = readIdentifierWithSchema();
  4609. Sequence sequence = getSchema().getSequence(sequenceName);
  4610. AlterSequence command = new AlterSequence(session, sequence.getSchema());
  4611. command.setSequence(sequence);
  4612. while (true) {
  4613. if (readIf("RESTART")) {
  4614. read("WITH");
  4615. command.setStartWith(readExpression());
  4616. } else if (readIf("INCREMENT")) {
  4617. read("BY");
  4618. command.setIncrement(readExpression());
  4619. } else if (readIf("MINVALUE")) {
  4620. command.setMinValue(readExpression());
  4621. } else if (readIf("NOMINVALUE")) {
  4622. command.setMinValue(null);
  4623. } else if (readIf("MAXVALUE")) {
  4624. command.setMaxValue(readExpression());
  4625. } else if (readIf("NOMAXVALUE")) {
  4626. command.setMaxValue(null);
  4627. } else if (readIf("CYCLE")) {
  4628. command.setCycle(true);
  4629. } else if (readIf("NOCYCLE")) {
  4630. command.setCycle(false);
  4631. } else if (readIf("NO")) {
  4632. if (readIf("MINVALUE")) {
  4633. command.setMinValue(null);
  4634. } else if (readIf("MAXVALUE")) {
  4635. command.setMaxValue(null);
  4636. } else if (readIf("CYCLE")) {
  4637. command.setCycle(false);
  4638. } else if (readIf("CACHE")) {
  4639. command.setCacheSize(ValueExpression.get(ValueLong.get(1)));
  4640. } else {
  4641. break;
  4642. }
  4643. } else if (readIf("CACHE")) {
  4644. command.setCacheSize(readExpression());
  4645. } else if (readIf("NOCACHE")) {
  4646. command.setCacheSize(ValueExpression.get(ValueLong.get(1)));
  4647. } else {
  4648. break;
  4649. }
  4650. }
  4651. return command;
  4652. }
  4653. private AlterUser parseAlterUser() {
  4654. String userName = readUniqueIdentifier();
  4655. if (readIf("SET")) {
  4656. AlterUser command = new AlterUser(session);
  4657. command.setType(CommandInterface.ALTER_USER_SET_PASSWORD);
  4658. command.setUser(database.getUser(userName));
  4659. if (readIf("PASSWORD")) {
  4660. command.setPassword(readExpression());
  4661. } else if (readIf("SALT")) {
  4662. command.setSalt(readExpression());
  4663. read("HASH");
  4664. command.setHash(readExpression());
  4665. } else {
  4666. throw getSyntaxError();
  4667. }
  4668. return command;
  4669. } else if (readIf("RENAME")) {
  4670. read("TO");
  4671. AlterUser command = new AlterUser(session);
  4672. command.setType(CommandInterface.ALTER_USER_RENAME);
  4673. command.setUser(database.getUser(userName));
  4674. String newName = readUniqueIdentifier();
  4675. command.setNewName(newName);
  4676. return command;
  4677. } else if (readIf("ADMIN")) {
  4678. AlterUser command = new AlterUser(session);
  4679. command.setType(CommandInterface.ALTER_USER_ADMIN);
  4680. User user = database.getUser(userName);
  4681. command.setUser(user);
  4682. if (readIf("TRUE")) {
  4683. command.setAdmin(true);
  4684. } else if (readIf("FALSE")) {
  4685. command.setAdmin(false);
  4686. } else {
  4687. throw getSyntaxError();
  4688. }
  4689. return command;
  4690. }
  4691. throw getSyntaxError();
  4692. }
  4693. private void readIfEqualOrTo() {
  4694. if (!readIf("=")) {
  4695. readIf("TO");
  4696. }
  4697. }
  4698. private Prepared parseSet() {
  4699. if (readIf("@")) {
  4700. Set command = new Set(session, SetTypes.VARIABLE);
  4701. command.setString(readAliasIdentifier());
  4702. readIfEqualOrTo();
  4703. command.setExpression(readExpression());
  4704. return command;
  4705. } else if (readIf("AUTOCOMMIT")) {
  4706. readIfEqualOrTo();
  4707. boolean value = readBooleanSetting();
  4708. int setting = value ? CommandInterface.SET_AUTOCOMMIT_TRUE
  4709. : CommandInterface.SET_AUTOCOMMIT_FALSE;
  4710. return new TransactionCommand(session, setting);
  4711. } else if (readIf("MVCC")) {
  4712. readIfEqualOrTo();
  4713. boolean value = readBooleanSetting();
  4714. Set command = new Set(session, SetTypes.MVCC);
  4715. command.setInt(value ? 1 : 0);
  4716. return command;
  4717. } else if (readIf("EXCLUSIVE")) {
  4718. readIfEqualOrTo();
  4719. Set command = new Set(session, SetTypes.EXCLUSIVE);
  4720. command.setExpression(readExpression());
  4721. return command;
  4722. } else if (readIf("IGNORECASE")) {
  4723. readIfEqualOrTo();
  4724. boolean value = readBooleanSetting();
  4725. Set command = new Set(session, SetTypes.IGNORECASE);
  4726. command.setInt(value ? 1 : 0);
  4727. return command;
  4728. } else if (readIf("PASSWORD")) {
  4729. readIfEqualOrTo();
  4730. AlterUser command = new AlterUser(session);
  4731. command.setType(CommandInterface.ALTER_USER_SET_PASSWORD);
  4732. command.setUser(session.getUser());
  4733. command.setPassword(readExpression());
  4734. return command;
  4735. } else if (readIf("SALT")) {
  4736. readIfEqualOrTo();
  4737. AlterUser command = new AlterUser(session);
  4738. command.setType(CommandInterface.ALTER_USER_SET_PASSWORD);
  4739. command.setUser(session.getUser());
  4740. command.setSalt(readExpression());
  4741. read("HASH");
  4742. command.setHash(readExpression());
  4743. return command;
  4744. } else if (readIf("MODE")) {
  4745. readIfEqualOrTo();
  4746. Set command = new Set(session, SetTypes.MODE);
  4747. command.setString(readAliasIdentifier());
  4748. return command;
  4749. } else if (readIf("COMPRESS_LOB")) {
  4750. readIfEqualOrTo();
  4751. Set command = new Set(session, SetTypes.COMPRESS_LOB);
  4752. if (currentTokenType == VALUE) {
  4753. command.setString(readString());
  4754. } else {
  4755. command.setString(readUniqueIdentifier());
  4756. }
  4757. return command;
  4758. } else if (readIf("DATABASE")) {
  4759. readIfEqualOrTo();
  4760. read("COLLATION");
  4761. return parseSetCollation();
  4762. } else if (readIf("COLLATION")) {
  4763. readIfEqualOrTo();
  4764. return parseSetCollation();
  4765. } else if (readIf("BINARY_COLLATION")) {
  4766. readIfEqualOrTo();
  4767. return parseSetBinaryCollation();
  4768. } else if (readIf("CLUSTER")) {
  4769. readIfEqualOrTo();
  4770. Set command = new Set(session, SetTypes.CLUSTER);
  4771. command.setString(readString());
  4772. return command;
  4773. } else if (readIf("DATABASE_EVENT_LISTENER")) {
  4774. readIfEqualOrTo();
  4775. Set command = new Set(session, SetTypes.DATABASE_EVENT_LISTENER);
  4776. command.setString(readString());
  4777. return command;
  4778. } else if (readIf("ALLOW_LITERALS")) {
  4779. readIfEqualOrTo();
  4780. Set command = new Set(session, SetTypes.ALLOW_LITERALS);
  4781. if (readIf("NONE")) {
  4782. command.setInt(Constants.ALLOW_LITERALS_NONE);
  4783. } else if (readIf("ALL")) {
  4784. command.setInt(Constants.ALLOW_LITERALS_ALL);
  4785. } else if (readIf("NUMBERS")) {
  4786. command.setInt(Constants.ALLOW_LITERALS_NUMBERS);
  4787. } else {
  4788. command.setInt(getPositiveInt());
  4789. }
  4790. return command;
  4791. } else if (readIf("DEFAULT_TABLE_TYPE")) {
  4792. readIfEqualOrTo();
  4793. Set command = new Set(session, SetTypes.DEFAULT_TABLE_TYPE);
  4794. if (readIf("MEMORY")) {
  4795. command.setInt(Table.TYPE_MEMORY);
  4796. } else if (readIf("CACHED")) {
  4797. command.setInt(Table.TYPE_CACHED);
  4798. } else {
  4799. command.setInt(getPositiveInt());
  4800. }
  4801. return command;
  4802. } else if (readIf("CREATE")) {
  4803. readIfEqualOrTo();
  4804. // Derby compatibility (CREATE=TRUE in the database URL)
  4805. read();
  4806. return new NoOperation(session);
  4807. } else if (readIf("HSQLDB.DEFAULT_TABLE_TYPE")) {
  4808. readIfEqualOrTo();
  4809. read();
  4810. return new NoOperation(session);
  4811. } else if (readIf("PAGE_STORE")) {
  4812. readIfEqualOrTo();
  4813. read();
  4814. return new NoOperation(session);
  4815. } else if (readIf("CACHE_TYPE")) {
  4816. readIfEqualOrTo();
  4817. read();
  4818. return new NoOperation(session);
  4819. } else if (readIf("FILE_LOCK")) {
  4820. readIfEqualOrTo();
  4821. read();
  4822. return new NoOperation(session);
  4823. } else if (readIf("DB_CLOSE_ON_EXIT")) {
  4824. readIfEqualOrTo();
  4825. read();
  4826. return new NoOperation(session);
  4827. } else if (readIf("AUTO_SERVER")) {
  4828. readIfEqualOrTo();
  4829. read();
  4830. return new NoOperation(session);
  4831. } else if (readIf("AUTO_SERVER_PORT")) {
  4832. readIfEqualOrTo();
  4833. read();
  4834. return new NoOperation(session);
  4835. } else if (readIf("AUTO_RECONNECT")) {
  4836. readIfEqualOrTo();
  4837. read();
  4838. return new NoOperation(session);
  4839. } else if (readIf("ASSERT")) {
  4840. readIfEqualOrTo();
  4841. read();
  4842. return new NoOperation(session);
  4843. } else if (readIf("ACCESS_MODE_DATA")) {
  4844. readIfEqualOrTo();
  4845. read();
  4846. return new NoOperation(session);
  4847. } else if (readIf("OPEN_NEW")) {
  4848. readIfEqualOrTo();
  4849. read();
  4850. return new NoOperation(session);
  4851. } else if (readIf("JMX")) {
  4852. readIfEqualOrTo();
  4853. read();
  4854. return new NoOperation(session);
  4855. } else if (readIf("PAGE_SIZE")) {
  4856. readIfEqualOrTo();
  4857. read();
  4858. return new NoOperation(session);
  4859. } else if (readIf("RECOVER")) {
  4860. readIfEqualOrTo();
  4861. read();
  4862. return new NoOperation(session);
  4863. } else if (readIf("NAMES")) {
  4864. // Quercus PHP MySQL driver compatibility
  4865. readIfEqualOrTo();
  4866. read();
  4867. return new NoOperation(session);
  4868. } else if (readIf("SCHEMA")) {
  4869. readIfEqualOrTo();
  4870. Set command = new Set(session, SetTypes.SCHEMA);
  4871. command.setString(readAliasIdentifier());
  4872. return command;
  4873. } else if (readIf("DATESTYLE")) {
  4874. // PostgreSQL compatibility
  4875. readIfEqualOrTo();
  4876. if (!readIf("ISO")) {
  4877. String s = readString();
  4878. if (!equalsToken(s, "ISO")) {
  4879. throw getSyntaxError();
  4880. }
  4881. }
  4882. return new NoOperation(session);
  4883. } else if (readIf("SEARCH_PATH") ||
  4884. readIf(SetTypes.getTypeName(SetTypes.SCHEMA_SEARCH_PATH))) {
  4885. readIfEqualOrTo();
  4886. Set command = new Set(session, SetTypes.SCHEMA_SEARCH_PATH);
  4887. ArrayList<String> list = New.arrayList();
  4888. list.add(readAliasIdentifier());
  4889. while (readIf(",")) {
  4890. list.add(readAliasIdentifier());
  4891. }
  4892. String[] schemaNames = new String[list.size()];
  4893. list.toArray(schemaNames);
  4894. command.setStringArray(schemaNames);
  4895. return command;
  4896. } else if (readIf("JAVA_OBJECT_SERIALIZER")) {
  4897. readIfEqualOrTo();
  4898. return parseSetJavaObjectSerializer();
  4899. } else {
  4900. if (isToken("LOGSIZE")) {
  4901. // HSQLDB compatibility
  4902. currentToken = SetTypes.getTypeName(SetTypes.MAX_LOG_SIZE);
  4903. }
  4904. if (isToken("FOREIGN_KEY_CHECKS")) {
  4905. // MySQL compatibility
  4906. currentToken = SetTypes
  4907. .getTypeName(SetTypes.REFERENTIAL_INTEGRITY);
  4908. }
  4909. int type = SetTypes.getType(currentToken);
  4910. if (type < 0) {
  4911. throw getSyntaxError();
  4912. }
  4913. read();
  4914. readIfEqualOrTo();
  4915. Set command = new Set(session, type);
  4916. command.setExpression(readExpression());
  4917. return command;
  4918. }
  4919. }
  4920. private Set parseSetCollation() {
  4921. Set command = new Set(session, SetTypes.COLLATION);
  4922. String name = readAliasIdentifier();
  4923. command.setString(name);
  4924. if (equalsToken(name, CompareMode.OFF)) {
  4925. return command;
  4926. }
  4927. Collator coll = CompareMode.getCollator(name);
  4928. if (coll == null) {
  4929. throw DbException.getInvalidValueException("collation", name);
  4930. }
  4931. if (readIf("STRENGTH")) {
  4932. if (readIf("PRIMARY")) {
  4933. command.setInt(Collator.PRIMARY);
  4934. } else if (readIf("SECONDARY")) {
  4935. command.setInt(Collator.SECONDARY);
  4936. } else if (readIf("TERTIARY")) {
  4937. command.setInt(Collator.TERTIARY);
  4938. } else if (readIf("IDENTICAL")) {
  4939. command.setInt(Collator.IDENTICAL);
  4940. }
  4941. } else {
  4942. command.setInt(coll.getStrength());
  4943. }
  4944. return command;
  4945. }
  4946. private Set parseSetBinaryCollation() {
  4947. Set command = new Set(session, SetTypes.BINARY_COLLATION);
  4948. String name = readAliasIdentifier();
  4949. command.setString(name);
  4950. if (equalsToken(name, CompareMode.UNSIGNED) ||
  4951. equalsToken(name, CompareMode.SIGNED)) {
  4952. return command;
  4953. }
  4954. throw DbException.getInvalidValueException("BINARY_COLLATION", name);
  4955. }
  4956. private Set parseSetJavaObjectSerializer() {
  4957. Set command = new Set(session, SetTypes.JAVA_OBJECT_SERIALIZER);
  4958. String name = readString();
  4959. command.setString(name);
  4960. return command;
  4961. }
  4962. private RunScriptCommand parseRunScript() {
  4963. RunScriptCommand command = new RunScriptCommand(session);
  4964. read("FROM");
  4965. command.setFileNameExpr(readExpression());
  4966. if (readIf("COMPRESSION")) {
  4967. command.setCompressionAlgorithm(readUniqueIdentifier());
  4968. }
  4969. if (readIf("CIPHER")) {
  4970. command.setCipher(readUniqueIdentifier());
  4971. if (readIf("PASSWORD")) {
  4972. command.setPassword(readExpression());
  4973. }
  4974. }
  4975. if (readIf("CHARSET")) {
  4976. command.setCharset(Charset.forName(readString()));
  4977. }
  4978. return command;
  4979. }
  4980. private ScriptCommand parseScript() {
  4981. ScriptCommand command = new ScriptCommand(session);
  4982. boolean data = true, passwords = true, settings = true;
  4983. boolean dropTables = false, simple = false;
  4984. if (readIf("SIMPLE")) {
  4985. simple = true;
  4986. }
  4987. if (readIf("NODATA")) {
  4988. data = false;
  4989. }
  4990. if (readIf("NOPASSWORDS")) {
  4991. passwords = false;
  4992. }
  4993. if (readIf("NOSETTINGS")) {
  4994. settings = false;
  4995. }
  4996. if (readIf("DROP")) {
  4997. dropTables = true;
  4998. }
  4999. if (readIf("BLOCKSIZE")) {
  5000. long blockSize = readLong();
  5001. command.setLobBlockSize(blockSize);
  5002. }
  5003. command.setData(data);
  5004. command.setPasswords(passwords);
  5005. command.setSettings(settings);
  5006. command.setDrop(dropTables);
  5007. command.setSimple(simple);
  5008. if (readIf("TO")) {
  5009. command.setFileNameExpr(readExpression());
  5010. if (readIf("COMPRESSION")) {
  5011. command.setCompressionAlgorithm(readUniqueIdentifier());
  5012. }
  5013. if (readIf("CIPHER")) {
  5014. command.setCipher(readUniqueIdentifier());
  5015. if (readIf("PASSWORD")) {
  5016. command.setPassword(readExpression());
  5017. }
  5018. }
  5019. if (readIf("CHARSET")) {
  5020. command.setCharset(Charset.forName(readString()));
  5021. }
  5022. }
  5023. if (readIf("SCHEMA")) {
  5024. HashSet<String> schemaNames = New.hashSet();
  5025. do {
  5026. schemaNames.add(readUniqueIdentifier());
  5027. } while (readIf(","));
  5028. command.setSchemaNames(schemaNames);
  5029. } else if (readIf("TABLE")) {
  5030. ArrayList<Table> tables = New.arrayList();
  5031. do {
  5032. tables.add(readTableOrView());
  5033. } while (readIf(","));
  5034. command.setTables(tables);
  5035. }
  5036. return command;
  5037. }
  5038. private Table readTableOrView() {
  5039. return readTableOrView(readIdentifierWithSchema(null));
  5040. }
  5041. private Table readTableOrView(String tableName) {
  5042. // same algorithm than readSequence
  5043. if (schemaName != null) {
  5044. return getSchema().getTableOrView(session, tableName);
  5045. }
  5046. Table table = database.getSchema(session.getCurrentSchemaName())
  5047. .findTableOrView(session, tableName);
  5048. if (table != null) {
  5049. return table;
  5050. }
  5051. String[] schemaNames = session.getSchemaSearchPath();
  5052. if (schemaNames != null) {
  5053. for (String name : schemaNames) {
  5054. Schema s = database.getSchema(name);
  5055. table = s.findTableOrView(session, tableName);
  5056. if (table != null) {
  5057. return table;
  5058. }
  5059. }
  5060. }
  5061. throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableName);
  5062. }
  5063. private FunctionAlias findFunctionAlias(String schema, String aliasName) {
  5064. FunctionAlias functionAlias = database.getSchema(schema).findFunction(
  5065. aliasName);
  5066. if (functionAlias != null) {
  5067. return functionAlias;
  5068. }
  5069. String[] schemaNames = session.getSchemaSearchPath();
  5070. if (schemaNames != null) {
  5071. for (String n : schemaNames) {
  5072. functionAlias = database.getSchema(n).findFunction(aliasName);
  5073. if (functionAlias != null) {
  5074. return functionAlias;
  5075. }
  5076. }
  5077. }
  5078. return null;
  5079. }
  5080. private Sequence findSequence(String schema, String sequenceName) {
  5081. Sequence sequence = database.getSchema(schema).findSequence(
  5082. sequenceName);
  5083. if (sequence != null) {
  5084. return sequence;
  5085. }
  5086. String[] schemaNames = session.getSchemaSearchPath();
  5087. if (schemaNames != null) {
  5088. for (String n : schemaNames) {
  5089. sequence = database.getSchema(n).findSequence(sequenceName);
  5090. if (sequence != null) {
  5091. return sequence;
  5092. }
  5093. }
  5094. }
  5095. return null;
  5096. }
  5097. private Sequence readSequence() {
  5098. // same algorithm as readTableOrView
  5099. String sequenceName = readIdentifierWithSchema(null);
  5100. if (schemaName != null) {
  5101. return getSchema().getSequence(sequenceName);
  5102. }
  5103. Sequence sequence = findSequence(session.getCurrentSchemaName(),
  5104. sequenceName);
  5105. if (sequence != null) {
  5106. return sequence;
  5107. }
  5108. throw DbException.get(ErrorCode.SEQUENCE_NOT_FOUND_1, sequenceName);
  5109. }
  5110. private Prepared parseAlterTable() {
  5111. Table table = readTableOrView();
  5112. if (readIf("ADD")) {
  5113. Prepared command = parseAlterTableAddConstraintIf(table.getName(),
  5114. table.getSchema());
  5115. if (command != null) {
  5116. return command;
  5117. }
  5118. return parseAlterTableAddColumn(table);
  5119. } else if (readIf("SET")) {
  5120. read("REFERENTIAL_INTEGRITY");
  5121. int type = CommandInterface.ALTER_TABLE_SET_REFERENTIAL_INTEGRITY;
  5122. boolean value = readBooleanSetting();
  5123. AlterTableSet command = new AlterTableSet(session,
  5124. table.getSchema(), type, value);
  5125. command.setTableName(table.getName());
  5126. if (readIf("CHECK")) {
  5127. command.setCheckExisting(true);
  5128. } else if (readIf("NOCHECK")) {
  5129. command.setCheckExisting(false);
  5130. }
  5131. return command;
  5132. } else if (readIf("RENAME")) {
  5133. read("TO");
  5134. String newName = readIdentifierWithSchema(table.getSchema()
  5135. .getName());
  5136. checkSchema(table.getSchema());
  5137. AlterTableRename command = new AlterTableRename(session,
  5138. getSchema());
  5139. command.setOldTable(table);
  5140. command.setNewTableName(newName);
  5141. command.setHidden(readIf("HIDDEN"));
  5142. return command;
  5143. } else if (readIf("DROP")) {
  5144. if (readIf("CONSTRAINT")) {
  5145. boolean ifExists = readIfExists(false);
  5146. String constraintName = readIdentifierWithSchema(table
  5147. .getSchema().getName());
  5148. ifExists = readIfExists(ifExists);
  5149. checkSchema(table.getSchema());
  5150. AlterTableDropConstraint command = new AlterTableDropConstraint(
  5151. session, getSchema(), ifExists);
  5152. command.setConstraintName(constraintName);
  5153. return command;
  5154. } else if (readIf("FOREIGN")) {
  5155. // MySQL compatibility
  5156. read("KEY");
  5157. String constraintName = readIdentifierWithSchema(table
  5158. .getSchema().getName());
  5159. checkSchema(table.getSchema());
  5160. AlterTableDropConstraint command = new AlterTableDropConstraint(
  5161. session, getSchema(), false);
  5162. command.setConstraintName(constraintName);
  5163. return command;
  5164. } else if (readIf("INDEX")) {
  5165. // MySQL compatibility
  5166. String indexName = readIdentifierWithSchema();
  5167. DropIndex command = new DropIndex(session, getSchema());
  5168. command.setIndexName(indexName);
  5169. return command;
  5170. } else if (readIf("PRIMARY")) {
  5171. read("KEY");
  5172. Index idx = table.getPrimaryKey();
  5173. DropIndex command = new DropIndex(session, table.getSchema());
  5174. command.setIndexName(idx.getName());
  5175. return command;
  5176. } else {
  5177. readIf("COLUMN");
  5178. boolean ifExists = readIfExists(false);
  5179. AlterTableAlterColumn command = new AlterTableAlterColumn(
  5180. session, table.getSchema());
  5181. command.setType(CommandInterface.ALTER_TABLE_DROP_COLUMN);
  5182. String columnName = readColumnIdentifier();
  5183. command.setTable(table);
  5184. if (ifExists && !table.doesColumnExist(columnName)) {
  5185. return new NoOperation(session);
  5186. }
  5187. command.setOldColumn(table.getColumn(columnName));
  5188. return command;
  5189. }
  5190. } else if (readIf("CHANGE")) {
  5191. // MySQL compatibility
  5192. readIf("COLUMN");
  5193. String columnName = readColumnIdentifier();
  5194. Column column = table.getColumn(columnName);
  5195. String newColumnName = readColumnIdentifier();
  5196. // new column type ignored. RENAME and MODIFY are
  5197. // a single command in MySQL but two different commands in H2.
  5198. parseColumnForTable(newColumnName, column.isNullable());
  5199. AlterTableRenameColumn command = new AlterTableRenameColumn(session);
  5200. command.setTable(table);
  5201. command.setColumn(column);
  5202. command.setNewColumnName(newColumnName);
  5203. return command;
  5204. } else if (readIf("MODIFY")) {
  5205. // MySQL compatibility
  5206. readIf("COLUMN");
  5207. String columnName = readColumnIdentifier();
  5208. Column column = table.getColumn(columnName);
  5209. return parseAlterTableAlterColumnType(table, columnName, column);
  5210. } else if (readIf("ALTER")) {
  5211. readIf("COLUMN");
  5212. String columnName = readColumnIdentifier();
  5213. Column column = table.getColumn(columnName);
  5214. if (readIf("RENAME")) {
  5215. read("TO");
  5216. AlterTableRenameColumn command = new AlterTableRenameColumn(
  5217. session);
  5218. command.setTable(table);
  5219. command.setColumn(column);
  5220. String newName = readColumnIdentifier();
  5221. command.setNewColumnName(newName);
  5222. return command;
  5223. } else if (readIf("DROP")) {
  5224. // PostgreSQL compatibility
  5225. if (readIf("DEFAULT")) {
  5226. AlterTableAlterColumn command = new AlterTableAlterColumn(
  5227. session, table.getSchema());
  5228. command.setTable(table);
  5229. command.setOldColumn(column);
  5230. command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT);
  5231. command.setDefaultExpression(null);
  5232. return command;
  5233. }
  5234. read("NOT");
  5235. read("NULL");
  5236. AlterTableAlterColumn command = new AlterTableAlterColumn(
  5237. session, table.getSchema());
  5238. command.setTable(table);
  5239. command.setOldColumn(column);
  5240. command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL);
  5241. return command;
  5242. } else if (readIf("TYPE")) {
  5243. // PostgreSQL compatibility
  5244. return parseAlterTableAlterColumnType(table, columnName, column);
  5245. } else if (readIf("SET")) {
  5246. if (readIf("DATA")) {
  5247. // Derby compatibility
  5248. read("TYPE");
  5249. return parseAlterTableAlterColumnType(table, columnName,
  5250. column);
  5251. }
  5252. AlterTableAlterColumn command = new AlterTableAlterColumn(
  5253. session, table.getSchema());
  5254. command.setTable(table);
  5255. command.setOldColumn(column);
  5256. if (readIf("NULL")) {
  5257. command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL);
  5258. return command;
  5259. } else if (readIf("NOT")) {
  5260. read("NULL");
  5261. command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL);
  5262. return command;
  5263. } else if (readIf("DEFAULT")) {
  5264. Expression defaultExpression = readExpression();
  5265. command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT);
  5266. command.setDefaultExpression(defaultExpression);
  5267. return command;
  5268. }
  5269. } else if (readIf("RESTART")) {
  5270. readIf("WITH");
  5271. Expression start = readExpression();
  5272. AlterSequence command = new AlterSequence(session,
  5273. table.getSchema());
  5274. command.setColumn(column);
  5275. command.setStartWith(start);
  5276. return command;
  5277. } else if (readIf("SELECTIVITY")) {
  5278. AlterTableAlterColumn command = new AlterTableAlterColumn(
  5279. session, table.getSchema());
  5280. command.setTable(table);
  5281. command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_SELECTIVITY);
  5282. command.setOldColumn(column);
  5283. command.setSelectivity(readExpression());
  5284. return command;
  5285. } else {
  5286. return parseAlterTableAlterColumnType(table, columnName, column);
  5287. }
  5288. }
  5289. throw getSyntaxError();
  5290. }
  5291. private AlterTableAlterColumn parseAlterTableAlterColumnType(Table table,
  5292. String columnName, Column column) {
  5293. Column newColumn = parseColumnForTable(columnName, column.isNullable());
  5294. AlterTableAlterColumn command = new AlterTableAlterColumn(session,
  5295. table.getSchema());
  5296. command.setTable(table);
  5297. command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE);
  5298. command.setOldColumn(column);
  5299. command.setNewColumn(newColumn);
  5300. return command;
  5301. }
  5302. private AlterTableAlterColumn parseAlterTableAddColumn(Table table) {
  5303. readIf("COLUMN");
  5304. Schema schema = table.getSchema();
  5305. AlterTableAlterColumn command = new AlterTableAlterColumn(session,
  5306. schema);
  5307. command.setType(CommandInterface.ALTER_TABLE_ADD_COLUMN);
  5308. command.setTable(table);
  5309. ArrayList<Column> columnsToAdd = New.arrayList();
  5310. if (readIf("(")) {
  5311. command.setIfNotExists(false);
  5312. do {
  5313. String columnName = readColumnIdentifier();
  5314. Column column = parseColumnForTable(columnName, true);
  5315. columnsToAdd.add(column);
  5316. } while (readIf(","));
  5317. read(")");
  5318. command.setNewColumns(columnsToAdd);
  5319. } else {
  5320. boolean ifNotExists = readIfNoExists();
  5321. command.setIfNotExists(ifNotExists);
  5322. String columnName = readColumnIdentifier();
  5323. Column column = parseColumnForTable(columnName, true);
  5324. columnsToAdd.add(column);
  5325. if (readIf("BEFORE")) {
  5326. command.setAddBefore(readColumnIdentifier());
  5327. } else if (readIf("AFTER")) {
  5328. command.setAddAfter(readColumnIdentifier());
  5329. }
  5330. }
  5331. command.setNewColumns(columnsToAdd);
  5332. return command;
  5333. }
  5334. private int parseAction() {
  5335. Integer result = parseCascadeOrRestrict();
  5336. if (result != null) {
  5337. return result;
  5338. }
  5339. if (readIf("NO")) {
  5340. read("ACTION");
  5341. return ConstraintReferential.RESTRICT;
  5342. }
  5343. read("SET");
  5344. if (readIf("NULL")) {
  5345. return ConstraintReferential.SET_NULL;
  5346. }
  5347. read("DEFAULT");
  5348. return ConstraintReferential.SET_DEFAULT;
  5349. }
  5350. private Integer parseCascadeOrRestrict() {
  5351. if (readIf("CASCADE")) {
  5352. return ConstraintReferential.CASCADE;
  5353. } else if (readIf("RESTRICT")) {
  5354. return ConstraintReferential.RESTRICT;
  5355. } else {
  5356. return null;
  5357. }
  5358. }
  5359. private DefineCommand parseAlterTableAddConstraintIf(String tableName,
  5360. Schema schema) {
  5361. String constraintName = null, comment = null;
  5362. boolean ifNotExists = false;
  5363. boolean allowIndexDefinition = database.getMode().indexDefinitionInCreateTable;
  5364. if (readIf("CONSTRAINT")) {
  5365. ifNotExists = readIfNoExists();
  5366. constraintName = readIdentifierWithSchema(schema.getName());
  5367. checkSchema(schema);
  5368. comment = readCommentIf();
  5369. allowIndexDefinition = true;
  5370. }
  5371. if (readIf("PRIMARY")) {
  5372. read("KEY");
  5373. AlterTableAddConstraint command = new AlterTableAddConstraint(
  5374. session, schema, ifNotExists);
  5375. command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY);
  5376. command.setComment(comment);
  5377. command.setConstraintName(constraintName);
  5378. command.setTableName(tableName);
  5379. if (readIf("HASH")) {
  5380. command.setPrimaryKeyHash(true);
  5381. }
  5382. read("(");
  5383. command.setIndexColumns(parseIndexColumnList());
  5384. if (readIf("INDEX")) {
  5385. String indexName = readIdentifierWithSchema();
  5386. command.setIndex(getSchema().findIndex(session, indexName));
  5387. }
  5388. return command;
  5389. } else if (allowIndexDefinition && (isToken("INDEX") || isToken("KEY"))) {
  5390. // MySQL
  5391. // need to read ahead, as it could be a column name
  5392. int start = lastParseIndex;
  5393. read();
  5394. if (DataType.getTypeByName(currentToken) != null) {
  5395. // known data type
  5396. parseIndex = start;
  5397. read();
  5398. return null;
  5399. }
  5400. CreateIndex command = new CreateIndex(session, schema);
  5401. command.setComment(comment);
  5402. command.setTableName(tableName);
  5403. if (!readIf("(")) {
  5404. command.setIndexName(readUniqueIdentifier());
  5405. read("(");
  5406. }
  5407. command.setIndexColumns(parseIndexColumnList());
  5408. // MySQL compatibility
  5409. if (readIf("USING")) {
  5410. read("BTREE");
  5411. }
  5412. return command;
  5413. }
  5414. AlterTableAddConstraint command;
  5415. if (readIf("CHECK")) {
  5416. command = new AlterTableAddConstraint(session, schema, ifNotExists);
  5417. command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_CHECK);
  5418. command.setCheckExpression(readExpression());
  5419. } else if (readIf("UNIQUE")) {
  5420. readIf("KEY");
  5421. readIf("INDEX");
  5422. command = new AlterTableAddConstraint(session, schema, ifNotExists);
  5423. command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_UNIQUE);
  5424. if (!readIf("(")) {
  5425. constraintName = readUniqueIdentifier();
  5426. read("(");
  5427. }
  5428. command.setIndexColumns(parseIndexColumnList());
  5429. if (readIf("INDEX")) {
  5430. String indexName = readIdentifierWithSchema();
  5431. command.setIndex(getSchema().findIndex(session, indexName));
  5432. }
  5433. // MySQL compatibility
  5434. if (readIf("USING")) {
  5435. read("BTREE");
  5436. }
  5437. } else if (readIf("FOREIGN")) {
  5438. command = new AlterTableAddConstraint(session, schema, ifNotExists);
  5439. command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL);
  5440. read("KEY");
  5441. read("(");
  5442. command.setIndexColumns(parseIndexColumnList());
  5443. if (readIf("INDEX")) {
  5444. String indexName = readIdentifierWithSchema();
  5445. command.setIndex(schema.findIndex(session, indexName));
  5446. }
  5447. read("REFERENCES");
  5448. parseReferences(command, schema, tableName);
  5449. } else {
  5450. if (constraintName != null) {
  5451. throw getSyntaxError();
  5452. }
  5453. return null;
  5454. }
  5455. if (readIf("NOCHECK")) {
  5456. command.setCheckExisting(false);
  5457. } else {
  5458. readIf("CHECK");
  5459. command.setCheckExisting(true);
  5460. }
  5461. command.setTableName(tableName);
  5462. command.setConstraintName(constraintName);
  5463. command.setComment(comment);
  5464. return command;
  5465. }
  5466. private void parseReferences(AlterTableAddConstraint command,
  5467. Schema schema, String tableName) {
  5468. if (readIf("(")) {
  5469. command.setRefTableName(schema, tableName);
  5470. command.setRefIndexColumns(parseIndexColumnList());
  5471. } else {
  5472. String refTableName = readIdentifierWithSchema(schema.getName());
  5473. command.setRefTableName(getSchema(), refTableName);
  5474. if (readIf("(")) {
  5475. command.setRefIndexColumns(parseIndexColumnList());
  5476. }
  5477. }
  5478. if (readIf("INDEX")) {
  5479. String indexName = readIdentifierWithSchema();
  5480. command.setRefIndex(getSchema().findIndex(session, indexName));
  5481. }
  5482. while (readIf("ON")) {
  5483. if (readIf("DELETE")) {
  5484. command.setDeleteAction(parseAction());
  5485. } else {
  5486. read("UPDATE");
  5487. command.setUpdateAction(parseAction());
  5488. }
  5489. }
  5490. if (readIf("NOT")) {
  5491. read("DEFERRABLE");
  5492. } else {
  5493. readIf("DEFERRABLE");
  5494. }
  5495. }
  5496. private CreateLinkedTable parseCreateLinkedTable(boolean temp,
  5497. boolean globalTemp, boolean force) {
  5498. read("TABLE");
  5499. boolean ifNotExists = readIfNoExists();
  5500. String tableName = readIdentifierWithSchema();
  5501. CreateLinkedTable command = new CreateLinkedTable(session, getSchema());
  5502. command.setTemporary(temp);
  5503. command.setGlobalTemporary(globalTemp);
  5504. command.setForce(force);
  5505. command.setIfNotExists(ifNotExists);
  5506. command.setTableName(tableName);
  5507. command.setComment(readCommentIf());
  5508. read("(");
  5509. command.setDriver(readString());
  5510. read(",");
  5511. command.setUrl(readString());
  5512. read(",");
  5513. command.setUser(readString());
  5514. read(",");
  5515. command.setPassword(readString());
  5516. read(",");
  5517. String originalTable = readString();
  5518. if (readIf(",")) {
  5519. command.setOriginalSchema(originalTable);
  5520. originalTable = readString();
  5521. }
  5522. command.setOriginalTable(originalTable);
  5523. read(")");
  5524. if (readIf("EMIT")) {
  5525. read("UPDATES");
  5526. command.setEmitUpdates(true);
  5527. } else if (readIf("READONLY")) {
  5528. command.setReadOnly(true);
  5529. }
  5530. return command;
  5531. }
  5532. private CreateTable parseCreateTable(boolean temp, boolean globalTemp,
  5533. boolean persistIndexes) {
  5534. boolean ifNotExists = readIfNoExists();
  5535. String tableName = readIdentifierWithSchema();
  5536. if (temp && globalTemp && equalsToken("SESSION", schemaName)) {
  5537. // support weird syntax: declare global temporary table session.xy
  5538. // (...) not logged
  5539. schemaName = session.getCurrentSchemaName();
  5540. globalTemp = false;
  5541. }
  5542. Schema schema = getSchema();
  5543. CreateTable command = new CreateTable(session, schema);
  5544. command.setPersistIndexes(persistIndexes);
  5545. command.setTemporary(temp);
  5546. command.setGlobalTemporary(globalTemp);
  5547. command.setIfNotExists(ifNotExists);
  5548. command.setTableName(tableName);
  5549. command.setComment(readCommentIf());
  5550. if (readIf("(")) {
  5551. if (!readIf(")")) {
  5552. do {
  5553. DefineCommand c = parseAlterTableAddConstraintIf(tableName,
  5554. schema);
  5555. if (c != null) {
  5556. command.addConstraintCommand(c);
  5557. } else {
  5558. String columnName = readColumnIdentifier();
  5559. Column column = parseColumnForTable(columnName, true);
  5560. if (column.isAutoIncrement() && column.isPrimaryKey()) {
  5561. column.setPrimaryKey(false);
  5562. IndexColumn[] cols = { new IndexColumn() };
  5563. cols[0].columnName = column.getName();
  5564. AlterTableAddConstraint pk = new AlterTableAddConstraint(
  5565. session, schema, false);
  5566. pk.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY);
  5567. pk.setTableName(tableName);
  5568. pk.setIndexColumns(cols);
  5569. command.addConstraintCommand(pk);
  5570. }
  5571. command.addColumn(column);
  5572. String constraintName = null;
  5573. if (readIf("CONSTRAINT")) {
  5574. constraintName = readColumnIdentifier();
  5575. }
  5576. if (readIf("PRIMARY")) {
  5577. read("KEY");
  5578. boolean hash = readIf("HASH");
  5579. IndexColumn[] cols = { new IndexColumn() };
  5580. cols[0].columnName = column.getName();
  5581. AlterTableAddConstraint pk = new AlterTableAddConstraint(
  5582. session, schema, false);
  5583. pk.setPrimaryKeyHash(hash);
  5584. pk.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY);
  5585. pk.setTableName(tableName);
  5586. pk.setIndexColumns(cols);
  5587. command.addConstraintCommand(pk);
  5588. if (readIf("AUTO_INCREMENT")) {
  5589. parseAutoIncrement(column);
  5590. }
  5591. } else if (readIf("UNIQUE")) {
  5592. AlterTableAddConstraint unique = new AlterTableAddConstraint(
  5593. session, schema, false);
  5594. unique.setConstraintName(constraintName);
  5595. unique.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_UNIQUE);
  5596. IndexColumn[] cols = { new IndexColumn() };
  5597. cols[0].columnName = columnName;
  5598. unique.setIndexColumns(cols);
  5599. unique.setTableName(tableName);
  5600. command.addConstraintCommand(unique);
  5601. }
  5602. if (readIf("NOT")) {
  5603. read("NULL");
  5604. column.setNullable(false);
  5605. } else {
  5606. readIf("NULL");
  5607. }
  5608. if (readIf("CHECK")) {
  5609. Expression expr = readExpression();
  5610. column.addCheckConstraint(session, expr);
  5611. }
  5612. if (readIf("REFERENCES")) {
  5613. AlterTableAddConstraint ref = new AlterTableAddConstraint(
  5614. session, schema, false);
  5615. ref.setConstraintName(constraintName);
  5616. ref.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL);
  5617. IndexColumn[] cols = { new IndexColumn() };
  5618. cols[0].columnName = columnName;
  5619. ref.setIndexColumns(cols);
  5620. ref.setTableName(tableName);
  5621. parseReferences(ref, schema, tableName);
  5622. command.addConstraintCommand(ref);
  5623. }
  5624. }
  5625. } while (readIfMore());
  5626. }
  5627. }
  5628. // Allows "COMMENT='comment'" in DDL statements (MySQL syntax)
  5629. if (readIf("COMMENT")) {
  5630. if (readIf("=")) {
  5631. // read the complete string comment, but nothing with it for now
  5632. readString();
  5633. }
  5634. }
  5635. if (readIf("ENGINE")) {
  5636. if (readIf("=")) {
  5637. // map MySQL engine types onto H2 behavior
  5638. String tableEngine = readUniqueIdentifier();
  5639. if ("InnoDb".equalsIgnoreCase(tableEngine)) {
  5640. // ok
  5641. } else if (!"MyISAM".equalsIgnoreCase(tableEngine)) {
  5642. throw DbException.getUnsupportedException(tableEngine);
  5643. }
  5644. } else {
  5645. command.setTableEngine(readUniqueIdentifier());
  5646. if (readIf("WITH")) {
  5647. ArrayList<String> tableEngineParams = New.arrayList();
  5648. do {
  5649. tableEngineParams.add(readUniqueIdentifier());
  5650. } while (readIf(","));
  5651. command.setTableEngineParams(tableEngineParams);
  5652. }
  5653. }
  5654. } else if (database.getSettings().defaultTableEngine != null) {
  5655. command.setTableEngine(database.getSettings().defaultTableEngine);
  5656. }
  5657. // MySQL compatibility
  5658. if (readIf("AUTO_INCREMENT")) {
  5659. read("=");
  5660. if (currentTokenType != VALUE ||
  5661. currentValue.getType() != Value.INT) {
  5662. throw DbException.getSyntaxError(sqlCommand, parseIndex,
  5663. "integer");
  5664. }
  5665. read();
  5666. }
  5667. readIf("DEFAULT");
  5668. if (readIf("CHARSET")) {
  5669. read("=");
  5670. read("UTF8");
  5671. }
  5672. if (temp) {
  5673. if (readIf("ON")) {
  5674. read("COMMIT");
  5675. if (readIf("DROP")) {
  5676. command.setOnCommitDrop();
  5677. } else if (readIf("DELETE")) {
  5678. read("ROWS");
  5679. command.setOnCommitTruncate();
  5680. }
  5681. } else if (readIf("NOT")) {
  5682. if (readIf("PERSISTENT")) {
  5683. command.setPersistData(false);
  5684. } else {
  5685. read("LOGGED");
  5686. }
  5687. }
  5688. if (readIf("TRANSACTIONAL")) {
  5689. command.setTransactional(true);
  5690. }
  5691. } else if (!persistIndexes && readIf("NOT")) {
  5692. read("PERSISTENT");
  5693. command.setPersistData(false);
  5694. }
  5695. if (readIf("HIDDEN")) {
  5696. command.setHidden(true);
  5697. }
  5698. if (readIf("AS")) {
  5699. if (readIf("SORTED")) {
  5700. command.setSortedInsertMode(true);
  5701. }
  5702. command.setQuery(parseSelect());
  5703. }
  5704. return command;
  5705. }
  5706. private static int getCompareType(int tokenType) {
  5707. switch (tokenType) {
  5708. case EQUAL:
  5709. return Comparison.EQUAL;
  5710. case BIGGER_EQUAL:
  5711. return Comparison.BIGGER_EQUAL;
  5712. case BIGGER:
  5713. return Comparison.BIGGER;
  5714. case SMALLER:
  5715. return Comparison.SMALLER;
  5716. case SMALLER_EQUAL:
  5717. return Comparison.SMALLER_EQUAL;
  5718. case NOT_EQUAL:
  5719. return Comparison.NOT_EQUAL;
  5720. case SPATIAL_INTERSECTS:
  5721. return Comparison.SPATIAL_INTERSECTS;
  5722. default:
  5723. return -1;
  5724. }
  5725. }
  5726. /**
  5727. * Add double quotes around an identifier if required.
  5728. *
  5729. * @param s the identifier
  5730. * @return the quoted identifier
  5731. */
  5732. public static String quoteIdentifier(String s) {
  5733. if (s == null || s.length() == 0) {
  5734. return "\"\"";
  5735. }
  5736. char c = s.charAt(0);
  5737. // lowercase a-z is quoted as well
  5738. if ((!Character.isLetter(c) && c != '_') || Character.isLowerCase(c)) {
  5739. return StringUtils.quoteIdentifier(s);
  5740. }
  5741. for (int i = 1, length = s.length(); i < length; i++) {
  5742. c = s.charAt(i);
  5743. if ((!Character.isLetterOrDigit(c) && c != '_') ||
  5744. Character.isLowerCase(c)) {
  5745. return StringUtils.quoteIdentifier(s);
  5746. }
  5747. }
  5748. if (isKeyword(s, true)) {
  5749. return StringUtils.quoteIdentifier(s);
  5750. }
  5751. return s;
  5752. }
  5753. public void setRightsChecked(boolean rightsChecked) {
  5754. this.rightsChecked = rightsChecked;
  5755. }
  5756. /**
  5757. * Parse a SQL code snippet that represents an expression.
  5758. *
  5759. * @param sql the code snippet
  5760. * @return the expression object
  5761. */
  5762. public Expression parseExpression(String sql) {
  5763. parameters = New.arrayList();
  5764. initialize(sql);
  5765. read();
  5766. return readExpression();
  5767. }
  5768. /**
  5769. * Parse a SQL code snippet that represents a table name.
  5770. *
  5771. * @param sql the code snippet
  5772. * @return the table object
  5773. */
  5774. public Table parseTableName(String sql) {
  5775. parameters = New.arrayList();
  5776. initialize(sql);
  5777. read();
  5778. return readTableOrView();
  5779. }
  5780. }