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 A1CE66EC41; Fri, 13 Aug 2021 06:17:36 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org A1CE66EC41 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1628824656; bh=/9aeyDMJQvLEbJMUMP4UcV1I6/kU5y3YIhMbAd8oc1M=; 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=gELgnGkareZ9tM20WtMhazNuGzzjHy2rbPFrlMuTzB7m2/V0VXQZAxwgNlOnoCFG3 lw6FlZyY9H/hm8ska4zyi01oZmfBaZlaokvj7lFLnwhtEtxdNegCfg3xeJC3P76ZP9 YXhXr3Vy2aNaRCnGuPNxC1cmPZZMaS3M1SZSHf44= Received: from smtpng2.i.mail.ru (smtpng2.i.mail.ru [94.100.179.3]) (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 941476EC41 for ; Fri, 13 Aug 2021 06:17:06 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 941476EC41 Received: by smtpng2.m.smailru.net with esmtpa (envelope-from ) id 1mENgv-0002Hj-Pw; Fri, 13 Aug 2021 06:17:06 +0300 To: vdavydov@tarantool.org Cc: tarantool-patches@dev.tarantool.org Date: Fri, 13 Aug 2021 06:17:05 +0300 Message-Id: X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD92087353F0EC44DD91BCCB18F2C129F87F36E61E9E4584E9D182A05F538085040896AFCA1C419E7ECE672CADF5F77E902C92A69092D62A9A6547C18D3925FE3B6 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7370DF012C2F9ACE3EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637525B22DCF689D4638638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D82D92C2B78DE47BFE79357FBFA2D2A5E8117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B66F6A3E018CF4DC80089D37D7C0E48F6C5571747095F342E88FB05168BE4CE3AF X-B7AD71C0: AC4F5C86D027EB782CDD5689AFBDA7A213B5FB47DCBC3458834459D11680B5059A91936EF7B6732D4109C3BC4125C38B X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975C69415AB31670C86C7D2092BBFC41563876E0092DE0F5DB719C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EFE37876E7723AB534DC48ACC2A39D04F89CDFB48F4795C241BDAD6C7F3747799A X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D347324AA9FA07FF01E45C0C27C7401AC02F2190C465DC646CDBC9030EE2A8CF3B3E61A8D289B3A9D941D7E09C32AA3244CF392B188983970C86AD173B52FE93EC8E8FBBEFAE1C4874C729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2bioj0dLV0c3jbkyqiXcPO8YlEA== X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5D83B39C9E29BEAF65854A4D6956F27F1183D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH v1 01/10] 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 1551d3ef2..c19a4dcde 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -1476,37 +1476,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 @@ -1516,32 +1490,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. @@ -1550,20 +1521,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); } @@ -1579,9 +1550,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; @@ -1590,7 +1558,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 bd041e862..d06f45fd9 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