DBNumber.java

/*
 * Copyright 2013 Gregory Graham.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nz.co.gregs.dbvolution.datatypes;

import nz.co.gregs.dbvolution.utility.comparators.NumberComparator;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import nz.co.gregs.dbvolution.databases.DBDatabase;
import nz.co.gregs.dbvolution.DBReport;
import nz.co.gregs.dbvolution.DBRow;
import nz.co.gregs.dbvolution.columns.NumberColumn;
import nz.co.gregs.dbvolution.databases.definitions.DBDefinition;
import nz.co.gregs.dbvolution.exceptions.IncorrectRowProviderInstanceSuppliedException;
import nz.co.gregs.dbvolution.expressions.IntegerExpression;
import nz.co.gregs.dbvolution.expressions.NumberExpression;
import nz.co.gregs.dbvolution.expressions.StringExpression;
import nz.co.gregs.dbvolution.results.NumberResult;
import nz.co.gregs.dbvolution.operators.DBPermittedRangeExclusiveOperator;
import nz.co.gregs.dbvolution.operators.DBPermittedRangeInclusiveOperator;
import nz.co.gregs.dbvolution.operators.DBPermittedRangeOperator;
import nz.co.gregs.dbvolution.operators.DBPermittedValuesOperator;
import nz.co.gregs.dbvolution.query.RowDefinition;
import nz.co.gregs.dbvolution.utility.StringCheck;

/**
 * Encapsulates database values that are Numbers.
 *
 * <p>
 * Use DBNumber when the column is a {@code NUMBER} or {@code NUMBER(x,y)}, that
 * is any integer or real datatype..
 *
 * <p>
 * Use {@link DBInteger} when the numbers do not have a decimal or fractional
 * part.
 *
 * <p>
 * Generally DBNumber is declared inside your DBRow sub-class as:
 * {@code @DBColumn public DBNumber myIntColumn = new DBNumber();}
 *
 * <p style="color: #F90;">Support DBvolution at
 * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
 *
 * @author Gregory Graham
 */
public class DBNumber extends QueryableDatatype<Number> implements NumberResult {

	private static final long serialVersionUID = 1;

	/**
	 * The default constructor for DBNumber.
	 *
	 * <p>
	 * Creates an unset undefined DBNumber object.
	 *
	 */
	public DBNumber() {
		super();
	}

	/**
	 * Creates a column expression with a number result from the expression
	 * provided.
	 *
	 * <p>
	 * Used in {@link DBReport}, and some {@link DBRow}, sub-classes to derive
	 * data from the database prior to retrieval.
	 *
	 * @param numberExpression	numberExpression
	 */
	public DBNumber(NumberExpression... numberExpression) {
		super(numberExpression);
	}

	/**
	 * Creates a new DBNumber with the value set to the number provided.
	 *
	 * @param aNumber	aNumber
	 */
	public DBNumber(Number aNumber) {
		super(aNumber);
	}

	/**
	 *
	 * @param aNumber	aNumber
	 */
	public DBNumber(Long aNumber) {
		super(aNumber);
	}

	public DBNumber(IntegerExpression integerExpression) {
		this(integerExpression.numberResult());
	}

	@Override
	public DBNumber copy() {
		return (DBNumber) super.copy();
	}

	/**
	 * Sets the value of this DBNumber to the value of the DBNumber provided.
	 *
	 * <p>
	 * This allows DBNumbers to be treated somewhat like normal numbers. However {@link #setValue(java.lang.Number)
	 * } may be more useful in normal usage.
	 *
	 * @param newLiteralValue	newLiteralValue
	 */
	public void setValue(DBNumber newLiteralValue) {
		setValue((newLiteralValue).getValue());
	}

