aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitalii Gridnev <gridnevvvit@gmail.com>2024-02-09 18:59:24 +0300
committerGitHub <noreply@github.com>2024-02-09 18:59:24 +0300
commit449285f5cf1b4b145fba1237bb7bc5170cc31db9 (patch)
tree6e84a039c2e9eff937f3237ec4b7c1729f194381
parentc0e24ba523a992c8c397f1af60dcdad2675f2ab2 (diff)
downloadydb-449285f5cf1b4b145fba1237bb7bc5170cc31db9.tar.gz
support cast in default values (#1754)
-rw-r--r--ydb/core/kqp/provider/yql_kikimr_datasink.cpp45
-rw-r--r--ydb/core/kqp/provider/yql_kikimr_type_ann.cpp45
-rw-r--r--ydb/core/kqp/ut/pg/kqp_pg_ut.cpp43
3 files changed, 117 insertions, 16 deletions
diff --git a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp
index 9c6243f35c..ff58db6e9f 100644
--- a/ydb/core/kqp/provider/yql_kikimr_datasink.cpp
+++ b/ydb/core/kqp/provider/yql_kikimr_datasink.cpp
@@ -787,7 +787,7 @@ public:
auto replaceIfExists = (settings.Mode.Cast().Value() == "create_or_replace");
auto existringOk = (settings.Mode.Cast().Value() == "create_if_not_exists");
- return Build<TKiCreateTable>(ctx, node->Pos())
+ auto createTable = Build<TKiCreateTable>(ctx, node->Pos())
.World(node->Child(0))
.DataSink(node->Child(1))
.Table().Build(key.GetTablePath())
@@ -807,8 +807,47 @@ public:
.ExistingOk<TCoAtom>()
.Value(existringOk)
.Build()
- .Done()
- .Ptr();
+ .Done();
+
+ bool exprEvalNeeded = false;
+
+ for(auto item: createTable.Cast<TKiCreateTable>().Columns()) {
+ auto columnTuple = item.Cast<TExprList>();
+ if (columnTuple.Size() > 2) {
+ const auto& columnConstraints = columnTuple.Item(2).Cast<TCoNameValueTuple>();
+ for(const auto& constraint: columnConstraints.Value().Cast<TCoNameValueTupleList>()) {
+ if (constraint.Name().Value() != "default")
+ continue;
+
+ YQL_ENSURE(constraint.Value().IsValid());
+ bool shouldEvaluate = (
+ constraint.Value().Cast().Ptr()->IsCallable() &&
+ (constraint.Value().Cast().Ptr()->Content() == "PgCast") &&
+ (constraint.Value().Cast().Ptr()->ChildrenSize() >= 1) &&
+ (constraint.Value().Cast().Ptr()->Child(0)->IsCallable()) &&
+ (constraint.Value().Cast().Ptr()->Child(0)->Content() == "PgConst")
+ );
+
+ if (shouldEvaluate) {
+ auto evaluatedExpr = ctx.Builder(constraint.Value().Cast().Ptr()->Pos())
+ .Callable("EvaluateExpr")
+ .Add(0, constraint.Value().Cast().Ptr())
+ .Seal()
+ .Build();
+
+ constraint.Ptr()->ChildRef(TCoNameValueTuple::idx_Value) = evaluatedExpr;
+ exprEvalNeeded = true;
+ }
+ }
+ }
+ }
+
+ if (exprEvalNeeded) {
+ ctx.Step.Repeat(TExprStep::ExprEval);
+ }
+
+ return createTable.Ptr();
+
} else if (mode == "alter") {
for (auto setting : settings.Other) {
if (setting.Name().Value() == "intent") {
diff --git a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp
index e2bbc5db7c..9db48a960e 100644
--- a/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp
+++ b/ydb/core/kqp/provider/yql_kikimr_type_ann.cpp
@@ -808,7 +808,13 @@ virtual TStatus HandleCreateTable(TKiCreateTable create, TExprContext& ctx) over
columnMeta.SetDefaultFromLiteral();
- if (auto pgConst = constraint.Value().Maybe<TCoPgConst>()) {
+ YQL_ENSURE(constraint.Value().IsValid());
+ const auto& constrValue = constraint.Value().Cast();
+ bool isPgNull = constrValue.Ptr()->IsCallable() &&
+ constrValue.Ptr()->Content() == "PgCast" && constrValue.Ptr()->ChildrenSize() >= 1 &&
+ constrValue.Ptr()->Child(0)->IsCallable() && constrValue.Ptr()->Child(0)->Content() == "Null";
+
+ if (constrValue.Maybe<TCoPgConst>() || isPgNull) {
auto actualPgType = actualType->Cast<TPgExprType>();
YQL_ENSURE(actualPgType);
@@ -819,25 +825,38 @@ virtual TStatus HandleCreateTable(TKiCreateTable create, TExprContext& ctx) over
return TStatus::Error;
}
- TString content = TString(pgConst.Cast().Value().Value());
- auto parseResult = NKikimr::NPg::PgNativeBinaryFromNativeText(content, typeDesc);
- if (parseResult.Error) {
- ctx.AddError(TIssue(ctx.GetPosition(constraint.Pos()),
- TStringBuilder() << "Failed to parse default expr for typename " << actualPgType->GetName()
- << ", error reason: " << *parseResult.Error));
- return TStatus::Error;
+ if (isPgNull) {
+ if (columnMeta.NotNull) {
+ ctx.AddError(TIssue(ctx.GetPosition(constraint.Pos()), TStringBuilder() << "Default expr " << columnName
+ << " is nullable or optional, but column has not null constraint. "));
+ return TStatus::Error;
+ }
+
+ columnMeta.DefaultFromLiteral.mutable_value()->set_null_flag_value(NProtoBuf::NULL_VALUE);
+
+ } else {
+ YQL_ENSURE(constrValue.Maybe<TCoPgConst>());
+ auto pgConst = constrValue.Cast<TCoPgConst>();
+ TString content = TString(pgConst.Value().Value());
+ auto parseResult = NKikimr::NPg::PgNativeBinaryFromNativeText(content, typeDesc);
+ if (parseResult.Error) {
+ ctx.AddError(TIssue(ctx.GetPosition(constraint.Pos()),
+ TStringBuilder() << "Failed to parse default expr for typename " << actualPgType->GetName()
+ << ", error reason: " << *parseResult.Error));
+ return TStatus::Error;
+ }
+
+ columnMeta.DefaultFromLiteral.mutable_value()->set_bytes_value(parseResult.Str);
}
- columnMeta.DefaultFromLiteral.mutable_value()->set_bytes_value(parseResult.Str);
auto* pg = columnMeta.DefaultFromLiteral.mutable_type()->mutable_pg_type();
-
pg->set_type_name(NKikimr::NPg::PgTypeNameFromTypeDesc(typeDesc));
pg->set_oid(NKikimr::NPg::PgTypeIdFromTypeDesc(typeDesc));
- } else if (auto literal = constraint.Value().Maybe<TCoDataCtor>()) {
- FillLiteralProto(constraint.Value().Cast<TCoDataCtor>(), columnMeta.DefaultFromLiteral);
+ } else if (auto literal = constrValue.Maybe<TCoDataCtor>()) {
+ FillLiteralProto(literal.Cast(), columnMeta.DefaultFromLiteral);
} else {
ctx.AddError(TIssue(ctx.GetPosition(constraint.Pos()),
- TStringBuilder() << "Unsupported type of default value " << constraint.Value().Cast().Ptr()->Content()));
+ TStringBuilder() << "Unsupported type of default value"));
return TStatus::Error;
}
diff --git a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
index 6eaabcfc43..1066a40bc5 100644
--- a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
+++ b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
@@ -3401,6 +3401,49 @@ Y_UNIT_TEST_SUITE(KqpPg) {
}
}
+ Y_UNIT_TEST(InsertValuesFromTableWithDefaultAndCast) {
+ NKikimrConfig::TAppConfig appConfig;
+ appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true);
+ auto setting = NKikimrKqp::TKqpSetting();
+ auto serverSettings = TKikimrSettings()
+ .SetAppConfig(appConfig)
+ .SetKqpSettings({setting});
+ TKikimrRunner kikimr(serverSettings.SetWithSampleTables(false));
+ auto db = kikimr.GetQueryClient();
+ auto settings = NYdb::NQuery::TExecuteQuerySettings().Syntax(NYdb::NQuery::ESyntax::Pg);
+ {
+ auto result = db.ExecuteQuery(R"(
+ CREATE TABLE t (
+ a INT,
+ b int DEFAULT 5::int4,
+ c int DEFAULT '7'::int4,
+ d varchar(20) DEFAULT 'foo'::varchar(2),
+ e int DEFAULT NULL,
+ f bit varying(5) DEFAULT '1001',
+ PRIMARY KEY(a)
+ );
+ )", NYdb::NQuery::TTxControl::NoTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+ {
+ auto result = db.ExecuteQuery(R"(
+ INSERT INTO t VALUES(1);
+ )", NYdb::NQuery::TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ }
+ {
+ auto result = db.ExecuteQuery(R"(
+ SELECT * FROM t;
+ )", NYdb::NQuery::TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+
+ UNIT_ASSERT_C(!result.GetResultSets().empty(), "results are empty");
+ CompareYson(R"(
+ [["1";"5";"7";"fo";#;"1001"]]
+ )", FormatResultSetYson(result.GetResultSet(0)));
+ }
+ }
+
Y_UNIT_TEST(InsertValuesFromTableWithDefaultBool) {
NKikimrConfig::TAppConfig appConfig;
appConfig.MutableTableServiceConfig()->SetEnablePreparedDdl(true);