Skip to content

Commit 99e8779

Browse files
author
xiaojun
committed
Add LEFTSHIFT function and rename << operator to BIT_LEFT_SHIFT for consistency
1 parent fbcce06 commit 99e8779

File tree

7 files changed

+350
-244
lines changed

7 files changed

+350
-244
lines changed

core/src/main/codegen/templates/Parser.jj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7968,7 +7968,7 @@ SqlBinaryOperator BinaryRowOperator() :
79687968
{
79697969
// <IN> is handled as a special case
79707970
<EQ> { return SqlStdOperatorTable.EQUALS; }
7971-
| <LEFTSHIFT> { return SqlStdOperatorTable.LEFT_SHIFT; }
7971+
| <LEFTSHIFT> { return SqlStdOperatorTable.BIT_LEFT_SHIFT; }
79727972
| <GT> { return SqlStdOperatorTable.GREATER_THAN; }
79737973
| <LT> { return SqlStdOperatorTable.LESS_THAN; }
79747974
| <LE> { return SqlStdOperatorTable.LESS_THAN_OR_EQUAL; }

core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@
373373
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BITXOR;
374374
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BITXOR_OPERATOR;
375375
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BIT_AND;
376+
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BIT_LEFT_SHIFT;
376377
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BIT_OR;
377378
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BIT_XOR;
378379
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CARDINALITY;
@@ -458,7 +459,7 @@
458459
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LAST_DAY;
459460
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LAST_VALUE;
460461
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LEAD;
461-
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LEFT_SHIFT;
462+
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LEFTSHIFT;
462463
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LESS_THAN;
463464
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LESS_THAN_OR_EQUAL;
464465
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.LIKE;
@@ -745,8 +746,6 @@ void populate1() {
745746
NullPolicy.STRICT);
746747
defineMethod(BITNOT, BuiltInMethod.BIT_NOT.method,
747748
NullPolicy.STRICT);
748-
defineMethod(LEFT_SHIFT, BuiltInMethod.LEFT_SHIFT.method,
749-
NullPolicy.STRICT);
750749
define(CONCAT, new ConcatImplementor());
751750
defineMethod(CONCAT_FUNCTION, BuiltInMethod.MULTI_STRING_CONCAT.method,
752751
NullPolicy.STRICT);
@@ -899,9 +898,8 @@ void populate1() {
899898
defineMethod(VARIANTNULL, BuiltInMethod.VARIANTNULL.method, NullPolicy.STRICT);
900899

901900
// shift
902-
defineMethod(LEFT_SHIFT,
903-
BuiltInMethod.LEFT_SHIFT.method, NullPolicy.STRICT);
904-
901+
defineMethod(LEFTSHIFT, BuiltInMethod.LEFT_SHIFT.method, NullPolicy.STRICT);
902+
defineMethod(BIT_LEFT_SHIFT, BuiltInMethod.LEFT_SHIFT.method, NullPolicy.STRICT);
905903
define(SAFE_ADD,
906904
new SafeArithmeticImplementor(BuiltInMethod.SAFE_ADD.method));
907905
define(SAFE_DIVIDE,

core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java

Lines changed: 137 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -3419,134 +3419,6 @@ public static ByteString bitNot(ByteString b) {
34193419
return new ByteString(result);
34203420
}
34213421

3422-
/**
3423-
* Validates shift count following modern database standards.
3424-
*/
3425-
private static void validateShiftCount(long shift) {
3426-
if (shift < 0) {
3427-
throw new IllegalArgumentException(
3428-
"Invalid shift parameter: " + shift);
3429-
}
3430-
}
3431-
3432-
/**
3433-
* Performs bitwise left shift on two integers.
3434-
* Equivalent to: {@code (long)x << y}.
3435-
* Returns 0 if shift {@code >= 64} (following BigQuery behavior).
3436-
*
3437-
* @throws IllegalArgumentException if {@code y} is negative.
3438-
*/
3439-
public static Long leftShift(int x, int y) {
3440-
validateShiftCount(y);
3441-
3442-
if (y >= 64) {
3443-
return 0L; // BigQuery behavior for large shifts
3444-
}
3445-
3446-
return (long) x << y;
3447-
}
3448-
3449-
/**
3450-
* Performs bitwise left shift on a long integer.
3451-
* Returns {@code x << y}.
3452-
* Returns 0 if shift {@code >= 64} (following BigQuery behavior).
3453-
*
3454-
* @throws IllegalArgumentException if {@code y} is negative.
3455-
*/
3456-
public static Long leftShift(long x, int y) {
3457-
validateShiftCount(y);
3458-
3459-
if (y >= 64) {
3460-
return 0L; // BigQuery behavior for large shifts
3461-
}
3462-
3463-
return x << y;
3464-
}
3465-
3466-
/**
3467-
* Performs bitwise left shift with long shift amount.
3468-
* Returns {@code x << y}.
3469-
* Returns 0 if shift {@code >= 64} (following BigQuery behavior).
3470-
*
3471-
* @throws IllegalArgumentException if {@code y} is negative.
3472-
*/
3473-
public static Long leftShift(int x, long y) {
3474-
validateShiftCount(y);
3475-
3476-
if (y >= 64) {
3477-
return 0L; // BigQuery behavior for large shifts
3478-
}
3479-
3480-
return (long) x << (int) y; // Safe cast since y < 64
3481-
}
3482-
3483-
/**
3484-
* Performs bitwise left shift on binary data.
3485-
* Shifts the entire byte array as a unit, following BigQuery BYTES semantics.
3486-
*
3487-
* @param bytes the binary input as ByteString
3488-
* @param y the shift amount (number of bit positions)
3489-
* @return new ByteString with shifted bits, or {@code null} if input is null
3490-
* @throws IllegalArgumentException if {@code y} is negative
3491-
*/
3492-
public static ByteString leftShift(ByteString bytes, int y) {
3493-
3494-
// Convert ByteString to byte array
3495-
byte[] byteArray = bytes.getBytes();
3496-
3497-
// Use the existing leftShift implementation
3498-
byte[] result = leftShift(byteArray, y);
3499-
3500-
// Convert back to ByteString
3501-
return new ByteString(result);
3502-
}
3503-
3504-
/**
3505-
* Performs bitwise left shift on binary data.
3506-
* Shifts the entire byte array as a unit, following BigQuery BYTES semantics.
3507-
*
3508-
* @param bytes the binary input
3509-
* @param y the shift amount (number of bit positions)
3510-
* @return new byte array with shifted bits, or {@code null} if input is null
3511-
* @throws IllegalArgumentException if {@code y} is negative
3512-
*/
3513-
public static byte[] leftShift(byte[] bytes, int y) {
3514-
validateShiftCount(y);
3515-
3516-
if (y == 0) {
3517-
return bytes.clone();
3518-
}
3519-
3520-
if (y >= bytes.length * 8) {
3521-
// All bits shifted out, return zero-filled array
3522-
return new byte[bytes.length];
3523-
}
3524-
3525-
byte[] result = new byte[bytes.length];
3526-
int byteShift = y / 8; // Number of whole bytes to shift
3527-
int bitShift = y % 8; // Remaining bit shift within bytes
3528-
3529-
if (bitShift == 0) {
3530-
// Simple byte-aligned shift
3531-
System.arraycopy(bytes, 0, result, byteShift, bytes.length - byteShift);
3532-
} else {
3533-
// Bit-level shifting required
3534-
int carry = 0;
3535-
for (int i = bytes.length - 1 - byteShift; i >= 0; i--) {
3536-
int current = (bytes[i] & 0xFF) << bitShift;
3537-
result[i + byteShift] = (byte) ((current | carry) & 0xFF);
3538-
carry = (current >> 8) & 0xFF;
3539-
}
3540-
// Handle the final carry if there's space
3541-
if (byteShift > 0) {
3542-
result[byteShift - 1] = (byte) carry;
3543-
}
3544-
}
3545-
3546-
return result;
3547-
}
3548-
3549-
35503422
/**
35513423
* Bitwise function <code>BITXOR</code> applied to {@link Long} values.
35523424
* Returns {@code null} if any operand is null.
@@ -3634,6 +3506,143 @@ private static ByteString binaryOperator(
36343506
return new ByteString(result);
36353507
}
36363508

3509+
/**
3510+
* Performs bitwise shift on two integers. Equivalent to: {@code x << (y % 32)} if y >= 0, or
3511+
* {@code x >>> (-y % 32)} if y < 0.
3512+
*/
3513+
public static int leftShift(int x, int y) {
3514+
int shift = Math.abs(y % 32);
3515+
return y >= 0 ? x << shift : x >>> shift;
3516+
}
3517+
3518+
/**
3519+
* Performs bitwise shift on a long. Equivalent to: {@code x << (y % 64)} if y >= 0, or
3520+
* {@code x >>> (-y % 64)} if y < 0.
3521+
*/
3522+
public static long leftShift(long x, int y) {
3523+
int shift = Math.abs(y % 64);
3524+
return y >= 0 ? x << shift : x >>> shift;
3525+
}
3526+
3527+
/**
3528+
* Performs bitwise shift with long shift amount. Note: input x is int, so shift mod 32 is used.
3529+
* Returns long to prevent overflow.
3530+
*/
3531+
public static long leftShift(int x, long y) {
3532+
int shift = (int) Math.abs(y % 32);
3533+
return y >= 0 ? (long) x << shift : (long) x >>> shift;
3534+
}
3535+
3536+
/**
3537+
* Performs bitwise shift on ByteString input. Returns a new ByteString with shifted bits. If y >=
3538+
* 0: left shift; if y < 0: logical right shift.
3539+
*/
3540+
public static ByteString leftShift(ByteString bytes, int y) {
3541+
byte[] result = leftShift(bytes.getBytes(), y);
3542+
return new ByteString(result);
3543+
}
3544+
3545+
/**
3546+
* Performs bitwise shift on byte array. If y >= 0: left shift; if y < 0: logical right shift.
3547+
* Shift amount is modulo 32 bits.
3548+
*/
3549+
public static byte[] leftShift(byte[] bytes, int y) {
3550+
int shift = Math.abs(y % 32);
3551+
3552+
if (shift == 0) {
3553+
return bytes.clone();
3554+
}
3555+
3556+
byte[] result = new byte[bytes.length];
3557+
3558+
if (y >= 0) {
3559+
// Left shift
3560+
int byteShift = shift / 8;
3561+
int bitShift = shift % 8;
3562+
3563+
if (shift >= bytes.length * 8) {
3564+
return new byte[bytes.length];
3565+
}
3566+
3567+
if (bitShift == 0) {
3568+
System.arraycopy(bytes, 0, result, byteShift, bytes.length - byteShift);
3569+
} else {
3570+
int carry = 0;
3571+
for (int i = bytes.length - 1 - byteShift; i >= 0; i--) {
3572+
int current = (bytes[i] & 0xFF) << bitShift;
3573+
result[i + byteShift] = (byte) ((current | carry) & 0xFF);
3574+
carry = (current >> 8) & 0xFF;
3575+
}
3576+
if (byteShift > 0) {
3577+
result[byteShift - 1] = (byte) carry;
3578+
}
3579+
}
3580+
3581+
} else {
3582+
// Logical right shift
3583+
int byteShift = shift / 8;
3584+
int bitShift = shift % 8;
3585+
3586+
if (shift >= bytes.length * 8) {
3587+
return new byte[bytes.length];
3588+
}
3589+
3590+
if (bitShift == 0) {
3591+
System.arraycopy(bytes, byteShift, result, 0, bytes.length - byteShift);
3592+
} else {
3593+
int carry = 0;
3594+
for (int i = byteShift; i < bytes.length; i++) {
3595+
int current = (bytes[i] & 0xFF) >>> bitShift;
3596+
result[i - byteShift] = (byte) ((current | carry) & 0xFF);
3597+
carry = (bytes[i] & ((1 << bitShift) - 1)) << (8 - bitShift);
3598+
}
3599+
}
3600+
}
3601+
return result;
3602+
}
3603+
3604+
/**
3605+
* PostgreSQL-style bitwise shift for {@link UByte}. Returns {@code null} if any operand is null.
3606+
*/
3607+
public static UByte leftShift(UByte x, int y) {
3608+
int shift = Math.abs(y % 8);
3609+
return y >= 0
3610+
? UByte.valueOf(x.byteValue() << shift)
3611+
: UByte.valueOf(x.byteValue() >>> shift);
3612+
}
3613+
3614+
/**
3615+
* PostgreSQL-style bitwise shift for {@link UShort}. Returns {@code null} if any operand is
3616+
* null.
3617+
*/
3618+
public static UShort leftShift(UShort x, int y) {
3619+
int shift = Math.abs(y % 16);
3620+
return y >= 0
3621+
? UShort.valueOf(x.shortValue() << shift)
3622+
: UShort.valueOf(x.shortValue() >>> shift);
3623+
}
3624+
3625+
/**
3626+
* PostgreSQL-style bitwise shift for {@link UInteger}. Returns {@code null} if any operand is
3627+
* null.
3628+
*/
3629+
public static UInteger leftShift(UInteger x, int y) {
3630+
int shift = Math.abs((int) (y % 32));
3631+
return y >= 0
3632+
? UInteger.valueOf(x.longValue() << shift)
3633+
: UInteger.valueOf(x.longValue() >>> shift);
3634+
}
3635+
3636+
/**
3637+
* PostgreSQL-style bitwise shift for {@link ULong}. Returns {@code null} if any operand is null.
3638+
*/
3639+
public static ULong leftShift(ULong x, int y) {
3640+
int shift = Math.abs((int) (y % 64));
3641+
return y >= 0
3642+
? ULong.valueOf(x.longValue() << shift)
3643+
: ULong.valueOf(x.longValue() >>> shift);
3644+
}
3645+
36373646
// EXP
36383647

36393648
/** SQL <code>EXP</code> operator applied to double values. */

core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.apache.calcite.sql.fun;
1818

1919
import org.apache.calcite.avatica.util.TimeUnit;
20-
import org.apache.calcite.rel.type.RelDataType;
2120
import org.apache.calcite.sql.SqlAggFunction;
2221
import org.apache.calcite.sql.SqlAsOperator;
2322
import org.apache.calcite.sql.SqlBasicCall;
@@ -67,8 +66,6 @@
6766
import org.apache.calcite.sql.type.SqlReturnTypeInference;
6867
import org.apache.calcite.sql.type.SqlTypeFamily;
6968
import org.apache.calcite.sql.type.SqlTypeName;
70-
import org.apache.calcite.sql.type.SqlTypeTransforms;
71-
import org.apache.calcite.sql.type.SqlTypeUtil;
7269
import org.apache.calcite.sql.util.ReflectiveSqlOperatorTable;
7370
import org.apache.calcite.sql.validate.SqlConformance;
7471
import org.apache.calcite.sql.validate.SqlConformanceEnum;
@@ -1345,29 +1342,31 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
13451342
/**
13461343
* <code>{@code <<}</code> (left shift) operator.
13471344
*/
1348-
public static final SqlBinaryOperator LEFT_SHIFT =
1345+
public static final SqlBinaryOperator BIT_LEFT_SHIFT =
13491346
new SqlBinaryOperator(
13501347
"<<",
13511348
SqlKind.OTHER,
13521349
32, // Standard shift operator precedence
13531350
true,
1354-
ReturnTypes.cascade(
1355-
// If first operand is BINARY, return BINARY with same precision
1356-
// If first operand is INTEGER family, return BIGINT
1357-
opBinding -> {
1358-
RelDataType firstOperandType = opBinding.getOperandType(0);
1359-
if (SqlTypeUtil.isBinary(firstOperandType)) {
1360-
return firstOperandType; // Return same BINARY type as input
1361-
} else {
1362-
// For INTEGER family, return BIGINT
1363-
return opBinding.getTypeFactory().createSqlType(SqlTypeName.BIGINT);
1364-
}
1365-
},
1366-
SqlTypeTransforms.TO_NULLABLE),
1351+
ReturnTypes.ARG0_NULLABLE,
13671352
InferTypes.FIRST_KNOWN,
13681353
OperandTypes.or(
13691354
OperandTypes.family(SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER),
1370-
OperandTypes.family(SqlTypeFamily.BINARY, SqlTypeFamily.INTEGER)));
1355+
OperandTypes.family(SqlTypeFamily.BINARY, SqlTypeFamily.INTEGER),
1356+
OperandTypes.family(SqlTypeFamily.UNSIGNED_NUMERIC, SqlTypeFamily.INTEGER)));
1357+
1358+
/**
1359+
* left shift function.
1360+
*/
1361+
public static final SqlFunction LEFTSHIFT =
1362+
SqlBasicFunction.create(
1363+
"LEFTSHIFT",
1364+
SqlKind.OTHER_FUNCTION,
1365+
ReturnTypes.ARG0_NULLABLE,
1366+
OperandTypes.or(
1367+
OperandTypes.family(SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER),
1368+
OperandTypes.family(SqlTypeFamily.BINARY, SqlTypeFamily.INTEGER),
1369+
OperandTypes.family(SqlTypeFamily.UNSIGNED_NUMERIC, SqlTypeFamily.INTEGER)));
13711370

13721371
//-------------------------------------------------------------
13731372
// WINDOW Aggregate Functions

0 commit comments

Comments
 (0)