	/**
	 * Set the value of this DBNumber to the Double, Long, Integer, or other
	 * number provided.
	 *
	 * <p>
	 * This is probably the method you want to use to set or change the value of
	 * this DBNumber. When creating a new row or updating an existing row use this
	 * method or {@link #setValue(nz.co.gregs.dbvolution.datatypes.DBNumber)} to
	 * correctly set the value.
	 *
	 * <p>
	 * Remember:</p>
	 *
	 * <ul>
	 * <li>Set the column to NULL using setValue((Number)null)</li>
	 * <li>Use {@link DBDatabase#insert(nz.co.gregs.dbvolution.DBRow...) } or {@link DBDatabase#update(nz.co.gregs.dbvolution.DBRow...)
	 * } to make the changes permanent.</li>
	 * </ul>
	 *
	 * @param newLiteralValue	newLiteralValue
	 */
	@Override
	public void setValue(Number newLiteralValue) {
		if (newLiteralValue == null) {
			super.setLiteralValue(null);
		} else {
			super.setLiteralValue(newLiteralValue.doubleValue());
		}
	}

	/**
	 * Set the value of this DBNumber to the Double, Long, Integer, or other
	 * number provided.
	 *
	 * <p>
	 * A convenience method the uses Double.parseDouble(String) to create a number
	 * from the string.
	 *
	 * <p>
	 * This is probably the method you want to use to set or change the value of
	 * this DBNumber. When creating a new row or updating an existing row use this
	 * method or {@link #setValue(nz.co.gregs.dbvolution.datatypes.DBNumber)} to
	 * correctly set the value.
	 *
	 * <p>
	 * Remember:</p>
	 *
	 * <ul>
	 * <li>Set the column to NULL using setValue((Number)null)</li>
	 * <li>Use {@link DBDatabase#insert(nz.co.gregs.dbvolution.DBRow...) } or {@link DBDatabase#update(nz.co.gregs.dbvolution.DBRow...)
	 * } to make the changes permanent.</li>
	 * </ul>
	 *
	 * @param newLiteralValue	newLiteralValue
	 */
	public void setValue(String newLiteralValue) {
		setValue(Double.valueOf(StringCheck.checkNotNullOrEmpty(newLiteralValue, null, null)));
	}

	/**
	 *
	 * <p style="color: #F90;">Support DBvolution at
	 * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
	 *
	 * @return the default database type as a string, may be gazumped by the
	 * DBDefinition
	 */
	@Override
	public String getSQLDatatype() {
		return "NUMERIC(" + getNumericPrecision() + "," + getNumericScale() + ")";
	}

	/**
	 * The number of decimal places supported by DBNumber.
	 *
	 * <p>
	 * Theoretically 16 decimals is the maximum accuracy of floating point
	 * numbers. given the max precision(28) of pre-2012 MS SQL Server, 16 decimals
	 * seems as accurate as is reasonable</p>
	 *
	 * @return 16
	 */
	public static int getNumericScale() {
		return 16;
	}

	/**
	 * The number of integer digits supported by DBNumber.
	 *
	 * <p>
	 * 28 is the maximum precision for MS SQL Server pre-2012, other databases
	 * seem not to be limited. 38 is the maximum for MSSQLServer 2012+</p>
	 *
	 * @return 28
	 */
	public static int getNumericPrecision() {
		return 28;
	}

	/**
	 *
	 * @param defn the DBDefinition to used in formatting the value
	 * @return the underlying number formatted for a SQL statement
	 */
	@Override
	public String formatValueForSQLStatement(DBDefinition defn) {
		if (isNull()) {
			return defn.getNull();
		}
		return defn.beginNumberValue() + getLiteralValue().toString() + defn.endNumberValue();
	}

	/**
	 * Gets the current literal value of this DBNumber, without any formatting.
	 *
	 * <p>
	 * The literal value is undefined (and {@code null}) if using an operator
	 * other than {@code equals}.
	 *
	 * <p style="color: #F90;">Support DBvolution at
	 * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
	 *
	 * @return the literal value, if defined, which may be null
	 */
	@Override
	public Number getValue() {
		return numberValue();
	}

	/**
	 * The current {@link #getValue()  literal value} of this DBNumber as a Number
	 *
	 * <p style="color: #F90;">Support DBvolution at
	 * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
	 *
	 * @return the number as the original number class
	 */
	public Number numberValue() {
		if (getLiteralValue() == null) {
			return null;
		} else if (getLiteralValue() instanceof Number) {
			return getLiteralValue().doubleValue();
		} else {
			return Double.valueOf(StringCheck.checkNotNullOrEmpty(getLiteralValue().toString(), null, null));
		}
	}

