diff options
Diffstat (limited to 'lib/statement.cpp')
-rw-r--r-- | lib/statement.cpp | 164 |
1 files changed, 145 insertions, 19 deletions
diff --git a/lib/statement.cpp b/lib/statement.cpp index 846b9de..1512aa5 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp | |||
@@ -5,11 +5,12 @@ | |||
5 | #include "util.h" | 5 | #include "util.h" |
6 | #include "notion.h" | 6 | #include "notion.h" |
7 | #include "word.h" | 7 | #include "word.h" |
8 | #include "group.h" | ||
9 | #include "frame.h" | 8 | #include "frame.h" |
9 | #include "part.h" | ||
10 | #include "lemma.h" | 10 | #include "lemma.h" |
11 | #include "form.h" | 11 | #include "form.h" |
12 | #include "pronunciation.h" | 12 | #include "pronunciation.h" |
13 | #include "order.h" | ||
13 | 14 | ||
14 | namespace verbly { | 15 | namespace verbly { |
15 | 16 | ||
@@ -20,7 +21,7 @@ namespace verbly { | |||
20 | { | 21 | { |
21 | } | 22 | } |
22 | 23 | ||
23 | std::string statement::getQueryString(std::list<std::string> select, bool random, int limit) const | 24 | std::string statement::getQueryString(std::list<std::string> select, order sortOrder, int limit, bool debug) const |
24 | { | 25 | { |
25 | std::stringstream queryStream; | 26 | std::stringstream queryStream; |
26 | 27 | ||
@@ -49,7 +50,7 @@ namespace verbly { | |||
49 | if (cte.getCondition().getType() != condition::type::empty) | 50 | if (cte.getCondition().getType() != condition::type::empty) |
50 | { | 51 | { |
51 | cteStream << " WHERE "; | 52 | cteStream << " WHERE "; |
52 | cteStream << cte.getCondition().toSql(); | 53 | cteStream << cte.getCondition().flatten().toSql(true, debug); |
53 | } | 54 | } |
54 | 55 | ||
55 | if (cte.isRecursive()) | 56 | if (cte.isRecursive()) |
@@ -101,12 +102,28 @@ namespace verbly { | |||
101 | if (topCondition_.getType() != condition::type::empty) | 102 | if (topCondition_.getType() != condition::type::empty) |
102 | { | 103 | { |
103 | queryStream << " WHERE "; | 104 | queryStream << " WHERE "; |
104 | queryStream << topCondition_.toSql(); | 105 | queryStream << topCondition_.flatten().toSql(true, debug); |
105 | } | 106 | } |
106 | 107 | ||
107 | if (random) | 108 | queryStream << " ORDER BY "; |
109 | |||
110 | switch (sortOrder.getType()) | ||
108 | { | 111 | { |
109 | queryStream << " ORDER BY RANDOM()"; | 112 | case order::type::random: |
113 | { | ||
114 | queryStream << "RANDOM()"; | ||
115 | |||
116 | break; | ||
117 | } | ||
118 | |||
119 | case order::type::field: | ||
120 | { | ||
121 | queryStream << topTable_; | ||
122 | queryStream << "."; | ||
123 | queryStream << sortOrder.getSortField().getColumn(); | ||
124 | |||
125 | break; | ||
126 | } | ||
110 | } | 127 | } |
111 | 128 | ||
112 | if (limit > 0) | 129 | if (limit > 0) |
@@ -260,6 +277,7 @@ namespace verbly { | |||
260 | } | 277 | } |
261 | 278 | ||
262 | case field::type::join: | 279 | case field::type::join: |
280 | case field::type::join_where: | ||
263 | { | 281 | { |
264 | // First, figure out what table we need to join against. | 282 | // First, figure out what table we need to join against. |
265 | std::string joinTableName; | 283 | std::string joinTableName; |
@@ -269,13 +287,22 @@ namespace verbly { | |||
269 | } else { | 287 | } else { |
270 | joinTableName = getTableForContext(clause.getField().getJoinObject()); | 288 | joinTableName = getTableForContext(clause.getField().getJoinObject()); |
271 | } | 289 | } |
290 | |||
291 | filter joinCondition = clause.getJoinCondition(); | ||
292 | |||
293 | // If this is a condition join, we need to add the field join | ||
294 | // condition to the clause. | ||
295 | if (clause.getField().getType() == field::type::join_where) | ||
296 | { | ||
297 | joinCondition &= (clause.getField().getConditionField() == clause.getField().getConditionValue()); | ||
298 | } | ||
272 | 299 | ||
273 | // Recursively parse the subquery, and therefore obtain an | 300 | // Recursively parse the subquery, and therefore obtain an |
274 | // instantiated table to join against, as well as any joins or CTEs | 301 | // instantiated table to join against, as well as any joins or CTEs |
275 | // that the subquery may require to function. | 302 | // that the subquery may require to function. |
276 | statement joinStmt( | 303 | statement joinStmt( |
277 | joinTableName, | 304 | joinTableName, |
278 | clause.getJoinCondition().normalize(clause.getField().getJoinObject()), | 305 | std::move(joinCondition).normalize(clause.getField().getJoinObject()), |
279 | nextTableId_, | 306 | nextTableId_, |
280 | nextWithId_); | 307 | nextWithId_); |
281 | 308 | ||
@@ -801,7 +828,7 @@ namespace verbly { | |||
801 | new(&singleton_.value_) binding(std::move(value)); | 828 | new(&singleton_.value_) binding(std::move(value)); |
802 | } | 829 | } |
803 | 830 | ||
804 | std::string statement::condition::toSql() const | 831 | std::string statement::condition::toSql(bool toplevel, bool debug) const |
805 | { | 832 | { |
806 | switch (type_) | 833 | switch (type_) |
807 | { | 834 | { |
@@ -816,42 +843,92 @@ namespace verbly { | |||
816 | { | 843 | { |
817 | case comparison::equals: | 844 | case comparison::equals: |
818 | { | 845 | { |
819 | return singleton_.table_ + "." + singleton_.column_ + " = ?"; | 846 | if (debug) |
847 | { | ||
848 | if (singleton_.value_.getType() == binding::type::string) | ||
849 | { | ||
850 | return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\""; | ||
851 | } else { | ||
852 | return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger()); | ||
853 | } | ||
854 | } else { | ||
855 | return singleton_.table_ + "." + singleton_.column_ + " = ?"; | ||
856 | } | ||
820 | } | 857 | } |
821 | 858 | ||
822 | case comparison::does_not_equal: | 859 | case comparison::does_not_equal: |
823 | { | 860 | { |
824 | return singleton_.table_ + "." + singleton_.column_ + " != ?"; | 861 | if (debug) |
862 | { | ||
863 | if (singleton_.value_.getType() == binding::type::string) | ||
864 | { | ||
865 | return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\""; | ||
866 | } else { | ||
867 | return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger()); | ||
868 | } | ||
869 | } else { | ||
870 | return singleton_.table_ + "." + singleton_.column_ + " != ?"; | ||
871 | } | ||
825 | } | 872 | } |
826 | 873 | ||
827 | case comparison::is_greater_than: | 874 | case comparison::is_greater_than: |
828 | { | 875 | { |
829 | return singleton_.table_ + "." + singleton_.column_ + " > ?"; | 876 | if (debug) |
877 | { | ||
878 | return singleton_.table_ + "." + singleton_.column_ + " > " + std::to_string(singleton_.value_.getInteger()); | ||
879 | } else { | ||
880 | return singleton_.table_ + "." + singleton_.column_ + " > ?"; | ||
881 | } | ||
830 | } | 882 | } |
831 | 883 | ||
832 | case comparison::is_at_most: | 884 | case comparison::is_at_most: |
833 | { | 885 | { |
834 | return singleton_.table_ + "." + singleton_.column_ + " <= ?"; | 886 | if (debug) |
887 | { | ||
888 | return singleton_.table_ + "." + singleton_.column_ + " <= " + std::to_string(singleton_.value_.getInteger()); | ||
889 | } else { | ||
890 | return singleton_.table_ + "." + singleton_.column_ + " <= ?"; | ||
891 | } | ||
835 | } | 892 | } |
836 | 893 | ||
837 | case comparison::is_less_than: | 894 | case comparison::is_less_than: |
838 | { | 895 | { |
839 | return singleton_.table_ + "." + singleton_.column_ + " < ?"; | 896 | if (debug) |
897 | { | ||
898 | return singleton_.table_ + "." + singleton_.column_ + " < " + std::to_string(singleton_.value_.getInteger()); | ||
899 | } else { | ||
900 | return singleton_.table_ + "." + singleton_.column_ + " < ?"; | ||
901 | } | ||
840 | } | 902 | } |
841 | 903 | ||
842 | case comparison::is_at_least: | 904 | case comparison::is_at_least: |
843 | { | 905 | { |
844 | return singleton_.table_ + "." + singleton_.column_ + " >= ?"; | 906 | if (debug) |
907 | { | ||
908 | return singleton_.table_ + "." + singleton_.column_ + " >= " + std::to_string(singleton_.value_.getInteger()); | ||
909 | } else { | ||
910 | return singleton_.table_ + "." + singleton_.column_ + " >= ?"; | ||
911 | } | ||
845 | } | 912 | } |
846 | 913 | ||
847 | case comparison::is_like: | 914 | case comparison::is_like: |
848 | { | 915 | { |
849 | return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; | 916 | if (debug) |
917 | { | ||
918 | return singleton_.table_ + "." + singleton_.column_ + " LIKE \"" + singleton_.value_.getString() + "\""; | ||
919 | } else { | ||
920 | return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; | ||
921 | } | ||
850 | } | 922 | } |
851 | 923 | ||
852 | case comparison::is_not_like: | 924 | case comparison::is_not_like: |
853 | { | 925 | { |
854 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; | 926 | if (debug) |
927 | { | ||
928 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE \"" + singleton_.value_.getString() + "\""; | ||
929 | } else { | ||
930 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; | ||
931 | } | ||
855 | } | 932 | } |
856 | 933 | ||
857 | case comparison::is_not_null: | 934 | case comparison::is_not_null: |
@@ -871,10 +948,25 @@ namespace verbly { | |||
871 | std::list<std::string> clauses; | 948 | std::list<std::string> clauses; |
872 | for (const condition& cond : group_.children_) | 949 | for (const condition& cond : group_.children_) |
873 | { | 950 | { |
874 | clauses.push_back(cond.toSql()); | 951 | clauses.push_back(cond.toSql(false, debug)); |
875 | } | 952 | } |
876 | 953 | ||
877 | return implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); | 954 | if (clauses.empty()) |
955 | { | ||
956 | return ""; | ||
957 | } else if (clauses.size() == 1) | ||
958 | { | ||
959 | return clauses.front(); | ||
960 | } else { | ||
961 | std::string result = implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); | ||
962 | |||
963 | if (toplevel) | ||
964 | { | ||
965 | return result; | ||
966 | } else { | ||
967 | return "(" + result + ")"; | ||
968 | } | ||
969 | } | ||
878 | } | 970 | } |
879 | } | 971 | } |
880 | } | 972 | } |
@@ -988,5 +1080,39 @@ namespace verbly { | |||
988 | throw std::domain_error("Cannot get children of non-group condition"); | 1080 | throw std::domain_error("Cannot get children of non-group condition"); |
989 | } | 1081 | } |
990 | } | 1082 | } |
1083 | |||
1084 | statement::condition statement::condition::flatten() const | ||
1085 | { | ||
1086 | switch (type_) | ||
1087 | { | ||
1088 | case type::empty: | ||
1089 | case type::singleton: | ||
1090 | { | ||
1091 | return *this; | ||
1092 | } | ||
1093 | |||
1094 | case type::group: | ||
1095 | { | ||
1096 | condition result(group_.orlogic_); | ||
1097 | |||
1098 | for (const condition& child : group_.children_) | ||
1099 | { | ||
1100 | condition newChild = child.flatten(); | ||
1101 | |||
1102 | if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_)) | ||
1103 | { | ||
1104 | for (condition subChild : std::move(newChild.group_.children_)) | ||
1105 | { | ||
1106 | result += std::move(subChild); | ||
1107 | } | ||
1108 | } else { | ||
1109 | result += std::move(newChild); | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | return result; | ||
1114 | } | ||
1115 | } | ||
1116 | } | ||
991 | 1117 | ||
992 | }; | 1118 | }; |