From 2b164f6240d37036dc36721c195813de995ea929 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@tarantool.org>
Date: Tue, 10 Oct 2023 17:17:48 +0300
Subject: [PATCH] sql: second lookup for collation names

Part of #4467

NO_DOC=will be added later
NO_CHANGELOG=will be added later
---
 src/box/sql.c                                      |  8 ++++++++
 src/box/sql/expr.c                                 | 10 ++++++++++
 src/box/sql/parse.y                                |  2 ++
 src/box/sql/sqlInt.h                               | 14 ++++++++++----
 ...gh_4467_sql_id_backwards_compatibility_test.lua | 13 +++++++++++++
 5 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/src/box/sql.c b/src/box/sql.c
index 9bfabb2ea6..783f9c497e 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1696,6 +1696,14 @@ sql_coll_id_by_token(const struct Token *name)
 	char *name_str = sql_name_from_token(name);
 	struct coll_id *coll_id = coll_by_name(name_str, strlen(name_str));
 	sql_xfree(name_str);
+	if (coll_id != NULL)
+		return coll_id->id;
+	if (name->z[0] == '"')
+		return UINT32_MAX;
+
+	char *old_name_str = sql_legacy_name_new(name->z, name->n);
+	coll_id = coll_by_name(old_name_str, strlen(old_name_str));
+	sql_xfree(old_name_str);
 	if (coll_id != NULL)
 		return coll_id->id;
 	return UINT32_MAX;
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index aed97cad5b..2d62ffae2d 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -1056,6 +1056,8 @@ sql_expr_new_dequoted(int op, const struct Token *token)
 	memcpy(e->u.zToken, token->z, token->n);
 	e->u.zToken[token->n] = '\0';
 	sqlDequote(e->u.zToken);
+	if (op == TK_ID || op == TK_COLLATE || op == TK_FUNCTION)
+		e->flags |= token->z[0] != '"' ? EP_Lookup2 : 0;
 	return e;
 }
 
@@ -5451,6 +5453,14 @@ sql_coll_id_by_expr(const struct Expr *expr)
 	assert(expr->op == TK_COLLATE);
 	const char *name = expr->u.zToken;
 	struct coll_id *coll_id = coll_by_name(name, strlen(name));
+	if (coll_id != NULL)
+		return coll_id->id;
+	if ((expr->flags & EP_Lookup2) == 0)
+		return UINT32_MAX;
+
+	char *old_name_str = sql_legacy_name_new0(expr->u.zToken);
+	coll_id = coll_by_name(old_name_str, strlen(old_name_str));
+	sql_xfree(old_name_str);
 	if (coll_id != NULL)
 		return coll_id->id;
 	return UINT32_MAX;
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 6a8c6c4a11..22df60beb7 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -940,6 +940,8 @@ idlist(A) ::= nm(Y). {
     memcpy(p->u.zToken, t.z, t.n);
     p->u.zToken[t.n] = '\0';
     sqlDequote(p->u.zToken);
+    if (op == TK_ID || op == TK_COLLATE || op == TK_FUNCTION)
+      p->flags |= t.z[0] != '"' ? EP_Lookup2 : 0;
 #if SQL_MAX_EXPR_DEPTH>0
     p->nHeight = 1;
 #endif  
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 1a527297c6..5beaf11a70 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -1415,6 +1415,8 @@ struct Expr {
 #define EP_Error     0x000008	/* Expression contains one or more errors */
 #define EP_Distinct  0x000010	/* Aggregate function with DISTINCT keyword */
 #define EP_VarSelect 0x000020	/* pSelect is correlated, not constant */
+/** Second lookup could be performed for the ID. */
+#define EP_Lookup2   0x000040
 #define EP_Collate   0x000100	/* Tree contains a TK_COLLATE operator */
 #define EP_IntValue  0x000400	/* Integer value contained in u.iValue */
 #define EP_xIsSelect 0x000800	/* x.pSelect is valid (otherwise x.pList is) */
@@ -3152,15 +3154,19 @@ uint32_t
 sql_fieldno_by_item(const struct space *space, const struct ExprList_item *it);
 
 /**
- * Return the ID of the collation with the name defined by the token. Return
- * UINT32_MAX if the field was not found.
+ * Return the ID of the collation with the name defined by the token. A second
+ * lookup will be performed if the collation is not found on the first try and
+ * token is not start with double quote. Return UINT32_MAX if the field was not
+ * found.
  */
 uint32_t
 sql_coll_id_by_token(const struct Token *name);
 
 /**
- * Return the ID of the collation with the name defined by the expression.
- * Return UINT32_MAX if the field was not found.
+ * Return the ID of the collation with the name defined by the expression. A
+ * second lookup will be performed if the collation is not found on the first
+ * try and EP_Lookup2 flag is set. Return UINT32_MAX if the collation was not
+ * found.
  */
 uint32_t
 sql_coll_id_by_expr(const struct Expr *expr);
diff --git a/test/sql-luatest/gh_4467_sql_id_backwards_compatibility_test.lua b/test/sql-luatest/gh_4467_sql_id_backwards_compatibility_test.lua
index 40433c9ef2..3c917b3171 100644
--- a/test/sql-luatest/gh_4467_sql_id_backwards_compatibility_test.lua
+++ b/test/sql-luatest/gh_4467_sql_id_backwards_compatibility_test.lua
@@ -87,6 +87,19 @@ g.test_collation_name = function()
         local sql = [[SELECT UPPER('asd' COLLATE qwE);]]
         t.assert_equals(box.execute(sql).rows, {{'ASD'}})
         box.space._collation:delete({coll.id})
+
+        coll_def = {'ZXC', 1, 'BINARY', '', map}
+        coll = box.space._collation:auto_increment(coll_def)
+        t.assert(coll ~= nil)
+        t.assert_equals(coll.name, 'ZXC')
+        sql = [[SELECT UPPER('asd' COLLATE zXc);]]
+        t.assert_equals(box.execute(sql).rows, {{'ASD'}})
+
+        sql = [[CREATE TABLE t(s STRING PRIMARY KEY COLLATE Zxc);]]
+        t.assert_equals(box.execute(sql), {row_count = 1})
+        t.assert_equals(box.space.t:format()[1].collation, coll.id)
+        box.space.t:drop()
+        box.space._collation:delete({coll.id})
     end)
 end
 
-- 
GitLab