/* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.test.synth.sql; import java.sql.SQLException; import java.util.HashMap; import org.h2.util.New; import org.h2.util.StatementBuilder; /** * Represents a statement. */ class Command { private static final int CONNECT = 0, RESET = 1, DISCONNECT = 2, CREATE_TABLE = 3, INSERT = 4, DROP_TABLE = 5, SELECT = 6, DELETE = 7, UPDATE = 8, COMMIT = 9, ROLLBACK = 10, AUTOCOMMIT_ON = 11, AUTOCOMMIT_OFF = 12, CREATE_INDEX = 13, DROP_INDEX = 14, END = 15; /** * The select list. */ String[] selectList; private TestSynth config; private int type; private Table table; private HashMap<String, Table> tables; private Index index; private Column[] columns; private Value[] values; private String condition; // private int nextAlias; private String order; private String join = ""; private Result result; private Command(TestSynth config, int type) { this.config = config; this.type = type; } private Command(TestSynth config, int type, Table table) { this.config = config; this.type = type; this.table = table; } private Command(TestSynth config, int type, Table table, String alias) { this.config = config; this.type = type; this.table = table; this.tables = New.hashMap(); this.tables.put(alias, table); } private Command(TestSynth config, int type, Index index) { this.config = config; this.type = type; this.index = index; } Command(int type, String alias, Table table) { this.type = type; if (alias == null) { alias = table.getName(); } addSubqueryTable(alias, table); this.table = table; } // static Command getDropTable(TestSynth config, Table table) { // return new Command(config, Command.DROP_TABLE, table); // } // Command getCommit(TestSynth config) { // return new Command(config, Command.COMMIT); // } // Command getRollback(TestSynth config) { // return new Command(config, Command.ROLLBACK); // } // Command getSetAutoCommit(TestSynth config, boolean auto) { // int type = auto ? Command.AUTOCOMMIT_ON : Command.AUTOCOMMIT_OFF; // return new Command(config, type); // } /** * Create a connect command. * * @param config the configuration * @return the command */ static Command getConnect(TestSynth config) { return new Command(config, CONNECT); } /** * Create a reset command. * * @param config the configuration * @return the command */ static Command getReset(TestSynth config) { return new Command(config, RESET); } /** * Create a disconnect command. * * @param config the configuration * @return the command */ static Command getDisconnect(TestSynth config) { return new Command(config, DISCONNECT); } /** * Create an end command. * * @param config the configuration * @return the command */ static Command getEnd(TestSynth config) { return new Command(config, END); } /** * Create a create table command. * * @param config the configuration * @param table the table * @return the command */ static Command getCreateTable(TestSynth config, Table table) { return new Command(config, CREATE_TABLE, table); } /** * Create a create index command. * * @param config the configuration * @param index the index * @return the command */ static Command getCreateIndex(TestSynth config, Index index) { return new Command(config, CREATE_INDEX, index); } /** * Create a random select command. * * @param config the configuration * @param table the table * @return the command */ static Command getRandomSelect(TestSynth config, Table table) { Command command = new Command(config, Command.SELECT, table, "M"); command.selectList = Expression.getRandomSelectList(config, command); // TODO group by, having, joins command.condition = Expression.getRandomCondition(config, command).getSQL(); command.order = Expression.getRandomOrder(config, command); return command; } // static Command getRandomSelectJoin(TestSynth config, Table table) { // Command command = new Command(config, Command.SELECT, table, "M"); // int len = config.random().getLog(5) + 1; // String globalJoinCondition = ""; // for (int i = 0; i < len; i++) { // Table t2 = config.randomTable(); // String alias = "J" + i; // command.addSubqueryTable(alias, t2); // Expression joinOn = // Expression.getRandomJoinOn(config, command, alias); // if (config.random().getBoolean(50)) { // // regular join // if (globalJoinCondition.length() > 0) { // globalJoinCondition += " AND "; // // } // globalJoinCondition += " (" + joinOn.getSQL() + ") "; // command.addJoin(", " + t2.getName() + " " + alias); // } else { // String join = " JOIN " + t2.getName() + // " " + alias + " ON " + joinOn.getSQL(); // if (config.random().getBoolean(20)) { // command.addJoin(" LEFT OUTER" + join); // } else { // command.addJoin(" INNER" + join); // } // } // } // command.selectList = // Expression.getRandomSelectList(config, command); // // TODO group by, having // String cond = Expression.getRandomCondition(config, command).getSQL(); // if (globalJoinCondition.length() > 0) { // if (cond != null) { // cond = "(" + globalJoinCondition + " ) AND (" + cond + ")"; // } else { // cond = globalJoinCondition; // } // } // command.condition = cond; // command.order = Expression.getRandomOrder(config, command); // return command; // } /** * Create a random delete command. * * @param config the configuration * @param table the table * @return the command */ static Command getRandomDelete(TestSynth config, Table table) { Command command = new Command(config, Command.DELETE, table); command.condition = Expression.getRandomCondition(config, command).getSQL(); return command; } /** * Create a random update command. * * @param config the configuration * @param table the table * @return the command */ static Command getRandomUpdate(TestSynth config, Table table) { Command command = new Command(config, Command.UPDATE, table); command.prepareUpdate(); return command; } /** * Create a random insert command. * * @param config the configuration * @param table the table * @return the command */ static Command getRandomInsert(TestSynth config, Table table) { Command command = new Command(config, Command.INSERT, table); command.prepareInsert(); return command; } /** * Add a subquery table to the command. * * @param alias the table alias * @param t the table */ void addSubqueryTable(String alias, Table t) { tables.put(alias, t); } // void removeSubqueryTable(String alias) { // tables.remove(alias); // } private void prepareInsert() { Column[] c; if (config.random().getBoolean(70)) { c = table.getColumns(); } else { int len = config.random().getInt(table.getColumnCount() - 1) + 1; c = columns = table.getRandomColumns(len); } values = new Value[c.length]; for (int i = 0; i < c.length; i++) { values[i] = c[i].getRandomValue(); } } private void prepareUpdate() { int len = config.random().getLog(table.getColumnCount() - 1) + 1; Column[] c = columns = table.getRandomColumns(len); values = new Value[c.length]; for (int i = 0; i < c.length; i++) { values[i] = c[i].getRandomValue(); } condition = Expression.getRandomCondition(config, this).getSQL(); } private Result select(DbInterface db) throws SQLException { StatementBuilder buff = new StatementBuilder("SELECT "); for (String s : selectList) { buff.appendExceptFirst(", "); buff.append(s); } buff.append(" FROM ").append(table.getName()).append(" M"). append(' ').append(join); if (condition != null) { buff.append(" WHERE ").append(condition); } if (order.trim().length() > 0) { buff.append(" ORDER BY ").append(order); } return db.select(buff.toString()); } /** * Run the command against the specified database. * * @param db the database * @return the result */ Result run(DbInterface db) throws Exception { try { switch (type) { case CONNECT: db.connect(); result = new Result("connect"); break; case RESET: db.reset(); result = new Result("reset"); break; case DISCONNECT: db.disconnect(); result = new Result("disconnect"); break; case END: db.end(); result = new Result("disconnect"); break; case CREATE_TABLE: db.createTable(table); result = new Result("createTable"); break; case DROP_TABLE: db.dropTable(table); result = new Result("dropTable"); break; case CREATE_INDEX: db.createIndex(index); result = new Result("createIndex"); break; case DROP_INDEX: db.dropIndex(index); result = new Result("dropIndex"); break; case INSERT: result = db.insert(table, columns, values); break; case SELECT: result = select(db); break; case DELETE: result = db.delete(table, condition); break; case UPDATE: result = db.update(table, columns, values, condition); break; case AUTOCOMMIT_ON: db.setAutoCommit(true); result = new Result("setAutoCommit true"); break; case AUTOCOMMIT_OFF: db.setAutoCommit(false); result = new Result("setAutoCommit false"); break; case COMMIT: db.commit(); result = new Result("commit"); break; case ROLLBACK: db.rollback(); result = new Result("rollback"); break; default: throw new AssertionError("type=" + type); } } catch (SQLException e) { result = new Result("", e); } return result; } // public String getNextTableAlias() { // return "S" + nextAlias++; // } /** * Get a random table alias name. * * @return the alias name */ String getRandomTableAlias() { if (tables == null) { return null; } Object[] list = tables.keySet().toArray(); int i = config.random().getInt(list.length); return (String) list[i]; } /** * Get the table with the specified alias. * * @param alias the alias or null if there is only one table * @return the table */ Table getTable(String alias) { if (alias == null) { return table; } return tables.get(alias); } // public void addJoin(String string) { // join += string; // } // static Command getSelectAll(TestSynth config, Table table) { // Command command = new Command(config, Command.SELECT, table, "M"); // command.selectList = new String[] { "*" }; // command.order = ""; // return command; // } }