[#661] Add support for bitwise operators

[#895] Add Field.power(Field<? extends Number>)
This commit is contained in:
Lukas Eder 2011-10-30 20:58:56 +00:00
parent de67521fb4
commit e0493dc775
8 changed files with 827 additions and 39 deletions

View File

@ -42,7 +42,9 @@ import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.DB2;
import static org.jooq.SQLDialect.SQLSERVER;
import static org.jooq.SQLDialect.SYBASE;
import static org.jooq.impl.Factory.cast;
import static org.jooq.impl.Factory.castNull;
@ -4792,7 +4794,7 @@ public abstract class jOOQAbstractTest<
}
@Test
public void testArithmeticExpressions() throws Exception {
public void testArithmeticOperations() throws Exception {
Field<Integer> f1 = val(1).add(2).add(3).div(2);
Field<Integer> f2 = val(10).div(5).add(val(3).sub(2));
Field<Integer> f3 = val(10).mod(3);
@ -4822,6 +4824,53 @@ public abstract class jOOQAbstractTest<
assertEquals(Integer.valueOf((1948 - 4) * -8), result.getValue(0, f5));
}
@Test
public void testBitwiseOperations() throws Exception {
switch (getDialect()) {
case DERBY:
case INGRES:
log.info("SKIPPING", "Tests for bitwise operations");
return;
}
Field<Integer> bitCount = val(3).bitCount();
// TODO [#896] This somehow doesn't work on some dialects
if (asList(ASE, DB2, SQLSERVER).contains(getDialect())) {
bitCount = val(2);
}
Record result =
create().select(
bitCount,
val(3).bitNot().bitNot(),
val(3).bitAnd(5),
val(3).bitOr(5),
val(3).bitXor(5),
val(3).bitNand(5).bitNot(),
val(3).bitNor(5).bitNot(),
val(3).bitXNor(5).bitNot(),
val(333).shl(3),
val(333).shr(3))
.fetchOne();
int index = 0;
assertEquals(2, result.getValue(index++));
assertEquals(~(~3), result.getValue(index++));
assertEquals(3 & 5, result.getValue(index++));
assertEquals(3 | 5, result.getValue(index++));
assertEquals(3 ^ 5, result.getValue(index++));
assertEquals(~(~(3 & 5)), result.getValue(index++));
assertEquals(~(~(3 | 5)), result.getValue(index++));
assertEquals(~(~(3 ^ 5)), result.getValue(index++));
assertEquals(333 << 3, result.getValue(index++));
assertEquals(333 >> 3, result.getValue(index++));
}
@Test
public void testAggregateFunctions() throws Exception {

View File

@ -252,7 +252,7 @@ public interface Field<T> extends NamedTypeProviderQueryPart<T>, AliasProvider<F
<Z> SortField<Z> sort(Map<T, Z> sortMap);
// ------------------------------------------------------------------------
// Arithmetic expressions
// Arithmetic operations
// ------------------------------------------------------------------------
/**
@ -335,6 +335,233 @@ public interface Field<T> extends NamedTypeProviderQueryPart<T>, AliasProvider<F
*/
Field<T> mod(Field<? extends Number> value);
// ------------------------------------------------------------------------
// Bitwise operations
// ------------------------------------------------------------------------
/**
* The MySQL <code>BIT_COUNT(field)</code> function, counting the number of
* bits that are set in this number.
* <p>
* This function is simulated in most other databases like this (for a
* TINYINT field): <code><pre>
* (my_field & 1) +
* (my_field & 2) >> 1 +
* (my_field & 4) >> 2 +
* (my_field & 8) >> 3 +
* (my_field & 16) >> 4 +
* ...
* (my_field & 128) >> 7
* </pre></code>
* <p>
* More efficient algorithms are very welcome
*/
Field<Integer> bitCount();
/**
* The bitwise not operator.
* <p>
* Most dialects natively support this using <code>~[this]</code>. jOOQ
* simulates this operator in some dialects using <code>-[this] - 1</code>
*/
Field<T> bitNot();
/**
* The bitwise and operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the and operation where available:
* <code><pre>[this] & [value]</pre></code>
* ... or the and function elsewhere:
* <code><pre>bitand([this], [value])</pre></code>
*/
Field<T> bitAnd(Number value);
/**
* The bitwise and operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the and operation where available:
* <code><pre>[this] & [value]</pre></code>
* ... or the and function elsewhere:
* <code><pre>bitand([this], [value])</pre></code>
*/
Field<T> bitAnd(Field<? extends Number> value);
/**
* The bitwise not and operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the not and operation where available:
* <code><pre>~([this] & [value])</pre></code>
* ... or the not and function elsewhere:
* <code><pre>bitnot(bitand([this], [value]))</pre></code>
*
* @see #bitNot()
*/
Field<T> bitNand(Number value);
/**
* The bitwise not and operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the not and operation where available:
* <code><pre>~([this] & [value])</pre></code>
* ... or the not and function elsewhere:
* <code><pre>bitnot(bitand([this], [value]))</pre></code>
*
* @see #bitNot()
*/
Field<T> bitNand(Field<? extends Number> value);
/**
* The bitwise or operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the or operation where available:
* <code><pre>[this] | [value]</pre></code>
* ... or the or function elsewhere:
* <code><pre>bitor([this], [value])</pre></code>
*/
Field<T> bitOr(Number value);
/**
* The bitwise or operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the or operation where available:
* <code><pre>[this] | [value]</pre></code>
* ... or the or function elsewhere:
* <code><pre>bitor([this], [value])</pre></code>
*/
Field<T> bitOr(Field<? extends Number> value);
/**
* The bitwise not or operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the not or operation where available:
* <code><pre>~([this] | [value])</pre></code>
* ... or the not or function elsewhere:
* <code><pre>bitnot(bitor([this], [value]))</pre></code>
*
* @see #bitNot()
*/
Field<T> bitNor(Number value);
/**
* The bitwise not or operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the not or operation where available:
* <code><pre>~([this] | [value])</pre></code>
* ... or the not or function elsewhere:
* <code><pre>bitnot(bitor([this], [value]))</pre></code>
*
* @see #bitNot()
*/
Field<T> bitNor(Field<? extends Number> value);
/**
* The bitwise xor operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the or operation where available:
* <code><pre>[this] ^ [value]</pre></code>
* ... or the xor function elsewhere:
* <code><pre>bitxor([this], [value])</pre></code>
*/
Field<T> bitXor(Number value);
/**
* The bitwise xor operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the or operation where available:
* <code><pre>[this] ^ [value]</pre></code>
* ... or the xor function elsewhere:
* <code><pre>bitxor([this], [value])</pre></code>
*/
Field<T> bitXor(Field<? extends Number> value);
/**
* The bitwise not xor operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the or operation where available:
* <code><pre>~([this] ^ [value])</pre></code>
* ... or the not xor function elsewhere:
* <code><pre>bitnot(bitxor([this], [value]))</pre></code>
*/
Field<T> bitXNor(Number value);
/**
* The bitwise not xor operator.
* <p>
* This is not supported by Derby, Ingres
* <p>
* This renders the or operation where available:
* <code><pre>~([this] ^ [value])</pre></code>
* ... or the not xor function elsewhere:
* <code><pre>bitnot(bitxor([this], [value]))</pre></code>
*/
Field<T> bitXNor(Field<? extends Number> value);
/**
* The bitwise left shift operator.
* <p>
* Some dialects natively support this using <code>[this] << [value]</code>.
* jOOQ simulates this operator in some dialects using
* <code>[this] * power(2, [value])</code>, where power might also be simulated.
*
* @see #power(Field)
*/
Field<T> shl(Number value);
/**
* The bitwise left shift operator.
* <p>
* Some dialects natively support this using <code>[this] << [value]</code>.
* jOOQ simulates this operator in some dialects using
* <code>[this] * power(2, [value])</code>, where power might also be simulated.
*
* @see #power(Field)
*/
Field<T> shl(Field<? extends Number> value);
/**
* The bitwise right shift operator.
* <p>
* Some dialects natively support this using <code>[this] >> [value]</code>.
* jOOQ simulates this operator in some dialects using
* <code>[this] / power(2, [value])</code>, where power might also be simulated.
*
* @see #power(Field)
*/
Field<T> shr(Number value);
/**
* The bitwise right shift operator.
* <p>
* Some dialects natively support this using <code>[this] >> [value]</code>.
* jOOQ simulates this operator in some dialects using
* <code>[this] / power(2, [value])</code>, where power might also be simulated.
*
* @see #power(Field)
*/
Field<T> shr(Field<? extends Number> value);
// ------------------------------------------------------------------------
// Mathematical functions created from this field
// ------------------------------------------------------------------------
@ -448,6 +675,16 @@ public interface Field<T> extends NamedTypeProviderQueryPart<T>, AliasProvider<F
*/
Field<BigDecimal> power(Number exponent);
/**
* Get the power(field, exponent) function
* <p>
* This renders the power function where available:
* <code><pre>power([this], [exponent])</pre></code> ... or simulates it
* elsewhere using ln and exp:
* <code><pre>exp(ln([this]) * [exponent])</pre></code>
*/
Field<BigDecimal> power(Field<? extends Number> exponent);
/**
* Get the arc cosine(field) function
* <p>

View File

@ -202,12 +202,12 @@ abstract class AbstractField<T> extends AbstractNamedTypeProviderQueryPart<T> im
}
// ------------------------------------------------------------------------
// Arithmetic expressions
// Arithmetic operations
// ------------------------------------------------------------------------
@Override
public final Field<T> neg() {
return new Neg<T>(this);
return new Neg<T>(this, ExpressionOperator.SUBTRACT);
}
@Override
@ -286,6 +286,100 @@ abstract class AbstractField<T> extends AbstractNamedTypeProviderQueryPart<T> im
return new Mod<T>(this, value);
}
// ------------------------------------------------------------------------
// Bitwise operations
// ------------------------------------------------------------------------
@Override
public final Field<Integer> bitCount() {
return new BitCount(this);
}
@Override
public final Field<T> bitNot() {
return new Neg<T>(this, ExpressionOperator.BIT_NOT);
}
@Override
public final Field<T> bitAnd(Number value) {
return bitAnd(val(value));
}
@Override
public final Field<T> bitAnd(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.BIT_AND, this, value);
}
@Override
public final Field<T> bitNand(Number value) {
return bitNand(val(value));
}
@Override
public final Field<T> bitNand(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.BIT_NAND, this, value);
}
@Override
public final Field<T> bitOr(Number value) {
return bitOr(val(value));
}
@Override
public final Field<T> bitOr(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.BIT_OR, this, value);
}
@Override
public final Field<T> bitNor(Number value) {
return bitNor(val(value));
}
@Override
public final Field<T> bitNor(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.BIT_NOR, this, value);
}
@Override
public final Field<T> bitXor(Number value) {
return bitXor(val(value));
}
@Override
public final Field<T> bitXor(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.BIT_XOR, this, value);
}
@Override
public final Field<T> bitXNor(Number value) {
return bitXNor(val(value));
}
@Override
public final Field<T> bitXNor(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.BIT_XNOR, this, value);
}
@Override
public final Field<T> shl(Number value) {
return shl(val(value));
}
@Override
public final Field<T> shl(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.SHL, this, value);
}
@Override
public final Field<T> shr(Number value) {
return shr(val(value));
}
@Override
public final Field<T> shr(Field<? extends Number> value) {
return new Expression<T>(ExpressionOperator.SHR, this, value);
}
// ------------------------------------------------------------------------
// Window functions created from this field
// ------------------------------------------------------------------------
@ -528,6 +622,11 @@ abstract class AbstractField<T> extends AbstractNamedTypeProviderQueryPart<T> im
@Override
public final Field<BigDecimal> power(Number exponent) {
return power(val(exponent));
}
@Override
public Field<BigDecimal> power(Field<? extends Number> exponent) {
return new Power(this, exponent);
}

View File

@ -0,0 +1,220 @@
/**
* Copyright (c) 2009-2011, Lukas Eder, lukas.eder@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.impl;
import static org.jooq.impl.Factory.function;
import static org.jooq.impl.Factory.literal;
import org.jooq.Configuration;
import org.jooq.Field;
/**
* @author Lukas Eder
*/
class BitCount extends AbstractFunction<Integer> {
/**
* Generated UID
*/
private static final long serialVersionUID = 7624782102883057433L;
BitCount(Field<?> field) {
super("bit_count", SQLDataType.INTEGER, field);
}
@Override
final Field<Integer> getFunction0(Configuration configuration) {
final Field<?> field = getArguments()[0];
switch (configuration.getDialect()) {
case MYSQL:
return function("bit_count", getDataType(), getArguments());
// Warning, some severe madness lies ahead. Better solutions very welcome!
// See also http://stackoverflow.com/questions/7946349/how-to-simulate-the-mysql-bit-count-function-in-sybase-sql-anywhere
default: {
if (field.getType() == Byte.class) {
@SuppressWarnings("unchecked")
Field<Byte> f = (Field<Byte>) field;
byte i = 0;
return f.bitAnd(literal((byte) 0x01)).add(
f.bitAnd(literal((byte) 0x02)).shr(literal(++i))).add(
f.bitAnd(literal((byte) 0x04)).shr(literal(++i))).add(
f.bitAnd(literal((byte) 0x08)).shr(literal(++i))).add(
f.bitAnd(literal((byte) 0x10)).shr(literal(++i))).add(
f.bitAnd(literal((byte) 0x20)).shr(literal(++i))).add(
f.bitAnd(literal((byte) 0x40)).shr(literal(++i))).add(
f.bitAnd(literal((byte) 0x80)).shr(literal(++i))).cast(Integer.class);
}
else if (field.getType() == Short.class) {
@SuppressWarnings("unchecked")
Field<Short> f = (Field<Short>) field;
short i = 0;
return f.bitAnd(literal((short) 0x0001)).add(
f.bitAnd(literal((short) 0x0002)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0004)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0008)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0010)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0020)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0040)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0080)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0100)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0200)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0400)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x0800)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x1000)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x2000)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x4000)).shr(literal(++i))).add(
f.bitAnd(literal((short) 0x8000)).shr(literal(++i))).cast(Integer.class);
}
else if (field.getType() == Integer.class) {
@SuppressWarnings("unchecked")
Field<Integer> f = (Field<Integer>) field;
int i = 0;
return f.bitAnd(literal(0x00000001)).add(
f.bitAnd(literal(0x00000002)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000004)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000008)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000010)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000020)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000040)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000080)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000100)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000200)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000400)).shr(literal(++i))).add(
f.bitAnd(literal(0x00000800)).shr(literal(++i))).add(
f.bitAnd(literal(0x00001000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00002000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00004000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00008000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00010000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00020000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00040000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00080000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00100000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00200000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00400000)).shr(literal(++i))).add(
f.bitAnd(literal(0x00800000)).shr(literal(++i))).add(
f.bitAnd(literal(0x01000000)).shr(literal(++i))).add(
f.bitAnd(literal(0x02000000)).shr(literal(++i))).add(
f.bitAnd(literal(0x04000000)).shr(literal(++i))).add(
f.bitAnd(literal(0x08000000)).shr(literal(++i))).add(
f.bitAnd(literal(0x10000000)).shr(literal(++i))).add(
f.bitAnd(literal(0x20000000)).shr(literal(++i))).add(
f.bitAnd(literal(0x40000000)).shr(literal(++i))).add(
f.bitAnd(literal(0x80000000)).shr(literal(++i)));
}
else if (field.getType() == Long.class) {
@SuppressWarnings("unchecked")
Field<Long> f = (Field<Long>) field;
long i = 0;
return f.bitAnd(literal(0x0000000000000001L)).add(
f.bitAnd(literal(0x0000000000000002L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000004L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000008L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000010L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000020L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000040L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000080L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000100L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000200L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000400L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000000800L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000001000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000002000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000004000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000008000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000010000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000020000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000040000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000080000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000100000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000200000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000400000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000000800000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000001000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000002000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000004000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000008000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000010000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000020000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000040000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000080000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000100000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000200000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000400000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000000800000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000001000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000002000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000004000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000008000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000010000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000020000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000040000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000080000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000100000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000200000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000400000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0000800000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0001000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0002000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0004000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0008000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0010000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0020000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0040000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0080000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0100000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0200000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0400000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x0800000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x1000000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x2000000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x4000000000000000L)).shr(literal(++i))).add(
f.bitAnd(literal(0x8000000000000000L)).shr(literal(++i))).cast(Integer.class);
}
else {
// Currently not supported
return function("bit_count", getDataType(), getArguments());
}
}
}
}
}

