Skip to content
This repository was archived by the owner on May 9, 2024. It is now read-only.

Commit 0570a23

Browse files
committed
Add cardinality API to QueryBuilder.
Signed-off-by: ienkovich <[email protected]>
1 parent 162f2a8 commit 0570a23

File tree

7 files changed

+123
-0
lines changed

7 files changed

+123
-0
lines changed

omniscidb/QueryBuilder/QueryBuilder.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,30 @@ BuilderExpr BuilderExpr::at(int64_t idx) const {
15871587
return at(builder_->cst(idx, builder_->ctx_.int64(false)));
15881588
}
15891589

1590+
BuilderExpr BuilderExpr::cardinality() const {
1591+
if (!expr_->type()->isArray()) {
1592+
throw InvalidQueryError() << "Non-array type used for CARDINALITY operator: "
1593+
<< expr_->type()->toString();
1594+
}
1595+
1596+
if (expr_->is<Constant>()) {
1597+
if (expr_->as<Constant>()->isNull()) {
1598+
return builder_->nullCst(builder_->ctx_.int32());
1599+
}
1600+
return builder_->cst(static_cast<int32_t>(expr_->as<Constant>()->valueList().size()),
1601+
builder_->ctx_.int32(false));
1602+
}
1603+
1604+
if (expr_->type()->size() > 0 && !expr_->type()->nullable()) {
1605+
auto elem_type = expr_->type()->as<hdk::ir::ArrayBaseType>()->elemType();
1606+
return builder_->cst(expr_->type()->size() / elem_type->size(),
1607+
builder_->ctx_.int32(false));
1608+
}
1609+
1610+
auto cardinality_expr = makeExpr<CardinalityExpr>(expr_);
1611+
return {builder_, cardinality_expr, "", true};
1612+
}
1613+
15901614
BuilderExpr BuilderExpr::over() const {
15911615
return over(std::vector<BuilderExpr>());
15921616
}

omniscidb/QueryBuilder/QueryBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ class BuilderExpr {
216216
BuilderExpr at(int idx) const;
217217
BuilderExpr at(int64_t idx) const;
218218

219+
BuilderExpr cardinality() const;
220+
219221
BuilderExpr over() const;
220222
BuilderExpr over(const BuilderExpr& key) const;
221223
BuilderExpr over(const std::vector<BuilderExpr>& keys) const;

omniscidb/Tests/QueryBuilderTest.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,12 @@ void checkWindowCollation(const BuilderExpr& expr,
302302
ASSERT_EQ(wnd_fn->collation()[idx].nulls_first, null_pos == NullSortedPosition::First);
303303
}
304304

305+
void checkCardinality(const BuilderExpr& expr, const BuilderExpr& op) {
306+
auto cardinality_expr = expr.expr()->as<CardinalityExpr>();
307+
ASSERT_TRUE(cardinality_expr);
308+
ASSERT_TRUE(cardinality_expr->arg()->equal(op.expr().get()));
309+
}
310+
305311
} // anonymous namespace
306312

307313
class QueryBuilderTest : public TestSuite {
@@ -463,6 +469,18 @@ class QueryBuilderTest : public TestSuite {
463469
"2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,,,,,,,,\n"
464470
"3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,,,,,,,,\n"
465471
",1,4,1,,1,4,1,,1,4,1,,1,4,1,,,,,,,,\n");
472+
473+
createTable("test_cardinality",
474+
{{"col_arr_i32", ctx().arrayVarLen(ctx().int32())},
475+
{"col_arr_i32x2", ctx().arrayFixed(2, ctx().int32())},
476+
{"col_arr_i32nn", ctx().arrayVarLen(ctx().int32(), 4, false)},
477+
{"col_arr_i32x2nn", ctx().arrayFixed(2, ctx().int32(), false)}});
478+
insertJsonValues(
479+
"test_cardinality",
480+
R"___({"col_arr_i32": [1], "col_arr_i32x2": [0, 1], "col_arr_i32nn": [1, 2], "col_arr_i32x2nn": [3, 4]}
481+
{"col_arr_i32": null, "col_arr_i32x2": null, "col_arr_i32nn": [1], "col_arr_i32x2nn": [3, 4]}
482+
{"col_arr_i32": [], "col_arr_i32x2": [0, 1], "col_arr_i32nn": [], "col_arr_i32x2nn": [3, 4]}
483+
{"col_arr_i32": [1, 2], "col_arr_i32x2": null, "col_arr_i32nn": [null], "col_arr_i32x2nn": [3, 4]})___");
466484
}
467485

468486
static void TearDownTestSuite() {
@@ -479,6 +497,8 @@ class QueryBuilderTest : public TestSuite {
479497
dropTable("withNull");
480498
dropTable("test_tmstmp");
481499
dropTable("test_tmstmp_nullable");
500+
dropTable("test_bitwise");
501+
dropTable("test_cardinality");
482502
}
483503

484504
void compare_res_fields(const ExecutionResult& res,
@@ -5196,6 +5216,42 @@ TEST_F(QueryBuilderTest, BwNot_Exec) {
51965216
inline_null_value<int64_t>()}));
51975217
}
51985218

