001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb.rowio;
032:
033: import java.math.BigDecimal;
034: import java.math.BigInteger;
035: import java.sql.Date;
036: import java.sql.Time;
037: import java.sql.Timestamp;
038:
039: import org.hsqldb.CachedRow;
040: import org.hsqldb.Trace;
041: import org.hsqldb.Types;
042: import org.hsqldb.lib.StringConverter;
043: import org.hsqldb.lib.java.JavaSystem;
044: import org.hsqldb.types.Binary;
045: import org.hsqldb.types.JavaObject;
046:
047: /**
048: * Provides methods for writing the data for a row to a
049: * byte array. The new format of data consists of mainly binary values
050: * and is not compatible with v.1.6.x databases.
051: *
052: * @author sqlbob@users (RMP)
053: * @author fredt@users
054: * @version 1.7.2
055: * @since 1.7.0
056: */
057: public class RowOutputBinary extends RowOutputBase {
058:
059: private static final int INT_STORE_SIZE = 4;
060: int storageSize;
061:
062: public RowOutputBinary() {
063: super ();
064: }
065:
066: public RowOutputBinary(int initialSize) {
067: super (initialSize);
068: }
069:
070: /**
071: * Constructor used for network transmission of result sets
072: *
073: * @exception IOException when an IO error is encountered
074: */
075: public RowOutputBinary(byte[] buffer) {
076: super (buffer);
077: }
078:
079: // fredt@users - comment - methods for writing column type, name and data size
080: public void writeShortData(short i) {
081: writeShort(i);
082: }
083:
084: public void writeIntData(int i) {
085: writeInt(i);
086: }
087:
088: public void writeIntData(int i, int position) {
089:
090: int temp = count;
091:
092: count = position;
093:
094: writeInt(i);
095:
096: if (count < temp) {
097: count = temp;
098: }
099: }
100:
101: public void writeLongData(long i) {
102: this .writeLong(i);
103: }
104:
105: public void writeEnd() {
106:
107: // fredt - this value is used in 1.7.0 when reading back, for a
108: // 'data integrity' check
109: // has been removed in 1.7.2 as compatibility is no longer necessary
110: // writeInt(pos);
111: for (; count < storageSize;) {
112: this .write(0);
113: }
114: }
115:
116: public void writeSize(int size) {
117:
118: storageSize = size;
119:
120: writeInt(size);
121: }
122:
123: public void writeType(int type) {
124: writeShort(type);
125: }
126:
127: public void writeString(String s) {
128:
129: int temp = count;
130:
131: writeInt(0);
132: StringConverter.writeUTF(s, this );
133: writeIntData(count - temp - 4, temp);
134: }
135:
136: /**
137: * Calculate the size of byte array required to store a row.
138: *
139: * @param row - a database row
140: * @return size of byte array
141: * @exception HsqlException When data is inconsistent
142: */
143: public int getSize(CachedRow row) {
144:
145: Object[] data = row.getData();
146: int[] type = row.getTable().getColumnTypes();
147: int cols = row.getTable().getColumnCount();
148:
149: return INT_STORE_SIZE + getSize(data, cols, type);
150: }
151:
152: public static int getRowSize(CachedRow row) {
153:
154: Object[] data = row.getData();
155: int[] type = row.getTable().getColumnTypes();
156: int cols = row.getTable().getColumnCount();
157:
158: return getSize(data, cols, type);
159: }
160:
161: // fredt@users - comment - methods used for writing each SQL type
162: protected void writeFieldType(int type) {
163: write(1);
164: }
165:
166: protected void writeNull(int type) {
167: write(0);
168: }
169:
170: protected void writeChar(String s, int t) {
171: writeString(s);
172: }
173:
174: protected void writeSmallint(Number o) {
175: writeShort(o.intValue());
176: }
177:
178: protected void writeInteger(Number o) {
179: writeInt(o.intValue());
180: }
181:
182: protected void writeBigint(Number o) {
183: writeLong(o.longValue());
184: }
185:
186: protected void writeReal(Double o, int type) {
187: writeLong(Double.doubleToLongBits((o.doubleValue())));
188: }
189:
190: protected void writeDecimal(BigDecimal o) {
191:
192: int scale = o.scale();
193: BigInteger bigint = JavaSystem.getUnscaledValue(o);
194: byte[] bytearr = bigint.toByteArray();
195:
196: writeByteArray(bytearr);
197: writeInt(scale);
198: }
199:
200: protected void writeBit(Boolean o) {
201: write(o.booleanValue() ? 1 : 0);
202: }
203:
204: protected void writeDate(Date o) {
205: writeLong(o.getTime());
206: }
207:
208: protected void writeTime(Time o) {
209: writeLong(o.getTime());
210: }
211:
212: protected void writeTimestamp(Timestamp o) {
213: writeLong(o.getTime());
214: writeInt(o.getNanos());
215: }
216:
217: protected void writeOther(JavaObject o) {
218: writeByteArray(o.getBytes());
219: }
220:
221: protected void writeBinary(Binary o, int t) {
222: writeByteArray(o.getBytes());
223: }
224:
225: // fredt@users - comment - helper and conversion methods
226: protected void writeByteArray(byte[] b) {
227: writeInt(b.length);
228: write(b, 0, b.length);
229: }
230:
231: /**
232: * Calculate the size of byte array required to store a row.
233: *
234: * @param data - the row data
235: * @param l - number of data[] elements to include in calculation
236: * @param type - array of java.sql.Types values
237: * @return size of byte array
238: * @exception HsqlException when data is inconsistent
239: */
240: private static int getSize(Object[] data, int l, int[] type) {
241:
242: int s = 0;
243:
244: for (int i = 0; i < l; i++) {
245: Object o = data[i];
246:
247: s += 1; // type or null
248:
249: if (o != null) {
250: switch (type[i]) {
251:
252: case Types.NULL:
253: case Types.CHAR:
254: case Types.VARCHAR:
255: case Types.VARCHAR_IGNORECASE:
256: case Types.LONGVARCHAR:
257: s += 4;
258: s += StringConverter.getUTFSize((String) o);
259: break;
260:
261: case Types.TINYINT:
262: case Types.SMALLINT:
263: s += 2;
264: break;
265:
266: case Types.INTEGER:
267: s += 4;
268: break;
269:
270: case Types.BIGINT:
271: case Types.REAL:
272: case Types.FLOAT:
273: case Types.DOUBLE:
274: s += 8;
275: break;
276:
277: case Types.NUMERIC:
278: case Types.DECIMAL:
279: s += 8;
280:
281: BigDecimal bigdecimal = (BigDecimal) o;
282: BigInteger bigint = JavaSystem
283: .getUnscaledValue(bigdecimal);
284:
285: s += bigint.toByteArray().length;
286: break;
287:
288: case Types.BOOLEAN:
289: s += 1;
290: break;
291:
292: case Types.DATE:
293: case Types.TIME:
294: s += 8;
295: break;
296:
297: case Types.TIMESTAMP:
298: s += 12;
299: break;
300:
301: case Types.BINARY:
302: case Types.VARBINARY:
303: case Types.LONGVARBINARY:
304: s += 4;
305: s += ((Binary) o).getBytesLength();
306: break;
307:
308: case Types.OTHER:
309: JavaObject jo = (JavaObject) o;
310:
311: s += 4;
312: s += jo.getBytesLength();
313: break;
314:
315: default:
316: Trace.printSystemOut(Trace.FUNCTION_NOT_SUPPORTED
317: + " " + Types.getTypeString(type[i]));
318: }
319: }
320: }
321:
322: return s;
323: }
324:
325: /**
326: * @param extra amount of extra space
327: */
328: public void ensureRoom(int extra) {
329: super .ensureRoom(extra);
330: }
331:
332: public void reset() {
333:
334: super .reset();
335:
336: storageSize = 0;
337: }
338:
339: public void reset(int newSize) {
340:
341: super .reset(newSize);
342:
343: storageSize = 0;
344: }
345:
346: public void setBuffer(byte[] buffer) {
347:
348: buf = buffer;
349:
350: reset();
351: }
352: }
|