@@ -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. */
0 commit comments