summary refs log tree commit diff stats
path: root/lib/statement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/statement.cpp')
-rw-r--r--lib/statement.cpp232
1 files changed, 180 insertions, 52 deletions
diff --git a/lib/statement.cpp b/lib/statement.cpp index 562eef2..b892cab 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp
@@ -3,13 +3,6 @@
3#include <utility> 3#include <utility>
4#include "filter.h" 4#include "filter.h"
5#include "util.h" 5#include "util.h"
6#include "notion.h"
7#include "word.h"
8#include "frame.h"
9#include "part.h"
10#include "lemma.h"
11#include "form.h"
12#include "pronunciation.h"
13#include "order.h" 6#include "order.h"
14 7
15namespace verbly { 8namespace verbly {
@@ -17,7 +10,7 @@ namespace verbly {
17 statement::statement( 10 statement::statement(
18 object context, 11 object context,
19 filter queryFilter) : 12 filter queryFilter) :
20 statement(getTableForContext(context), queryFilter.compact().normalize(context)) 13 statement(context, getTableForContext(context), queryFilter.compact().normalize(context))
21 { 14 {
22 } 15 }
23 16
@@ -104,24 +97,29 @@ namespace verbly {
104 queryStream << " WHERE "; 97 queryStream << " WHERE ";
105 queryStream << topCondition_.flatten().toSql(true, debug); 98 queryStream << topCondition_.flatten().toSql(true, debug);
106 } 99 }
107 100
101 queryStream << " GROUP BY ";
102 queryStream << topTable_;
103 queryStream << ".";
104 queryStream << select.front();
105
108 queryStream << " ORDER BY "; 106 queryStream << " ORDER BY ";
109 107
110 switch (sortOrder.getType()) 108 switch (sortOrder.getType())
111 { 109 {
112 case order::type::random: 110 case order::type::random:
113 { 111 {
114 queryStream << "RANDOM()"; 112 queryStream << "RANDOM()";
115 113
116 break; 114 break;
117 } 115 }
118 116
119 case order::type::field: 117 case order::type::field:
120 { 118 {
121 queryStream << topTable_; 119 queryStream << topTable_;
122 queryStream << "."; 120 queryStream << ".";
123 queryStream << sortOrder.getSortField().getColumn(); 121 queryStream << sortOrder.getSortField().getColumn();
124 122
125 break; 123 break;
126 } 124 }
127 } 125 }
@@ -156,10 +154,12 @@ namespace verbly {
156 } 154 }
157 155
158 statement::statement( 156 statement::statement(
157 object context,
159 std::string tableName, 158 std::string tableName,
160 filter clause, 159 filter clause,
161 int nextTableId, 160 int nextTableId,
162 int nextWithId) : 161 int nextWithId) :
162 context_(context),
163 nextTableId_(nextTableId), 163 nextTableId_(nextTableId),
164 nextWithId_(nextWithId), 164 nextWithId_(nextWithId),
165 topTable_(instantiateTable(std::move(tableName))), 165 topTable_(instantiateTable(std::move(tableName))),
@@ -266,6 +266,16 @@ namespace verbly {
266 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument()); 266 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument());
267 } 267 }
268 268
269 case filter::comparison::field_equals:
270 {
271 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject());
272 }
273
274 case filter::comparison::field_does_not_equal:
275 {
276 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject());
277 }
278
269 case filter::comparison::matches: 279 case filter::comparison::matches:
270 case filter::comparison::does_not_match: 280 case filter::comparison::does_not_match:
271 case filter::comparison::hierarchally_matches: 281 case filter::comparison::hierarchally_matches:
@@ -281,26 +291,29 @@ namespace verbly {
281 { 291 {
282 // First, figure out what table we need to join against. 292 // First, figure out what table we need to join against.
283 std::string joinTableName; 293 std::string joinTableName;
294 object joinContext = object::undefined;
284 if (clause.getField().hasTable()) 295 if (clause.getField().hasTable())
285 { 296 {
286 joinTableName = clause.getField().getTable(); 297 joinTableName = clause.getField().getTable();
287 } else { 298 } else {
288 joinTableName = getTableForContext(clause.getField().getJoinObject()); 299 joinContext = clause.getField().getJoinObject();
300 joinTableName = getTableForContext(joinContext);
289 } 301 }
290 302
291 filter joinCondition = clause.getJoinCondition(); 303 filter joinCondition = clause.getJoinCondition();
292 304
293 // If this is a condition join, we need to add the field join 305 // If this is a condition join, we need to add the field join
294 // condition to the clause. 306 // condition to the clause.
295 if (clause.getField().getType() == field::type::join_where) 307 if (clause.getField().getType() == field::type::join_where)
296 { 308 {
297 joinCondition &= (clause.getField().getConditionField() == clause.getField().getConditionValue()); 309 joinCondition &= (field::integerField(joinTableName.c_str(), clause.getField().getConditionColumn()) == clause.getField().getConditionValue());
298 } 310 }
299 311
300 // Recursively parse the subquery, and therefore obtain an 312 // Recursively parse the subquery, and therefore obtain an
301 // instantiated table to join against, as well as any joins or CTEs 313 // instantiated table to join against, as well as any joins or CTEs
302 // that the subquery may require to function. 314 // that the subquery may require to function.
303 statement joinStmt( 315 statement joinStmt(
316 joinContext,
304 joinTableName, 317 joinTableName,
305 std::move(joinCondition).normalize(clause.getField().getJoinObject()), 318 std::move(joinCondition).normalize(clause.getField().getJoinObject()),
306 nextTableId_, 319 nextTableId_,
@@ -368,11 +381,13 @@ namespace verbly {
368 } 381 }
369 382
370 case field::type::join_through: 383 case field::type::join_through:
384 case field::type::join_through_where:
371 { 385 {
372 // Recursively parse the subquery, and therefore obtain an 386 // Recursively parse the subquery, and therefore obtain an
373 // instantiated table to join against, as well as any joins or CTEs 387 // instantiated table to join against, as well as any joins or CTEs
374 // that the subquery may require to function. 388 // that the subquery may require to function.
375 statement joinStmt( 389 statement joinStmt(
390 clause.getField().getJoinObject(),
376 getTableForContext(clause.getField().getJoinObject()), 391 getTableForContext(clause.getField().getJoinObject()),
377 clause.getJoinCondition().normalize(clause.getField().getJoinObject()), 392 clause.getJoinCondition().normalize(clause.getField().getJoinObject()),
378 nextTableId_, 393 nextTableId_,
@@ -424,6 +439,17 @@ namespace verbly {
424 std::list<join> cteJoins = std::move(joinStmt.joins_); 439 std::list<join> cteJoins = std::move(joinStmt.joins_);
425 condition cteCondition = integrate(std::move(joinStmt), true); 440 condition cteCondition = integrate(std::move(joinStmt), true);
426 441
442 // If this is a condition join, add the condition.
443 if (clause.getField().getType() == field::type::join_through_where)
444 {
445 cteCondition &=
446 condition(
447 throughTable,
448 clause.getField().getConditionColumn(),
449 condition::comparison::equals,
450 clause.getField().getConditionValue());
451 }
452
427 withs_.emplace_back( 453 withs_.emplace_back(
428 std::move(withName), 454 std::move(withName),
429 clause.getField(), 455 clause.getField(),
@@ -453,7 +479,7 @@ namespace verbly {
453 joins_.emplace_back( 479 joins_.emplace_back(
454 false, 480 false,
455 getTableForContext(clause.getField().getJoinObject()), 481 getTableForContext(clause.getField().getJoinObject()),
456 std::move(throughTable), 482 throughTable,
457 clause.getField().getForeignJoinColumn(), 483 clause.getField().getForeignJoinColumn(),
458 std::move(joinTable), 484 std::move(joinTable),
459 clause.getField().getForeignColumn()); 485 clause.getField().getForeignColumn());
@@ -461,7 +487,20 @@ namespace verbly {
461 // Integrate the subquery's table mappings, joins, and CTEs into 487 // Integrate the subquery's table mappings, joins, and CTEs into
462 // this statement, and return the subquery condition as our 488 // this statement, and return the subquery condition as our
463 // condition. 489 // condition.
464 return integrate(std::move(joinStmt)); 490 condition resultCond = integrate(std::move(joinStmt));
491
492 // If this is a condition join, add the condition.
493 if (clause.getField().getType() == field::type::join_through_where)
494 {
495 resultCond &=
496 condition(
497 throughTable,
498 clause.getField().getConditionColumn(),
499 condition::comparison::equals,
500 clause.getField().getConditionValue());
501 }
502
503 return std::move(resultCond);
465 } 504 }
466 } 505 }
467 506
@@ -491,6 +530,7 @@ namespace verbly {
491 530
492 // Recursively parse the subquery in order to create the CTE. 531 // Recursively parse the subquery in order to create the CTE.
493 statement withStmt( 532 statement withStmt(
533 clause.getField().getObject(),
494 getTableForContext(clause.getField().getObject()), 534 getTableForContext(clause.getField().getObject()),
495 clause.getJoinCondition().normalize(clause.getField().getObject()), 535 clause.getJoinCondition().normalize(clause.getField().getObject()),
496 nextTableId_, 536 nextTableId_,
@@ -593,7 +633,7 @@ namespace verbly {
593 nextTableId_ = subStmt.nextTableId_; 633 nextTableId_ = subStmt.nextTableId_;
594 nextWithId_ = subStmt.nextWithId_; 634 nextWithId_ = subStmt.nextWithId_;
595 635
596 return subStmt.topCondition_; 636 return subStmt.topCondition_.resolveCompareFields(context_, topTable_);
597 } 637 }
598 638
599 std::ostream& operator<<(std::ostream& oss, const statement::join& j) 639 std::ostream& operator<<(std::ostream& oss, const statement::join& j)
@@ -637,6 +677,7 @@ namespace verbly {
637 new(&singleton_.column_) std::string(other.singleton_.column_); 677 new(&singleton_.column_) std::string(other.singleton_.column_);
638 singleton_.comparison_ = other.singleton_.comparison_; 678 singleton_.comparison_ = other.singleton_.comparison_;
639 new(&singleton_.value_) binding(other.singleton_.value_); 679 new(&singleton_.value_) binding(other.singleton_.value_);
680 singleton_.parentObject_ = other.singleton_.parentObject_;
640 681
641 break; 682 break;
642 } 683 }
@@ -673,6 +714,7 @@ namespace verbly {
673 std::string tempColumn; 714 std::string tempColumn;
674 condition::comparison tempComparison; 715 condition::comparison tempComparison;
675 binding tempBinding; 716 binding tempBinding;
717 object tempParentObject;
676 std::list<condition> tempChildren; 718 std::list<condition> tempChildren;
677 bool tempOrlogic; 719 bool tempOrlogic;
678 720
@@ -689,6 +731,7 @@ namespace verbly {
689 tempColumn = std::move(first.singleton_.column_); 731 tempColumn = std::move(first.singleton_.column_);
690 tempComparison = first.singleton_.comparison_; 732 tempComparison = first.singleton_.comparison_;
691 tempBinding = std::move(first.singleton_.value_); 733 tempBinding = std::move(first.singleton_.value_);
734 tempParentObject = first.singleton_.parentObject_;
692 735
693 break; 736 break;
694 } 737 }
@@ -719,6 +762,7 @@ namespace verbly {
719 new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_)); 762 new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_));
720 first.singleton_.comparison_ = second.singleton_.comparison_; 763 first.singleton_.comparison_ = second.singleton_.comparison_;
721 new(&first.singleton_.value_) binding(std::move(second.singleton_.value_)); 764 new(&first.singleton_.value_) binding(std::move(second.singleton_.value_));
765 first.singleton_.parentObject_ = second.singleton_.parentObject_;
722 766
723 break; 767 break;
724 } 768 }
@@ -749,6 +793,7 @@ namespace verbly {
749 new(&second.singleton_.column_) std::string(std::move(tempColumn)); 793 new(&second.singleton_.column_) std::string(std::move(tempColumn));
750 second.singleton_.comparison_ = tempComparison; 794 second.singleton_.comparison_ = tempComparison;
751 new(&second.singleton_.value_) binding(std::move(tempBinding)); 795 new(&second.singleton_.value_) binding(std::move(tempBinding));
796 second.singleton_.parentObject_ = tempParentObject;
752 797
753 break; 798 break;
754 } 799 }
@@ -813,19 +858,23 @@ namespace verbly {
813 } else { 858 } else {
814 singleton_.comparison_ = comparison::is_not_null; 859 singleton_.comparison_ = comparison::is_not_null;
815 } 860 }
861
862 singleton_.parentObject_ = object::undefined;
816 } 863 }
817 864
818 statement::condition::condition( 865 statement::condition::condition(
819 std::string table, 866 std::string table,
820 std::string column, 867 std::string column,
821 comparison comp, 868 comparison comp,
822 binding value) : 869 binding value,
870 object parentObject) :
823 type_(type::singleton) 871 type_(type::singleton)
824 { 872 {
825 new(&singleton_.table_) std::string(std::move(table)); 873 new(&singleton_.table_) std::string(std::move(table));
826 new(&singleton_.column_) std::string(std::move(column)); 874 new(&singleton_.column_) std::string(std::move(column));
827 singleton_.comparison_ = comp; 875 singleton_.comparison_ = comp;
828 new(&singleton_.value_) binding(std::move(value)); 876 new(&singleton_.value_) binding(std::move(value));
877 singleton_.parentObject_ = parentObject;
829 } 878 }
830 879
831 std::string statement::condition::toSql(bool toplevel, bool debug) const 880 std::string statement::condition::toSql(bool toplevel, bool debug) const
@@ -845,14 +894,35 @@ namespace verbly {
845 { 894 {
846 if (debug) 895 if (debug)
847 { 896 {
848 if (singleton_.value_.getType() == binding::type::string) 897 switch (singleton_.value_.getType())
849 { 898 {
850 return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\""; 899 case binding::type::string:
851 } else { 900 {
852 return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger()); 901 return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\"";
902 }
903
904 case binding::type::integer:
905 {
906 return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger());
907 }
908
909 case binding::type::field:
910 {
911 return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
912 }
913
914 case binding::type::invalid:
915 {
916 throw std::logic_error("Invalid binding in statement generation");
917 }
853 } 918 }
854 } else { 919 } else {
855 return singleton_.table_ + "." + singleton_.column_ + " = ?"; 920 if (singleton_.value_.getType() == binding::type::field)
921 {
922 return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
923 } else {
924 return singleton_.table_ + "." + singleton_.column_ + " = ?";
925 }
856 } 926 }
857 } 927 }
858 928
@@ -860,14 +930,35 @@ namespace verbly {
860 { 930 {
861 if (debug) 931 if (debug)
862 { 932 {
863 if (singleton_.value_.getType() == binding::type::string) 933 switch (singleton_.value_.getType())
864 { 934 {
865 return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\""; 935 case binding::type::string:
866 } else { 936 {
867 return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger()); 937 return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\"";
938 }
939
940 case binding::type::integer:
941 {
942 return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger());
943 }
944
945 case binding::type::field:
946 {
947 return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
948 }
949
950 case binding::type::invalid:
951 {
952 throw std::logic_error("Invalid binding in statement generation");
953 }
868 } 954 }
869 } else { 955 } else {
870 return singleton_.table_ + "." + singleton_.column_ + " != ?"; 956 if (singleton_.value_.getType() == binding::type::field)
957 {
958 return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
959 } else {
960 return singleton_.table_ + "." + singleton_.column_ + " != ?";
961 }
871 } 962 }
872 } 963 }
873 964
@@ -959,7 +1050,7 @@ namespace verbly {
959 return clauses.front(); 1050 return clauses.front();
960 } else { 1051 } else {
961 std::string result = implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); 1052 std::string result = implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND ");
962 1053
963 if (toplevel) 1054 if (toplevel)
964 { 1055 {
965 return result; 1056 return result;
@@ -982,24 +1073,29 @@ namespace verbly {
982 1073
983 case type::singleton: 1074 case type::singleton:
984 { 1075 {
985 switch (singleton_.comparison_) 1076 if (singleton_.value_.getType() == binding::type::field)
986 { 1077 {
987 case comparison::equals: 1078 return {};
988 case comparison::does_not_equal: 1079 } else {
989 case comparison::is_greater_than: 1080 switch (singleton_.comparison_)
990 case comparison::is_at_most:
991 case comparison::is_less_than:
992 case comparison::is_at_least:
993 case comparison::is_like:
994 case comparison::is_not_like:
995 { 1081 {
996 return {singleton_.value_}; 1082 case comparison::equals:
997 } 1083 case comparison::does_not_equal:
1084 case comparison::is_greater_than:
1085 case comparison::is_at_most:
1086 case comparison::is_less_than:
1087 case comparison::is_at_least:
1088 case comparison::is_like:
1089 case comparison::is_not_like:
1090 {
1091 return {singleton_.value_};
1092 }
998 1093
999 case comparison::is_not_null: 1094 case comparison::is_not_null:
1000 case comparison::is_null: 1095 case comparison::is_null:
1001 { 1096 {
1002 return {}; 1097 return {};
1098 }
1003 } 1099 }
1004 } 1100 }
1005 } 1101 }
@@ -1080,7 +1176,7 @@ namespace verbly {
1080 throw std::domain_error("Cannot get children of non-group condition"); 1176 throw std::domain_error("Cannot get children of non-group condition");
1081 } 1177 }
1082 } 1178 }
1083 1179
1084 statement::condition statement::condition::flatten() const 1180 statement::condition statement::condition::flatten() const
1085 { 1181 {
1086 switch (type_) 1182 switch (type_)
@@ -1090,15 +1186,15 @@ namespace verbly {
1090 { 1186 {
1091 return *this; 1187 return *this;
1092 } 1188 }
1093 1189
1094 case type::group: 1190 case type::group:
1095 { 1191 {
1096 condition result(group_.orlogic_); 1192 condition result(group_.orlogic_);
1097 1193
1098 for (const condition& child : group_.children_) 1194 for (const condition& child : group_.children_)
1099 { 1195 {
1100 condition newChild = child.flatten(); 1196 condition newChild = child.flatten();
1101 1197
1102 if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_)) 1198 if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_))
1103 { 1199 {
1104 for (condition subChild : std::move(newChild.group_.children_)) 1200 for (condition subChild : std::move(newChild.group_.children_))
@@ -1109,7 +1205,39 @@ namespace verbly {
1109 result += std::move(newChild); 1205 result += std::move(newChild);
1110 } 1206 }
1111 } 1207 }
1112 1208
1209 return result;
1210 }
1211 }
1212 }
1213
1214 statement::condition statement::condition::resolveCompareFields(object context, std::string tableName) const
1215 {
1216 switch (type_)
1217 {
1218 case type::empty:
1219 {
1220 return *this;
1221 }
1222
1223 case type::singleton:
1224 {
1225 if ((singleton_.parentObject_ != object::undefined) && (singleton_.parentObject_ == context))
1226 {
1227 return condition(singleton_.table_, singleton_.column_, singleton_.comparison_, {tableName, singleton_.value_.getColumn()});
1228 } else {
1229 return *this;
1230 }
1231 }
1232
1233 case type::group:
1234 {
1235 condition result(group_.orlogic_);
1236 for (const condition& cond : group_.children_)
1237 {
1238 result += cond.resolveCompareFields(context, tableName);
1239 }
1240
1113 return result; 1241 return result;
1114 } 1242 }
1115 } 1243 }