|
@@ -12,6 +12,7 @@
|
|
|
#include <ydb/library/yql/parser/pg_wrapper/interface/utils.h>
|
|
|
|
|
|
#include <util/generic/set.h>
|
|
|
+#include <util/generic/hash.h>
|
|
|
|
|
|
namespace NYql {
|
|
|
|
|
@@ -64,8 +65,8 @@ bool ValidateInputTypes(TExprNode& node, TExprContext& ctx) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-TExprNodePtr WrapWithPgCast(TExprNodePtr&& node, ui32 targetTypeId, TContext& ctx) {
|
|
|
- return ctx.Expr.Builder(node->Pos())
|
|
|
+TExprNodePtr WrapWithPgCast(TExprNodePtr&& node, ui32 targetTypeId, TExprContext& ctx) {
|
|
|
+ return ctx.Builder(node->Pos())
|
|
|
.Callable("PgCast")
|
|
|
.Add(0, std::move(node))
|
|
|
.Callable(1, "PgType")
|
|
@@ -75,6 +76,113 @@ TExprNodePtr WrapWithPgCast(TExprNodePtr&& node, ui32 targetTypeId, TContext& ct
|
|
|
.Build();
|
|
|
};
|
|
|
|
|
|
+TExprNodePtr FindLeftCombinatorOfNthSetItem(const TExprNode* setItems, const TExprNode* setOps, ui32 n) {
|
|
|
+ TVector<ui32> setItemsStack(setItems->ChildrenSize());
|
|
|
+ i32 sp = -1;
|
|
|
+ ui32 itemIdx = 0;
|
|
|
+ for (const auto& op : setOps->Children()) {
|
|
|
+ if (op->Content() == "push") {
|
|
|
+ setItemsStack[++sp] = itemIdx++;
|
|
|
+ } else {
|
|
|
+ if (setItemsStack[sp] == n) {
|
|
|
+ return op;
|
|
|
+ }
|
|
|
+ --sp;
|
|
|
+ Y_ENSURE(0 <= sp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Y_UNREACHABLE();
|
|
|
+}
|
|
|
+
|
|
|
+IGraphTransformer::TStatus InferPgCommonType(TPositionHandle pos, const TExprNode* setItems, const TExprNode* setOps,
|
|
|
+ TColumnOrder& resultColumnOrder, const TStructExprType*& resultStructType, TExtContext& ctx)
|
|
|
+{
|
|
|
+ TVector<TVector<ui32>> pgTypes;
|
|
|
+ size_t fieldsCnt = 0;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < setItems->ChildrenSize(); ++i) {
|
|
|
+ const auto* child = setItems->Child(i);
|
|
|
+
|
|
|
+ if (!EnsureListType(*child, ctx.Expr)) {
|
|
|
+ return IGraphTransformer::TStatus::Error;
|
|
|
+ }
|
|
|
+ auto itemType = child->GetTypeAnn()->Cast<TListExprType>()->GetItemType();
|
|
|
+ YQL_ENSURE(itemType);
|
|
|
+
|
|
|
+ if (!EnsureStructType(child->Pos(), *itemType, ctx.Expr)) {
|
|
|
+ return IGraphTransformer::TStatus::Error;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto childColumnOrder = ctx.Types.LookupColumnOrder(*child);
|
|
|
+ if (!childColumnOrder) {
|
|
|
+ ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(child->Pos()), TStringBuilder()
|
|
|
+ << "Input #" << i << " does not have ordered columns. "
|
|
|
+ << "Consider making column order explicit by using SELECT with column names"));
|
|
|
+ return IGraphTransformer::TStatus::Error;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (0 == i) {
|
|
|
+ resultColumnOrder = *childColumnOrder;
|
|
|
+ fieldsCnt = resultColumnOrder.size();
|
|
|
+
|
|
|
+ pgTypes.resize(fieldsCnt);
|
|
|
+ for (size_t j = 0; j < fieldsCnt; ++j) {
|
|
|
+ pgTypes[j].reserve(setItems->ChildrenSize());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ((*childColumnOrder).size() != fieldsCnt) {
|
|
|
+ TExprNodePtr combinator = FindLeftCombinatorOfNthSetItem(setItems, setOps, i);
|
|
|
+ Y_ENSURE(combinator);
|
|
|
+
|
|
|
+ TString op(combinator->Content());
|
|
|
+ if (op.EndsWith("_all")) {
|
|
|
+ op.erase(op.length() - 4);
|
|
|
+ }
|
|
|
+ op.to_upper();
|
|
|
+
|
|
|
+ ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(child->Pos()), TStringBuilder()
|
|
|
+ << "each " << op << " query must have the same number of columns"));
|
|
|
+
|
|
|
+ return IGraphTransformer::TStatus::Error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const auto structType = itemType->Cast<TStructExprType>();
|
|
|
+ {
|
|
|
+ size_t j = 0;
|
|
|
+ for (const auto& col : *childColumnOrder) {
|
|
|
+ auto itemIdx = structType->FindItem(col);
|
|
|
+ YQL_ENSURE(itemIdx);
|
|
|
+ pgTypes[j].push_back(structType->GetItems()[*itemIdx]->GetItemType()->Cast<TPgExprType>()->GetId());
|
|
|
+
|
|
|
+ ++j;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ TVector<const TItemExprType*> structItems;
|
|
|
+ for (size_t j = 0; j < fieldsCnt; ++j) {
|
|
|
+ const NPg::TTypeDesc* commonType;
|
|
|
+ if (const auto issue = NPg::LookupCommonType(pgTypes[j],
|
|
|
+ [j, &setItems, &ctx](size_t i) {
|
|
|
+ return ctx.Expr.GetPosition(setItems->Child(i)->Child(j)->Pos());
|
|
|
+ }, commonType))
|
|
|
+ {
|
|
|
+ ctx.Expr.AddError(*issue);
|
|
|
+ return IGraphTransformer::TStatus::Error;
|
|
|
+ }
|
|
|
+ structItems.push_back(ctx.Expr.MakeType<TItemExprType>(resultColumnOrder[j],
|
|
|
+ ctx.Expr.MakeType<TPgExprType>(commonType->TypeId)));
|
|
|
+ }
|
|
|
+
|
|
|
+ resultStructType = ctx.Expr.MakeType<TStructExprType>(structItems);
|
|
|
+ if (!resultStructType->Validate(pos, ctx.Expr)) {
|
|
|
+ return IGraphTransformer::TStatus::Error;
|
|
|
+ }
|
|
|
+
|
|
|
+ return IGraphTransformer::TStatus::Ok;
|
|
|
+}
|
|
|
+
|
|
|
IGraphTransformer::TStatus PgStarWrapper(const TExprNode::TPtr& input, TExprNode::TPtr& output, TContext& ctx) {
|
|
|
Y_UNUSED(output);
|
|
|
if (!EnsureArgsCount(*input, 0, ctx.Expr)) {
|
|
@@ -212,12 +320,12 @@ IGraphTransformer::TStatus PgCallWrapper(const TExprNode::TPtr& input, TExprNode
|
|
|
const auto& fargTypes = (*procPtr)->ArgTypes;
|
|
|
for (size_t i = 0; i < argTypes.size(); ++i) {
|
|
|
if (IsCastRequired(argTypes[i], fargTypes[i])) {
|
|
|
- children[i+3] = WrapWithPgCast(std::move(children[i+3]), fargTypes[i], ctx);
|
|
|
+ children[i+3] = WrapWithPgCast(std::move(children[i+3]), fargTypes[i], ctx.Expr);
|
|
|
}
|
|
|
}
|
|
|
output = ctx.Expr.NewCallable(input->Pos(), "PgResolvedCall", std::move(children));
|
|
|
} else if (const auto* typePtr = std::get_if<const NPg::TTypeDesc*>(&procOrType)) {
|
|
|
- output = WrapWithPgCast(std::move(children[2]), (*typePtr)->TypeId, ctx);
|
|
|
+ output = WrapWithPgCast(std::move(children[2]), (*typePtr)->TypeId, ctx.Expr);
|
|
|
} else {
|
|
|
Y_UNREACHABLE();
|
|
|
}
|
|
@@ -454,16 +562,16 @@ IGraphTransformer::TStatus PgOpWrapper(const TExprNode::TPtr& input, TExprNode::
|
|
|
switch(oper.Kind) {
|
|
|
case NPg::EOperKind::LeftUnary:
|
|
|
if (IsCastRequired(argTypes[0], oper.RightType)) {
|
|
|
- children[1] = WrapWithPgCast(std::move(children[1]), oper.RightType, ctx);
|
|
|
+ children[1] = WrapWithPgCast(std::move(children[1]), oper.RightType, ctx.Expr);
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case NYql::NPg::EOperKind::Binary:
|
|
|
if (IsCastRequired(argTypes[0], oper.LeftType)) {
|
|
|
- children[1] = WrapWithPgCast(std::move(children[1]), oper.LeftType, ctx);
|
|
|
+ children[1] = WrapWithPgCast(std::move(children[1]), oper.LeftType, ctx.Expr);
|
|
|
}
|
|
|
if (IsCastRequired(argTypes[1], oper.RightType)) {
|
|
|
- children[2] = WrapWithPgCast(std::move(children[2]), oper.RightType, ctx);
|
|
|
+ children[2] = WrapWithPgCast(std::move(children[2]), oper.RightType, ctx.Expr);
|
|
|
}
|
|
|
break;
|
|
|
|
|
@@ -648,7 +756,7 @@ IGraphTransformer::TStatus PgAggWrapper(const TExprNode::TPtr& input, TExprNode:
|
|
|
for (ui32 i = 0; i < argTypes.size(); ++i, ++argIdx) {
|
|
|
if (IsCastRequired(argTypes[i], aggDesc.ArgTypes[i])) {
|
|
|
auto& argNode = input->ChildRef(argIdx);
|
|
|
- argNode = WrapWithPgCast(std::move(argNode), aggDesc.ArgTypes[i], ctx);
|
|
|
+ argNode = WrapWithPgCast(std::move(argNode), aggDesc.ArgTypes[i], ctx.Expr);
|
|
|
needRetype = true;
|
|
|
}
|
|
|
}
|
|
@@ -4155,7 +4263,7 @@ IGraphTransformer::TStatus PgValuesListWrapper(const TExprNode::TPtr& input, TEx
|
|
|
if (item->GetTypeAnn()->Cast<TPgExprType>()->GetId() == commonTypes[j]) {
|
|
|
rowValues.push_back(item);
|
|
|
} else {
|
|
|
- rowValues.push_back(WrapWithPgCast(std::move(item), commonTypes[j], ctx));
|
|
|
+ rowValues.push_back(WrapWithPgCast(std::move(item), commonTypes[j], ctx.Expr));
|
|
|
}
|
|
|
}
|
|
|
resultValues.push_back(ctx.Expr.NewList(value->Pos(), std::move(rowValues)));
|
|
@@ -4338,7 +4446,11 @@ IGraphTransformer::TStatus PgSelectWrapper(const TExprNode::TPtr& input, TExprNo
|
|
|
|
|
|
TColumnOrder resultColumnOrder;
|
|
|
const TStructExprType* resultStructType = nullptr;
|
|
|
- auto status = InferPositionalUnionType(input->Pos(), setItems->ChildrenList(), resultColumnOrder, resultStructType, ctx);
|
|
|
+
|
|
|
+ auto status = (1 == setItems->ChildrenSize() && HasSetting(*setItems->Child(0)->Child(0), "unknowns_allowed"))
|
|
|
+ ? InferPositionalUnionType(input->Pos(), setItems->ChildrenList(), resultColumnOrder, resultStructType, ctx)
|
|
|
+ : InferPgCommonType(input->Pos(), setItems, setOps, resultColumnOrder, resultStructType, ctx);
|
|
|
+
|
|
|
if (status != IGraphTransformer::TStatus::Ok) {
|
|
|
return status;
|
|
|
}
|
|
@@ -4471,7 +4583,7 @@ IGraphTransformer::TStatus PgArrayWrapper(const TExprNode::TPtr& input, TExprNod
|
|
|
if (argTypes[i] == elemType) {
|
|
|
castArrayElems.push_back(child);
|
|
|
} else {
|
|
|
- castArrayElems.push_back(WrapWithPgCast(std::move(child), elemType, ctx));
|
|
|
+ castArrayElems.push_back(WrapWithPgCast(std::move(child), elemType, ctx.Expr));
|
|
|
}
|
|
|
}
|
|
|
output = ctx.Expr.NewCallable(input->Pos(), "PgArray", std::move(castArrayElems));
|
|
@@ -4587,7 +4699,7 @@ IGraphTransformer::TStatus PgLikeWrapper(const TExprNode::TPtr& input, TExprNode
|
|
|
if (argTypes[i] != textTypeId) {
|
|
|
if (argTypes[i] == NPg::UnknownOid) {
|
|
|
auto& argNode = input->ChildRef(i);
|
|
|
- argNode = WrapWithPgCast(std::move(argNode), textTypeId, ctx);
|
|
|
+ argNode = WrapWithPgCast(std::move(argNode), textTypeId, ctx.Expr);
|
|
|
return IGraphTransformer::TStatus::Repeat;
|
|
|
}
|
|
|
ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(input->Pos()),
|
|
@@ -4656,7 +4768,7 @@ IGraphTransformer::TStatus PgInWrapper(const TExprNode::TPtr& input, TExprNode::
|
|
|
if (itemTypePg && inputTypePg && itemTypePg != inputTypePg) {
|
|
|
if (inputTypePg == NPg::UnknownOid) {
|
|
|
|
|
|
- input->ChildRef(0) = WrapWithPgCast(std::move(input->Child(0)), itemTypePg, ctx);
|
|
|
+ input->ChildRef(0) = WrapWithPgCast(std::move(input->Child(0)), itemTypePg, ctx.Expr);
|
|
|
return IGraphTransformer::TStatus::Repeat;
|
|
|
}
|
|
|
if (itemTypePg == NPg::UnknownOid) {
|