This is an automated email from the ASF dual-hosted git repository.

blerer pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 5cf62c6  Add support for string concatenations through the + operator
5cf62c6 is described below

commit 5cf62c6c02322505db9260d2aa9031386326fc75
Author: Manish Ghildiyal <manish.ghildi...@lunatech.be>
AuthorDate: Sat Dec 18 18:26:31 2021 +0100

    Add support for string concatenations through the + operator
    
    Patch by Manish Ghildiyal; review by Benjamin Lerer, Berenguer Blassi,
    Brandon Williams for CASSANDRA-17190
---
 CHANGES.txt                                        |  1 +
 NEWS.txt                                           |  1 +
 src/java/org/apache/cassandra/cql3/Constants.java  | 14 +++-
 .../cassandra/cql3/functions/OperationFcts.java    | 92 ++++++++++++++++++----
 .../apache/cassandra/db/marshal/StringType.java    | 13 +++
 .../cql3/functions/OperationFctsTest.java          | 14 ++++
 6 files changed, 118 insertions(+), 17 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 2a313ab..51e39bf 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.1
+ * Add support for string concatenations through the + operator 
(CASSANDRA-17190)
  * Limit the maximum hints size per host (CASSANDRA-17142)
  * Add a virtual table for exposing batch metrics (CASSANDRA-17225)
  * Flatten guardrails config (CASSANDRA-17353)
diff --git a/NEWS.txt b/NEWS.txt
index f5d76d5..26a1c8d 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -38,6 +38,7 @@ using the provided 'sstableupgrade' tool.
 
 New features
 ------------
+    - Support for String concatenation has been added through the + operator.
     - New configuration max_hints_size_per_host to limit the size of local 
hints files per host in megabytes. Setting to
       non-positive value disables the limit, which is the default behavior. 
Setting to a positive value to ensure
       the total size of the hints files per host does not exceed the limit.
diff --git a/src/java/org/apache/cassandra/cql3/Constants.java 
b/src/java/org/apache/cassandra/cql3/Constants.java
index 3457e33..e8989ad 100644
--- a/src/java/org/apache/cassandra/cql3/Constants.java
+++ b/src/java/org/apache/cassandra/cql3/Constants.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.cql3;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,7 +45,18 @@ public abstract class Constants
 
     public enum Type
     {
-        STRING,
+        STRING
+        {
+            public AbstractType<?> getPreferedTypeFor(String text)
+            {
+                 if(Charset.forName("US-ASCII").newEncoder().canEncode(text))
+                 {
+                     return AsciiType.instance;
+                 }
+
+                 return UTF8Type.instance;
+            }
+        },
         INTEGER
         {
             public AbstractType<?> getPreferedTypeFor(String text)
diff --git a/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java 
b/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java
index 4994660..b00ced7 100644
--- a/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java
+++ b/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java
@@ -53,14 +53,24 @@ public final class OperationFcts
             {
                 return type.addDuration(temporal, duration);
             }
+
+            @Override
+            protected ByteBuffer excuteOnStrings(StringType resultType,
+                                                 StringType leftType,
+                                                 ByteBuffer left,
+                                                 StringType rightType,
+                                                 ByteBuffer right)
+            {
+                return resultType.concat(leftType, left, rightType, right);
+            }
         },
         SUBSTRACTION('-', "_substract")
         {
             protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
-                                         NumberType<?> leftType,
-                                         ByteBuffer left,
-                                         NumberType<?> rightType,
-                                         ByteBuffer right)
+                                                   NumberType<?> leftType,
+                                                   ByteBuffer left,
+                                                   NumberType<?> rightType,
+                                                   ByteBuffer right)
             {
                 return resultType.substract(leftType, left, rightType, right);
             }
@@ -76,10 +86,10 @@ public final class OperationFcts
         MULTIPLICATION('*', "_multiply")
         {
             protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
-                                         NumberType<?> leftType,
-                                         ByteBuffer left,
-                                         NumberType<?> rightType,
-                                         ByteBuffer right)
+                                                   NumberType<?> leftType,
+                                                   ByteBuffer left,
+                                                   NumberType<?> rightType,
+                                                   ByteBuffer right)
             {
                 return resultType.multiply(leftType, left, rightType, right);
             }
@@ -87,10 +97,10 @@ public final class OperationFcts
         DIVISION('/', "_divide")
         {
             protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
-                                         NumberType<?> leftType,
-                                         ByteBuffer left,
-                                         NumberType<?> rightType,
-                                         ByteBuffer right)
+                                                   NumberType<?> leftType,
+                                                   ByteBuffer left,
+                                                   NumberType<?> rightType,
+                                                   ByteBuffer right)
             {
                 return resultType.divide(leftType, left, rightType, right);
             }
@@ -98,10 +108,10 @@ public final class OperationFcts
         MODULO('%', "_modulo")
         {
             protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
-                                         NumberType<?> leftType,
-                                         ByteBuffer left,
-                                         NumberType<?> rightType,
-                                         ByteBuffer right)
+                                                   NumberType<?> leftType,
+                                                   ByteBuffer left,
+                                                   NumberType<?> rightType,
+                                                   ByteBuffer right)
             {
                 return resultType.mod(leftType, left, rightType, right);
             }