5219+
TEST_F(QueryBuilderTest, Cardinality) {
5220+
QueryBuilder builder(ctx(), schema_mgr_, configPtr());
5221+
auto scan = builder.scan("test_cardinality");
5222+
checkCardinality(scan.ref("col_arr_i32").cardinality(), scan.ref("col_arr_i32"));
5223+
checkCardinality(scan.ref("col_arr_i32x2").cardinality(), scan.ref("col_arr_i32x2"));
5224+
checkCardinality(scan.ref("col_arr_i32nn").cardinality(), scan.ref("col_arr_i32nn"));
5225+
checkCst(scan.ref("col_arr_i32x2nn").cardinality(), 2, ctx().int32(false));
5226+
checkCst(builder.cst({1, 2, 3, 4}, "array(int8)").cardinality(), 4, ctx().int32(false));
5227+
checkNullCst(builder.nullCst("array(int8)").cardinality(), ctx().int32());
5228+
auto scan2 = builder.scan("test3");
5229+
EXPECT_THROW(scan2.ref("col_i").cardinality(), InvalidQueryError);
5230+
EXPECT_THROW(scan2.ref("col_d").cardinality(), InvalidQueryError);
5231+
EXPECT_THROW(scan2.ref("col_dec").cardinality(), InvalidQueryError);
5232+
EXPECT_THROW(scan2.ref("col_time").cardinality(), InvalidQueryError);
5233+
EXPECT_THROW(scan2.ref("col_str").cardinality(), InvalidQueryError);
5234+
EXPECT_THROW(builder.cst(1).cardinality(), InvalidQueryError);
5235+
}
5236+
5237+
TEST_F(QueryBuilderTest, Cardinality_Exec) {
5238+
QueryBuilder builder(ctx(), schema_mgr_, configPtr());
5239+
auto scan = builder.scan("test_cardinality");
5240+
auto dag = scan.proj({scan.ref("col_arr_i32").cardinality(),
5241+
scan.ref("col_arr_i32x2").cardinality(),
5242+
scan.ref("col_arr_i32nn").cardinality(),
5243+
scan.ref("col_arr_i32x2nn").cardinality()})
5244+
.finalize();
5245+
auto res = runQuery(std::move(dag));
5246+
compare_res_data(
5247+
res,
5248+
std::vector<int32_t>({1, inline_null_value<int32_t>(), 0, 2}),
5249+
std::vector<int32_t>(
5250+
{2, inline_null_value<int32_t>(), 2, inline_null_value<int32_t>()}),
5251+
std::vector<int32_t>({2, 1, 0, 1}),
5252+
std::vector<int32_t>({2, 2, 2, 2}));
5253+
}
5254+
51995255
TEST_F(QueryBuilderTest, SimpleProjection) {
52005256
QueryBuilder builder(ctx(), schema_mgr_, configPtr());
52015257
compare_test1_data(builder.scan("test1").proj({0, 1, 2, 3}));

python/pyhdk/_builder.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ cdef extern from "omniscidb/QueryBuilder/QueryBuilder.h":
8888
CBuilderExpr ge(const CBuilderExpr&) except +
8989

9090
CBuilderExpr at(const CBuilderExpr&) except +
91+
CBuilderExpr cardinality() except +
9192

9293
CBuilderExpr over(const vector[CBuilderExpr]&) except +
9394
CBuilderExpr orderBy(const vector[CBuilderOrderByKey]&) except +

python/pyhdk/_builder.pyx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,11 @@ cdef class QueryExpr:
308308
res.c_expr = self.c_expr.at((<QueryExpr>value).c_expr)
309309
return res
310310

311+
def cardinality(self):
312+
res = QueryExpr()
313+
res.c_expr = self.c_expr.cardinality()
314+
return res
315+
311316
def over(self, *args):
312317
cdef vector[CBuilderExpr] keys
313318
for arg in args:

python/pyhdk/hdk.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,29 @@ def at(self, index):
13471347
"""
13481348
pass
13491349

1350+
def cardinality(self):
1351+
"""
1352+
Create cardinality expression to access array size.
1353+
1354+
-------
1355+
QueryExpr
1356+
1357+
Examples
1358+
--------
1359+
>>> hdk = pyhdk.init()
1360+
>>> ht = hdk.create_table("test_arr", [("a", "array(int)")])
1361+
>>> hdk.import_pydict({"a": [[1, 2], [2, 3, 4], None, []]}, ht)
1362+
>>> ht.proj(len=ht["a"].cardinality()).run()
1363+
Schema:
1364+
len: INT32
1365+
Data:
1366+
2
1367+
3
1368+
null
1369+
0
1370+
"""
1371+
pass
1372+
13501373
def over(self, *args):
13511374
"""
13521375
Add partition keys to window function expression. Also, transforms min, max, sum, avg, and count

python/tests/test_pyhdk_api.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,18 @@ def test_at(self, exe_cfg):
917917

918918
hdk.drop_table(ht)
919919

920+
def test_cardinality(self, exe_cfg):
921+
hdk = pyhdk.init()
922+
ht = hdk.create_table("test_arr", [("a", "array(int)")])
923+
hdk.import_pydict({"a": [[1, 2], [2, 3, 4], None, []]}, ht)
924+
925+
check_res(
926+
ht.proj(len=ht["a"].cardinality()).run(device_type=exe_cfg.device_type),
927+
{"len": [2, 3, "null", 0]},
928+
)
929+
930+
hdk.drop_table(ht)
931+
920932
def test_run_on_res(self, exe_cfg):
921933
hdk = pyhdk.init()
922934
ht = hdk.import_pydict({"a": [1, 2, 3, 4, 5], "b": [10, 20, 30, 40, 50]})

0 commit comments

Comments
 (0)