From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 6E1136EC42; Thu, 19 Aug 2021 15:03:30 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 6E1136EC42 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1629374610; bh=lXmNvwU4G6rc8ah3zcx7X56ZNKI/4E2tHwkIkb57lY4=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=Dv9ftID1kXKEdrEJzFBpOut1IXdM5xJGrnxAmmT9DVN6KBfucWvqRa1Jy5tcGh0vs irMRed7qI8ZaVWBM9z5gkGINZWih7eMSi3ovFaxEpEBYZa/2ATMrXMIjYlceotq6Wl PWVxH3AIl5juFkXWLbLmEB9c1hqgo8aKhKCdzC/o= Received: from smtpng1.i.mail.ru (smtpng1.i.mail.ru [94.100.181.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 7636E6EC42 for ; Thu, 19 Aug 2021 15:02:58 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 7636E6EC42 Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1mGgl7-0006Rk-1t; Thu, 19 Aug 2021 15:02:57 +0300 To: kyukhin@tarantool.org, v.ioffe@tarantool.org Cc: tarantool-patches@dev.tarantool.org Date: Thu, 19 Aug 2021 15:02:56 +0300 Message-Id: <5ad7461c72af3b9b814fc2dba3d9ab085eca5e1e.1629374448.git.imeevma@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD92087353F0EC44DD9736CF3E71F18CE0C3E1D5927724F4AAA182A05F5380850405A7E543ECFCD68312EDF6BE5A4EAE8F51D2C8CEE4C9570539BC9F75A10A170B6 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7A9228A07F073865DEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637D82ED515D6052E03EA1F7E6F0F101C6723150C8DA25C47586E58E00D9D99D84E1BDDB23E98D2D38BBCA57AF85F7723F2B22FA7C89F027A1A7E7AEA0EEC33C91DCC7F00164DA146DAFE8445B8C89999728AA50765F7900637F6B57BC7E64490618DEB871D839B7333395957E7521B51C2DFABB839C843B9C08941B15DA834481F8AA50765F7900637F6B57BC7E6449061A352F6E88A58FB86F5D81C698A659EA7E827F84554CEF5019E625A9149C048EE9ECD01F8117BC8BEE2021AF6380DFAD18AA50765F790063735872C767BF85DA227C277FBC8AE2E8BDAE3FA6833AEA0C275ECD9A6C639B01B4E70A05D1297E1BBCB5012B2E24CD356 X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975CF160826E4E1956AE0E788EFADF99E76D385D58F5EEC401309C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EF836F5ADB0B4F9314699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3416EA6E382A5BB1766549372B6CC3A05214F472BA4E551EDDFF20FA4788635DF792D742E765F4E4771D7E09C32AA3244C9890AD6C68BC7CB84F38F3909B98363DBBA718C7E6A9E042FACE5A9C96DEB163 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojGSxK+6r6oBGN/Eh415zCVg== X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5D109733E112FB0FB57DD1385F7757679083D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH v1 1/9] sql: modify signature of TRIM() X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Mergen Imeev via Tarantool-patches Reply-To: imeevma@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" This patch changes the signature of SQL built-in function TRIM(). This gives us an easier way to check the types of the arguments to this function. Additionally, these changes fix a bug where using TRIM with the BOTH, LEADING, or TRAILING keywords would result in a loss of a collation. Needed for #6105 Closes #6299 --- src/box/sql/func.c | 80 ++++++------------- src/box/sql/parse.y | 36 +++++---- .../gh-6299-lost-collation-on-trim.test.lua | 47 +++++++++++ 3 files changed, 90 insertions(+), 73 deletions(-) create mode 100755 test/sql-tap/gh-6299-lost-collation-on-trim.test.lua diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 8cdb370d1..90359a23a 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -1467,37 +1467,11 @@ trim_prepare_char_len(struct sql_context *context, } /** - * Normalize args from @a argv input array when it has one arg - * only. + * Normalize args from @a argv input array when it has two args. * * Case: TRIM() * Call trimming procedure with TRIM_BOTH as the flags and " " as * the trimming set. - */ -static void -trim_func_one_arg(struct sql_context *context, sql_value *arg) -{ - /* In case of VARBINARY type default trim octet is X'00'. */ - const unsigned char *default_trim; - if (mem_is_null(arg)) - return; - if (mem_is_bin(arg)) - default_trim = (const unsigned char *) "\0"; - else - default_trim = (const unsigned char *) " "; - const unsigned char *input_str = mem_as_ustr(arg); - int input_str_sz = mem_len_unsafe(arg); - uint8_t trim_char_len[1] = { 1 }; - trim_procedure(context, TRIM_BOTH, default_trim, trim_char_len, 1, - input_str, input_str_sz); -} - -/** - * Normalize args from @a argv input array when it has two args. - * - * Case: TRIM( FROM ) - * If user has specified only, call trimming - * procedure with TRIM_BOTH as the flags and that trimming set. * * Case: TRIM(LEADING/TRAILING/BOTH FROM ) * If user has specified side keyword only, then call trimming @@ -1507,32 +1481,29 @@ static void trim_func_two_args(struct sql_context *context, sql_value *arg1, sql_value *arg2) { - const unsigned char *input_str, *trim_set; - if ((input_str = mem_as_ustr(arg2)) == NULL) + const unsigned char *trim_set; + if (mem_is_bin(arg1)) + trim_set = (const unsigned char *)"\0"; + else + trim_set = (const unsigned char *)" "; + const unsigned char *input_str; + if ((input_str = mem_as_ustr(arg1)) == NULL) return; - int input_str_sz = mem_len_unsafe(arg2); - if (sql_value_type(arg1) == MP_INT || sql_value_type(arg1) == MP_UINT) { - uint8_t len_one = 1; - trim_procedure(context, mem_get_int_unsafe(arg1), - (const unsigned char *) " ", &len_one, 1, - input_str, input_str_sz); - } else if ((trim_set = mem_as_ustr(arg1)) != NULL) { - int trim_set_sz = mem_len_unsafe(arg1); - uint8_t *char_len; - int char_cnt = trim_prepare_char_len(context, trim_set, - trim_set_sz, &char_len); - if (char_cnt == -1) - return; - trim_procedure(context, TRIM_BOTH, trim_set, char_len, char_cnt, - input_str, input_str_sz); - sql_free(char_len); - } + int input_str_sz = mem_len_unsafe(arg1); + assert(arg2->type == MEM_TYPE_UINT); + uint8_t len_one = 1; + trim_procedure(context, arg2->u.u, trim_set, + &len_one, 1, input_str, input_str_sz); } /** * Normalize args from @a argv input array when it has three args. * + * Case: TRIM( FROM ) + * If user has specified only, call trimming procedure with + * TRIM_BOTH as the flags and that trimming set. + * * Case: TRIM(LEADING/TRAILING/BOTH FROM ) * If user has specified side keyword and , then * call trimming procedure with that args. @@ -1541,20 +1512,20 @@ static void trim_func_three_args(struct sql_context *context, sql_value *arg1, sql_value *arg2, sql_value *arg3) { - assert(sql_value_type(arg1) == MP_INT || sql_value_type(arg1) == MP_UINT); + assert(arg2->type == MEM_TYPE_UINT); const unsigned char *input_str, *trim_set; - if ((input_str = mem_as_ustr(arg3)) == NULL || - (trim_set = mem_as_ustr(arg2)) == NULL) + if ((input_str = mem_as_ustr(arg1)) == NULL || + (trim_set = mem_as_ustr(arg3)) == NULL) return; - int trim_set_sz = mem_len_unsafe(arg2); - int input_str_sz = mem_len_unsafe(arg3); + int trim_set_sz = mem_len_unsafe(arg3); + int input_str_sz = mem_len_unsafe(arg1); uint8_t *char_len; int char_cnt = trim_prepare_char_len(context, trim_set, trim_set_sz, &char_len); if (char_cnt == -1) return; - trim_procedure(context, mem_get_int_unsafe(arg1), trim_set, char_len, + trim_procedure(context, arg2->u.u, trim_set, char_len, char_cnt, input_str, input_str_sz); sql_free(char_len); } @@ -1570,9 +1541,6 @@ static void trim_func(struct sql_context *context, int argc, sql_value **argv) { switch (argc) { - case 1: - trim_func_one_arg(context, argv[0]); - break; case 2: trim_func_two_args(context, argv[0], argv[1]); break; @@ -1581,7 +1549,7 @@ trim_func(struct sql_context *context, int argc, sql_value **argv) break; default: diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, "TRIM", - "1 or 2 or 3", argc); + "2 or 3", argc); context->is_aborted = true; } } diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index 436c98cd9..337df4916 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -1132,32 +1132,34 @@ expr(A) ::= TRIM(X) LP trim_operands(Y) RP(E). { %type trim_operands {struct ExprList *} %destructor trim_operands {sql_expr_list_delete(pParse->db, $$);} -trim_operands(A) ::= trim_from_clause(F) expr(Y). { - A = sql_expr_list_append(pParse->db, F, Y.pExpr); +trim_operands(A) ::= trim_specification(N) expr(Z) FROM expr(Y). { + A = sql_expr_list_append(pParse->db, NULL, Y.pExpr); + struct Expr *p = sql_expr_new_dequoted(pParse->db, TK_INTEGER, + &sqlIntTokens[N]); + A = sql_expr_list_append(pParse->db, A, p); + A = sql_expr_list_append(pParse->db, A, Z.pExpr); } -trim_operands(A) ::= expr(Y). { +trim_operands(A) ::= trim_specification(N) FROM expr(Y). { A = sql_expr_list_append(pParse->db, NULL, Y.pExpr); + struct Expr *p = sql_expr_new_dequoted(pParse->db, TK_INTEGER, + &sqlIntTokens[N]); + A = sql_expr_list_append(pParse->db, A, p); } -%type trim_from_clause {struct ExprList *} -%destructor trim_from_clause {sql_expr_list_delete(pParse->db, $$);} - -/* - * The following two rules cover three cases of keyword - * (LEADING/TRAILING/BOTH) and combination. - * The case when both of them are absent is disallowed. - */ -trim_from_clause(A) ::= expr(Y) FROM. { +trim_operands(A) ::= expr(Z) FROM expr(Y). { A = sql_expr_list_append(pParse->db, NULL, Y.pExpr); + struct Expr *p = sql_expr_new_dequoted(pParse->db, TK_INTEGER, + &sqlIntTokens[TRIM_BOTH]); + A = sql_expr_list_append(pParse->db, A, p); + A = sql_expr_list_append(pParse->db, A, Z.pExpr); } -trim_from_clause(A) ::= trim_specification(N) expr_optional(Y) FROM. { +trim_operands(A) ::= expr(Y). { + A = sql_expr_list_append(pParse->db, NULL, Y.pExpr); struct Expr *p = sql_expr_new_dequoted(pParse->db, TK_INTEGER, - &sqlIntTokens[N]); - A = sql_expr_list_append(pParse->db, NULL, p); - if (Y != NULL) - A = sql_expr_list_append(pParse->db, A, Y); + &sqlIntTokens[TRIM_BOTH]); + A = sql_expr_list_append(pParse->db, A, p); } %type expr_optional {struct Expr *} diff --git a/test/sql-tap/gh-6299-lost-collation-on-trim.test.lua b/test/sql-tap/gh-6299-lost-collation-on-trim.test.lua new file mode 100755 index 000000000..1799da839 --- /dev/null +++ b/test/sql-tap/gh-6299-lost-collation-on-trim.test.lua @@ -0,0 +1,47 @@ +#!/usr/bin/env tarantool +local test = require("sqltester") +test:plan(4) + +-- +-- Make sure that collation is not lost when TRIM called with BOTH, LEADING, or +-- TRAILING keywords specified. +-- + +test:execsql[[ + CREATE TABLE t (i INT PRIMARY KEY, s STRING COLLATE "unicode_ci"); + INSERT INTO t VALUES (1,'A'), (2,'a'); +]] + +test:do_execsql_test( + "gh-6299-2", + [[ + SELECT DISTINCT trim(LEADING FROM s) FROM t; + ]], { + 'A' + }) + +test:do_execsql_test( + "gh-6299-3", + [[ + SELECT DISTINCT trim(TRAILING FROM s) FROM t; + ]], { + 'A' + }) + +test:do_execsql_test( + "gh-6299-4", + [[ + SELECT DISTINCT trim(BOTH FROM s) FROM t; + ]], { + 'A' + }) + +test:do_execsql_test( + "gh-6299-1", + [[ + SELECT DISTINCT trim(s) FROM t; + ]], { + 'A' + }) + +test:finish_test() -- 2.25.1