@@ -155,6 +165,25 @@ public final class OperationFcts
         }
 
         /**
+         * Executes the operation between the specified string operand.
+         *
+         * @param resultType the result type of the operation
+         * @param leftType the type of the left operand
+         * @param left the left operand
+         * @param rightType  the type of the right operand
+         * @param right the right operand
+         * @return the operation result
+         */
+        protected ByteBuffer excuteOnStrings(StringType resultType,
+                                             StringType leftType,
+                                             ByteBuffer left,
+                                             StringType rightType,
+                                             ByteBuffer right)
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
          * Returns the {@code OPERATOR} associated to the specified function.
          * @param functionName the function name
          * @return the {@code OPERATOR} associated to the specified function
@@ -221,9 +250,19 @@ public final class OperationFcts
             functions.add(new 
TemporalOperationFunction(SimpleDateType.instance, operation));
         }
 
+        addStringConcatenations(functions);
+
         return functions;
     }
 
+    private static void addStringConcatenations(List<Function> functions)
+    {
+        functions.add(new StringOperationFunction(UTF8Type.instance, 
UTF8Type.instance, OPERATION.ADDITION, UTF8Type.instance));
+        functions.add(new StringOperationFunction(AsciiType.instance, 
AsciiType.instance, OPERATION.ADDITION, AsciiType.instance));
+        functions.add(new StringOperationFunction(UTF8Type.instance, 
AsciiType.instance, OPERATION.ADDITION, UTF8Type.instance));
+        functions.add(new StringOperationFunction(UTF8Type.instance, 
UTF8Type.instance, OPERATION.ADDITION, AsciiType.instance));
+    }
+
     /**
      * Checks if the function with the specified name is an operation.
      *
@@ -415,6 +454,27 @@ public final class OperationFcts
         }
     }
 
+    private static class StringOperationFunction extends OperationFunction
+    {
+        public StringOperationFunction(StringType returnType,
+                                       StringType left,
+                                       OPERATION operation,
+                                       StringType right)
+        {
+            super(returnType, left, operation, right);
+        }
+
+        @Override
+        protected ByteBuffer doExecute(ByteBuffer left, OPERATION operation, 
ByteBuffer right)
+        {
+            StringType leftType = (StringType) argTypes().get(0);
+            StringType rightType = (StringType) argTypes().get(1);
+            StringType resultType = (StringType) returnType();
+
+            return operation.excuteOnStrings(resultType, leftType, left, 
rightType, right);
+        }
+    }
+
     /**
      * Function that execute operations on temporals (timestamp, date, ...).
      */
diff --git a/src/java/org/apache/cassandra/db/marshal/StringType.java 
b/src/java/org/apache/cassandra/db/marshal/StringType.java
index f9ce444..29aff58 100644
--- a/src/java/org/apache/cassandra/db/marshal/StringType.java
+++ b/src/java/org/apache/cassandra/db/marshal/StringType.java
@@ -18,10 +18,23 @@
 
 package org.apache.cassandra.db.marshal;
 
+import java.nio.ByteBuffer;
+
 public abstract class StringType extends AbstractType<String>
 {
     protected StringType(ComparisonType comparisonType)
     {
         super(comparisonType);
     }
+
+    public ByteBuffer concat(StringType leftType,
+                             ByteBuffer left,
+                             StringType rightType,
+                             ByteBuffer right)
+    {
+        String leftS = leftType.compose(left);
+        String rightS = rightType.compose(right);
+
+        return decompose(leftS + rightS);
+    }
 }
diff --git 
a/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java 
b/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java
index 053283d..58c2c29 100644
--- a/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java
+++ b/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java
@@ -33,6 +33,20 @@ import org.apache.cassandra.transport.ProtocolVersion;
 
 public class OperationFctsTest extends CQLTester
 {
+
+    @Test
+    public void testStringConcatenation() throws Throwable
+    {
+        createTable("CREATE TABLE %s (a text, b ascii, c text, PRIMARY KEY(a, 
b, c))");
+        execute("INSERT INTO %S (a, b, c) VALUES ('जॉन', 'Doe', 'जॉन Doe')");
+
+        assertColumnNames(execute("SELECT a + a, a + b, b + a, b + b FROM %s 
WHERE a = 'जॉन' AND b = 'Doe' AND c = 'जॉन Doe'"),
+                "a + a", "a + b", "b + a", "b + b");
+
+        assertRows(execute("SELECT a + ' ' + a, a + ' ' + b, b + ' ' + a, b + 
' ' + b FROM %s WHERE a = 'जॉन' AND b = 'Doe' AND c = 'जॉन Doe'"),
+                row("जॉन जॉन", "जॉन Doe", "Doe जॉन", "Doe Doe"));
+    }
+
     @Test
     public void testSingleOperations() throws Throwable
     {

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to