	/**
	 * The current {@link #getValue()  literal value} of this DBNumber as a Double
	 *
	 * <p style="color: #F90;">Support DBvolution at
	 * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
	 *
	 * @return the number as a Double
	 */
	@SuppressWarnings("deprecation")
	public Double doubleValue() {
		if (getLiteralValue() == null) {
			return null;
		} else {
			return getLiteralValue().doubleValue();
		}
	}

	/**
	 * The current {@link #getValue()  literal value} of this DBNumber as a Long
	 *
	 * <p style="color: #F90;">Support DBvolution at
	 * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
	 *
	 * @return the number as a Long
	 */
	@SuppressWarnings("deprecation")
	public Long longValue() {
		if (getLiteralValue() == null) {
			return null;
		} else {
			return getLiteralValue().longValue();
		}
	}

	/**
	 * The current {@link #getValue()  literal value} of this DBNumber as an
	 * Integer
	 *
	 * <p style="color: #F90;">Support DBvolution at
	 * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
	 *
	 * @return the number as an Integer
	 */
	@SuppressWarnings("deprecation")
	public Integer intValue() {
		if (getLiteralValue() == null) {
			return null;
		} else {
			return getLiteralValue().intValue();
		}
	}

	@Override
	public DBNumber getQueryableDatatypeForExpressionValue() {
		return new DBNumber();
	}

	@Override
	public boolean isAggregator() {
		return false;
	}

	@Override
	public Set<DBRow> getTablesInvolved() {
		return new HashSet<>();
	}

	/**
	 *
	 * reduces the rows to only the object, Set, List, Array, or vararg of objects
	 *
	 * @param permitted	permitted
	 */
	public void permittedValues(Number... permitted) {
		this.setOperator(new DBPermittedValuesOperator<Number>(permitted));
	}

	/**
	 *
	 * reduces the rows to only the object, Set, List, Array, or vararg of objects
	 *
	 * @param permitted	permitted
	 */
	public void permittedValues(Collection<Number> permitted) {
		this.setOperator(new DBPermittedValuesOperator<Number>(permitted));
	}

	/**
	 *
	 * reduces the rows to only the object, Set, List, Array, or vararg of objects
	 *
	 * @param permitted	permitted
	 */
	public void permittedValues(NumberResult... permitted) {
		this.setOperator(new DBPermittedValuesOperator<NumberResult>(permitted));
	}

	/**
	 *
	 * excludes the object, Set, List, Array, or vararg of objects
	 *
	 *
	 * @param excluded	excluded
	 */
	public void excludedValues(Number... excluded) {
		this.setOperator(new DBPermittedValuesOperator<Number>(excluded));
		negateOperator();
	}

	/**
	 *
	 * excludes the object, Set, List, Array, or vararg of objects
	 *
	 *
	 * @param excluded	excluded
	 */
	public void excludedValues(Collection<Number> excluded) {
		this.setOperator(new DBPermittedValuesOperator<Number>(excluded));
		negateOperator();
	}

