001: package com.quadcap.sql.types;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.Externalizable;
042: import java.io.IOException;
043: import java.io.ObjectInput;
044: import java.io.ObjectOutput;
045:
046: import java.util.Calendar;
047:
048: import antlr.RecognitionException;
049:
050: import com.quadcap.util.Debug;
051:
052: /**
053: * An <b>INTERVAL</b> value.
054: *
055: * @author Stan Bailes
056: */
057: public class ValueInterval extends Value implements Externalizable {
058: long val;
059: boolean ym;
060: TypeInterval type;
061:
062: public ValueInterval() {
063: }
064:
065: public ValueInterval(TypeInterval type, long val, boolean ym) {
066: this .type = type;
067: this .val = val;
068: this .ym = ym;
069: }
070:
071: public ValueInterval(String sval, int sign, TypeInterval type)
072: throws RecognitionException {
073: this .type = type;
074: long v = 0;
075: int start = type.getStart();
076: ym = start == TypeInterval.YEAR || start == TypeInterval.MONTH;
077: long accum = 0;
078: int len = 0;
079: char c = 0;
080: for (int i = 0; i < sval.length(); i++) {
081: c = sval.charAt(i);
082: if (i == 0 && c == '-')
083: sign = sign * -1;
084: else if (Character.isDigit(c)) {
085: accum *= 10;
086: accum += Character.digit(c, 10);
087: len++;
088: } else if (c == ' ' || c == ':' || c == '-' || c == '.') {
089: v += sign * accum * type.units(start++, ym);
090: accum = 0;
091: len = 0;
092: }
093: }
094:
095: long xtra = 1;
096: if (c == '.') {
097: // assert type.end == ns
098: while (len < type.getSecPrecision()) {
099: xtra *= 10;
100: len++;
101: }
102: } else {
103: xtra = type.units(start, ym);
104: }
105: v += (sign * accum * xtra);
106: this .val = v;
107: }
108:
109: public long getValue() {
110: return val;
111: }
112:
113: public Calendar getCalendar() {
114: Calendar c = Calendar.getInstance();
115: for (int i = 0; i < Calendar.FIELD_COUNT - 1; i++)
116: c.set(i, 0);
117: if (ym) {
118: c.add(Calendar.MONTH, (int) val);
119: } else {
120: long mult = type.getMult();
121: long v = val;
122: if (mult > 1000000) {
123: v *= (mult / 1000000);
124: } else {
125: v = (v * mult) / 1000000;
126: }
127: c.add(Calendar.MILLISECOND, (int) (v));
128: }
129: return c;
130: }
131:
132: public Value getTimeComponent(int field) throws ValueException {
133: final int NANO = TypeInterval.NANO;
134:
135: Value ret = null;
136: int f = TypeInterval.convertCalendarField(field);
137: if (f < type.getStart() || f > type.getEnd()) {
138: ret = new ValueLong(0);
139: } else {
140: int e = type.getEnd();
141: int s = type.getStart();
142: if (e == s) {
143: ret = new ValueLong(val);
144: } else if (f == e) {
145: ret = new ValueLong(val % type.units(f - 1, ym));
146: } else if (f == s) {
147: ret = new ValueLong(val / type.units(s, ym));
148: } else {
149: if (e != NANO) {
150: ret = new ValueLong((val / type.units(f, ym))
151: % type.units(f - 1, ym));
152: } else {
153: ret = new ValueLong((val / type.units(f, ym))
154: % type.units(f - 1, ym));
155: }
156: }
157: }
158: return ret;
159: }
160:
161: public Value unop(int op) throws ValueException {
162: switch (op) {
163: case Op.NULL:
164: return ValueBoolean.falseBoolean;
165: case Op.PLUS:
166: return this ;
167: case Op.MINUS:
168: return new ValueInterval(type, 0 - val, ym);
169: default:
170: throw new ValueException("Unary op: " + Op.toString(op)
171: + " not implemented for this type");
172: }
173: }
174:
175: public Value binop(int op, Value l) throws ValueException {
176: return l.binop(op, this );
177: }
178:
179: public Value binop(int op, ValueNull r) throws ValueException {
180: switch (op) {
181: case Op.EQ:
182: case Op.NE:
183: case Op.LT:
184: case Op.LE:
185: case Op.GT:
186: case Op.GE:
187: case Op.PLUS:
188: case Op.MINUS:
189: return ValueUnknown.valueUnknown;
190: case Op.COMPARE:
191: return r.valCmpNull();
192: default:
193: throw badBinop(op, r);
194: }
195: }
196:
197: public Value binop(int op, ValueDouble r) throws ValueException {
198: switch (op) {
199: case Op.TIMES:
200: return new ValueInterval(type, (long) (val * r
201: .doubleValue()), ym);
202: case Op.DIVIDE:
203: return new ValueInterval(type, (long) (val / r
204: .doubleValue()), ym);
205: default:
206: throw badBinop(op, r);
207: }
208: }
209:
210: public Value binop(int op, ValueFloat r) throws ValueException {
211: switch (op) {
212: case Op.TIMES:
213: return new ValueInterval(type,
214: (long) (val * r.floatValue()), ym);
215: case Op.DIVIDE:
216: return new ValueInterval(type,
217: (long) (val / r.floatValue()), ym);
218: default:
219: throw badBinop(op, r);
220: }
221: }
222:
223: public Value binop(int op, ValueScaledInteger r)
224: throws ValueException {
225: switch (op) {
226: case Op.TIMES:
227: return new ValueInterval(type, (long) (val * r
228: .doubleValue()), ym);
229: case Op.DIVIDE:
230: return new ValueInterval(type, (long) (val / r
231: .doubleValue()), ym);
232: default:
233: throw badBinop(op, r);
234: }
235: }
236:
237: public Value binop(int op, ValueLong r) throws ValueException {
238: switch (op) {
239: case Op.TIMES:
240: return new ValueInterval(type,
241: (long) (val * r.longValue()), ym);
242: case Op.DIVIDE:
243: return new ValueInterval(type,
244: (long) (val / r.longValue()), ym);
245: default:
246: throw badBinop(op, r);
247: }
248: }
249:
250: public Value binop(int op, ValueInteger r) throws ValueException {
251: switch (op) {
252: case Op.TIMES:
253: return new ValueInterval(type, (long) (val * r.intValue()),
254: ym);
255: case Op.DIVIDE:
256: return new ValueInterval(type, (long) (val / r.intValue()),
257: ym);
258: default:
259: throw badBinop(op, r);
260: }
261: }
262:
263: public Value binop(int op, ValueShort r) throws ValueException {
264: switch (op) {
265: case Op.TIMES:
266: return new ValueInterval(type,
267: (long) (val * r.shortValue()), ym);
268: case Op.DIVIDE:
269: return new ValueInterval(type,
270: (long) (val / r.shortValue()), ym);
271: default:
272: throw badBinop(op, r);
273: }
274: }
275:
276: public Value binop(int op, ValueByte r) throws ValueException {
277: switch (op) {
278: case Op.TIMES:
279: return new ValueInterval(type,
280: (long) (val * r.byteValue()), ym);
281: case Op.DIVIDE:
282: return new ValueInterval(type,
283: (long) (val / r.byteValue()), ym);
284: default:
285: throw badBinop(op, r);
286: }
287: }
288:
289: public Value binop(int op, ValueInterval r) throws ValueException {
290: return ValueInterval.binop(op, this , r);
291: }
292:
293: public static final Value binop(int op, ValueInterval e,
294: ValueInterval f) throws ValueException {
295: if (e.ym != f.ym) {
296: throw new ValueException("Incompatible interval types: "
297: + e.toString() + " vs " + f.toString());
298: }
299: switch (op) {
300: case Op.EQ:
301: return new ValueBoolean(e.val == f.val);
302: case Op.GE:
303: return new ValueBoolean(e.val >= f.val);
304: case Op.GT:
305: return new ValueBoolean(e.val > f.val);
306: case Op.LE:
307: return new ValueBoolean(e.val <= f.val);
308: case Op.LT:
309: return new ValueBoolean(e.val < f.val);
310: case Op.MINUS:
311: return new ValueInterval(e.type, e.val - f.val, e.ym);
312: case Op.NE:
313: return new ValueBoolean(e.val != f.val);
314: case Op.PLUS:
315: return new ValueInterval(e.type, e.val + f.val, e.ym);
316: case Op.COMPARE:
317: if (e.ym == f.ym) {
318: if (e.val < f.val)
319: return ValueInteger.MINUS_ONE;
320: if (e.val > f.val)
321: return ValueInteger.PLUS_ONE;
322: return ValueInteger.ZERO;
323: } else {
324: throw new ValueException(
325: "Can't compare year/month interval "
326: + "to day-time interval");
327: }
328: default:
329: throw badBinop(op, e, f);
330: }
331: }
332:
333: public void readExternal(ObjectInput in) throws IOException,
334: ClassNotFoundException {
335: val = in.readLong();
336: type = (TypeInterval) in.readObject();
337: int start = type.getStart();
338: ym = start == TypeInterval.YEAR || start == TypeInterval.MONTH;
339: }
340:
341: public void writeExternal(ObjectOutput out) throws IOException {
342: out.writeLong(val);
343: out.writeObject(type);
344: }
345:
346: public Object asJavaObject() {
347: return toString();
348: }
349:
350: public void fromJavaObject(Object obj) throws ValueException {
351: throw new ValueException("bad type: " + obj);
352: }
353:
354: public String toString() {
355: StringBuffer sb = new StringBuffer("INTERVAL ");
356: sb.append('\'');
357: if (type.getStart() == type.getEnd()) {
358: sb.append(String.valueOf(val
359: / type.units(type.getStart(), ym)));
360: } else {
361: String delim = "";
362: for (int i = type.getStart(); i <= type.getEnd(); i++) {
363: long t1 = (i == type.getStart()) ? val : val
364: % type.units(i - 1, ym);
365: long t2 = t1 / type.units(i, ym);
366: sb.append(delim);
367: sb.append(Long.toString(t2));
368: switch (i) {
369: case TypeInterval.YEAR:
370: case TypeInterval.MONTH:
371: delim = "-";
372: break;
373: case TypeInterval.DAY:
374: delim = " ";
375: break;
376: case TypeInterval.HOUR:
377: case TypeInterval.MINUTE:
378: delim = ":";
379: break;
380: case TypeInterval.SECOND:
381: delim = ".";
382: break;
383: default:
384: }
385: }
386: }
387: sb.append("' ");
388: sb.append(type.toString().substring(9));
389: return sb.toString();
390: }
391:
392: public Value convert(TypeInterval newType) throws ValueException {
393: long m1 = type.getMult();
394: long m2 = newType.getMult();
395: long v = val;
396:
397: if (m1 > m2) {
398: v *= (m1 / m2);
399: } else if (m1 < m2) {
400: v /= (m2 / m1);
401: }
402: Value ret = new ValueInterval(newType, v, ym);
403: return ret;
404: }
405:
406: public Value convert(TypeDecimal t) {
407: int f = type.getStart();
408: return new ValueScaledInteger(val / type.units(f, ym));
409: }
410:
411: public Type getType() {
412: return type;
413: }
414:
415: public void serializeKey(KeyStream out) throws IOException {
416: out.writeBoolean(ym);
417: out.writeLong(val);
418: }
419:
420: }
|