AMashenkov commented on code in PR #5652:
URL: https://github.com/apache/ignite-3/pull/5652#discussion_r2050896531


##########
modules/catalog-dsl/src/main/java/org/apache/ignite/internal/catalog/sql/Name.java:
##########
@@ -18,49 +18,86 @@
 package org.apache.ignite.internal.catalog.sql;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
-import java.util.regex.Pattern;
-import org.apache.ignite.internal.util.StringUtils;
+import org.apache.ignite.lang.util.IgniteNameUtils;
 
 /**
  * SQL identifier.
  */
 class Name extends QueryPart {
+    private final List<String> names;
+
     /**
-     * Pattern to find possible SQL injections in identifiers.
+     * Creates a simple name.
+     *
+     * @param name Name.
+     * @return Name.
      */
-    private static final Pattern PATTERN = 
Pattern.compile("[';\r\n\t\\s\\/]|(--[^\r\n]*)");
-
-    private final List<String> names = new ArrayList<>();
+    static Name simple(String name) {
+        return new Name(List.of(name));
+    }
 
     /**
-     * Identifier name. E.g [db, schema, table] become 'db.schema.table' or 
'"db"."schema"."table"' depending on DDL options.
+     * Creates a compound name (e.g. {@code my_schema.my_table} or {@code 
my_table}). Accepts both simple and compound names.
      *
-     * @param names name parts of qualified identifier.
+     * @param names Array of names.
+     * @return Name.
      */
-    Name(String... names) {
-        Objects.requireNonNull(names, "Names must not be null");
+    static Name compound(String... names) {
+        List<String> parts = new ArrayList<>(2);
 
-        for (String name : names) {
-            if (StringUtils.nullOrBlank(name)) {
-                // Skip parts instead of failure as nulls can be used as 
defaults from annotations or builders.
-                continue;
+        if (names.length == 0) {
+            throw new IllegalArgumentException("Names can not be empty");
+        } else if (names.length == 1) {
+            return new Name(Arrays.asList(names));
+        } else {
+            boolean canSkipEmpty = true;
+            for (String part : names) {
+                if (part == null || part.isEmpty()) {
+                    if (canSkipEmpty) {
+                        canSkipEmpty = false;
+                        continue;
+                    }
+                } else {
+                    // Do not allow non-leading elements to be empty
+                    canSkipEmpty = false;
+                }
+                parts.add(part);
             }
-            // We need to sanitize the identifiers to prevent SQL injection.
-            // Ignite DDL doesn't have prepared statements yet which could be 
used instead of creating a raw query.
-            if (PATTERN.matcher(name).find()) {
-                throw new IllegalArgumentException("Name part " + name + " is 
invalid");
+
+            return new Name(parts);
+        }
+    }
+
+    private Name(List<String> names) {
+        for (String name : names) {
+            if (name == null || name.isEmpty()) {
+                throw new IllegalArgumentException("Name parts can not be null 
or empty: " + names);
             }
-            this.names.add(name);
         }
+        this.names = names;
     }
 
     @Override
     protected void accept(QueryContext ctx) {
         String separator = "";
         for (String name : names) {
-            ctx.sql(separator).sql(name);
+            // If a name is quoted, we must preserve case sensitivity -> write 
it as is
+            // If a name UPPER(name) = QUOTED(UPPER(name)), then this is a 
case insensitive name, write it in uppercase for consistency.
+            // Otherwise UPPER(name) != QUOTED(UPPER(name)) and we must quote 
it.
+            if (name.startsWith("\"")) {
+                ctx.sql(separator).sql(name);
+            } else  {
+                String upperCase = name.toUpperCase();
+                String quoted = IgniteNameUtils.quoteIfNeeded(upperCase);
+
+                if (quoted.equals(upperCase)) {
+                    ctx.sql(separator).sql(upperCase);
+                } else {
+                    
ctx.sql(separator).sql(IgniteNameUtils.quoteIfNeeded(name));
+                }

Review Comment:
   Will it be the same 
   ```suggestion               
                   if (IgniteNameUtils.isValidNormalizedIdentifier(upperCase)) {
                       ctx.sql(separator).sql(upperCase);
                   } else {
                       ctx.sql(separator).sql(IgniteNameUtils.quote(name));
                   }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@ignite.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to