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 EFA416E459; Wed, 17 Nov 2021 17:42:29 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org EFA416E459 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1637160150; bh=Nq4ETSUMPD8gcSVjm2eXmP3CAYkVwBAS5Slg/DX98Sg=; 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=Xgb7s08T8xKCWwIG4W1zE2kgPobFW17+2ZCgCiqzWXT2rh9IsEEYQY8e95GulHvOX Dd4m4ZWOc+N8ZXZBHKga6voitkR0tOxEcUkIvcT8Rh+lQOPyVeIGbQxcuABe+o1mDK jUkF1LzpAloO3FpSywZ0oKJzlTiFZFdgYeuB4xG4= 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 7F3F56DB3F for ; Wed, 17 Nov 2021 17:41:17 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 7F3F56DB3F Received: by smtpng1.m.smailru.net with esmtpa (envelope-from ) id 1mnM7g-0000bE-S8; Wed, 17 Nov 2021 17:41:17 +0300 To: v.shpilevoy@tarantool.org Cc: tarantool-patches@dev.tarantool.org Date: Wed, 17 Nov 2021 17:41:16 +0300 Message-Id: <0304eeda12ed2a459370656121cb70ededdbb977.1637159909.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: EEAE043A70213CC8 X-77F55803: 4F1203BC0FB41BD9731B3922EC06397990E8B89D97A64D716CAA5505BE500FF700894C459B0CD1B9B3ED8B5EDCC9B26E6DF5D0D9C6FC386E7C9387547105DA2832395092C4B9E977 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7956F10FFCC7409BAEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F79006379CBE0668FF2CDAD68638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D84F289A56B219BA9BE0ED0497A854532A117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BF1175FABE1C0F9B6A471835C12D1D977C4224003CC8364762BB6847A3DEAEFB0F43C7A68FF6260569E8FC8737B5C2249EC8D19AE6D49635B68655334FD4449CB9ECD01F8117BC8BEAAAE862A0553A39223F8577A6DFFEA7CE31A2885C41F97C443847C11F186F3C59DAA53EE0834AAEE X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975C83792D63EF07D36BD813E212A8CB70386C1C68A9A4C773269C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EF505D71D783575ABE699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D344A431191C56981FED61A2F296798E605CE6C8D0984348A2123E2D15CF0385A58FF88850D57AF26EC1D7E09C32AA3244C91D3FDF729C08316141AC75114D66BFB3C6EB905E3A8056B729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2bioj81eoY04Pbok7DNQjmFUhLw== X-Mailru-Sender: 689FA8AB762F7393C37E3C1AEC41BA5D7049647353A541DF4D7D62788F40F84D83D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH v1 3/3] sql: introduce syntax for ARRAY values 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 introduces a new syntax that allows to create ARRAY values in an SQL query. Part of #4762 @TarantoolBot document Title: Syntax for ARRAY in SQL The syntax for creating ARRAY values is available in SQL. You can use `[` and `]` to create an ARRAY value - all values in those brackets will be part of ARRAY. The position of the values will be translated to the same positions in ARRAY. Examples: ``` tarantool> box.execute("SELECT [1, 'a', 1.5];") --- - metadata: - name: COLUMN_1 type: array rows: - [[1, 'a', 1.5]] ... ``` ``` tarantool> box.execute("SELECT [1, 'a', ['abc', 321], 1.5];") --- - metadata: - name: COLUMN_1 type: array rows: - [[1, 'a', ['abc', 321], 1.5]] ... ``` --- .../gh-4762-introduce-array-to-sql.md | 3 +- src/box/sql/expr.c | 20 +++++++++++++ src/box/sql/parse.y | 14 ++++++++++ src/box/sql/tokenize.c | 10 ++++++- src/box/sql/vdbe.c | 20 +++++++++++++ test/sql-tap/array.test.lua | 28 ++++++++++++++++++- test/sql-tap/colname.test.lua | 4 +-- 7 files changed, 93 insertions(+), 6 deletions(-) diff --git a/changelogs/unreleased/gh-4762-introduce-array-to-sql.md b/changelogs/unreleased/gh-4762-introduce-array-to-sql.md index 1446ab1cb..fcfa53c73 100644 --- a/changelogs/unreleased/gh-4762-introduce-array-to-sql.md +++ b/changelogs/unreleased/gh-4762-introduce-array-to-sql.md @@ -1,3 +1,4 @@ ## feature/core - * Field type ARRAY is now available in SQL (gh-4762). + * Field type ARRAY is now available in SQL. The syntax has also been + implemented to allow the creation of ARRAY values (gh-4762). diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 2c8021060..eb169aeb8 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -3370,6 +3370,22 @@ int_overflow: is_neg ? P4_INT64 : P4_UINT64); } +static void +expr_code_array(struct Parse *parser, struct Expr *expr, int reg) +{ + struct Vdbe *vdbe = parser->pVdbe; + struct ExprList *list = expr->x.pList; + if (list == NULL) { + sqlVdbeAddOp3(vdbe, OP_Array, 0, reg, 0); + return; + } + int count = list->nExpr; + int values_reg = parser->nMem + 1; + parser->nMem += count; + sqlExprCodeExprList(parser, list, values_reg, 0, SQL_ECEL_FACTOR); + sqlVdbeAddOp3(vdbe, OP_Array, count, reg, values_reg); +} + /* * Erase column-cache entry number i */ @@ -3821,6 +3837,10 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target) return inReg; } + case TK_ARRAY: + expr_code_array(pParse, pExpr, target); + break; + case TK_LT: case TK_LE: case TK_GT: diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index c93125a8b..499f235be 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -1128,6 +1128,20 @@ expr(A) ::= CAST(X) LP expr(E) AS typedef(T) RP(Y). { sqlExprAttachSubtrees(pParse->db, A.pExpr, E.pExpr, 0); } +expr(A) ::= LB(X) exprlist(Y) RB(E). { + struct Expr *expr = sql_expr_new_dequoted(pParse->db, TK_ARRAY, NULL); + if (expr == NULL) { + sql_expr_list_delete(pParse->db, Y); + pParse->is_aborted = true; + return; + } + expr->x.pList = Y; + expr->type = FIELD_TYPE_ARRAY; + sqlExprSetHeightAndFlags(pParse, expr); + A.pExpr = expr; + spanSet(&A, &X, &E); +} + expr(A) ::= TRIM(X) LP trim_operands(Y) RP(E). { A.pExpr = sqlExprFunction(pParse, Y, &X); spanSet(&A, &X, &E); diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c index b3cf8f6e6..f2d5a2df5 100644 --- a/src/box/sql/tokenize.c +++ b/src/box/sql/tokenize.c @@ -83,6 +83,8 @@ #define CC_DOT 26 /* '.' */ #define CC_ILLEGAL 27 /* Illegal character */ #define CC_LINEFEED 28 /* '\n' */ +#define CC_LB 29 /* '[' */ +#define CC_RB 30 /* ']' */ static const char sql_ascii_class[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ @@ -91,7 +93,7 @@ static const char sql_ascii_class[] = { /* 2x */ 7, 15, 9, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, /* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, /* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 1, +/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 29, 27, 30, 27, 1, /* 6x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27, /* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -220,6 +222,12 @@ sql_token(const char *z, int *type, bool *is_reserved) case CC_RP: *type = TK_RP; return 1; + case CC_LB: + *type = TK_LB; + return 1; + case CC_RB: + *type = TK_RB; + return 1; case CC_SEMI: *type = TK_SEMI; return 1; diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 2e6893f1a..55e494332 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1418,6 +1418,26 @@ case OP_Cast: { /* in1 */ goto abort_due_to_error; } +/* Opcode: Array P1 P2 P3 * * + * Synopsis: r[P2]=array(P3@P1) + * + * Construct an ARRAY value from P1 registers starting at reg(P3). + */ +case OP_Array: { + pOut = &aMem[pOp->p2]; + + uint32_t size; + struct region *region = &fiber()->gc; + size_t svp = region_used(region); + char *val = mem_encode_array(&aMem[pOp->p3], pOp->p1, &size, region); + if (val == NULL || mem_copy_array(pOut, val, size) != 0) { + region_truncate(region, svp); + goto abort_due_to_error; + } + region_truncate(region, svp); + break; +} + /* Opcode: Eq P1 P2 P3 P4 P5 * Synopsis: IF r[P3]==r[P1] * diff --git a/test/sql-tap/array.test.lua b/test/sql-tap/array.test.lua index 752cb24f2..1f2ba6d5d 100755 --- a/test/sql-tap/array.test.lua +++ b/test/sql-tap/array.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(110) +test:plan(113) box.schema.func.create('A1', { language = 'Lua', @@ -979,6 +979,32 @@ test:do_catchsql_test( 1, "Failed to execute SQL statement: wrong arguments for function ZEROBLOB()" }) +-- Make sure syntax for ARRAY values works as intended. +test:do_execsql_test( + "array-13.1", + [[ + SELECT [a, g, t, n, f, i, b, v, s, d, u] FROM t1 WHERE id = 1; + ]], { + {{1}, 1, '1', 1, 1, 1, true, '1', 1, require('decimal').new(1), + require('uuid').fromstr('11111111-1111-1111-1111-111111111111')} + }) + +test:do_execsql_test( + "array-13.2", + [[ + SELECT [1, true, 1.5e0, ['asd', x'32'], 1234.0]; + ]], { + {1, true, 1.5, {'asd', '2'}, require('decimal').new(1234)} + }) + +test:do_execsql_test( + "array-13.3", + [[ + SELECT typeof([1]); + ]], { + "array" + }) + box.execute([[DROP TABLE t1;]]) box.execute([[DROP TABLE t;]]) diff --git a/test/sql-tap/colname.test.lua b/test/sql-tap/colname.test.lua index ff7585c7a..698a446e1 100755 --- a/test/sql-tap/colname.test.lua +++ b/test/sql-tap/colname.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(79) +test:plan(76) --!./tcltestrunner.lua -- 2008 July 15 @@ -546,7 +546,6 @@ test:do_test( local data = { [[`a`]], - "[a]", } for i, val in ipairs(data) do test:do_catchsql_test( @@ -559,7 +558,6 @@ end local data2 = { {[['a']],{1, "/Syntax error/"}}, -- because ' is delimiter for strings {[[`a`]],{1, "/unrecognized token/"}}, -- because ` is undefined symbol - {"[a]",{1, "/unrecognized token/"}} -- because [ is undefined symbol } for i, val in ipairs(data2) do test:do_catchsql_test( -- 2.25.1