@@ -1520,12 +1520,9 @@ class TConverter : public IPGParseEvents {
1520
1520
}
1521
1521
} else if (NodeTag(r->val) == T_FuncCall) {
1522
1522
auto func = CAST_NODE(FuncCall, r->val);
1523
- TVector<TString> names;
1524
- if (!ExtractFuncName(func, names)) {
1523
+ if (!ExtractFuncName(func, name, nullptr)) {
1525
1524
return nullptr;
1526
1525
}
1527
-
1528
- name = names.back();
1529
1526
}
1530
1527
}
1531
1528
@@ -3427,12 +3424,13 @@ class TConverter : public IPGParseEvents {
3427
3424
return {};
3428
3425
}
3429
3426
3430
- auto func = ParseFuncCall(CAST_NODE(FuncCall, node), settings, true);
3427
+ bool injectRead = false;
3428
+ auto func = ParseFuncCall(CAST_NODE(FuncCall, node), settings, true, injectRead);
3431
3429
if (!func) {
3432
3430
return {};
3433
3431
}
3434
3432
3435
- return TFromDesc{ func, alias, colnames, false };
3433
+ return TFromDesc{ func, alias, colnames, injectRead };
3436
3434
}
3437
3435
3438
3436
TMaybe<TFromDesc> ParseRangeSubselect(const RangeSubselect* value) {
@@ -3723,7 +3721,8 @@ class TConverter : public IPGParseEvents {
3723
3721
return ParseNullTestExpr(CAST_NODE(NullTest, node), settings);
3724
3722
}
3725
3723
case T_FuncCall: {
3726
- return ParseFuncCall(CAST_NODE(FuncCall, node), settings, false);
3724
+ bool injectRead;
3725
+ return ParseFuncCall(CAST_NODE(FuncCall, node), settings, false, injectRead);
3727
3726
}
3728
3727
case T_A_ArrayExpr: {
3729
3728
return ParseAArrayExpr(CAST_NODE(A_ArrayExpr, node), settings);
@@ -4009,7 +4008,124 @@ class TConverter : public IPGParseEvents {
4009
4008
return L(A("PgSubLink"), QA(linkType), L(A("Void")), L(A("Void")), rowTest, L(A("lambda"), QL(), select));
4010
4009
}
4011
4010
4012
- TAstNode* ParseFuncCall(const FuncCall* value, const TExprSettings& settings, bool rangeFunction) {
4011
+ TAstNode* ParseTableRangeFunction(const TString& name, const TString& schema, List* args) {
4012
+ auto source = BuildClusterSinkOrSourceExpression(false, schema);
4013
+ if (!source) {
4014
+ return nullptr;
4015
+ }
4016
+
4017
+ TVector<TString> argStrs;
4018
+ for (int i = 0; i < ListLength(args); ++i) {
4019
+ auto arg = ListNodeNth(args, i);
4020
+ if (NodeTag(arg) == T_A_Const && (NodeTag(CAST_NODE(A_Const, arg)->val) == T_String)) {
4021
+ TString rawStr = StrVal(CAST_NODE(A_Const, arg)->val);
4022
+ argStrs.push_back(rawStr);
4023
+ } else {
4024
+ AddError("Expected String argument for table function");
4025
+ return nullptr;
4026
+ }
4027
+ }
4028
+
4029
+ if (argStrs.empty()) {
4030
+ AddError("Expected at least one argument for table function");
4031
+ return nullptr;
4032
+ }
4033
+
4034
+ TAstNode* key;
4035
+ auto lowerName = to_lower(name);
4036
+ auto options = QL();
4037
+ if (lowerName == "concat") {
4038
+ TVector<TAstNode*> concatArgs;
4039
+ concatArgs.push_back(A("MrTableConcat"));
4040
+ for (const auto& s : argStrs) {
4041
+ concatArgs.push_back(L(A("Key"), QL(QA("table"),L(A("String"), QAX(s)))));
4042
+ }
4043
+
4044
+ key = VL(concatArgs);
4045
+ } else if (lowerName == "concat_view") {
4046
+ if (argStrs.size() % 2 != 0) {
4047
+ AddError("Expected sequence of pairs of table and view for concat_view");
4048
+ return nullptr;
4049
+ }
4050
+
4051
+ TVector<TAstNode*> concatArgs;
4052
+ concatArgs.push_back(A("MrTableConcat"));
4053
+ for (ui32 i = 0; i < argStrs.size(); i += 2) {
4054
+ concatArgs.push_back(L(A("Key"),
4055
+ QL(QA("table"),L(A("String"), QAX(argStrs[i]))),
4056
+ QL(QA("view"),L(A("String"), QAX(argStrs[i + 1])))));
4057
+ }
4058
+
4059
+ key = VL(concatArgs);
4060
+ } else if (lowerName == "range") {
4061
+ if (argStrs.size() > 5) {
4062
+ AddError("Too many arguments");
4063
+ return nullptr;
4064
+ }
4065
+
4066
+ options = QL(QL(QA("ignorenonexisting")));
4067
+ TAstNode* expr;
4068
+ if (argStrs.size() == 1) {
4069
+ expr = L(A("Bool"),QA("true"));
4070
+ } else if (argStrs.size() == 2) {
4071
+ expr = L(A(">="),A("item"),L(A("String"),QAX(argStrs[1])));
4072
+ } else {
4073
+ expr = L(A("And"),
4074
+ L(A(">="),A("item"),L(A("String"),QAX(argStrs[1]))),
4075
+ L(A("<="),A("item"),L(A("String"),QAX(argStrs[2])))
4076
+ );
4077
+ }
4078
+
4079
+ auto lambda = L(A("lambda"), QL(A("item")), expr);
4080
+ auto range = L(A("MrTableRange"), QAX(argStrs[0]), lambda, QAX(argStrs.size() < 4 ? "" : argStrs[3]));
4081
+ if (argStrs.size() < 5) {
4082
+ key = L(A("Key"), QL(QA("table"),range));
4083
+ } else {
4084
+ key = L(A("Key"), QL(QA("table"),range), QL(QA("view"),L(A("String"), QAX(argStrs[4]))));
4085
+ }
4086
+ } else if (lowerName == "regexp" || lowerName == "like") {
4087
+ if (argStrs.size() < 2 || argStrs.size() > 4) {
4088
+ AddError("Expected from 2 to 4 arguments");
4089
+ return nullptr;
4090
+ }
4091
+
4092
+ options = QL(QL(QA("ignorenonexisting")));
4093
+ TAstNode* expr;
4094
+ if (lowerName == "regexp") {
4095
+ expr = L(A("Apply"),L(A("Udf"),QA("Re2.Grep"),
4096
+ QL(L(A("String"),QAX(argStrs[1])),L(A("Null")))),
4097
+ A("item"));
4098
+ } else {
4099
+ expr = L(A("Apply"),L(A("Udf"),QA("Re2.Match"),
4100
+ QL(L(A("Apply"),
4101
+ L(A("Udf"), QA("Re2.PatternFromLike")),
4102
+ L(A("String"),QAX(argStrs[1]))),L(A("Null")))),
4103
+ A("item"));
4104
+ }
4105
+
4106
+ auto lambda = L(A("lambda"), QL(A("item")), expr);
4107
+ auto range = L(A("MrTableRange"), QAX(argStrs[0]), lambda, QAX(argStrs.size() < 3 ? "" : argStrs[2]));
4108
+ if (argStrs.size() < 4) {
4109
+ key = L(A("Key"), QL(QA("table"),range));
4110
+ } else {
4111
+ key = L(A("Key"), QL(QA("table"),range), QL(QA("view"),L(A("String"), QAX(argStrs[3]))));
4112
+ }
4113
+ } else {
4114
+ AddError(TStringBuilder() << "Unknown table function: " << name);
4115
+ return nullptr;
4116
+ }
4117
+
4118
+ return L(
4119
+ A("Read!"),
4120
+ A("world"),
4121
+ source,
4122
+ key,
4123
+ L(A("Void")),
4124
+ options
4125
+ );
4126
+ }
4127
+
4128
+ TAstNode* ParseFuncCall(const FuncCall* value, const TExprSettings& settings, bool rangeFunction, bool& injectRead) {
4013
4129
AT_LOCATION(value);
4014
4130
if (ListLength(value->agg_order) > 0) {
4015
4131
AddError("FuncCall: unsupported agg_order");
@@ -4052,12 +4168,17 @@ class TConverter : public IPGParseEvents {
4052
4168
}
4053
4169
}
4054
4170
4055
- TVector<TString> names;
4056
- if (!ExtractFuncName(value, names)) {
4171
+ TString name;
4172
+ TString schema;
4173
+ if (!ExtractFuncName(value, name, rangeFunction ? &schema : nullptr)) {
4057
4174
return nullptr;
4058
4175
}
4059
4176
4060
- auto name = names.back();
4177
+ if (rangeFunction && !schema.empty() && schema != "pg_catalog") {
4178
+ injectRead = true;
4179
+ return ParseTableRangeFunction(name, schema, value->args);
4180
+ }
4181
+
4061
4182
if (name == "shobj_description" || name == "obj_description") {
4062
4183
AddWarning(TIssuesIds::PG_COMPAT, name + " function forced to NULL");
4063
4184
return L(A("Null"));
@@ -4159,7 +4280,8 @@ class TConverter : public IPGParseEvents {
4159
4280
return VL(args.data(), args.size());
4160
4281
}
4161
4282
4162
- bool ExtractFuncName(const FuncCall* value, TVector<TString>& names) {
4283
+ bool ExtractFuncName(const FuncCall* value, TString& name, TString* schemaName) {
4284
+ TVector<TString> names;
4163
4285
for (int i = 0; i < ListLength(value->funcname); ++i) {
4164
4286
auto x = ListNodeNth(value->funcname, i);
4165
4287
if (NodeTag(x) != T_String) {
@@ -4180,11 +4302,18 @@ class TConverter : public IPGParseEvents {
4180
4302
return false;
4181
4303
}
4182
4304
4183
- if (names.size() == 2 && names[0] != "pg_catalog") {
4184
- AddError(TStringBuilder() << "FuncCall: expected pg_catalog, but got: " << names[0]);
4185
- return false;
4305
+ if (names.size() == 2) {
4306
+ if (!schemaName && names[0] != "pg_catalog") {
4307
+ AddError(TStringBuilder() << "FuncCall: expected pg_catalog, but got: " << names[0]);
4308
+ return false;
4309
+ }
4310
+
4311
+ if (schemaName) {
4312
+ *schemaName = names[0];
4313
+ }
4186
4314
}
4187
4315
4316
+ name = names.back();
4188
4317
return true;
4189
4318
}
4190
4319
0 commit comments