001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (license2)
004: * Initial Developer: H2 Group
005: */
006: package org.h2.test.synth.sql;
007:
008: import java.sql.SQLException;
009: import java.util.HashMap;
010:
011: /**
012: * Represents a statement.
013: */
014: class Command {
015: TestSynth config;
016: static final int CONNECT = 0, RESET = 1, DISCONNECT = 2,
017: CREATE_TABLE = 3, INSERT = 4, DROP_TABLE = 5, SELECT = 6,
018: DELETE = 7, UPDATE = 8, COMMIT = 9, ROLLBACK = 10,
019: AUTOCOMMIT_ON = 11, AUTOCOMMIT_OFF = 12, CREATE_INDEX = 13,
020: DROP_INDEX = 14, END = 15;
021: private int type;
022: private Table table;
023: private HashMap tables;
024: private Index index;
025: private Column[] columns;
026: private Value[] values;
027: private String condition;
028: private int nextAlias;
029: private String order;
030: String[] selectList;
031: private String join = "";
032: private Result result;
033:
034: static Command getDropTable(TestSynth config, Table table) {
035: return new Command(config, Command.DROP_TABLE, table);
036: }
037:
038: Command getCommit(TestSynth config) {
039: return new Command(config, Command.COMMIT);
040: }
041:
042: Command getRollback(TestSynth config) {
043: return new Command(config, Command.ROLLBACK);
044: }
045:
046: Command getSetAutoCommit(TestSynth config, boolean auto) {
047: int type = auto ? Command.AUTOCOMMIT_ON
048: : Command.AUTOCOMMIT_OFF;
049: return new Command(config, type);
050: }
051:
052: static Command getConnect(TestSynth config) {
053: return new Command(config, CONNECT);
054: }
055:
056: static Command getReset(TestSynth config) {
057: return new Command(config, RESET);
058: }
059:
060: static Command getDisconnect(TestSynth config) {
061: return new Command(config, DISCONNECT);
062: }
063:
064: static Command getEnd(TestSynth config) {
065: return new Command(config, END);
066: }
067:
068: static Command getCreateTable(TestSynth config, Table table) {
069: return new Command(config, CREATE_TABLE, table);
070: }
071:
072: static Command getCreateIndex(TestSynth config, Index index) {
073: return new Command(config, CREATE_INDEX, index);
074: }
075:
076: static Command getRandomSelect(TestSynth config, Table table) {
077: Command command = new Command(config, Command.SELECT, table,
078: "M");
079: command.selectList = Expression.getRandomSelectList(config,
080: command);
081: // TODO group by, having, joins
082: command.condition = Expression.getRandomCondition(config,
083: command).getSQL();
084: command.order = Expression.getRandomOrder(config, command);
085: return command;
086: }
087:
088: static Command getRandomSelectJoin(TestSynth config, Table table) {
089: Command command = new Command(config, Command.SELECT, table,
090: "M");
091: int len = config.random().getLog(5) + 1;
092: String globalJoinCondition = "";
093: for (int i = 0; i < len; i++) {
094: Table t2 = config.randomTable();
095: String alias = "J" + i;
096: command.addSubqueryTable(alias, t2);
097: Expression joinOn = Expression.getRandomJoinOn(config,
098: command, alias);
099: if (config.random().getBoolean(50)) {
100: // regular join
101: if (globalJoinCondition.length() > 0) {
102: globalJoinCondition += " AND ";
103:
104: }
105: globalJoinCondition += " (" + joinOn.getSQL() + ") ";
106: command.addJoin(", " + t2.getName() + " " + alias);
107: } else {
108: String join = " JOIN " + t2.getName() + " " + alias
109: + " ON " + joinOn.getSQL();
110: if (config.random().getBoolean(20)) {
111: command.addJoin(" LEFT OUTER" + join);
112: } else {
113: command.addJoin(" INNER" + join);
114: }
115: }
116: }
117: command.selectList = Expression.getRandomSelectList(config,
118: command);
119: // TODO group by, having
120: String cond = Expression.getRandomCondition(config, command)
121: .getSQL();
122: if (globalJoinCondition.length() > 0) {
123: if (cond != null) {
124: cond = "(" + globalJoinCondition + " ) AND (" + cond
125: + ")";
126: } else {
127: cond = globalJoinCondition;
128: }
129: }
130: command.condition = cond;
131: command.order = Expression.getRandomOrder(config, command);
132: return command;
133: }
134:
135: static Command getRandomDelete(TestSynth config, Table table) {
136: Command command = new Command(config, Command.DELETE, table);
137: command.condition = Expression.getRandomCondition(config,
138: command).getSQL();
139: return command;
140: }
141:
142: static Command getRandomUpdate(TestSynth config, Table table) {
143: Command command = new Command(config, Command.UPDATE, table);
144: command.prepareUpdate();
145: return command;
146: }
147:
148: static Command getRandomInsert(TestSynth config, Table table) {
149: Command command = new Command(config, Command.INSERT, table);
150: command.prepareInsert();
151: return command;
152: }
153:
154: private Command(TestSynth config, int type) {
155: this .config = config;
156: this .type = type;
157: }
158:
159: private Command(TestSynth config, int type, Table table) {
160: this .config = config;
161: this .type = type;
162: this .table = table;
163: }
164:
165: private Command(TestSynth config, int type, Table table,
166: String alias) {
167: this .config = config;
168: this .type = type;
169: this .table = table;
170: this .tables = new HashMap();
171: this .tables.put(alias, table);
172: }
173:
174: private Command(TestSynth config, int type, Index index) {
175: this .config = config;
176: this .type = type;
177: this .index = index;
178: }
179:
180: Command(int type, String alias, Table table) {
181: this .type = type;
182: if (alias == null) {
183: alias = table.getName();
184: }
185: addSubqueryTable(alias, table);
186: this .table = table;
187: }
188:
189: void addSubqueryTable(String alias, Table t) {
190: tables.put(alias, t);
191: }
192:
193: void removeSubqueryTable(String alias) {
194: tables.remove(alias);
195: }
196:
197: void prepareInsert() {
198: Column[] c;
199: if (config.random().getBoolean(70)) {
200: c = table.getColumns();
201: } else {
202: int len = config.random()
203: .getInt(table.getColumnCount() - 1) + 1;
204: c = columns = table.getRandomColumns(len);
205: }
206: values = new Value[c.length];
207: for (int i = 0; i < c.length; i++) {
208: values[i] = c[i].getRandomValue();
209: }
210: }
211:
212: void prepareUpdate() {
213: int len = config.random().getLog(table.getColumnCount() - 1) + 1;
214: Column[] c = columns = table.getRandomColumns(len);
215: values = new Value[c.length];
216: for (int i = 0; i < c.length; i++) {
217: values[i] = c[i].getRandomValue();
218: }
219: condition = Expression.getRandomCondition(config, this )
220: .getSQL();
221: }
222:
223: private Result select(DbInterface db) throws SQLException {
224: String sql = "SELECT ";
225: for (int i = 0; i < selectList.length; i++) {
226: if (i > 0) {
227: sql += ", ";
228: }
229: sql += selectList[i];
230: }
231: sql += " FROM " + table.getName() + " M";
232: sql += " " + join;
233: if (condition != null) {
234: sql += " WHERE " + condition;
235: }
236: if (order.trim().length() > 0) {
237: sql += " ORDER BY " + order;
238: }
239: return db.select(sql);
240: }
241:
242: Result run(DbInterface db) throws Exception {
243: try {
244: switch (type) {
245: case CONNECT:
246: db.connect();
247: result = new Result("connect");
248: break;
249: case RESET:
250: db.reset();
251: result = new Result("reset");
252: break;
253: case DISCONNECT:
254: db.disconnect();
255: result = new Result("disconnect");
256: break;
257: case END:
258: db.end();
259: result = new Result("disconnect");
260: break;
261: case CREATE_TABLE:
262: db.createTable(table);
263: result = new Result("createTable");
264: break;
265: case DROP_TABLE:
266: db.dropTable(table);
267: result = new Result("dropTable");
268: break;
269: case CREATE_INDEX:
270: db.createIndex(index);
271: result = new Result("createIndex");
272: break;
273: case DROP_INDEX:
274: db.dropIndex(index);
275: result = new Result("dropIndex");
276: break;
277: case INSERT:
278: result = db.insert(table, columns, values);
279: break;
280: case SELECT:
281: result = select(db);
282: break;
283: case DELETE:
284: result = db.delete(table, condition);
285: break;
286: case UPDATE:
287: result = db.update(table, columns, values, condition);
288: break;
289: case AUTOCOMMIT_ON:
290: db.setAutoCommit(true);
291: result = new Result("setAutoCommit true");
292: break;
293: case AUTOCOMMIT_OFF:
294: db.setAutoCommit(false);
295: result = new Result("setAutoCommit false");
296: break;
297: case COMMIT:
298: db.commit();
299: result = new Result("commit");
300: break;
301: case ROLLBACK:
302: db.rollback();
303: result = new Result("rollback");
304: break;
305: default:
306: throw new Error("internal");
307: }
308: } catch (SQLException e) {
309: result = new Result("", e);
310: }
311: return result;
312: }
313:
314: public String getNextTableAlias() {
315: return "S" + nextAlias++;
316: }
317:
318: public String getRandomTableAlias() {
319: if (tables == null) {
320: return null;
321: }
322: Object[] list = tables.keySet().toArray();
323: int i = config.random().getInt(list.length);
324: return (String) list[i];
325: }
326:
327: public Table getTable(String alias) {
328: if (alias == null) {
329: return table;
330: }
331: return (Table) tables.get(alias);
332: }
333:
334: public void addJoin(String string) {
335: join += string;
336: }
337:
338: static Command getSelectAll(TestSynth config, Table table) {
339: Command command = new Command(config, Command.SELECT, table,
340: "M");
341: command.selectList = new String[] { "*" };
342: command.order = "";
343: return command;
344: }
345:
346: }
|