diff options
author | aneporada <aneporada@yandex-team.com> | 2024-11-12 20:02:10 +0300 |
---|---|---|
committer | Maxim Yurchuk <maxim-yurchuk@ydb.tech> | 2024-11-12 22:40:29 +0300 |
commit | 06791fb116406f98a10593436968aabe51d1a856 (patch) | |
tree | 3a4c8f662423b3602767da02508ce5df0f54a2f2 | |
parent | 4e4600bae44c02ba4a94c8f7a397a2c63c3cc235 (diff) | |
download | ydb-06791fb116406f98a10593436968aabe51d1a856.tar.gz |
Merge PR #10831, #11068, #11075, #11152
#11152 - Allow to choose normal or aggreation PG function
#11075 - Handle invalid base
#11068 - Allow more postgis functions
#10831 - Views: if exists / if not exists for DDL
commit_hash:0ebf35e45ac6de147c9000440ca25237db061d2e
17 files changed, 260 insertions, 53 deletions
diff --git a/yql/essentials/parser/pg_catalog/catalog.cpp b/yql/essentials/parser/pg_catalog/catalog.cpp index 72ce7ade8c..05e6a48875 100644 --- a/yql/essentials/parser/pg_catalog/catalog.cpp +++ b/yql/essentials/parser/pg_catalog/catalog.cpp @@ -2362,6 +2362,24 @@ void EnumProc(std::function<void(ui32, const TProcDesc&)> f) { } } +bool HasProc(const TString& name, EProcKind kind) { + const auto& catalog = TCatalog::Instance(); + auto procIdPtr = catalog.State->ProcByName.FindPtr(to_lower(name)); + if (!procIdPtr) { + return false; + } + + for (const auto& id : *procIdPtr) { + const auto& d = catalog.State->Procs.FindPtr(id); + Y_ENSURE(d); + if (d->Kind == kind) { + return true; + } + } + + return false; +} + bool HasReturnSetProc(const TString& name) { const auto& catalog = TCatalog::Instance(); auto procIdPtr = catalog.State->ProcByName.FindPtr(to_lower(name)); diff --git a/yql/essentials/parser/pg_catalog/catalog.h b/yql/essentials/parser/pg_catalog/catalog.h index 4dac35dd1c..e753f2ebc8 100644 --- a/yql/essentials/parser/pg_catalog/catalog.h +++ b/yql/essentials/parser/pg_catalog/catalog.h @@ -283,6 +283,7 @@ const TProcDesc& LookupProc(ui32 procId); std::variant<const TProcDesc*, const TTypeDesc*> LookupProcWithCasts(const TString& name, const TVector<ui32>& argTypeIds); bool HasReturnSetProc(const TString& name); void EnumProc(std::function<void(ui32, const TProcDesc&)> f); +bool HasProc(const TString& name, EProcKind kind); bool HasType(const TString& name); bool HasType(ui32 typeId); diff --git a/yql/essentials/parser/pg_catalog/safe_procs.h b/yql/essentials/parser/pg_catalog/safe_procs.h index be13dd59c0..475711e601 100644 --- a/yql/essentials/parser/pg_catalog/safe_procs.h +++ b/yql/essentials/parser/pg_catalog/safe_procs.h @@ -39,6 +39,9 @@ // postgis "postgis_lib_version", +"st_interiorringn", +"st_collectionhomogenize", +"st_makeline", //dbeaver "pg_get_expr", diff --git a/yql/essentials/sql/v1/SQLv1.g.in b/yql/essentials/sql/v1/SQLv1.g.in index 653fd7a4b0..9369b111a9 100644 --- a/yql/essentials/sql/v1/SQLv1.g.in +++ b/yql/essentials/sql/v1/SQLv1.g.in @@ -601,12 +601,12 @@ alter_external_data_source_action: drop_external_data_source_stmt: DROP EXTERNAL DATA SOURCE (IF EXISTS)? object_ref; -create_view_stmt: CREATE VIEW object_ref +create_view_stmt: CREATE VIEW (IF NOT EXISTS)? object_ref create_object_features? AS select_stmt ; -drop_view_stmt: DROP VIEW object_ref; +drop_view_stmt: DROP VIEW (IF EXISTS)? object_ref; upsert_object_stmt: UPSERT OBJECT object_ref LPAREN TYPE object_type_ref RPAREN diff --git a/yql/essentials/sql/v1/SQLv1Antlr4.g.in b/yql/essentials/sql/v1/SQLv1Antlr4.g.in index 875774323a..229b15dfae 100644 --- a/yql/essentials/sql/v1/SQLv1Antlr4.g.in +++ b/yql/essentials/sql/v1/SQLv1Antlr4.g.in @@ -600,12 +600,12 @@ alter_external_data_source_action: drop_external_data_source_stmt: DROP EXTERNAL DATA SOURCE (IF EXISTS)? object_ref; -create_view_stmt: CREATE VIEW object_ref +create_view_stmt: CREATE VIEW (IF NOT EXISTS)? object_ref create_object_features? AS select_stmt ; -drop_view_stmt: DROP VIEW object_ref; +drop_view_stmt: DROP VIEW (IF EXISTS)? object_ref; upsert_object_stmt: UPSERT OBJECT object_ref LPAREN TYPE object_type_ref RPAREN diff --git a/yql/essentials/sql/v1/builtin.cpp b/yql/essentials/sql/v1/builtin.cpp index e066cd846d..e327c2d2ea 100644 --- a/yql/essentials/sql/v1/builtin.cpp +++ b/yql/essentials/sql/v1/builtin.cpp @@ -3421,8 +3421,31 @@ TNodePtr BuildBuiltinFunc(TContext& ctx, TPosition pos, TString name, const TVec } } else if (ns == "datetime2" && (name == "Parse")) { return BuildUdf(ctx, pos, nameSpace, name, args); - } else if (ns == "pg") { - const bool isAggregateFunc = NYql::NPg::HasAggregation(name, NYql::NPg::EAggKind::Normal); + } else if (ns == "pg" || ns == "pgagg" || ns == "pgproc") { + bool isAggregateFunc = NYql::NPg::HasAggregation(name, NYql::NPg::EAggKind::Normal); + bool isNormalFunc = NYql::NPg::HasProc(name, NYql::NPg::EProcKind::Function); + if (!isAggregateFunc && !isNormalFunc) { + return new TInvalidBuiltin(pos, TStringBuilder() << "Unknown function: " << name); + } + + if (isAggregateFunc && isNormalFunc) { + if (ns == "pg") { + return new TInvalidBuiltin(pos, TStringBuilder() << "Ambigious function: " << name << ", use either PgAgg:: or PgProc:: namespace"); + } else if (ns == "pgagg") { + isNormalFunc = false; + } else { + isAggregateFunc = false; + } + } + + if (isAggregateFunc && ns == "pgproc") { + return new TInvalidBuiltin(pos, TStringBuilder() << "Invalid namespace for aggregation function: " << name << ", use either Pg:: or PgAgg:: namespace"); + } + + if (isNormalFunc && ns == "pgagg") { + return new TInvalidBuiltin(pos, TStringBuilder() << "Invalid namespace for normal function: " << name << ", use either Pg:: or PgProc:: namespace"); + } + if (isAggregateFunc) { if (aggMode == EAggregateMode::Distinct) { return new TInvalidBuiltin(pos, "Distinct is not supported yet for PG aggregation "); @@ -3430,6 +3453,7 @@ TNodePtr BuildBuiltinFunc(TContext& ctx, TPosition pos, TString name, const TVec return BuildAggrFuncFactoryCallback(name, "", EAggrFuncTypeCallback::PG)(pos, args, aggMode, false); } else { + YQL_ENSURE(isNormalFunc); TVector<TNodePtr> pgCallArgs; pgCallArgs.push_back(BuildLiteralRawString(pos, name)); pgCallArgs.insert(pgCallArgs.end(), args.begin(), args.end()); diff --git a/yql/essentials/sql/v1/format/sql_format_ut.h b/yql/essentials/sql/v1/format/sql_format_ut.h index 951bf42798..6d92bd29eb 100644 --- a/yql/essentials/sql/v1/format/sql_format_ut.h +++ b/yql/essentials/sql/v1/format/sql_format_ut.h @@ -1538,9 +1538,16 @@ Y_UNIT_TEST(ObfuscatePragma) { } Y_UNIT_TEST(CreateView) { - TCases cases = { - {"creAte vIEw TheView wiTh (security_invoker = trUE) As SELect 1", - "CREATE VIEW TheView WITH (security_invoker = TRUE) AS\nSELECT\n\t1;\n"}, + TCases cases = {{ + "creAte vIEw TheView As SELect 1", + "CREATE VIEW TheView AS\nSELECT\n\t1;\n" + }, { + "creAte vIEw If Not ExIsTs TheView As SELect 1", + "CREATE VIEW IF NOT EXISTS TheView AS\nSELECT\n\t1;\n" + }, { + "creAte vIEw TheView wiTh (option = tRuE) As SELect 1", + "CREATE VIEW TheView WITH (option = TRUE) AS\nSELECT\n\t1;\n" + } }; TSetup setup; @@ -1548,9 +1555,13 @@ Y_UNIT_TEST(CreateView) { } Y_UNIT_TEST(DropView) { - TCases cases = { - {"dRop viEW theVIEW", - "DROP VIEW theVIEW;\n"}, + TCases cases = {{ + "dRop viEW theVIEW", + "DROP VIEW theVIEW;\n" + }, { + "dRop viEW iF EXistS theVIEW", + "DROP VIEW IF EXISTS theVIEW;\n" + } }; TSetup setup; diff --git a/yql/essentials/sql/v1/sql_query.cpp b/yql/essentials/sql/v1/sql_query.cpp index d0fb8737e1..f3755bf6f0 100644 --- a/yql/essentials/sql/v1/sql_query.cpp +++ b/yql/essentials/sql/v1/sql_query.cpp @@ -1228,11 +1228,11 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core& break; } case TRule_sql_stmt_core::kAltSqlStmtCore42: { - // create_view_stmt: CREATE VIEW name WITH (k = v, ...) AS select_stmt; + // create_view_stmt: CREATE VIEW (IF NOT EXISTS)? name (WITH (k = v, ...))? AS select_stmt; auto& node = core.GetAlt_sql_stmt_core42().GetRule_create_view_stmt1(); TObjectOperatorContext context(Ctx.Scoped); - if (node.GetRule_object_ref3().HasBlock1()) { - if (!ClusterExpr(node.GetRule_object_ref3().GetBlock1().GetRule_cluster_expr1(), + if (node.GetRule_object_ref4().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref4().GetBlock1().GetRule_cluster_expr1(), false, context.ServiceId, context.Cluster)) { @@ -1240,34 +1240,36 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core& } } + const bool existingOk = node.HasBlock3(); + std::map<TString, TDeferredAtom> features; - if (node.HasBlock4()) { - if (!ParseObjectFeatures(features, node.GetBlock4().GetRule_create_object_features1().GetRule_object_features2())) { + if (node.HasBlock5()) { + if (!ParseObjectFeatures(features, node.GetBlock5().GetRule_create_object_features1().GetRule_object_features2())) { return false; } } - if (!ParseViewQuery(features, node.GetRule_select_stmt6())) { + if (!ParseViewQuery(features, node.GetRule_select_stmt7())) { return false; } - const TString objectId = Id(node.GetRule_object_ref3().GetRule_id_or_at2(), *this).second; + const TString objectId = Id(node.GetRule_object_ref4().GetRule_id_or_at2(), *this).second; constexpr const char* TypeId = "VIEW"; AddStatementToBlocks(blocks, BuildCreateObjectOperation(Ctx.Pos(), BuildTablePath(Ctx.GetPrefixPath(context.ServiceId, context.Cluster), objectId), TypeId, - false, + existingOk, false, std::move(features), context)); break; } case TRule_sql_stmt_core::kAltSqlStmtCore43: { - // drop_view_stmt: DROP VIEW name; + // drop_view_stmt: DROP VIEW (IF EXISTS)? name; auto& node = core.GetAlt_sql_stmt_core43().GetRule_drop_view_stmt1(); TObjectOperatorContext context(Ctx.Scoped); - if (node.GetRule_object_ref3().HasBlock1()) { - if (!ClusterExpr(node.GetRule_object_ref3().GetBlock1().GetRule_cluster_expr1(), + if (node.GetRule_object_ref4().HasBlock1()) { + if (!ClusterExpr(node.GetRule_object_ref4().GetBlock1().GetRule_cluster_expr1(), false, context.ServiceId, context.Cluster)) { @@ -1275,13 +1277,15 @@ bool TSqlQuery::Statement(TVector<TNodePtr>& blocks, const TRule_sql_stmt_core& } } - const TString objectId = Id(node.GetRule_object_ref3().GetRule_id_or_at2(), *this).second; + const bool missingOk = node.HasBlock3(); + + const TString objectId = Id(node.GetRule_object_ref4().GetRule_id_or_at2(), *this).second; constexpr const char* TypeId = "VIEW"; AddStatementToBlocks(blocks, BuildDropObjectOperation(Ctx.Pos(), BuildTablePath(Ctx.GetPrefixPath(context.ServiceId, context.Cluster), objectId), TypeId, - false, + missingOk, {}, context)); break; diff --git a/yql/essentials/sql/v1/sql_ut.cpp b/yql/essentials/sql/v1/sql_ut.cpp index 6663fe9765..a4251890a7 100644 --- a/yql/essentials/sql/v1/sql_ut.cpp +++ b/yql/essentials/sql/v1/sql_ut.cpp @@ -2533,8 +2533,8 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { const auto result = SqlToYql(R"(USE plato; CREATE TABLE table ( pk INT32 NOT NULL, - col String, - INDEX idx GLOBAL USING vector_kmeans_tree + col String, + INDEX idx GLOBAL USING vector_kmeans_tree ON (col) COVER (col) WITH (distance=cosine, vector_type=float, vector_dimension=1024,), PRIMARY KEY (pk)) @@ -2543,11 +2543,11 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { } Y_UNIT_TEST(AlterTableAddIndexVector) { - const auto result = SqlToYql(R"(USE plato; - ALTER TABLE table ADD INDEX idx - GLOBAL USING vector_kmeans_tree + const auto result = SqlToYql(R"(USE plato; + ALTER TABLE table ADD INDEX idx + GLOBAL USING vector_kmeans_tree ON (col) COVER (col) - WITH (distance=cosine, vector_type="float", vector_dimension=1024) + WITH (distance=cosine, vector_type="float", vector_dimension=1024) )"); UNIT_ASSERT_C(result.IsOk(), result.Issues.ToString()); } @@ -2558,11 +2558,11 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { } Y_UNIT_TEST(AlterTableAddIndexMissedParameter) { - ExpectFailWithError(R"(USE plato; - ALTER TABLE table ADD INDEX idx - GLOBAL USING vector_kmeans_tree + ExpectFailWithError(R"(USE plato; + ALTER TABLE table ADD INDEX idx + GLOBAL USING vector_kmeans_tree ON (col) - WITH (distance=cosine, vector_type=float) + WITH (distance=cosine, vector_type=float) )", "<main>:5:52: Error: vector_dimension should be set\n"); } @@ -2790,7 +2790,7 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { auto req = Sprintf(reqTpl, key.c_str(), value.c_str()); auto res = SqlToYql(req); UNIT_ASSERT(res.Root); - + TVerifyLineFunc verifyLine = [&key, &value](const TString& word, const TString& line) { if (word == "Write") { UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("MyReplication")); @@ -6716,6 +6716,28 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) { UNIT_ASSERT_C(res.Root, res.Issues.ToString()); } + Y_UNIT_TEST(CreateViewIfNotExists) { + constexpr const char* name = "TheView"; + NYql::TAstParseResult res = SqlToYql(std::format(R"( + USE plato; + CREATE VIEW IF NOT EXISTS {} WITH (security_invoker = TRUE) AS SELECT 1; + )", name + )); + UNIT_ASSERT_C(res.Root, res.Issues.ToString()); + + TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) { + if (word == "Write!") { + UNIT_ASSERT_STRING_CONTAINS(line, name); + UNIT_ASSERT_STRING_CONTAINS(line, "createObjectIfNotExists"); + } + }; + + TWordCountHive elementStat = { {"Write!"} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); + } + Y_UNIT_TEST(CreateViewFromTable) { constexpr const char* path = "/PathPrefix/TheView"; constexpr const char* query = R"( @@ -6795,6 +6817,28 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) { UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); } + Y_UNIT_TEST(DropViewIfExists) { + constexpr const char* name = "TheView"; + NYql::TAstParseResult res = SqlToYql(std::format(R"( + USE plato; + DROP VIEW IF EXISTS {}; + )", name + )); + UNIT_ASSERT_C(res.Root, res.Issues.ToString()); + + TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) { + if (word == "Write!") { + UNIT_ASSERT_STRING_CONTAINS(line, name); + UNIT_ASSERT_STRING_CONTAINS(line, "dropObjectIfExists"); + } + }; + + TWordCountHive elementStat = { {"Write!"} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); + } + Y_UNIT_TEST(CreateViewWithTablePrefix) { NYql::TAstParseResult res = SqlToYql(R"( USE plato; @@ -6838,7 +6882,7 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) { UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); } - + Y_UNIT_TEST(YtAlternativeSchemaSyntax) { NYql::TAstParseResult res = SqlToYql(R"( SELECT * FROM plato.Input WITH schema(y Int32, x String not null); @@ -6907,7 +6951,7 @@ Y_UNIT_TEST_SUITE(CompactNamedExprs) { pragma CompactNamedExprs; pragma ValidateUnusedExprs; - define subquery $x() as + define subquery $x() as select count(1, 2); end define; select 1; @@ -6930,7 +6974,7 @@ Y_UNIT_TEST_SUITE(CompactNamedExprs) { pragma CompactNamedExprs; pragma DisableValidateUnusedExprs; - define subquery $x() as + define subquery $x() as select count(1, 2); end define; select 1; diff --git a/yql/essentials/sql/v1/sql_ut_antlr4.cpp b/yql/essentials/sql/v1/sql_ut_antlr4.cpp index b92ea5f460..29a306cddf 100644 --- a/yql/essentials/sql/v1/sql_ut_antlr4.cpp +++ b/yql/essentials/sql/v1/sql_ut_antlr4.cpp @@ -2533,8 +2533,8 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { const auto result = SqlToYql(R"(USE plato; CREATE TABLE table ( pk INT32 NOT NULL, - col String, - INDEX idx GLOBAL USING vector_kmeans_tree + col String, + INDEX idx GLOBAL USING vector_kmeans_tree ON (col) COVER (col) WITH (distance=cosine, vector_type=float, vector_dimension=1024,), PRIMARY KEY (pk)) @@ -2543,11 +2543,11 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { } Y_UNIT_TEST(AlterTableAddIndexVector) { - const auto result = SqlToYql(R"(USE plato; - ALTER TABLE table ADD INDEX idx - GLOBAL USING vector_kmeans_tree + const auto result = SqlToYql(R"(USE plato; + ALTER TABLE table ADD INDEX idx + GLOBAL USING vector_kmeans_tree ON (col) COVER (col) - WITH (distance=cosine, vector_type="float", vector_dimension=1024) + WITH (distance=cosine, vector_type="float", vector_dimension=1024) )"); UNIT_ASSERT_C(result.IsOk(), result.Issues.ToString()); } @@ -2558,11 +2558,11 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { } Y_UNIT_TEST(AlterTableAddIndexMissedParameter) { - ExpectFailWithError(R"(USE plato; - ALTER TABLE table ADD INDEX idx - GLOBAL USING vector_kmeans_tree + ExpectFailWithError(R"(USE plato; + ALTER TABLE table ADD INDEX idx + GLOBAL USING vector_kmeans_tree ON (col) - WITH (distance=cosine, vector_type=float) + WITH (distance=cosine, vector_type=float) )", "<main>:5:52: Error: vector_dimension should be set\n"); } @@ -2790,7 +2790,7 @@ Y_UNIT_TEST_SUITE(SqlParsingOnly) { auto req = Sprintf(reqTpl, key.c_str(), value.c_str()); auto res = SqlToYql(req); UNIT_ASSERT(res.Root); - + TVerifyLineFunc verifyLine = [&key, &value](const TString& word, const TString& line) { if (word == "Write") { UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("MyReplication")); @@ -6713,6 +6713,28 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) { UNIT_ASSERT_C(res.Root, res.Issues.ToString()); } + Y_UNIT_TEST(CreateViewIfNotExists) { + constexpr const char* name = "TheView"; + NYql::TAstParseResult res = SqlToYql(std::format(R"( + USE plato; + CREATE VIEW IF NOT EXISTS {} AS SELECT 1; + )", name + )); + UNIT_ASSERT_C(res.Root, res.Issues.ToString()); + + TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) { + if (word == "Write!") { + UNIT_ASSERT_STRING_CONTAINS(line, name); + UNIT_ASSERT_STRING_CONTAINS(line, "createObjectIfNotExists"); + } + }; + + TWordCountHive elementStat = { {"Write!"} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); + } + Y_UNIT_TEST(CreateViewFromTable) { constexpr const char* path = "/PathPrefix/TheView"; constexpr const char* query = R"( @@ -6792,6 +6814,28 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) { UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); } + Y_UNIT_TEST(DropViewIfExists) { + constexpr const char* name = "TheView"; + NYql::TAstParseResult res = SqlToYql(std::format(R"( + USE plato; + DROP VIEW IF EXISTS {}; + )", name + )); + UNIT_ASSERT_C(res.Root, res.Issues.ToString()); + + TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) { + if (word == "Write!") { + UNIT_ASSERT_STRING_CONTAINS(line, name); + UNIT_ASSERT_STRING_CONTAINS(line, "dropObjectIfExists"); + } + }; + + TWordCountHive elementStat = { {"Write!"} }; + VerifyProgram(res, elementStat, verifyLine); + + UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); + } + Y_UNIT_TEST(CreateViewWithTablePrefix) { NYql::TAstParseResult res = SqlToYql(R"( USE plato; @@ -6835,7 +6879,7 @@ Y_UNIT_TEST_SUITE(TViewSyntaxTest) { UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1); } - + Y_UNIT_TEST(YtAlternativeSchemaSyntax) { NYql::TAstParseResult res = SqlToYql(R"( SELECT * FROM plato.Input WITH schema(y Int32, x String not null); @@ -6904,7 +6948,7 @@ Y_UNIT_TEST_SUITE(CompactNamedExprs) { pragma CompactNamedExprs; pragma ValidateUnusedExprs; - define subquery $x() as + define subquery $x() as select count(1, 2); end define; select 1; @@ -6927,7 +6971,7 @@ Y_UNIT_TEST_SUITE(CompactNamedExprs) { pragma CompactNamedExprs; pragma DisableValidateUnusedExprs; - define subquery $x() as + define subquery $x() as select count(1, 2); end define; select 1; diff --git a/yql/essentials/udfs/common/unicode_base/lib/unicode_base_udf.h b/yql/essentials/udfs/common/unicode_base/lib/unicode_base_udf.h index 6cbf4b493a..2155a2d626 100644 --- a/yql/essentials/udfs/common/unicode_base/lib/unicode_base_udf.h +++ b/yql/essentials/udfs/common/unicode_base/lib/unicode_base_udf.h @@ -107,6 +107,10 @@ namespace { const int base = static_cast<int>(args[1].GetOrDefault<ui16>(0)); char* pos = nullptr; unsigned long long res = std::strtoull(input, &pos, base); + if (!res && errno == EINVAL) { + UdfTerminate("Incorrect base"); + } + ui64 ret = static_cast<ui64>(res); if (!res && pos == input) { UdfTerminate("Input string is not a number"); @@ -125,6 +129,10 @@ namespace { const int base = static_cast<int>(args[1].GetOrDefault<ui16>(0)); char* pos = nullptr; unsigned long long res = std::strtoull(input, &pos, base); + if (!res && errno == EINVAL) { + return TUnboxedValuePod(); + } + ui64 ret = static_cast<ui64>(res); if (!res && pos == input) { return TUnboxedValuePod(); diff --git a/yql/essentials/udfs/common/unicode_base/test/canondata/result.json b/yql/essentials/udfs/common/unicode_base/test/canondata/result.json index 0b47a67444..c9012f2333 100644 --- a/yql/essentials/udfs/common/unicode_base/test/canondata/result.json +++ b/yql/essentials/udfs/common/unicode_base/test/canondata/result.json @@ -44,6 +44,11 @@ "uri": "file://test.test_ToUint64F2_/extracted" } ], + "test.test[ToUint64F3]": [ + { + "uri": "file://test.test_ToUint64F3_/extracted" + } + ], "test.test[ToUint64]": [ { "uri": "file://test.test_ToUint64_/results.txt" diff --git a/yql/essentials/udfs/common/unicode_base/test/canondata/test.test_ToUint64F3_/extracted b/yql/essentials/udfs/common/unicode_base/test/canondata/test.test_ToUint64F3_/extracted new file mode 100644 index 0000000000..23c6342305 --- /dev/null +++ b/yql/essentials/udfs/common/unicode_base/test/canondata/test.test_ToUint64F3_/extracted @@ -0,0 +1,8 @@ +<tmp_path>/program.sql:<main>: Fatal: Execution + + <tmp_path>/program.sql:<main>:2:1: Fatal: Execution of node: Result + SELECT + ^ + <tmp_path>/program.sql:<main>:2:1: Fatal: Incorrect base + SELECT + ^
\ No newline at end of file diff --git a/yql/essentials/udfs/common/unicode_base/test/canondata/test.test_TryToUint64_/results.txt b/yql/essentials/udfs/common/unicode_base/test/canondata/test.test_TryToUint64_/results.txt index 594ac1486c..b2afcec500 100644 --- a/yql/essentials/udfs/common/unicode_base/test/canondata/test.test_TryToUint64_/results.txt +++ b/yql/essentials/udfs/common/unicode_base/test/canondata/test.test_TryToUint64_/results.txt @@ -103,6 +103,35 @@ "Uint64" ] ] + ] + ] + ] + ]; + "Data" = [ + [ + # + ] + ] + } + ] + }; + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "column0"; + [ + "OptionalType"; + [ + "DataType"; + "Uint64" + ] + ] ]; [ "column1"; diff --git a/yql/essentials/udfs/common/unicode_base/test/cases/ToUint64F3.cfg b/yql/essentials/udfs/common/unicode_base/test/cases/ToUint64F3.cfg new file mode 100644 index 0000000000..83cfd96179 --- /dev/null +++ b/yql/essentials/udfs/common/unicode_base/test/cases/ToUint64F3.cfg @@ -0,0 +1,2 @@ +xfail + diff --git a/yql/essentials/udfs/common/unicode_base/test/cases/ToUint64F3.sql b/yql/essentials/udfs/common/unicode_base/test/cases/ToUint64F3.sql new file mode 100644 index 0000000000..527fb1da1b --- /dev/null +++ b/yql/essentials/udfs/common/unicode_base/test/cases/ToUint64F3.sql @@ -0,0 +1,3 @@ +SELECT + Unicode::ToUint64("0",1); + diff --git a/yql/essentials/udfs/common/unicode_base/test/cases/TryToUint64.sql b/yql/essentials/udfs/common/unicode_base/test/cases/TryToUint64.sql index b2f4fa850a..c4b0aa609f 100644 --- a/yql/essentials/udfs/common/unicode_base/test/cases/TryToUint64.sql +++ b/yql/essentials/udfs/common/unicode_base/test/cases/TryToUint64.sql @@ -8,6 +8,9 @@ SELECT Unicode::TryToUint64("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16); SELECT + Unicode::TryToUint64("0", 1); + +SELECT Unicode::TryToUint64("0x1234abcd", 16), Unicode::TryToUint64("0X4", 16), Unicode::TryToUint64("0644", 8), |