From 6aefda7185fc8a1e80dd8daa98d3d0a6fd860068 Mon Sep 17 00:00:00 2001 From: Denis Smirnov <sd@picodata.io> Date: Mon, 20 Jun 2022 20:36:49 +0700 Subject: [PATCH] fix: default result parameter type Problem description. When we prepare a statement with parameters in the result columns (for example box.prepare('select ?')) Tarantool has no information about the type of the output column and set it to default boolean. Then, on the execution phase, the type would be recalculated during the parameter binding. Tarantool expects that there is no way for parameter to appear in the result tuple other than exactly be mentioned in the final projection. But it is incorrect - we can easily propagate parameter from the inner part of the join. For example box.prepare([[select COLUMN_1 from t1 join (values (?)) as t2 on true]]) In this case column COLUMN_1 in the final projection is not a parameter, but a "reference" to it and its type depends on the parameter from the inner part of the join. But as Tarantool recalculates only binded parameters in the result projection, it doesn't change the default boolean metadata type of the COLUMN_1 and the query fails on comparison with the actual type of the tuple. Solution. As we don't want to patch Vdbe to make COLUMN_1 refer inner parameter, it was decided to make a simple workaround: change the default column type from BOOLEAN to ANY for parameters. It fixes the comparison with the actual tuple type (we do not fail), but in some cases get ANY column in the results where we would like to have explicitly defined type. Also NULL parameters would also have ANY type, though Tarantool prefers to have BOOLEAN in this case. Closes https://github.com/tarantool/tarantool/issues/7283 NO_DOC=bug fix --- .../gh-7283-result-parameter-type.md | 3 +++ src/box/sql/expr.c | 8 ++++++- .../gh_7283_result_parameter_type_test.lua | 23 +++++++++++++++++++ test/sql/bind.result | 2 +- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/gh-7283-result-parameter-type.md create mode 100644 test/sql-luatest/gh_7283_result_parameter_type_test.lua diff --git a/changelogs/unreleased/gh-7283-result-parameter-type.md b/changelogs/unreleased/gh-7283-result-parameter-type.md new file mode 100644 index 0000000000..f31556cfb3 --- /dev/null +++ b/changelogs/unreleased/gh-7283-result-parameter-type.md @@ -0,0 +1,3 @@ +## bugfix/sql + +Fixes a failing inner join query, projecting parameters from the inner table to the result projection. As a side effect the default column metadata was changed from `boolean` to `any` type. diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index b5aa42ff1e..c1226a151a 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -1300,7 +1300,13 @@ expr_new_variable(struct Parse *parse, const struct Token *spec, len += id->n; } struct Expr *expr = sql_expr_new_empty(TK_VARIABLE, len + 1); - expr->type = FIELD_TYPE_BOOLEAN; + if (expr == NULL) + return NULL; + if (spec->n == 1 && spec->z[0] == '?') { + expr->type = FIELD_TYPE_ANY; + } else { + expr->type = FIELD_TYPE_BOOLEAN; + } expr->flags = EP_Leaf; expr->u.zToken = (char *)(expr + 1); expr->u.zToken[0] = spec->z[0]; diff --git a/test/sql-luatest/gh_7283_result_parameter_type_test.lua b/test/sql-luatest/gh_7283_result_parameter_type_test.lua new file mode 100644 index 0000000000..56fcf65701 --- /dev/null +++ b/test/sql-luatest/gh_7283_result_parameter_type_test.lua @@ -0,0 +1,23 @@ +local server = require('luatest.server') +local t = require('luatest') +local g = t.group() + +g.before_all(function() + g.server = server:new({alias = 'result_parameter_type'}) + g.server:start() +end) + +g.after_all(function() + g.server:stop() +end) + +g.test_result_parameter_type_1 = function() + g.server:exec(function() + local t = require('luatest') + box.execute([[CREATE TABLE t1(a INT PRIMARY KEY);]]) + local q = box.prepare([[SELECT COLUMN_1 FROM t1 JOIN (VALUES (?)) AS t2 ON true]]) + local res, _ = q:execute() + t.assert_equals(res.metadata[1].type, 'any') + box.execute([[DROP TABLE t1;]]) + end) +end diff --git a/test/sql/bind.result b/test/sql/bind.result index 3b4e8cbe78..08486c020e 100644 --- a/test/sql/bind.result +++ b/test/sql/bind.result @@ -166,7 +166,7 @@ execute('SELECT :value3, ?, :value1, ?, ?, @value2, ?, :value3', parameters) - name: COLUMN_6 type: integer - name: COLUMN_7 - type: boolean + type: any - name: COLUMN_8 type: boolean rows: -- GitLab