001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.value;
007:
008: import java.math.BigInteger;
009: import java.sql.PreparedStatement;
010: import java.sql.SQLException;
011:
012: import org.h2.constant.ErrorCode;
013: import org.h2.constant.SysProperties;
014: import org.h2.message.Message;
015: import org.h2.util.ObjectUtils;
016:
017: /**
018: * Implementation of the BIGINT data type.
019: */
020: public class ValueLong extends Value {
021:
022: private final long value;
023:
024: public static final int PRECISION = 19;
025: public static final int DISPLAY_SIZE = 20; // -9223372036854775808
026: private static final int STATIC_SIZE = 10;
027: private static ValueLong[] cache;
028: private static final BigInteger MIN = new BigInteger(""
029: + Long.MIN_VALUE);
030: private static final BigInteger MAX = new BigInteger(""
031: + Long.MAX_VALUE);
032:
033: static {
034: cache = new ValueLong[STATIC_SIZE];
035: for (int i = 0; i < STATIC_SIZE; i++) {
036: cache[i] = new ValueLong(i);
037: }
038: }
039:
040: private ValueLong(long value) {
041: this .value = value;
042: }
043:
044: public Value add(Value v) throws SQLException {
045: ValueLong other = (ValueLong) v;
046: if (SysProperties.OVERFLOW_EXCEPTIONS) {
047: long result = value + other.value;
048: int sv = value == 0 ? 0 : (value < 0 ? -1 : 1);
049: int so = other.value == 0 ? 0 : (other.value < 0 ? -1 : 1);
050: int sr = result == 0 ? 0 : (result < 0 ? -1 : 1);
051: // if the operands have different signs overflow can not occur
052: // if the operands have the same sign,
053: // and the result has a different sign, then it is an overflow
054: // it can not be an overflow when one of the operands is 0
055: if (sv != so || sr == so || sv == 0 || so == 0) {
056: return ValueLong.get(result);
057: }
058: throw getOverflow();
059: }
060: return ValueLong.get(value + other.value);
061: }
062:
063: public int getSignum() {
064: return value == 0 ? 0 : (value < 0 ? -1 : 1);
065: }
066:
067: public Value negate() throws SQLException {
068: if (SysProperties.OVERFLOW_EXCEPTIONS) {
069: if (value == Long.MIN_VALUE) {
070: throw getOverflow();
071: }
072: }
073: return ValueLong.get(-value);
074: }
075:
076: private SQLException getOverflow() {
077: return Message.getSQLException(ErrorCode.OVERFLOW_FOR_TYPE_1,
078: DataType.getDataType(Value.LONG).name);
079: }
080:
081: public Value subtract(Value v) throws SQLException {
082: ValueLong other = (ValueLong) v;
083: if (SysProperties.OVERFLOW_EXCEPTIONS) {
084: int sv = value == 0 ? 0 : (value < 0 ? -1 : 1);
085: int so = other.value == 0 ? 0 : (other.value < 0 ? -1 : 1);
086: // if the operands have the same sign, then overflow can not occur
087: // if the second operand is 0, then overflow can not occur
088: if (sv == so || so == 0) {
089: return ValueLong.get(value - other.value);
090: }
091: // now, if the other value is Long.MIN_VALUE, it must be an overflow
092: // x - Long.MIN_VALUE overflows for x>=0
093: return add(other.negate());
094: }
095: return ValueLong.get(value - other.value);
096: }
097:
098: private boolean isInteger(long a) {
099: return a >= Integer.MIN_VALUE && a <= Integer.MAX_VALUE;
100: }
101:
102: public Value multiply(Value v) throws SQLException {
103: ValueLong other = (ValueLong) v;
104: if (SysProperties.OVERFLOW_EXCEPTIONS) {
105: long result = value * other.value;
106: if (value == 0 || value == 1 || other.value == 0
107: || other.value == 1) {
108: return ValueLong.get(result);
109: }
110: if (isInteger(value) && isInteger(other.value)) {
111: return ValueLong.get(result);
112: }
113: // just checking one case is not enough: Long.MIN_VALUE * -1
114: // probably this is correct but I'm not sure
115: // if(result / value == other.value && result / other.value == value) {
116: // return ValueLong.get(result);
117: //}
118: BigInteger bv = new BigInteger("" + value);
119: BigInteger bo = new BigInteger("" + other.value);
120: BigInteger br = bv.multiply(bo);
121: if (br.compareTo(MIN) < 0 || br.compareTo(MAX) > 0) {
122: throw getOverflow();
123: }
124: return ValueLong.get(br.longValue());
125: }
126: return ValueLong.get(value * other.value);
127: }
128:
129: public Value divide(Value v) throws SQLException {
130: ValueLong other = (ValueLong) v;
131: if (other.value == 0) {
132: throw Message.getSQLException(ErrorCode.DIVISION_BY_ZERO_1,
133: getSQL());
134: }
135: return ValueLong.get(value / other.value);
136: }
137:
138: public String getSQL() {
139: return getString();
140: }
141:
142: public int getType() {
143: return Value.LONG;
144: }
145:
146: public long getLong() {
147: return value;
148: }
149:
150: protected int compareSecure(Value o, CompareMode mode) {
151: ValueLong v = (ValueLong) o;
152: if (value == v.value) {
153: return 0;
154: }
155: return value > v.value ? 1 : -1;
156: }
157:
158: public String getString() {
159: return String.valueOf(value);
160: }
161:
162: public long getPrecision() {
163: return PRECISION;
164: }
165:
166: public int hashCode() {
167: return (int) (value ^ (value >> 32));
168: }
169:
170: public Object getObject() {
171: return ObjectUtils.getLong(value);
172: }
173:
174: public void set(PreparedStatement prep, int parameterIndex)
175: throws SQLException {
176: prep.setLong(parameterIndex, value);
177: }
178:
179: public static ValueLong get(long i) {
180: if (i >= 0 && i < STATIC_SIZE) {
181: return cache[(int) i];
182: }
183: return (ValueLong) Value.cache(new ValueLong(i));
184: }
185:
186: public int getDisplaySize() {
187: return DISPLAY_SIZE;
188: }
189:
190: public boolean equals(Object other) {
191: return other instanceof ValueLong
192: && value == ((ValueLong) other).value;
193: }
194:
195: }
|