	/**
	 *
	 * excludes the object, Set, List, Array, or vararg of objects
	 *
	 *
	 * @param excluded	excluded
	 */
	public void excludedValues(NumberResult... excluded) {
		this.setOperator(new DBPermittedValuesOperator<NumberResult>(excluded));
		negateOperator();
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified the lower-bound will be included in
	 * the search and the upper-bound excluded. I.e permittedRange(1,3) will
	 * return 1 and 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e permittedRange(1,null) will return 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e permittedRange(null, 5) will return 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void permittedRange(Number lowerBound, Number upperBound) {
		setOperator(new DBPermittedRangeOperator<Number>(lowerBound, upperBound));
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified the lower-bound will be included in
	 * the search and the upper-bound excluded. I.e permittedRange(1,3) will
	 * return 1 and 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e permittedRange(1,null) will return 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e permittedRange(null, 5) will return 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void permittedRange(NumberResult lowerBound, NumberResult upperBound) {
		setOperator(new DBPermittedRangeOperator<NumberResult>(lowerBound, upperBound));
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be included in the search. I.e permittedRangeInclusive(1,3) will
	 * return 1, 2, and 3.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e permittedRangeInclusive(1,null) will return 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e permittedRangeInclusive(null, 5) will return 5,4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void permittedRangeInclusive(Number lowerBound, Number upperBound) {
		setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be included in the search. I.e permittedRangeInclusive(1,3) will
	 * return 1, 2, and 3.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e permittedRangeInclusive(1,null) will return 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e permittedRangeInclusive(null, 5) will return 5,4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void permittedRangeInclusive(NumberResult lowerBound, NumberResult upperBound) {
		setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be excluded in the search. I.e permittedRangeExclusive(1,3) will
	 * return 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e permittedRangeExclusive(1,null) will return 2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e permittedRangeExclusive(null, 5) will return 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void permittedRangeExclusive(Number lowerBound, Number upperBound) {
		setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be excluded in the search. I.e permittedRangeExclusive(1,3) will
	 * return 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e permittedRangeExclusive(1,null) will return 2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e permittedRangeExclusive(null, 5) will return 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void permittedRangeExclusive(NumberResult lowerBound, NumberResult upperBound) {
		setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified the lower-bound will be within the
	 * range and the upper-bound outside. I.e excludedRange(1,3) will exclude 1
	 * and 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e excludedRange(1,null) will exclude 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e excludedRange(null, 5) will exclude 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void excludedRange(Number lowerBound, Number upperBound) {
		setOperator(new DBPermittedRangeOperator<Number>(lowerBound, upperBound));
		negateOperator();
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified the lower-bound will be within in
	 * the range and the upper-bound outside. I.e excludedRange(1,3) will exclude
	 * 1 and 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e excludedRange(1,null) will exclude 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e excludedRange(null, 5) will return 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void excludedRange(NumberResult lowerBound, NumberResult upperBound) {
		setOperator(new DBPermittedRangeOperator<NumberResult>(lowerBound, upperBound));
		negateOperator();
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be included in the range. I.e excludedRangeInclusive(1,3) will exclude
	 * 1, 2, and 3.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e excludedRangeInclusive(1,null) will exclude 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e excludedRangeInclusive(null, 5) will exclude 5,4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void excludedRangeInclusive(Number lowerBound, Number upperBound) {
		setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
		negateOperator();
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be included in the range. I.e excludedRangeInclusive(1,3) will exclude
	 * 1, 2, and 3.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e excludedRangeInclusive(1,null) will exclude 1,2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and inclusive.
	 * <br>
	 * I.e excludedRangeInclusive(null, 5) will exclude 5,4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void excludedRangeInclusive(NumberResult lowerBound, NumberResult upperBound) {
		setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
		negateOperator();
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be excluded in the range. I.e excludedRangeExclusive(1,3) will exclude
	 * 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e excludedRangeExclusive(1,null) will exclude 2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e excludedRangeExclusive(null, 5) will exclude 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void excludedRangeExclusive(Number lowerBound, Number upperBound) {
		setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
		negateOperator();
	}

	/**
	 * Performs searches based on a range.
	 *
	 * if both ends of the range are specified both the lower- and upper-bound
	 * will be excluded in the range. I.e excludedRangeExclusive(1,3) will exclude
	 * 2.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e excludedRangeExclusive(1,null) will exclude 2,3,4,5, etc.
	 *
	 * <p>
	 * if the upper-bound is null the range will be open ended and exclusive.
	 * <br>
	 * I.e excludedRangeExclusive(null, 5) will exclude 4,3,2,1, etc.
	 *
	 * @param lowerBound lowerBound
	 * @param upperBound upperBound
	 */
	public void excludedRangeExclusive(NumberResult lowerBound, NumberResult upperBound) {
		setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
		negateOperator();
	}

	@Override
	public boolean getIncludesNull() {
		return false;
	}

	@Override
	protected Number getFromResultSet(DBDefinition defn, ResultSet resultSet, String fullColumnName) throws SQLException {
		try {
			return resultSet.getBigDecimal(fullColumnName);
		} catch (SQLException ex) {
			try {
				return resultSet.getLong(fullColumnName);
			} catch (SQLException ex2) {
				return null;
			}
		}
	}

	@Override
	public StringExpression stringResult() {
		return NumberExpression.value(this).stringResult();
	}

	@Override
	protected void setValueFromStandardStringEncoding(String encodedValue) {
		setValue(Double.valueOf(StringCheck.checkNotNullOrEmpty(encodedValue, null, null)));
	}

	@Override
	public NumberColumn getColumn(RowDefinition row) throws IncorrectRowProviderInstanceSuppliedException {
		return new NumberColumn(row, this);
	}

	public void excludeNotNull() {
		this.permittedValues((Number) null);
	}

	public void excludeNull() {
		this.excludedValues((Number) null);
	}

	public void permitOnlyNull() {
		excludeNotNull();
	}

	public void permitOnlyNotNull() {
		excludeNull();
	}

	/**
	 * Set the value to be inserted when no value has been set, using
	 * {@link #setValue(java.lang.Object) setValue(...)}, for the QDT.
	 *
	 * <p>
	 * The value is only used during the initial insert and does not effect the
	 * definition of the column within the database.</p>
	 *
	 * <p>
	 * Care should be taken when using this as some "obvious" uses are better
	 * handled using the
	 * {@link #setDefaultInsertValue(nz.co.gregs.dbvolution.results.AnyResult) expression version}.
	 * In particular, setDefaultInsertValue(new Date()) is probably NOT what you
	 * want, setDefaultInsertValue(DateExpression.currentDate()) will produce a
	 * correct creation date value.</p>
	 *
	 * @param value the value to use during insertion when no particular value has
	 * been specified.
	 * @return This QDT
	 */
	@Override
	public synchronized DBNumber setDefaultInsertValue(Number value) {
		super.setDefaultInsertValue(value.longValue());
		return this;
	}

	/**
	 * Set the value to be inserted when no value has been set, using
	 * {@link #setValue(java.lang.Object) setValue(...)}, for the QDT.
	 *
	 * <p>
	 * The value is only used during the initial insert and does not effect the
	 * definition of the column within the database.</p>
	 *
	 * @param value the value to use during insertion when no particular value has
	 * been specified.
	 * @return This QDT
	 */
	public synchronized DBNumber setDefaultInsertValue(NumberResult value) {
		super.setDefaultInsertValue(value);
		return this;
	}

	/**
	 * Set the value to be used during an update when no value has been set, using
	 * {@link #setValue(java.lang.Object) setValue(...)}, for the QDT.
	 *
	 * <p>
	 * The value is only used during updates and does not effect the definition of
	 * the column within the database nor the initial value of the column.</p>
	 *
	 * <p>
	 * Care should be taken when using this as some "obvious" uses are better
	 * handled using the
	 * {@link #setDefaultUpdateValue(nz.co.gregs.dbvolution.results.AnyResult) expression version}.
	 * In particular, setDefaultUpdateValue(new Date()) is probably NOT what you
	 * want, setDefaultUpdateValue(DateExpression.currentDate()) will produce a
	 * correct update time value.</p>
	 *
	 * @param value the value to use during update when no particular value has
	 * been specified.
	 * @return This QDT
	 */
	@Override
	public synchronized DBNumber setDefaultUpdateValue(Number value) {
		super.setDefaultUpdateValue(value.longValue());
		return this;
	}

	/**
	 * Set the value to be used during an update when no value has been set, using
	 * {@link #setValue(java.lang.Object) setValue(...)}, for the QDT.
	 *
	 * <p>
	 * The value is only used during updates and does not effect the definition of
	 * the column within the database nor the initial value of the column.</p>
	 *
	 * @param value the value to use during update when no particular value has
	 * been specified.
	 * @return This QDT
	 */
	public synchronized DBNumber setDefaultUpdateValue(NumberResult value) {
		super.setDefaultUpdateValue(value);
		return this;
	}

	@Override
	public Comparator<Number> getComparator() {
		return new NumberComparator();
	}

}