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.math.BigDecimal;
009: import java.sql.Date;
010: import java.sql.ResultSet;
011: import java.sql.ResultSetMetaData;
012: import java.sql.SQLException;
013: import java.sql.Time;
014: import java.sql.Timestamp;
015: import java.sql.Types;
016:
017: import org.h2.value.DataType;
018:
019: /**
020: * Represents a simple value.
021: */
022: public class Value {
023: private int type;
024: private Object data;
025: private TestSynth config;
026:
027: private Value(TestSynth config, int type, Object data) {
028: this .config = config;
029: this .type = type;
030: this .data = data;
031: }
032:
033: String getSQL() {
034: if (data == null) {
035: return "NULL";
036: }
037: switch (type) {
038: case Types.DECIMAL:
039: case Types.NUMERIC:
040: case Types.BIGINT:
041: case Types.INTEGER:
042: case Types.DOUBLE:
043: case Types.REAL:
044: return data.toString();
045: case Types.CLOB:
046: case Types.VARCHAR:
047: case Types.CHAR:
048: case Types.OTHER:
049: case Types.LONGVARCHAR:
050: return "'" + data.toString() + "'";
051: case Types.BLOB:
052: case Types.BINARY:
053: case Types.VARBINARY:
054: case Types.LONGVARBINARY:
055: return getBlobSQL();
056: case Types.DATE:
057: return getDateSQL((Date) data);
058: case Types.TIME:
059: return getTimeSQL((Time) data);
060: case Types.TIMESTAMP:
061: return getTimestampSQL((Timestamp) data);
062: case DataType.TYPE_BOOLEAN:
063: case Types.BIT:
064: return (String) data;
065: default:
066: throw new Error("type=" + type);
067: }
068: }
069:
070: private static Date randomDate(TestSynth config) {
071: return config.random().randomDate();
072:
073: }
074:
075: private static Double randomDouble(TestSynth config) {
076: return new Double(config.random().getInt(100) / 10.);
077: }
078:
079: private static Long randomLong(TestSynth config) {
080: return new Long(config.random().getInt(1000));
081: }
082:
083: private static Time randomTime(TestSynth config) {
084: return config.random().randomTime();
085: }
086:
087: private static Timestamp randomTimestamp(TestSynth config) {
088: return config.random().randomTimestamp();
089: }
090:
091: private String getTimestampSQL(Timestamp ts) {
092: String s = "'" + ts.toString() + "'";
093: if (config.getMode() != TestSynth.HSQLDB) {
094: s = "TIMESTAMP " + s;
095: }
096: return s;
097: }
098:
099: private String getDateSQL(Date date) {
100: String s = "'" + date.toString() + "'";
101: if (config.getMode() != TestSynth.HSQLDB) {
102: s = "DATE " + s;
103: }
104: return s;
105: }
106:
107: private String getTimeSQL(Time time) {
108: String s = "'" + time.toString() + "'";
109: if (config.getMode() != TestSynth.HSQLDB) {
110: s = "TIME " + s;
111: }
112: return s;
113: }
114:
115: private String getBlobSQL() {
116: byte[] bytes = (byte[]) data;
117: // StringBuffer buff = new StringBuffer("X'");
118: StringBuffer buff = new StringBuffer("'");
119: for (int i = 0; i < bytes.length; i++) {
120: int c = bytes[i] & 0xff;
121: buff.append(Integer.toHexString(c >> 4 & 0xf));
122: buff.append(Integer.toHexString(c & 0xf));
123:
124: }
125: buff.append("'");
126: return buff.toString();
127: }
128:
129: public static Value read(TestSynth config, ResultSet rs, int index)
130: throws SQLException {
131: ResultSetMetaData meta = rs.getMetaData();
132: Object data;
133: int type = meta.getColumnType(index);
134: switch (type) {
135: case Types.REAL:
136: case Types.DOUBLE:
137: data = new Double(rs.getDouble(index));
138: break;
139: case Types.BIGINT:
140: data = new Long(rs.getLong(index));
141: break;
142: case Types.DECIMAL:
143: case Types.NUMERIC:
144: data = rs.getBigDecimal(index);
145: break;
146: case Types.BLOB:
147: case Types.BINARY:
148: case Types.VARBINARY:
149: case Types.LONGVARBINARY:
150: data = rs.getBytes(index);
151: break;
152: case Types.OTHER:
153: case Types.CLOB:
154: case Types.VARCHAR:
155: case Types.LONGVARCHAR:
156: case Types.CHAR:
157: data = rs.getString(index);
158: break;
159: case Types.DATE:
160: data = rs.getDate(index);
161: break;
162: case Types.TIME:
163: data = rs.getTime(index);
164: break;
165: case Types.TIMESTAMP:
166: data = rs.getTimestamp(index);
167: break;
168: case Types.INTEGER:
169: data = new Integer(rs.getInt(index));
170: break;
171: case Types.NULL:
172: data = null;
173: break;
174: case DataType.TYPE_BOOLEAN:
175: case Types.BIT:
176: data = rs.getBoolean(index) ? "TRUE" : "FALSE";
177: break;
178: default:
179: throw new Error("type=" + type);
180: }
181: if (rs.wasNull()) {
182: data = null;
183: }
184: return new Value(config, type, data);
185: }
186:
187: static Value getRandom(TestSynth config, int type, int precision,
188: int scale, boolean mayBeNull) {
189: Object data;
190: if (mayBeNull && config.random().getBoolean(20)) {
191: return new Value(config, type, null);
192: }
193: switch (type) {
194: case Types.BIGINT:
195: data = randomLong(config);
196: break;
197: case Types.DOUBLE:
198: data = randomDouble(config);
199: break;
200: case Types.DECIMAL:
201: data = randomDecimal(config, precision, scale);
202: break;
203: case Types.VARBINARY:
204: case Types.BINARY:
205: case Types.BLOB:
206: data = randomBytes(config, precision);
207: break;
208: case Types.CLOB:
209: case Types.VARCHAR:
210: data = config.random().randomString(
211: config.random().getInt(precision));
212: break;
213: case Types.DATE:
214: data = randomDate(config);
215: break;
216: case Types.TIME:
217: data = randomTime(config);
218: break;
219: case Types.TIMESTAMP:
220: data = randomTimestamp(config);
221: break;
222: case Types.INTEGER:
223: data = randomInt(config);
224: break;
225: case DataType.TYPE_BOOLEAN:
226: case Types.BIT:
227: data = config.random().getBoolean(50) ? "TRUE" : "FALSE";
228: break;
229: default:
230: throw new Error("type=" + type);
231: }
232: return new Value(config, type, data);
233: }
234:
235: private static Object randomInt(TestSynth config) {
236: int value;
237: if (config.is(TestSynth.POSTGRESQL)) {
238: value = config.random().getInt(1000000);
239: } else {
240: value = config.random().getRandomInt();
241: }
242: return new Integer(value);
243: }
244:
245: private static byte[] randomBytes(TestSynth config, int max) {
246: int len = config.random().getLog(max);
247: byte[] data = new byte[len];
248: config.random().getBytes(data);
249: return data;
250: }
251:
252: private static BigDecimal randomDecimal(TestSynth config,
253: int precision, int scale) {
254: int len = config.random().getLog(precision - scale) + scale;
255: if (len == 0) {
256: len++;
257: }
258: StringBuffer buff = new StringBuffer();
259: for (int i = 0; i < len; i++) {
260: buff.append((char) ('0' + config.random().getInt(10)));
261: }
262: buff.insert(len - scale, '.');
263: if (config.random().getBoolean(20)) {
264: buff.insert(0, '-');
265: }
266: return new BigDecimal(buff.toString());
267: }
268:
269: public int compareTo(Object o) {
270: Value v = (Value) o;
271: if (type != v.type) {
272: throw new Error("compare " + type + " " + v.type + " "
273: + data + " " + v.data);
274: }
275: if (data == null) {
276: return (v.data == null) ? 0 : -1;
277: } else if (v.data == null) {
278: return 1;
279: }
280: switch (type) {
281: case Types.DECIMAL:
282: return ((BigDecimal) data).compareTo((BigDecimal) v.data);
283: case Types.BLOB:
284: case Types.VARBINARY:
285: case Types.BINARY:
286: return compareBytes((byte[]) data, (byte[]) v.data);
287: case Types.CLOB:
288: case Types.VARCHAR:
289: return data.toString().compareTo(v.data.toString());
290: case Types.DATE:
291: return ((Date) data).compareTo((Date) v.data);
292: case Types.INTEGER:
293: return ((Integer) data).compareTo((Integer) v.data);
294: default:
295: throw new Error("type=" + type);
296: }
297: }
298:
299: static int compareBytes(byte[] a, byte[] b) {
300: int al = a.length, bl = b.length;
301: int len = Math.min(al, bl);
302: for (int i = 0; i < len; i++) {
303: int x = a[i] & 0xff;
304: int y = b[i] & 0xff;
305: if (x == y) {
306: continue;
307: }
308: return x > y ? 1 : -1;
309: }
310: return al == bl ? 0 : al > bl ? 1 : -1;
311: }
312:
313: public String toString() {
314: return getSQL();
315: }
316:
317: }
|