Skip to content

Commit 487f2e1

Browse files
committed
Add spatial join and area restrictor tests
1 parent 633cd9e commit 487f2e1

1 file changed

Lines changed: 186 additions & 0 deletions

File tree

src/qproc/testQueryAnaGeneral.cc

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,192 @@ BOOST_AUTO_TEST_CASE(ObjectSelfJoinDistance) {
633633
BOOST_CHECK_EQUAL(actual, expected);
634634
}
635635

636+
BOOST_AUTO_TEST_CASE(ObjectSelfJoinPtInCircle) {
637+
// A spatial self-join expressed with point-in-circle syntax is equivalent to a scisql_angSep()
638+
// comparison and should be recognized as a near-neighbor join.
639+
std::string stmt =
640+
"select count(*) from LSST.Object o1,LSST.Object o2 "
641+
"WHERE qserv_areaspec_box(5.5, 5.5, 6.1, 6.1) AND "
642+
"scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,0.02) = 1";
643+
std::string expected =
644+
"SELECT count(*) AS `QS1_COUNT` "
645+
"FROM `Subchunks_LSST_100`.`Object_100_%S\007S%` AS `o1`,"
646+
"`Subchunks_LSST_100`.`Object_100_%S\007S%` AS `o2` "
647+
"WHERE scisql_s2PtInBox(`o1`.`ra_Test`,`o1`.`decl_Test`,5.5,5.5,6.1,6.1)=1 "
648+
"AND scisql_s2PtInBox(`o2`.`ra_Test`,`o2`.`decl_Test`,5.5,5.5,6.1,6.1)=1 "
649+
"AND scisql_s2PtInCircle(`o1`.`ra_Test`,`o1`.`decl_Test`,"
650+
"`o2`.`ra_Test`,`o2`.`decl_Test`,0.02)=1";
651+
qsTest.sqlConfig =
652+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test"}}}}}));
653+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt);
654+
std::shared_ptr<QueryContext> context = qs->dbgGetContext();
655+
BOOST_CHECK(context);
656+
BOOST_CHECK(nullptr == context->secIdxRestrictors);
657+
BOOST_CHECK(nullptr != context->areaRestrictors);
658+
BOOST_CHECK(context->hasChunks());
659+
BOOST_CHECK(context->hasSubChunks());
660+
BOOST_CHECK(context->needsMerge);
661+
std::string actual2 = queryAnaHelper.buildFirstParallelQuery();
662+
BOOST_CHECK_EQUAL(actual2, expected);
663+
}
664+
665+
BOOST_AUTO_TEST_CASE(PtInCircleJoinForms) {
666+
// scisql_s2PtInCircle() call may appear on either side of "="
667+
std::vector<std::string> const predicates = {
668+
"scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,0.02) = 1",
669+
"1 = scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,0.02)"};
670+
for (auto const& predicate : predicates) {
671+
std::string stmt = "select count(*) from LSST.Object o1,LSST.Object o2 WHERE " + predicate;
672+
qsTest.sqlConfig =
673+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test"}}}}}));
674+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt);
675+
BOOST_CHECK_EQUAL(qs->getError(), "");
676+
std::shared_ptr<QueryContext> context = qs->dbgGetContext();
677+
BOOST_CHECK(context);
678+
BOOST_CHECK(context->hasChunks());
679+
BOOST_CHECK(context->hasSubChunks());
680+
}
681+
}
682+
683+
BOOST_AUTO_TEST_CASE(PtInCircleJoinUnsupportedOperators) {
684+
// scisql_s2PtInCircle() only ever returns 0 or 1, so only plain equality against 1 is recognized as a
685+
// join predicate
686+
std::vector<std::string> const predicates = {
687+
"scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,0.02) != 0",
688+
"0 < scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,0.02)"};
689+
for (auto const& predicate : predicates) {
690+
std::string stmt = "select count(*) from LSST.Object o1,LSST.Object o2 WHERE " + predicate;
691+
qsTest.sqlConfig =
692+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test"}}}}}));
693+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt, true);
694+
BOOST_CHECK_EQUAL(qs->getError(), NOT_EVALUABLE_MSG);
695+
}
696+
}
697+
698+
BOOST_AUTO_TEST_CASE(PtInCircleAntiJoin) {
699+
// A point outside the circle selects distant pairs, which cannot be evaluated using partition-local data.
700+
std::string stmt =
701+
"select count(*) from LSST.Object o1,LSST.Object o2 "
702+
"WHERE scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,0.02) = 0";
703+
qsTest.sqlConfig =
704+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test"}}}}}));
705+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt, true);
706+
BOOST_CHECK_EQUAL(qs->getError(), NOT_EVALUABLE_MSG);
707+
}
708+
709+
BOOST_AUTO_TEST_CASE(PtInCircleJoinWithConeRestrictor) {
710+
// Join AND a spatial restrictor
711+
std::string stmt =
712+
"select count(*) from LSST.Object o1,LSST.Object o2 "
713+
"WHERE scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,6,6,0.3) = 1 AND "
714+
"scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,0.02) = 1";
715+
qsTest.sqlConfig =
716+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test"}}}}}));
717+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt);
718+
BOOST_CHECK_EQUAL(qs->getError(), "");
719+
std::shared_ptr<QueryContext> context = qs->dbgGetContext();
720+
BOOST_CHECK(context);
721+
BOOST_REQUIRE(context->areaRestrictors);
722+
BOOST_CHECK_EQUAL(context->areaRestrictors->size(), 1U);
723+
BOOST_REQUIRE(context->areaRestrictors->front());
724+
BOOST_CHECK_EQUAL(*context->areaRestrictors->front(), AreaRestrictorCircle("6", "6", "0.3"));
725+
BOOST_CHECK(context->hasChunks());
726+
BOOST_CHECK(context->hasSubChunks());
727+
}
728+
729+
BOOST_AUTO_TEST_CASE(AngSepAsConeRestrictor) {
730+
// scisql_angSep() with a constant center, bounded above, is equivalent to scisql_s2PtInCircle() = 1
731+
std::vector<std::string> const predicates = {
732+
"scisql_angSep(ra_PS, decl_PS, 1.5, 3) < 0.1", "scisql_angSep(ra_PS, decl_PS, 1.5, 3) <= 0.1",
733+
"0.1 > scisql_angSep(ra_PS, decl_PS, 1.5, 3)", "scisql_angSep(1.5, 3, ra_PS, decl_PS) < 0.1"};
734+
for (auto const& predicate : predicates) {
735+
std::string stmt = "select * from Object where " + predicate;
736+
qsTest.sqlConfig =
737+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_PS", "decl_PS"}}}}}));
738+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt);
739+
BOOST_CHECK_EQUAL(qs->getError(), "");
740+
std::shared_ptr<QueryContext> context = qs->dbgGetContext();
741+
BOOST_CHECK(context);
742+
BOOST_REQUIRE(context->areaRestrictors);
743+
BOOST_CHECK_EQUAL(context->areaRestrictors->size(), 1U);
744+
BOOST_REQUIRE(context->areaRestrictors->front());
745+
BOOST_CHECK_EQUAL(*context->areaRestrictors->front(), AreaRestrictorCircle("1.5", "3", "0.1"));
746+
BOOST_CHECK(context->hasChunks());
747+
BOOST_CHECK(!context->hasSubChunks());
748+
}
749+
}
750+
751+
BOOST_AUTO_TEST_CASE(AngSepLowerBoundNoRestrictor) {
752+
// Bounding scisql_angSep() from below selects points outside the cone; no restrictor produced
753+
std::string stmt = "select * from Object where scisql_angSep(ra_PS, decl_PS, 1.5, 3) > 0.1";
754+
qsTest.sqlConfig =
755+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_PS", "decl_PS"}}}}}));
756+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt);
757+
BOOST_CHECK_EQUAL(qs->getError(), "");
758+
std::shared_ptr<QueryContext> context = qs->dbgGetContext();
759+
BOOST_CHECK(context);
760+
BOOST_CHECK(nullptr == context->areaRestrictors);
761+
BOOST_CHECK(context->hasChunks());
762+
}
763+
764+
BOOST_AUTO_TEST_CASE(AngSepConeRestrictorWithAngSepJoin) {
765+
// Cone restrictor AND a spatial join, both via scisql_angSep()
766+
std::string stmt =
767+
"select count(*) from LSST.Object o1,LSST.Object o2 "
768+
"WHERE scisql_angSep(o1.ra_Test, o1.decl_Test, 6, 6) < 0.3 AND "
769+
"scisql_angSep(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test) < 0.02";
770+
qsTest.sqlConfig =
771+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test"}}}}}));
772+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt);
773+
BOOST_CHECK_EQUAL(qs->getError(), "");
774+
std::shared_ptr<QueryContext> context = qs->dbgGetContext();
775+
BOOST_CHECK(context);
776+
BOOST_REQUIRE(context->areaRestrictors);
777+
BOOST_CHECK_EQUAL(context->areaRestrictors->size(), 1U);
778+
BOOST_REQUIRE(context->areaRestrictors->front());
779+
BOOST_CHECK_EQUAL(*context->areaRestrictors->front(), AreaRestrictorCircle("6", "6", "0.3"));
780+
BOOST_CHECK(context->hasChunks());
781+
BOOST_CHECK(context->hasSubChunks());
782+
}
783+
784+
BOOST_AUTO_TEST_CASE(UnrelatedNegativeConstantNotMistakenForAngSep) {
785+
// A "col < negative constant" predicate unrelated to scisql_angSep() must not be rejected
786+
std::string stmt = "select * from LSST.Object o1 WHERE o1.mag < -5";
787+
qsTest.sqlConfig = SqlConfig(
788+
SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test", "mag"}}}}}));
789+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt);
790+
BOOST_CHECK_EQUAL(qs->getError(), "");
791+
}
792+
793+
BOOST_AUTO_TEST_CASE(NegativeAngSepThresholdRejected) {
794+
// A negative scisql_angSep() threshold can never be satisfied, so it must error, not be ignored
795+
std::string stmt =
796+
"select * from LSST.Object o, Source s "
797+
"WHERE o.objectIdObjTest = s.objectIdSourceTest AND "
798+
"scisql_angSep(o.ra_Test,o.decl_Test,s.ra_Test,s.decl_Test) < -0.5;";
799+
qsTest.sqlConfig = SqlConfig(
800+
SqlConfig::MockDbTableColumns({{"LSST",
801+
{{"Object", {"objectIdObjTest", "ra_Test", "decl_Test"}},
802+
{"Source", {"objectIdSourceTest", "ra_Test", "decl_Test"}}}}}));
803+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt, true);
804+
BOOST_CHECK_EQUAL(qs->getError(),
805+
"AnalysisError:scisql_angSep() comparison threshold must be a non-negative "
806+
"number, got -0.500000");
807+
}
808+
809+
BOOST_AUTO_TEST_CASE(NegativePtInCircleRadiusRejected) {
810+
// A negative scisql_s2PtInCircle() radius can never be satisfied, so it must error, not be ignored
811+
std::string stmt =
812+
"select count(*) from LSST.Object o1,LSST.Object o2 "
813+
"WHERE scisql_s2PtInCircle(o1.ra_Test,o1.decl_Test,o2.ra_Test,o2.decl_Test,-0.5) = 1";
814+
qsTest.sqlConfig =
815+
SqlConfig(SqlConfig::MockDbTableColumns({{"LSST", {{"Object", {"ra_Test", "decl_Test"}}}}}));
816+
std::shared_ptr<QuerySession> qs = queryAnaHelper.buildQuerySession(qsTest, stmt, true);
817+
BOOST_CHECK_EQUAL(qs->getError(),
818+
"AnalysisError:scisql_s2PtInCircle() radius must be a non-negative number, "
819+
"got -0.500000");
820+
}
821+
636822
BOOST_AUTO_TEST_CASE(SelfJoinAliased) {
637823
// o2.ra_PS and o2.ra_PS_Sigma have to be aliased in order to produce
638824
// a result that can't be stored in a table as-is.

0 commit comments

Comments
 (0)