View File

@ -35,17 +35,41 @@
*/
package org.jooq.impl;
import static java.util.Arrays.asList;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.DB2;
import static org.jooq.SQLDialect.H2;
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.INGRES;
import static org.jooq.SQLDialect.ORACLE;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.SQLDialect.SQLSERVER;
import static org.jooq.SQLDialect.SYBASE;
import static org.jooq.impl.ExpressionOperator.BIT_AND;
import static org.jooq.impl.ExpressionOperator.BIT_NAND;
import static org.jooq.impl.ExpressionOperator.BIT_NOR;
import static org.jooq.impl.ExpressionOperator.BIT_OR;
import static org.jooq.impl.ExpressionOperator.BIT_XNOR;
import static org.jooq.impl.ExpressionOperator.BIT_XOR;
import static org.jooq.impl.ExpressionOperator.SHL;
import static org.jooq.impl.ExpressionOperator.SHR;
import static org.jooq.impl.Factory.function;
import static org.jooq.impl.Factory.literal;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.jooq.Attachable;
import org.jooq.BindContext;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.QueryPart;
import org.jooq.RenderContext;
import org.jooq.SQLDialect;
class Expression<T> extends AbstractField<T> {
class Expression<T> extends AbstractFunction<T> {
/**
* Generated UID
@ -56,7 +80,7 @@ class Expression<T> extends AbstractField<T> {
private final ExpressionOperator operator;
Expression(ExpressionOperator operator, Field<T> lhs, Field<?>... rhs) {
super(operator.toSQL(), lhs.getDataType());
super(operator.toSQL(), lhs.getDataType(), JooqUtil.combine(lhs, rhs));
this.operator = operator;
this.lhs = lhs;
@ -64,11 +88,6 @@ class Expression<T> extends AbstractField<T> {
this.rhs.addAll(Arrays.asList(rhs));
}
@Override
public final List<Attachable> getAttachables() {
return getAttachables(lhs, rhs);
}
@Override
public final Field<T> add(Field<? extends Number> value) {
if (operator == ExpressionOperator.ADD) {
@ -90,27 +109,117 @@ class Expression<T> extends AbstractField<T> {
}
@Override
public final void toSQL(RenderContext context) {
context.sql("(");
context.sql(lhs);
final Field<T> getFunction0(Configuration configuration) {
SQLDialect dialect = configuration.getDialect();
for (Field<?> field : rhs) {
context.sql(" ")
.sql(operator.toSQL())
.sql(" ")
.sql(field);
// DB2, H2 and HSQLDB know functions, instead of operators
if (BIT_AND == operator && asList(DB2, H2, HSQLDB, ORACLE).contains(dialect)) {
return function("bitand", getDataType(), getArguments());
}
else if (BIT_XOR == operator && asList(DB2, H2, HSQLDB).contains(dialect)) {
return function("bitxor", getDataType(), getArguments());
}
else if (BIT_OR == operator && asList(DB2, H2, HSQLDB).contains(dialect)) {
return function("bitor", getDataType(), getArguments());
}
context.sql(")");
// Oracle has to simulate or/xor
else if (BIT_OR == operator && ORACLE == dialect) {
return lhs.sub(lhsAsNumber().bitAnd(rhsAsNumber())).add(rhsAsNumber());
}
// ~(a & b) & (a | b)
else if (BIT_XOR == operator && asList(ORACLE, SQLITE).contains(dialect)) {
return lhs.bitAnd(rhsAsNumber()).bitNot().bitAnd(
lhsAsNumber().bitOr(rhsAsNumber()));
}
// Many dialects don't support shifts. Use multiplication/division instead
else if (SHL == operator && asList(ASE, DB2, H2, HSQLDB, INGRES, ORACLE, SQLSERVER, SYBASE).contains(dialect)) {
return lhs.mul(literal(2).power(rhsAsNumber()));
}
else if (SHR == operator && asList(ASE, DB2, H2, HSQLDB, INGRES, ORACLE, SQLSERVER, SYBASE).contains(dialect)) {
return lhs.div(literal(2).power(rhsAsNumber()));
}
// These operators are not supported in any dialect
else if (BIT_NAND == operator) {
return lhs.bitAnd(rhsAsNumber()).bitNot();
}
else if (BIT_NOR == operator) {
return lhs.bitOr(rhsAsNumber()).bitNot();
}
else if (BIT_XNOR == operator) {
return lhs.bitXor(rhsAsNumber()).bitNot();
}
// Use the default operator expression
else {
return new DefaultExpression();
}
}
@Override
public final void bind(BindContext context) throws SQLException {
context.bind(lhs).bind((QueryPart) rhs);
/**
* In some expressions, the lhs can be safely assumed to be a single number
*/
@SuppressWarnings("unchecked")
private final Field<? extends Number> lhsAsNumber() {
return (Field<? extends Number>) lhs;
}
@Override
public final boolean isNullLiteral() {
return false;
/**
* In some expressions, the rhs can be safely assumed to be a single number
*/
@SuppressWarnings("unchecked")
private final Field<? extends Number> rhsAsNumber() {
return (Field<? extends Number>) rhs.get(0);
}
private class DefaultExpression extends AbstractField<T> {
/**
* Generated UID
*/
private static final long serialVersionUID = -5105004317793995419L;
private DefaultExpression() {
super(operator.toSQL(), lhs.getDataType());
}
@Override
public final List<Attachable> getAttachables() {
return Expression.this.getAttachables();
}
@Override
public final void toSQL(RenderContext context) {
String op = operator.toSQL();
if (operator == BIT_XOR && context.getDialect() == POSTGRES) {
op = "#";
}
context.sql("(");
context.sql(lhs);
for (Field<?> field : rhs) {
context.sql(" ")
.sql(op)
.sql(" ")
.sql(field);
}
context.sql(")");
}
@Override
public final void bind(BindContext context) throws SQLException {
context.bind(lhs).bind((QueryPart) rhs);
}
@Override
public final boolean isNullLiteral() {
return false;
}
}
}

View File

@ -70,7 +70,54 @@ enum ExpressionOperator {
/**
* Modulo
*/
MODULO("%");
MODULO("%"),
/**
* Bitwise not
*/
BIT_NOT("~"),
/**
* Bitwise and
*/
BIT_AND("&"),
/**
* Bitwise or
*/
BIT_OR("|"),
/**
* Bitwise xor
*/
BIT_XOR("^"),
/**
* Bitwise and
*/
BIT_NAND("~&"),
/**
* Bitwise or
*/
BIT_NOR("~|"),
/**
* Bitwise xor
*/
BIT_XNOR("~^"),
/**
* Bitwise shift left
*/
SHL("<<"),
/**
* Bitwise shift right
*/
SHR(">>"),
;
private final String sql;

View File

@ -35,6 +35,14 @@
*/
package org.jooq.impl;
import static java.util.Arrays.asList;
import static org.jooq.SQLDialect.DB2;
import static org.jooq.SQLDialect.H2;
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.INGRES;
import static org.jooq.SQLDialect.ORACLE;
import static org.jooq.impl.ExpressionOperator.BIT_NOT;
import java.sql.SQLException;
import java.util.List;
@ -42,6 +50,7 @@ import org.jooq.Attachable;
import org.jooq.BindContext;
import org.jooq.Field;
import org.jooq.RenderContext;
import org.jooq.SQLDialect;
/**
* @author Lukas Eder
@ -51,13 +60,15 @@ class Neg<T> extends AbstractField<T> {
/**
* Generated UID
*/
private static final long serialVersionUID = 7624782102883057433L;
private static final long serialVersionUID = 7624782102883057433L;
private final Field<T> field;
private final ExpressionOperator operator;
private final Field<T> field;
Neg(Field<T> field) {
super("-" + field.getName(), field.getDataType());
Neg(Field<T> field, ExpressionOperator operator) {
super(operator.toSQL() + field.getName(), field.getDataType());
this.operator = operator;
this.field = field;
}
@ -68,7 +79,24 @@ class Neg<T> extends AbstractField<T> {
@Override
public final void toSQL(RenderContext context) {
context.sql("-").sql(field);
SQLDialect dialect = context.getDialect();
if (operator == BIT_NOT && asList(H2, HSQLDB, INGRES, ORACLE).contains(dialect)) {
context.sql("(0 -")
.sql(field)
.sql(" - 1)");
}
else if (operator == BIT_NOT && dialect == DB2) {
context.sql("bitnot(")
.sql(field)
.sql(")");
}
else {
context.sql(operator.toSQL())
.sql("(")
.sql(field)
.sql(")");
}
}
@Override

View File

@ -36,7 +36,6 @@
package org.jooq.impl;
import static org.jooq.impl.Factory.function;
import static org.jooq.impl.Factory.literal;
import java.math.BigDecimal;
@ -53,11 +52,11 @@ class Power extends AbstractFunction<BigDecimal> {
*/
private static final long serialVersionUID = -7273879239726265322L;
private final Field<?> arg1;
private final Number arg2;
private final Field<?> arg1;
private final Field<? extends Number> arg2;
Power(Field<?> arg1, Number arg2) {
super("ceil", SQLDataType.NUMERIC, arg1);
Power(Field<?> arg1, Field<? extends Number> arg2) {
super("ceil", SQLDataType.NUMERIC, arg1, arg2);
this.arg1 = arg1;
this.arg2 = arg2;
@ -68,10 +67,10 @@ class Power extends AbstractFunction<BigDecimal> {
switch (configuration.getDialect()) {
case DERBY:
case SQLITE:
return arg1.ln().mul(literal(arg2)).exp();
return arg1.ln().mul(arg2).exp();
default:
return function("power", SQLDataType.NUMERIC, arg1, literal(arg2));
return function("power", SQLDataType.NUMERIC, getArguments());
}
}
}