gqlite 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/gqlite/gqlite-amalgamate.cpp +816 -307
- metadata +2 -2
@@ -68,6 +68,11 @@ namespace gqlite
|
|
68
68
|
return _v;
|
69
69
|
}
|
70
70
|
template<>
|
71
|
+
inline std::string to_string<std::string_view>(const std::string_view& _v)
|
72
|
+
{
|
73
|
+
return std::string(_v);
|
74
|
+
}
|
75
|
+
template<>
|
71
76
|
inline std::string to_string<const char*>(const char* const& _v)
|
72
77
|
{
|
73
78
|
return _v;
|
@@ -249,7 +254,9 @@ namespace gqlite
|
|
249
254
|
unimplemented_error,
|
250
255
|
// OpenCypher error code
|
251
256
|
column_name_conflict = 100,
|
257
|
+
delete_connected_node,
|
252
258
|
integer_overflow,
|
259
|
+
invalid_aggregation,
|
253
260
|
invalid_argument_type,
|
254
261
|
invalid_delete,
|
255
262
|
invalid_number_literal,
|
@@ -523,12 +530,13 @@ namespace gqlite::oc::algebra
|
|
523
530
|
{
|
524
531
|
enum class expression_type
|
525
532
|
{
|
526
|
-
empty, value, boolean, integer, floating_point, string, map, vector, node, edge, path
|
533
|
+
empty, value, boolean, integer, floating_point, string, map, vector, node, edge, path, all
|
527
534
|
};
|
528
535
|
struct expression_info
|
529
536
|
{
|
530
537
|
expression_type type = expression_type::empty;
|
531
538
|
bool constant = true;
|
539
|
+
bool aggregation_result;
|
532
540
|
};
|
533
541
|
}
|
534
542
|
//END oc/algebra/expression_info.h
|
@@ -669,6 +677,7 @@ TOKEN_KEYWORD(NOT)
|
|
669
677
|
TOKEN_KEYWORD(MATCH)
|
670
678
|
TOKEN_KEYWORD2(NULL_CAPS, "NULL")
|
671
679
|
TOKEN_KEYWORD2(NULL_TOKEN, "null")
|
680
|
+
TOKEN_KEYWORD(OPTIONAL)
|
672
681
|
TOKEN_KEYWORD(OR)
|
673
682
|
TOKEN_KEYWORD(ORDER)
|
674
683
|
TOKEN_KEYWORD(REMOVE)
|
@@ -775,7 +784,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
775
784
|
|
776
785
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
777
786
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
778
|
-
F(_KLASS_NAME_, node_csp, where)
|
787
|
+
F(_KLASS_NAME_, node_csp, where) \
|
788
|
+
F(_KLASS_NAME_, bool, optional)
|
779
789
|
|
780
790
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
781
791
|
|
@@ -877,6 +887,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
877
887
|
|
878
888
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
879
889
|
|
890
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
880
891
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
881
892
|
|
882
893
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -901,7 +912,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
901
912
|
|
902
913
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
903
914
|
|
904
|
-
|
905
915
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
906
916
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
907
917
|
|
@@ -1133,7 +1143,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
1133
1143
|
|
1134
1144
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
1135
1145
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
1136
|
-
F(_KLASS_NAME_, node_csp, where)
|
1146
|
+
F(_KLASS_NAME_, node_csp, where) \
|
1147
|
+
F(_KLASS_NAME_, bool, optional)
|
1137
1148
|
|
1138
1149
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
1139
1150
|
|
@@ -1235,6 +1246,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
1235
1246
|
|
1236
1247
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
1237
1248
|
|
1249
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
1238
1250
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
1239
1251
|
|
1240
1252
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -1259,7 +1271,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
1259
1271
|
|
1260
1272
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
1261
1273
|
|
1262
|
-
|
1263
1274
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
1264
1275
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
1265
1276
|
|
@@ -1376,7 +1387,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
1376
1387
|
|
1377
1388
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
1378
1389
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
1379
|
-
F(_KLASS_NAME_, node_csp, where)
|
1390
|
+
F(_KLASS_NAME_, node_csp, where) \
|
1391
|
+
F(_KLASS_NAME_, bool, optional)
|
1380
1392
|
|
1381
1393
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
1382
1394
|
|
@@ -1478,6 +1490,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
1478
1490
|
|
1479
1491
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
1480
1492
|
|
1493
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
1481
1494
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
1482
1495
|
|
1483
1496
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -1502,7 +1515,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
1502
1515
|
|
1503
1516
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
1504
1517
|
|
1505
|
-
|
1506
1518
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
1507
1519
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
1508
1520
|
|
@@ -1618,7 +1630,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
1618
1630
|
|
1619
1631
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
1620
1632
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
1621
|
-
F(_KLASS_NAME_, node_csp, where)
|
1633
|
+
F(_KLASS_NAME_, node_csp, where) \
|
1634
|
+
F(_KLASS_NAME_, bool, optional)
|
1622
1635
|
|
1623
1636
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
1624
1637
|
|
@@ -1720,6 +1733,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
1720
1733
|
|
1721
1734
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
1722
1735
|
|
1736
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
1723
1737
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
1724
1738
|
|
1725
1739
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -1744,7 +1758,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
1744
1758
|
|
1745
1759
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
1746
1760
|
|
1747
|
-
|
1748
1761
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
1749
1762
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
1750
1763
|
|
@@ -1877,7 +1890,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
1877
1890
|
|
1878
1891
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
1879
1892
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
1880
|
-
F(_KLASS_NAME_, node_csp, where)
|
1893
|
+
F(_KLASS_NAME_, node_csp, where) \
|
1894
|
+
F(_KLASS_NAME_, bool, optional)
|
1881
1895
|
|
1882
1896
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
1883
1897
|
|
@@ -1979,6 +1993,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
1979
1993
|
|
1980
1994
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
1981
1995
|
|
1996
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
1982
1997
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
1983
1998
|
|
1984
1999
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -2003,7 +2018,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
2003
2018
|
|
2004
2019
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
2005
2020
|
|
2006
|
-
|
2007
2021
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
2008
2022
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
2009
2023
|
|
@@ -2137,7 +2151,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
2137
2151
|
|
2138
2152
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
2139
2153
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
2140
|
-
F(_KLASS_NAME_, node_csp, where)
|
2154
|
+
F(_KLASS_NAME_, node_csp, where) \
|
2155
|
+
F(_KLASS_NAME_, bool, optional)
|
2141
2156
|
|
2142
2157
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
2143
2158
|
|
@@ -2239,6 +2254,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
2239
2254
|
|
2240
2255
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
2241
2256
|
|
2257
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
2242
2258
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
2243
2259
|
|
2244
2260
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -2263,7 +2279,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
2263
2279
|
|
2264
2280
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
2265
2281
|
|
2266
|
-
|
2267
2282
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
2268
2283
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
2269
2284
|
|
@@ -2400,7 +2415,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
2400
2415
|
|
2401
2416
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
2402
2417
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
2403
|
-
F(_KLASS_NAME_, node_csp, where)
|
2418
|
+
F(_KLASS_NAME_, node_csp, where) \
|
2419
|
+
F(_KLASS_NAME_, bool, optional)
|
2404
2420
|
|
2405
2421
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
2406
2422
|
|
@@ -2502,6 +2518,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
2502
2518
|
|
2503
2519
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
2504
2520
|
|
2521
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
2505
2522
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
2506
2523
|
|
2507
2524
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -2526,7 +2543,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
2526
2543
|
|
2527
2544
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
2528
2545
|
|
2529
|
-
|
2530
2546
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
2531
2547
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
2532
2548
|
|
@@ -2639,19 +2655,19 @@ namespace gqlite::oc::algebra::visitors
|
|
2639
2655
|
switch(_var->get_value().get_type())
|
2640
2656
|
{
|
2641
2657
|
case value_type::invalid:
|
2642
|
-
return {expression_type::empty, true };
|
2658
|
+
return {expression_type::empty, true, false};
|
2643
2659
|
case value_type::boolean:
|
2644
|
-
return {expression_type::boolean, true };
|
2660
|
+
return {expression_type::boolean, true, false};
|
2645
2661
|
case value_type::integer:
|
2646
|
-
return {expression_type::integer, true };
|
2662
|
+
return {expression_type::integer, true , false};
|
2647
2663
|
case value_type::floating_point:
|
2648
|
-
return {expression_type::floating_point, true };
|
2664
|
+
return {expression_type::floating_point, true, false};
|
2649
2665
|
case value_type::string:
|
2650
|
-
return {expression_type::string, true };
|
2666
|
+
return {expression_type::string, true, false};
|
2651
2667
|
case value_type::map:
|
2652
|
-
return {expression_type::map, true };
|
2668
|
+
return {expression_type::map, true, false};
|
2653
2669
|
case value_type::vector:
|
2654
|
-
return {expression_type::vector, true };
|
2670
|
+
return {expression_type::vector, true, false};
|
2655
2671
|
};
|
2656
2672
|
throw_exception(exception_stage::unspecified, exception_code::internal_error, "Unknown value type.");
|
2657
2673
|
}
|
@@ -2667,32 +2683,50 @@ namespace gqlite::oc::algebra::visitors
|
|
2667
2683
|
}
|
2668
2684
|
return true;
|
2669
2685
|
}
|
2686
|
+
template<typename _T_>
|
2687
|
+
bool aggregation_result_nodes(const _T_& _nodes)
|
2688
|
+
{
|
2689
|
+
for(algebra::node_csp n : _nodes)
|
2690
|
+
{
|
2691
|
+
if(start(n).aggregation_result)
|
2692
|
+
{
|
2693
|
+
return true;
|
2694
|
+
}
|
2695
|
+
}
|
2696
|
+
return false;
|
2697
|
+
}
|
2670
2698
|
expression_info visit(algebra::array_csp _value) override
|
2671
2699
|
{
|
2672
|
-
return {expression_type::vector, constant_nodes(_value->get_array())};
|
2700
|
+
return {expression_type::vector, constant_nodes(_value->get_array()), aggregation_result_nodes(_value->get_array())};
|
2673
2701
|
}
|
2674
2702
|
expression_info visit(algebra::map_csp _value) override
|
2675
2703
|
{
|
2676
|
-
return {expression_type::map, constant_nodes(workarounds::views::values(_value->get_map()))};
|
2704
|
+
return {expression_type::map, constant_nodes(workarounds::views::values(_value->get_map())), aggregation_result_nodes(workarounds::views::values(_value->get_map()))};
|
2677
2705
|
}
|
2678
2706
|
expression_info visit(algebra::member_access_csp _ma) override
|
2679
2707
|
{
|
2680
|
-
return {expression_type::value, start(_ma->get_left()).constant};
|
2708
|
+
return {expression_type::value, start(_ma->get_left()).constant, false};
|
2709
|
+
}
|
2710
|
+
expression_info visit(algebra::all_csp) override
|
2711
|
+
{
|
2712
|
+
return {expression_type::all, false, false};
|
2681
2713
|
}
|
2682
2714
|
expression_info visit(algebra::indexed_access_csp _ia) override
|
2683
2715
|
{
|
2684
|
-
return {expression_type::value, start(_ia->get_left()).constant};
|
2716
|
+
return {expression_type::value, start(_ia->get_left()).constant, false};
|
2685
2717
|
}
|
2686
2718
|
expression_info visit(algebra::has_labels_csp) override
|
2687
2719
|
{
|
2688
|
-
return {expression_type::boolean, false};
|
2720
|
+
return {expression_type::boolean, false, false};
|
2689
2721
|
}
|
2690
|
-
#define GQLITE_ET_LOGICAL_OP(_NAME_)
|
2691
|
-
expression_info visit(algebra::_NAME_ ## _csp _node) override
|
2692
|
-
{
|
2693
|
-
|
2694
|
-
|
2695
|
-
|
2722
|
+
#define GQLITE_ET_LOGICAL_OP(_NAME_) \
|
2723
|
+
expression_info visit(algebra::_NAME_ ## _csp _node) override \
|
2724
|
+
{ \
|
2725
|
+
expression_info left = start(_node->get_left()); \
|
2726
|
+
expression_info right = start(_node->get_right()); \
|
2727
|
+
bool constant = left.constant and right.constant; \
|
2728
|
+
bool aggregation_result = left.aggregation_result or right.aggregation_result; \
|
2729
|
+
return {expression_type::boolean, constant, aggregation_result}; \
|
2696
2730
|
}
|
2697
2731
|
GQLITE_ET_LOGICAL_OP(logical_and)
|
2698
2732
|
GQLITE_ET_LOGICAL_OP(logical_or)
|
@@ -2705,11 +2739,11 @@ namespace gqlite::oc::algebra::visitors
|
|
2705
2739
|
GQLITE_ET_LOGICAL_OP(relational_superior_equal)
|
2706
2740
|
GQLITE_ET_LOGICAL_OP(relational_in)
|
2707
2741
|
GQLITE_ET_LOGICAL_OP(relational_not_in)
|
2708
|
-
#define GQLITE_ET_LOGICAL_UNARY_OP(_NAME_)
|
2709
|
-
expression_info visit(algebra::_NAME_ ## _csp _node) override
|
2710
|
-
{
|
2711
|
-
|
2712
|
-
return {expression_type::boolean, constant};
|
2742
|
+
#define GQLITE_ET_LOGICAL_UNARY_OP(_NAME_) \
|
2743
|
+
expression_info visit(algebra::_NAME_ ## _csp _node) override \
|
2744
|
+
{ \
|
2745
|
+
expression_info info = start(_node->get_value()); \
|
2746
|
+
return {expression_type::boolean, info.constant, info.aggregation_result}; \
|
2713
2747
|
}
|
2714
2748
|
GQLITE_ET_LOGICAL_UNARY_OP(is_null)
|
2715
2749
|
GQLITE_ET_LOGICAL_UNARY_OP(is_not_null)
|
@@ -2719,21 +2753,22 @@ namespace gqlite::oc::algebra::visitors
|
|
2719
2753
|
expression_info left = start(_node->get_left()); \
|
2720
2754
|
expression_info right = start(_node->get_right()); \
|
2721
2755
|
bool constant = left.constant and right.constant; \
|
2722
|
-
|
2756
|
+
bool aggregation_result = left.aggregation_result or right.aggregation_result; \
|
2757
|
+
if(left.type == right.type) return {left.type, constant, aggregation_result}; \
|
2723
2758
|
if(left.type == expression_type::value or right.type == expression_type::value) \
|
2724
|
-
return {expression_type::value, constant};
|
2759
|
+
return {expression_type::value, constant, aggregation_result}; \
|
2725
2760
|
if(left.type == expression_type::floating_point or right.type == expression_type::floating_point) \
|
2726
2761
|
{ \
|
2727
|
-
return {expression_type::floating_point, constant};
|
2762
|
+
return {expression_type::floating_point, constant, aggregation_result}; \
|
2728
2763
|
} \
|
2729
2764
|
if(left.type == expression_type::string or right.type == expression_type::string) \
|
2730
2765
|
{ \
|
2731
|
-
return {expression_type::string, constant};
|
2766
|
+
return {expression_type::string, constant, aggregation_result}; \
|
2732
2767
|
} \
|
2733
2768
|
if(std::is_same_v<algebra::_NAME_ ## _csp, algebra::addition_csp> \
|
2734
2769
|
and left.type == expression_type::vector) \
|
2735
2770
|
{ \
|
2736
|
-
return {expression_type::vector, constant};
|
2771
|
+
return {expression_type::vector, constant, aggregation_result}; \
|
2737
2772
|
} \
|
2738
2773
|
errors::invalid_argument_type(stage, "In binary operation."); \
|
2739
2774
|
}
|
@@ -2745,18 +2780,19 @@ namespace gqlite::oc::algebra::visitors
|
|
2745
2780
|
|
2746
2781
|
expression_info visit(algebra::logical_negation_csp _node)
|
2747
2782
|
{
|
2748
|
-
|
2749
|
-
return {expression_type::boolean, constant};
|
2783
|
+
expression_info ei = start(_node->get_value());
|
2784
|
+
return {expression_type::boolean, ei.constant, ei.aggregation_result};
|
2750
2785
|
}
|
2751
2786
|
expression_info visit(algebra::variable_csp _var) override
|
2752
2787
|
{
|
2753
|
-
return {variables_f(_var->get_identifier()), false};
|
2788
|
+
return {variables_f(_var->get_identifier()), false, false};
|
2754
2789
|
}
|
2755
2790
|
struct function_info
|
2756
2791
|
{
|
2757
2792
|
expression_type return_type;
|
2758
2793
|
std::vector<expression_type> arguments_types;
|
2759
2794
|
bool deterministic;
|
2795
|
+
bool aggregation;
|
2760
2796
|
};
|
2761
2797
|
static std::unordered_multimap<std::string, function_info> create_functions()
|
2762
2798
|
{
|
@@ -2764,29 +2800,52 @@ namespace gqlite::oc::algebra::visitors
|
|
2764
2800
|
using enum expression_type;
|
2765
2801
|
using FI = function_info;
|
2766
2802
|
using V = std::vector<expression_type>;
|
2767
|
-
f.emplace("head", FI{value, V{vector}, true});
|
2768
|
-
f.emplace("id", FI{integer, V{node}, true});
|
2769
|
-
f.emplace("id", FI{integer, V{edge}, true});
|
2770
|
-
f.emplace("keys", FI{vector, V{edge}, true});
|
2771
|
-
f.emplace("keys", FI{vector, V{node}, true});
|
2772
|
-
f.emplace("keys", FI{vector, V{map}, true});
|
2773
|
-
f.emplace("labels", FI{vector, V{node}, true});
|
2774
|
-
f.emplace("properties", FI{map, V{node}, true});
|
2775
|
-
f.emplace("properties", FI{map, V{edge}, true});
|
2776
|
-
f.emplace("properties", FI{map, V{map}, true});
|
2777
|
-
f.emplace("range", FI{string, V{integer, integer}, true});
|
2778
|
-
f.emplace("size", FI{integer, V{vector}, true});
|
2779
|
-
f.emplace("tail", FI{vector, V{vector}, true});
|
2780
|
-
f.emplace("toInteger", FI{integer, V{integer}, true});
|
2781
|
-
f.emplace("toInteger", FI{integer, V{floating_point}, true});
|
2782
|
-
f.emplace("type", FI{string, V{edge}, true});
|
2803
|
+
f.emplace("head", FI{value, V{vector}, true, false});
|
2804
|
+
f.emplace("id", FI{integer, V{node}, true, false});
|
2805
|
+
f.emplace("id", FI{integer, V{edge}, true, false});
|
2806
|
+
f.emplace("keys", FI{vector, V{edge}, true, false});
|
2807
|
+
f.emplace("keys", FI{vector, V{node}, true, false});
|
2808
|
+
f.emplace("keys", FI{vector, V{map}, true, false});
|
2809
|
+
f.emplace("labels", FI{vector, V{node}, true, false});
|
2810
|
+
f.emplace("properties", FI{map, V{node}, true, false});
|
2811
|
+
f.emplace("properties", FI{map, V{edge}, true, false});
|
2812
|
+
f.emplace("properties", FI{map, V{map}, true, false});
|
2813
|
+
f.emplace("range", FI{string, V{integer, integer}, true, false});
|
2814
|
+
f.emplace("size", FI{integer, V{vector}, true, false});
|
2815
|
+
f.emplace("tail", FI{vector, V{vector}, true, false});
|
2816
|
+
f.emplace("toInteger", FI{integer, V{integer}, true, false});
|
2817
|
+
f.emplace("toInteger", FI{integer, V{floating_point}, true, false});
|
2818
|
+
f.emplace("type", FI{string, V{edge}, true, false});
|
2819
|
+
// aggregations
|
2820
|
+
f.emplace("avg", FI{integer, V{value}, true, true});
|
2821
|
+
f.emplace("count", FI{integer, V{value}, true, true});
|
2822
|
+
f.emplace("count", FI{integer, V{all}, true, true});
|
2823
|
+
f.emplace("collect", FI{vector, V{value}, true, true});
|
2824
|
+
f.emplace("max", FI{value, V{value}, true, true});
|
2825
|
+
f.emplace("min", FI{value, V{value}, true, true});
|
2826
|
+
f.emplace("sum", FI{value, V{value}, true, true});
|
2783
2827
|
return f;
|
2784
2828
|
}
|
2785
2829
|
expression_info visit(algebra::function_call_csp _node) override
|
2786
2830
|
{
|
2787
2831
|
if(_node->get_name() == "coalesce")
|
2788
2832
|
{ // coalesce is a special case that can accept any value
|
2789
|
-
|
2833
|
+
expression_type et = expression_type::empty;
|
2834
|
+
bool first = true;
|
2835
|
+
for(const algebra::node_csp& n : _node->get_arguments())
|
2836
|
+
{
|
2837
|
+
expression_info ei = start(n);
|
2838
|
+
if(first)
|
2839
|
+
{
|
2840
|
+
first = false;
|
2841
|
+
et = ei.type;
|
2842
|
+
} else if(et != ei.type)
|
2843
|
+
{
|
2844
|
+
et = expression_type::value;
|
2845
|
+
break;
|
2846
|
+
}
|
2847
|
+
}
|
2848
|
+
return {et, constant_nodes(_node->get_arguments()), aggregation_result_nodes(_node->get_arguments())};
|
2790
2849
|
}
|
2791
2850
|
// 1) Check if all arguments are constant and get their type
|
2792
2851
|
bool constant_arguments = true;
|
@@ -2815,7 +2874,7 @@ namespace gqlite::oc::algebra::visitors
|
|
2815
2874
|
}
|
2816
2875
|
break;
|
2817
2876
|
}
|
2818
|
-
if(match) return {it->second.return_type, it->second.deterministic and constant_arguments};
|
2877
|
+
if(match) return {it->second.return_type, it->second.deterministic and constant_arguments, it->second.aggregation};
|
2819
2878
|
}
|
2820
2879
|
}
|
2821
2880
|
// 3) If no function was found, return an exception for unknown function or invalid arguments
|
@@ -2876,6 +2935,10 @@ namespace gqlite::oc::algebra::visitors
|
|
2876
2935
|
std::string visit(algebra::value_csp _var) override
|
2877
2936
|
{
|
2878
2937
|
return _var->get_value().to_json();
|
2938
|
+
}
|
2939
|
+
std::string visit(algebra::all_csp) override
|
2940
|
+
{
|
2941
|
+
return "*";
|
2879
2942
|
}
|
2880
2943
|
std::string visit(algebra::array_csp _var) override
|
2881
2944
|
{
|
@@ -2922,9 +2985,16 @@ namespace gqlite::oc::algebra::visitors
|
|
2922
2985
|
#define GQLITE_STRINGIFY_UNARY_OP(_NAME_, _OP_) \
|
2923
2986
|
std::string visit(algebra::_NAME_ ## _csp _var) override \
|
2924
2987
|
{ \
|
2925
|
-
return # _OP_ " " + start(_var->get_value());
|
2988
|
+
return # _OP_ " " + start(_var->get_value()); \
|
2926
2989
|
}
|
2927
2990
|
GQLITE_STRINGIFY_UNARY_OP(logical_negation, NOT)
|
2991
|
+
#define GQLITE_STRINGIFY_UNARY_END_OP(_NAME_, _OP_) \
|
2992
|
+
std::string visit(algebra::_NAME_ ## _csp _var) override \
|
2993
|
+
{ \
|
2994
|
+
return start(_var->get_value()) + " " # _OP_; \
|
2995
|
+
}
|
2996
|
+
GQLITE_STRINGIFY_UNARY_END_OP(is_null, IS NULL)
|
2997
|
+
GQLITE_STRINGIFY_UNARY_END_OP(is_not_null, IS NOT NULL)
|
2928
2998
|
std::string visit(algebra::variable_csp _var) override
|
2929
2999
|
{
|
2930
3000
|
return _var->get_identifier();
|
@@ -2984,7 +3054,7 @@ namespace gqlite
|
|
2984
3054
|
|
2985
3055
|
namespace gqlite::backends::sqlite_queries
|
2986
3056
|
{
|
2987
|
-
std::string edge_add_properties(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _edge_id)
|
3057
|
+
inline std::string edge_add_properties(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _edge_id)
|
2988
3058
|
{
|
2989
3059
|
std::stringstream stream;
|
2990
3060
|
|
@@ -2996,11 +3066,11 @@ stream << "_edges AS tblu SET properties=json_patch(tblu.properties, json_set('{
|
|
2996
3066
|
|
2997
3067
|
stream << ( _path );
|
2998
3068
|
|
2999
|
-
stream << "\", ";
|
3069
|
+
stream << "\", gqlite_jsonify(";
|
3000
3070
|
|
3001
3071
|
stream << ( _expr );
|
3002
3072
|
|
3003
|
-
stream << ")) ";
|
3073
|
+
stream << "))) ";
|
3004
3074
|
|
3005
3075
|
stream << ( _what );
|
3006
3076
|
|
@@ -3010,19 +3080,24 @@ stream << ( _edge_id );
|
|
3010
3080
|
|
3011
3081
|
return stream.str();
|
3012
3082
|
}
|
3013
|
-
std::string
|
3083
|
+
inline std::string edge_count_by_nodes(const std::string& _graph_name, const std::string& _what)
|
3014
3084
|
{
|
3015
3085
|
std::stringstream stream;
|
3016
3086
|
|
3017
|
-
stream << "
|
3087
|
+
stream << "WITH source_delete AS NOT MATERIALIZED (";
|
3088
|
+
|
3089
|
+
stream << ( _what );
|
3090
|
+
|
3091
|
+
stream << ")\n"
|
3092
|
+
"SELECT count(*) FROM gqlite_";
|
3018
3093
|
|
3019
3094
|
stream << ( _graph_name );
|
3020
3095
|
|
3021
|
-
stream << "_edges WHERE left
|
3096
|
+
stream << "_edges WHERE left IN source_delete or right IN source_delete";
|
3022
3097
|
|
3023
3098
|
return stream.str();
|
3024
3099
|
}
|
3025
|
-
std::string edge_create(const std::string& _graph_name, const std::string& _values)
|
3100
|
+
inline std::string edge_create(const std::string& _graph_name, const std::string& _values)
|
3026
3101
|
{
|
3027
3102
|
std::stringstream stream;
|
3028
3103
|
|
@@ -3030,7 +3105,7 @@ stream << "INSERT INTO gqlite_";
|
|
3030
3105
|
|
3031
3106
|
stream << ( _graph_name );
|
3032
3107
|
|
3033
|
-
stream << "_edges (label, properties, left, right) ";
|
3108
|
+
stream << "_edges (id, label, properties, left, right) ";
|
3034
3109
|
|
3035
3110
|
stream << ( _values );
|
3036
3111
|
|
@@ -3040,7 +3115,7 @@ stream << "\n"
|
|
3040
3115
|
|
3041
3116
|
return stream.str();
|
3042
3117
|
}
|
3043
|
-
std::string edge_delete(const std::string& _graph_name, const std::string& _what)
|
3118
|
+
inline std::string edge_delete(const std::string& _graph_name, const std::string& _what)
|
3044
3119
|
{
|
3045
3120
|
std::stringstream stream;
|
3046
3121
|
|
@@ -3056,7 +3131,7 @@ stream << ")";
|
|
3056
3131
|
|
3057
3132
|
return stream.str();
|
3058
3133
|
}
|
3059
|
-
std::string
|
3134
|
+
inline std::string edge_delete_by_nodes(const std::string& _graph_name, const std::string& _what)
|
3060
3135
|
{
|
3061
3136
|
std::stringstream stream;
|
3062
3137
|
|
@@ -3073,7 +3148,7 @@ stream << "_edges WHERE left IN source_delete or right IN source_delete";
|
|
3073
3148
|
|
3074
3149
|
return stream.str();
|
3075
3150
|
}
|
3076
|
-
std::string edge_get_label_properties(const std::string& _graph_name)
|
3151
|
+
inline std::string edge_get_label_properties(const std::string& _graph_name)
|
3077
3152
|
{
|
3078
3153
|
std::stringstream stream;
|
3079
3154
|
|
@@ -3085,7 +3160,7 @@ stream << "_edges WHERE id = ?001";
|
|
3085
3160
|
|
3086
3161
|
return stream.str();
|
3087
3162
|
}
|
3088
|
-
std::string edge_set_property(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _edge_id)
|
3163
|
+
inline std::string edge_set_property(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _edge_id)
|
3089
3164
|
{
|
3090
3165
|
std::stringstream stream;
|
3091
3166
|
|
@@ -3097,11 +3172,11 @@ stream << "_edges AS tblu SET properties=json_patch('{}', json_set(tblu.properti
|
|
3097
3172
|
|
3098
3173
|
stream << ( _path );
|
3099
3174
|
|
3100
|
-
stream << "\", ";
|
3175
|
+
stream << "\", gqlite_jsonify(";
|
3101
3176
|
|
3102
3177
|
stream << ( _expr );
|
3103
3178
|
|
3104
|
-
stream << ")) ";
|
3179
|
+
stream << "))) ";
|
3105
3180
|
|
3106
3181
|
stream << ( _what );
|
3107
3182
|
|
@@ -3111,7 +3186,7 @@ stream << ( _edge_id );
|
|
3111
3186
|
|
3112
3187
|
return stream.str();
|
3113
3188
|
}
|
3114
|
-
std::string edge_remove_property(const std::string& _graph_name, const std::string& _what, const std::string& _path, const std::string& _edge_id)
|
3189
|
+
inline std::string edge_remove_property(const std::string& _graph_name, const std::string& _what, const std::string& _path, const std::string& _edge_id)
|
3115
3190
|
{
|
3116
3191
|
std::stringstream stream;
|
3117
3192
|
|
@@ -3133,26 +3208,34 @@ stream << ( _edge_id );
|
|
3133
3208
|
|
3134
3209
|
return stream.str();
|
3135
3210
|
}
|
3136
|
-
std::string function_labels(const std::string& _graph_name, const std::string& _node_id)
|
3211
|
+
inline std::string function_labels(const std::string& _graph_name, const std::string& _node_id)
|
3137
3212
|
{
|
3138
3213
|
std::stringstream stream;
|
3139
3214
|
|
3140
|
-
stream << "(
|
3141
|
-
|
3215
|
+
stream << "(CASE WHEN ";
|
3216
|
+
|
3217
|
+
stream << ( _node_id );
|
3218
|
+
|
3219
|
+
stream << " IS NULL\n"
|
3220
|
+
" THEN NULL\n"
|
3221
|
+
" ELSE\n"
|
3222
|
+
" (SELECT json_group_array(labels.label)\n"
|
3223
|
+
" FROM gqlite_";
|
3142
3224
|
|
3143
3225
|
stream << ( _graph_name );
|
3144
3226
|
|
3145
3227
|
stream << "_labels as l\n"
|
3146
|
-
"
|
3228
|
+
" JOIN gqlite_labels AS labels ON labels.id = l.label WHERE l.node_id = ";
|
3147
3229
|
|
3148
3230
|
stream << ( _node_id );
|
3149
3231
|
|
3150
3232
|
stream << ")\n"
|
3233
|
+
" END)\n"
|
3151
3234
|
"";
|
3152
3235
|
|
3153
3236
|
return stream.str();
|
3154
3237
|
}
|
3155
|
-
std::string get_debug_stats(const std::string& _graph_name)
|
3238
|
+
inline std::string get_debug_stats(const std::string& _graph_name)
|
3156
3239
|
{
|
3157
3240
|
std::stringstream stream;
|
3158
3241
|
|
@@ -3186,11 +3269,26 @@ stream << "_edges t, json_each(properties) j\n"
|
|
3186
3269
|
|
3187
3270
|
stream << ( _graph_name );
|
3188
3271
|
|
3189
|
-
stream << "_labels"
|
3272
|
+
stream << "_labels\n"
|
3273
|
+
"UNION ALL SELECT COUNT(DISTINCT label) FROM (SELECT label FROM gqlite_";
|
3274
|
+
|
3275
|
+
stream << ( _graph_name );
|
3276
|
+
|
3277
|
+
stream << "_edges UNION SELECT label FROM gqlite_";
|
3278
|
+
|
3279
|
+
stream << ( _graph_name );
|
3280
|
+
|
3281
|
+
stream << "_labels)\n"
|
3282
|
+
"UNION ALL SELECT COUNT(DISTINCT label) FROM gqlite_";
|
3283
|
+
|
3284
|
+
stream << ( _graph_name );
|
3285
|
+
|
3286
|
+
stream << "_labels\n"
|
3287
|
+
"";
|
3190
3288
|
|
3191
3289
|
return stream.str();
|
3192
3290
|
}
|
3193
|
-
std::string graph_create(const std::string& _graph_name)
|
3291
|
+
inline std::string graph_create(const std::string& _graph_name)
|
3194
3292
|
{
|
3195
3293
|
std::stringstream stream;
|
3196
3294
|
|
@@ -3269,7 +3367,8 @@ stream << ( _graph_name );
|
|
3269
3367
|
|
3270
3368
|
stream << "_labels as l ON l.node_id = n.id\n"
|
3271
3369
|
" LEFT JOIN gqlite_labels AS labels ON labels.id = l.label\n"
|
3272
|
-
" GROUP BY n.id)
|
3370
|
+
" GROUP BY n.id)\n"
|
3371
|
+
" UNION SELECT NULL, NULL;\n"
|
3273
3372
|
"\n"
|
3274
3373
|
"CREATE VIEW gqlite_";
|
3275
3374
|
|
@@ -3285,12 +3384,12 @@ stream << ( _graph_name );
|
|
3285
3384
|
|
3286
3385
|
stream << "_edges e\n"
|
3287
3386
|
" JOIN gqlite_labels label ON label.id = e.label\n"
|
3288
|
-
"\n"
|
3387
|
+
" UNION SELECT NULL, NULL\n"
|
3289
3388
|
"";
|
3290
3389
|
|
3291
3390
|
return stream.str();
|
3292
3391
|
}
|
3293
|
-
std::string graph_has(const std::string& _graph_name)
|
3392
|
+
inline std::string graph_has(const std::string& _graph_name)
|
3294
3393
|
{
|
3295
3394
|
std::stringstream stream;
|
3296
3395
|
|
@@ -3312,7 +3411,7 @@ stream << "_labels')";
|
|
3312
3411
|
|
3313
3412
|
return stream.str();
|
3314
3413
|
}
|
3315
|
-
std::string label_create_table()
|
3414
|
+
inline std::string label_create_table()
|
3316
3415
|
{
|
3317
3416
|
std::stringstream stream;
|
3318
3417
|
|
@@ -3321,7 +3420,7 @@ stream << "CREATE TABLE gqlite_labels(id INTEGER PRIMARY KEY AUTOINCREMENT, labe
|
|
3321
3420
|
|
3322
3421
|
return stream.str();
|
3323
3422
|
}
|
3324
|
-
std::string label_get_from_id()
|
3423
|
+
inline std::string label_get_from_id()
|
3325
3424
|
{
|
3326
3425
|
std::stringstream stream;
|
3327
3426
|
|
@@ -3330,7 +3429,7 @@ stream << "SELECT label FROM gqlite_labels WHERE id = ?001\n"
|
|
3330
3429
|
|
3331
3430
|
return stream.str();
|
3332
3431
|
}
|
3333
|
-
std::string label_get_from_name()
|
3432
|
+
inline std::string label_get_from_name()
|
3334
3433
|
{
|
3335
3434
|
std::stringstream stream;
|
3336
3435
|
|
@@ -3339,7 +3438,7 @@ stream << "SELECT id FROM gqlite_labels WHERE label = ?001\n"
|
|
3339
3438
|
|
3340
3439
|
return stream.str();
|
3341
3440
|
}
|
3342
|
-
std::string label_insert()
|
3441
|
+
inline std::string label_insert()
|
3343
3442
|
{
|
3344
3443
|
std::stringstream stream;
|
3345
3444
|
|
@@ -3347,7 +3446,7 @@ stream << "INSERT INTO gqlite_labels(label) VALUES (?001)";
|
|
3347
3446
|
|
3348
3447
|
return stream.str();
|
3349
3448
|
}
|
3350
|
-
std::string node_add_label(const std::string& _graph_name)
|
3449
|
+
inline std::string node_add_label(const std::string& _graph_name)
|
3351
3450
|
{
|
3352
3451
|
std::stringstream stream;
|
3353
3452
|
|
@@ -3355,11 +3454,11 @@ stream << "INSERT INTO gqlite_";
|
|
3355
3454
|
|
3356
3455
|
stream << ( _graph_name );
|
3357
3456
|
|
3358
|
-
stream << "_labels(label, node_id) SELECT label.value, node.value FROM json_each(?001) label JOIN json_each(?002) node";
|
3457
|
+
stream << "_labels(label, node_id) SELECT label.value, node.value FROM json_each(?001) label JOIN json_each(?002) node WHERE node.value IS NOT NULL";
|
3359
3458
|
|
3360
3459
|
return stream.str();
|
3361
3460
|
}
|
3362
|
-
std::string node_add_labels(const std::string& _graph_name, const std::string& _what)
|
3461
|
+
inline std::string node_add_labels(const std::string& _graph_name, const std::string& _what)
|
3363
3462
|
{
|
3364
3463
|
std::stringstream stream;
|
3365
3464
|
|
@@ -3376,7 +3475,7 @@ stream << "\n"
|
|
3376
3475
|
|
3377
3476
|
return stream.str();
|
3378
3477
|
}
|
3379
|
-
std::string node_add_properties(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _node_id)
|
3478
|
+
inline std::string node_add_properties(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _node_id)
|
3380
3479
|
{
|
3381
3480
|
std::stringstream stream;
|
3382
3481
|
|
@@ -3388,11 +3487,11 @@ stream << "_nodes AS tblu SET properties=json_patch(tblu.properties, json_set('{
|
|
3388
3487
|
|
3389
3488
|
stream << ( _path );
|
3390
3489
|
|
3391
|
-
stream << "\", ";
|
3490
|
+
stream << "\", gqlite_jsonify(";
|
3392
3491
|
|
3393
3492
|
stream << ( _expr );
|
3394
3493
|
|
3395
|
-
stream << ")) ";
|
3494
|
+
stream << "))) ";
|
3396
3495
|
|
3397
3496
|
stream << ( _what );
|
3398
3497
|
|
@@ -3402,7 +3501,7 @@ stream << ( _node_id );
|
|
3402
3501
|
|
3403
3502
|
return stream.str();
|
3404
3503
|
}
|
3405
|
-
std::string node_create(const std::string& _graph_name, const std::string& _values)
|
3504
|
+
inline std::string node_create(const std::string& _graph_name, const std::string& _values)
|
3406
3505
|
{
|
3407
3506
|
std::stringstream stream;
|
3408
3507
|
|
@@ -3410,7 +3509,7 @@ stream << "INSERT INTO gqlite_";
|
|
3410
3509
|
|
3411
3510
|
stream << ( _graph_name );
|
3412
3511
|
|
3413
|
-
stream << "_nodes (properties) ";
|
3512
|
+
stream << "_nodes (id, properties) ";
|
3414
3513
|
|
3415
3514
|
stream << ( _values );
|
3416
3515
|
|
@@ -3419,7 +3518,7 @@ stream << "\n"
|
|
3419
3518
|
|
3420
3519
|
return stream.str();
|
3421
3520
|
}
|
3422
|
-
std::string node_delete(const std::string& _graph_name, const std::string& _what)
|
3521
|
+
inline std::string node_delete(const std::string& _graph_name, const std::string& _what)
|
3423
3522
|
{
|
3424
3523
|
std::stringstream stream;
|
3425
3524
|
|
@@ -3444,7 +3543,7 @@ stream << ")";
|
|
3444
3543
|
|
3445
3544
|
return stream.str();
|
3446
3545
|
}
|
3447
|
-
std::string node_get_labels(const std::string& _graph_name)
|
3546
|
+
inline std::string node_get_labels(const std::string& _graph_name)
|
3448
3547
|
{
|
3449
3548
|
std::stringstream stream;
|
3450
3549
|
|
@@ -3456,7 +3555,7 @@ stream << "_labels WHERE node_id = ?001";
|
|
3456
3555
|
|
3457
3556
|
return stream.str();
|
3458
3557
|
}
|
3459
|
-
std::string node_get_properties(const std::string& _graph_name)
|
3558
|
+
inline std::string node_get_properties(const std::string& _graph_name)
|
3460
3559
|
{
|
3461
3560
|
std::stringstream stream;
|
3462
3561
|
|
@@ -3468,7 +3567,7 @@ stream << "_nodes WHERE id = ?001";
|
|
3468
3567
|
|
3469
3568
|
return stream.str();
|
3470
3569
|
}
|
3471
|
-
std::string node_remove_label(const std::string& _graph_name, const std::string& _what, const std::string& _labels)
|
3570
|
+
inline std::string node_remove_label(const std::string& _graph_name, const std::string& _what, const std::string& _labels)
|
3472
3571
|
{
|
3473
3572
|
std::stringstream stream;
|
3474
3573
|
|
@@ -3489,7 +3588,7 @@ stream << ")\n"
|
|
3489
3588
|
|
3490
3589
|
return stream.str();
|
3491
3590
|
}
|
3492
|
-
std::string node_remove_property(const std::string& _graph_name, const std::string& _what, const std::string& _path, const std::string& _node_id)
|
3591
|
+
inline std::string node_remove_property(const std::string& _graph_name, const std::string& _what, const std::string& _path, const std::string& _node_id)
|
3493
3592
|
{
|
3494
3593
|
std::stringstream stream;
|
3495
3594
|
|
@@ -3511,7 +3610,7 @@ stream << ( _node_id );
|
|
3511
3610
|
|
3512
3611
|
return stream.str();
|
3513
3612
|
}
|
3514
|
-
std::string node_set_property(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _node_id)
|
3613
|
+
inline std::string node_set_property(const std::string& _graph_name, const std::string& _what, const std::string& _expr, const std::string& _path, const std::string& _node_id)
|
3515
3614
|
{
|
3516
3615
|
std::stringstream stream;
|
3517
3616
|
|
@@ -3523,11 +3622,11 @@ stream << "_nodes AS tblu SET properties=json_patch('{}', json_set(tblu.properti
|
|
3523
3622
|
|
3524
3623
|
stream << ( _path );
|
3525
3624
|
|
3526
|
-
stream << "\", ";
|
3625
|
+
stream << "\", gqlite_jsonify(";
|
3527
3626
|
|
3528
3627
|
stream << ( _expr );
|
3529
3628
|
|
3530
|
-
stream << ")) ";
|
3629
|
+
stream << "))) ";
|
3531
3630
|
|
3532
3631
|
stream << ( _what );
|
3533
3632
|
|
@@ -3537,7 +3636,7 @@ stream << ( _node_id );
|
|
3537
3636
|
|
3538
3637
|
return stream.str();
|
3539
3638
|
}
|
3540
|
-
std::string node_select_many(const std::string& _graph_name, int _idx)
|
3639
|
+
inline std::string node_select_many(const std::string& _graph_name, int _idx)
|
3541
3640
|
{
|
3542
3641
|
std::stringstream stream;
|
3543
3642
|
|
@@ -3556,12 +3655,32 @@ stream << ") s ON s.value = nas.id\n"
|
|
3556
3655
|
|
3557
3656
|
return stream.str();
|
3558
3657
|
}
|
3559
|
-
std::string table_has()
|
3658
|
+
inline std::string table_has()
|
3560
3659
|
{
|
3561
3660
|
std::stringstream stream;
|
3562
3661
|
|
3563
3662
|
stream << "SELECT count(*) FROM sqlite_master WHERE type='table' AND (name=?001)";
|
3564
3663
|
|
3664
|
+
return stream.str();
|
3665
|
+
}
|
3666
|
+
inline std::string uid_create_table()
|
3667
|
+
{
|
3668
|
+
std::stringstream stream;
|
3669
|
+
|
3670
|
+
stream << "CREATE TABLE gqlite_uids(name TEXT PRIMARY KEY, value INTEGER NOT NULL);\n"
|
3671
|
+
"INSERT INTO gqlite_uids VALUES ('nodes', 0);\n"
|
3672
|
+
"INSERT INTO gqlite_uids VALUES ('edges', 0)\n"
|
3673
|
+
"";
|
3674
|
+
|
3675
|
+
return stream.str();
|
3676
|
+
}
|
3677
|
+
inline std::string uid_next()
|
3678
|
+
{
|
3679
|
+
std::stringstream stream;
|
3680
|
+
|
3681
|
+
stream << "UPDATE gqlite_uids SET value=value+1 WHERE name=?001\n"
|
3682
|
+
"RETURNING value";
|
3683
|
+
|
3565
3684
|
return stream.str();
|
3566
3685
|
}
|
3567
3686
|
}
|
@@ -3646,6 +3765,11 @@ connection connection::create_from_sqlite_file(const std::string& _filename, con
|
|
3646
3765
|
|
3647
3766
|
value connection::execute_oc_query(const std::string& _string, const value_map& _bindings)
|
3648
3767
|
{
|
3768
|
+
#if 0
|
3769
|
+
std::cout << "============= execute_oc_query =============\n"
|
3770
|
+
<< _string <<
|
3771
|
+
"\n============================================" << std::endl;
|
3772
|
+
#endif
|
3649
3773
|
std::stringstream ss(_string);
|
3650
3774
|
oc::lexer l(&ss);
|
3651
3775
|
oc::parser parser(&l, _bindings);
|
@@ -3776,8 +3900,12 @@ const char* exception::what() const throw()
|
|
3776
3900
|
d->full_error += "UnimplementedError: "; break;
|
3777
3901
|
case column_name_conflict:
|
3778
3902
|
d->full_error += "ColumnNameConflict: "; break;
|
3903
|
+
case delete_connected_node:
|
3904
|
+
d->full_error += "DeleteConnectedNode: "; break;
|
3779
3905
|
case integer_overflow:
|
3780
3906
|
d->full_error += "IntegerOverflow: "; break;
|
3907
|
+
case invalid_aggregation:
|
3908
|
+
d->full_error += "InvalidAggregation: "; break;
|
3781
3909
|
case invalid_argument_type:
|
3782
3910
|
d->full_error += "InvalidArgumentType: "; break;
|
3783
3911
|
case invalid_delete:
|
@@ -4549,6 +4677,7 @@ TOKEN_KEYWORD(NOT)
|
|
4549
4677
|
TOKEN_KEYWORD(MATCH)
|
4550
4678
|
TOKEN_KEYWORD2(NULL_CAPS, "NULL")
|
4551
4679
|
TOKEN_KEYWORD2(NULL_TOKEN, "null")
|
4680
|
+
TOKEN_KEYWORD(OPTIONAL)
|
4552
4681
|
TOKEN_KEYWORD(OR)
|
4553
4682
|
TOKEN_KEYWORD(ORDER)
|
4554
4683
|
TOKEN_KEYWORD(REMOVE)
|
@@ -4786,14 +4915,14 @@ struct parser::data
|
|
4786
4915
|
int id = 0;
|
4787
4916
|
algebra::node_csp parse_call();
|
4788
4917
|
algebra::node_csp parse_create();
|
4789
|
-
algebra::node_csp parse_match();
|
4918
|
+
algebra::node_csp parse_match(bool _optional);
|
4790
4919
|
algebra::node_csp parse_return();
|
4791
4920
|
algebra::node_csp parse_with();
|
4792
4921
|
algebra::node_csp parse_unwind();
|
4793
4922
|
algebra::node_csp parse_delete();
|
4794
4923
|
algebra::node_csp parse_set();
|
4795
4924
|
algebra::node_csp parse_remove();
|
4796
|
-
algebra::modifiers_csp parse_modifiers();
|
4925
|
+
algebra::modifiers_csp parse_modifiers(const std::vector<algebra::named_expression_csp>& _expressions);
|
4797
4926
|
std::vector<algebra::alternative<algebra::graph_node, algebra::graph_edge>> parse_patterns(bool _creation_mode);
|
4798
4927
|
algebra::node_csp parse_map();
|
4799
4928
|
algebra::node_csp parse_properties();
|
@@ -4973,7 +5102,7 @@ algebra::node_csp parser::data::parse_create()
|
|
4973
5102
|
return std::make_shared<algebra::create>(parse_patterns(true));
|
4974
5103
|
}
|
4975
5104
|
|
4976
|
-
algebra::node_csp parser::data::parse_match()
|
5105
|
+
algebra::node_csp parser::data::parse_match(bool _optional)
|
4977
5106
|
{
|
4978
5107
|
get_next_token();
|
4979
5108
|
std::vector<algebra::alternative<algebra::graph_node, algebra::graph_edge>> patterns = parse_patterns(false);
|
@@ -4982,8 +5111,12 @@ algebra::node_csp parser::data::parse_match()
|
|
4982
5111
|
{
|
4983
5112
|
get_next_token();
|
4984
5113
|
where = parse_expression();
|
5114
|
+
if(expression_analyser.start(where).aggregation_result)
|
5115
|
+
{
|
5116
|
+
report_error(tok, exception_code::invalid_aggregation, "in where expression.");
|
5117
|
+
}
|
4985
5118
|
}
|
4986
|
-
return std::make_shared<algebra::match>(patterns, where);
|
5119
|
+
return std::make_shared<algebra::match>(patterns, where, _optional);
|
4987
5120
|
}
|
4988
5121
|
|
4989
5122
|
std::vector<algebra::named_expression_csp> parser::data::parse_named_expressions()
|
@@ -5030,7 +5163,7 @@ algebra::node_csp parser::data::parse_with()
|
|
5030
5163
|
if(tok.type == token_type::STAR)
|
5031
5164
|
{
|
5032
5165
|
get_next_token();
|
5033
|
-
return std::make_shared<algebra::with>(true, std::vector<algebra::named_expression_csp>(), parse_modifiers());
|
5166
|
+
return std::make_shared<algebra::with>(true, std::vector<algebra::named_expression_csp>(), parse_modifiers({}));
|
5034
5167
|
}
|
5035
5168
|
std::vector<algebra::named_expression_csp> named_expressions = parse_named_expressions();
|
5036
5169
|
std::vector<std::string> new_variables;
|
@@ -5048,8 +5181,8 @@ algebra::node_csp parser::data::parse_with()
|
|
5048
5181
|
++it;
|
5049
5182
|
}
|
5050
5183
|
}
|
5051
|
-
gqlite_debug("With new variables {} kept variables {}", new_variables, std::views::keys(bounded_variables));
|
5052
|
-
return std::make_shared<algebra::with>(false, named_expressions, parse_modifiers());
|
5184
|
+
// gqlite_debug("With new variables {} kept variables {}", new_variables, std::views::keys(bounded_variables));
|
5185
|
+
return std::make_shared<algebra::with>(false, named_expressions, parse_modifiers(named_expressions));
|
5053
5186
|
}
|
5054
5187
|
|
5055
5188
|
algebra::node_csp parser::data::parse_unwind()
|
@@ -5218,14 +5351,14 @@ algebra::node_csp parser::data::parse_return()
|
|
5218
5351
|
if(tok.type == token_type::STAR)
|
5219
5352
|
{
|
5220
5353
|
get_next_token();
|
5221
|
-
return std::make_shared<algebra::return_statement>(true, std::vector<algebra::named_expression_csp>(), parse_modifiers());
|
5354
|
+
return std::make_shared<algebra::return_statement>(true, std::vector<algebra::named_expression_csp>(), parse_modifiers({}));
|
5222
5355
|
}
|
5223
5356
|
std::vector<algebra::named_expression_csp> named_expressions = parse_named_expressions();
|
5224
5357
|
for(algebra::named_expression_csp ne : named_expressions)
|
5225
5358
|
{
|
5226
5359
|
bind_variable(ne->get_name(), ne->get_expression(), expression_analyser.start(ne->get_expression()).type, true);
|
5227
5360
|
}
|
5228
|
-
return std::make_shared<algebra::return_statement>(false, named_expressions, parse_modifiers());
|
5361
|
+
return std::make_shared<algebra::return_statement>(false, named_expressions, parse_modifiers(named_expressions));
|
5229
5362
|
}
|
5230
5363
|
|
5231
5364
|
namespace
|
@@ -5241,7 +5374,7 @@ namespace
|
|
5241
5374
|
};
|
5242
5375
|
}
|
5243
5376
|
|
5244
|
-
algebra::modifiers_csp parser::data::parse_modifiers()
|
5377
|
+
algebra::modifiers_csp parser::data::parse_modifiers(const std::vector<algebra::named_expression_csp>& _expressions)
|
5245
5378
|
{
|
5246
5379
|
algebra::node_csp skip, limit;
|
5247
5380
|
algebra::order_by_csp order_by;
|
@@ -5285,6 +5418,24 @@ algebra::modifiers_csp parser::data::parse_modifiers()
|
|
5285
5418
|
{
|
5286
5419
|
bool asc = true;
|
5287
5420
|
algebra::node_csp expression = parse_expression();
|
5421
|
+
if(expression_analyser.start(expression).aggregation_result)
|
5422
|
+
{
|
5423
|
+
bool has_same = false;
|
5424
|
+
|
5425
|
+
for(const algebra::named_expression_csp& ne : _expressions)
|
5426
|
+
{
|
5427
|
+
if(ne->get_expression()->equals(expression))
|
5428
|
+
{
|
5429
|
+
has_same = true;
|
5430
|
+
break;
|
5431
|
+
}
|
5432
|
+
}
|
5433
|
+
if(not has_same)
|
5434
|
+
{
|
5435
|
+
report_error(tok, exception_code::invalid_aggregation, "in order by expression.");
|
5436
|
+
}
|
5437
|
+
|
5438
|
+
}
|
5288
5439
|
if(tok.type == token_type::ASC)
|
5289
5440
|
{
|
5290
5441
|
get_next_token();
|
@@ -5660,6 +5811,11 @@ algebra::node_csp parser::data::parse_terminal_expression()
|
|
5660
5811
|
get_next_token();
|
5661
5812
|
return std::make_shared<algebra::value>(it->second);
|
5662
5813
|
}
|
5814
|
+
case token_type::STAR:
|
5815
|
+
{
|
5816
|
+
get_next_token();
|
5817
|
+
return std::make_shared<algebra::all>();
|
5818
|
+
}
|
5663
5819
|
default:
|
5664
5820
|
report_unexpected(tok);
|
5665
5821
|
}
|
@@ -5769,29 +5925,71 @@ algebra::node_csp parser::data::parse_relational_expression()
|
|
5769
5925
|
}
|
5770
5926
|
}
|
5771
5927
|
case token_type::EQUAL:
|
5772
|
-
get_next_token();
|
5773
|
-
return std::make_shared<algebra::relational_equal>(node, parse_relational_expression());
|
5774
5928
|
case token_type::DIFFERENT:
|
5775
|
-
get_next_token();
|
5776
|
-
return std::make_shared<algebra::relational_different>(node, parse_relational_expression());
|
5777
5929
|
case token_type::INFERIOR:
|
5778
|
-
get_next_token();
|
5779
|
-
return std::make_shared<algebra::relational_inferior>(node, parse_relational_expression());
|
5780
5930
|
case token_type::SUPERIOR:
|
5781
|
-
get_next_token();
|
5782
|
-
return std::make_shared<algebra::relational_superior>(node, parse_relational_expression());
|
5783
5931
|
case token_type::INFERIOR_EQUAL:
|
5784
|
-
get_next_token();
|
5785
|
-
return std::make_shared<algebra::relational_inferior_equal>(node, parse_relational_expression());
|
5786
5932
|
case token_type::SUPERIOR_EQUAL:
|
5787
|
-
|
5788
|
-
|
5933
|
+
{
|
5934
|
+
algebra::node_csp out_node;
|
5935
|
+
while(tok.type != token_type::END_OF_FILE)
|
5936
|
+
{
|
5937
|
+
token_type current_op = tok.type;
|
5938
|
+
get_next_token();
|
5939
|
+
algebra::node_csp node_rhs = parse_additive_expression();
|
5940
|
+
algebra::node_csp current_rel_node;
|
5941
|
+
switch (current_op)
|
5942
|
+
{
|
5943
|
+
case token_type::EQUAL:
|
5944
|
+
current_rel_node = std::make_shared<algebra::relational_equal>(node, node_rhs);
|
5945
|
+
break;
|
5946
|
+
case token_type::DIFFERENT:
|
5947
|
+
current_rel_node = std::make_shared<algebra::relational_different>(node, node_rhs);
|
5948
|
+
break;
|
5949
|
+
case token_type::INFERIOR:
|
5950
|
+
current_rel_node = std::make_shared<algebra::relational_inferior>(node, node_rhs);
|
5951
|
+
break;
|
5952
|
+
case token_type::SUPERIOR:
|
5953
|
+
current_rel_node = std::make_shared<algebra::relational_superior>(node, node_rhs);
|
5954
|
+
break;
|
5955
|
+
case token_type::INFERIOR_EQUAL:
|
5956
|
+
current_rel_node = std::make_shared<algebra::relational_inferior_equal>(node, node_rhs);
|
5957
|
+
break;
|
5958
|
+
case token_type::SUPERIOR_EQUAL:
|
5959
|
+
current_rel_node = std::make_shared<algebra::relational_superior_equal>(node, node_rhs);
|
5960
|
+
break;
|
5961
|
+
default:
|
5962
|
+
report_error(tok, exception_code::internal_error, "While parsing relational expression.");
|
5963
|
+
}
|
5964
|
+
if(out_node)
|
5965
|
+
{
|
5966
|
+
out_node = std::make_shared<algebra::logical_and>(out_node, current_rel_node);
|
5967
|
+
} else {
|
5968
|
+
out_node = current_rel_node;
|
5969
|
+
}
|
5970
|
+
switch(tok.type)
|
5971
|
+
{
|
5972
|
+
case token_type::EQUAL:
|
5973
|
+
case token_type::DIFFERENT:
|
5974
|
+
case token_type::INFERIOR:
|
5975
|
+
case token_type::SUPERIOR:
|
5976
|
+
case token_type::INFERIOR_EQUAL:
|
5977
|
+
case token_type::SUPERIOR_EQUAL:
|
5978
|
+
node = node_rhs;
|
5979
|
+
break;
|
5980
|
+
default:
|
5981
|
+
return out_node;
|
5982
|
+
}
|
5983
|
+
}
|
5984
|
+
report_unexpected(tok);
|
5985
|
+
}
|
5986
|
+
|
5789
5987
|
case token_type::IN:
|
5790
5988
|
{
|
5791
5989
|
get_next_token();
|
5792
5990
|
algebra::node_csp container = parse_expression();
|
5793
5991
|
algebra::expression_type container_type = expression_analyser.start(container).type;
|
5794
|
-
errors::check_argument_types(container_type, {algebra::expression_type::map, algebra::expression_type::vector, algebra::expression_type::value}, exception_stage::compiletime, "Relational IN can only be applied on vector/map.");
|
5992
|
+
errors::check_argument_types(container_type, {algebra::expression_type::map, algebra::expression_type::vector, algebra::expression_type::value, algebra::expression_type::empty}, exception_stage::compiletime, "Relational IN can only be applied on vector/map.");
|
5795
5993
|
if(container_type == algebra::expression_type::map)
|
5796
5994
|
{
|
5797
5995
|
errors::check_argument_types(expression_analyser.start(node).type, {algebra::expression_type::string, algebra::expression_type::value}, exception_stage::compiletime, "Relational IN on map expect a string.");
|
@@ -6021,8 +6219,13 @@ algebra::node_csp parser::parse()
|
|
6021
6219
|
case token_type::CREATE:
|
6022
6220
|
nodes.push_back(d->parse_create());
|
6023
6221
|
break;
|
6222
|
+
case token_type::OPTIONAL:
|
6223
|
+
d->get_next_token();
|
6224
|
+
d->is_of_type(token_type::MATCH);
|
6225
|
+
nodes.push_back(d->parse_match(true));
|
6226
|
+
break;
|
6024
6227
|
case token_type::MATCH:
|
6025
|
-
nodes.push_back(d->parse_match());
|
6228
|
+
nodes.push_back(d->parse_match(false));
|
6026
6229
|
break;
|
6027
6230
|
case token_type::WITH:
|
6028
6231
|
nodes.push_back(d->parse_with());
|
@@ -6175,6 +6378,7 @@ TOKEN_KEYWORD(NOT)
|
|
6175
6378
|
TOKEN_KEYWORD(MATCH)
|
6176
6379
|
TOKEN_KEYWORD2(NULL_CAPS, "NULL")
|
6177
6380
|
TOKEN_KEYWORD2(NULL_TOKEN, "null")
|
6381
|
+
TOKEN_KEYWORD(OPTIONAL)
|
6178
6382
|
TOKEN_KEYWORD(OR)
|
6179
6383
|
TOKEN_KEYWORD(ORDER)
|
6180
6384
|
TOKEN_KEYWORD(REMOVE)
|
@@ -6245,7 +6449,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
6245
6449
|
|
6246
6450
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
6247
6451
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
6248
|
-
F(_KLASS_NAME_, node_csp, where)
|
6452
|
+
F(_KLASS_NAME_, node_csp, where) \
|
6453
|
+
F(_KLASS_NAME_, bool, optional)
|
6249
6454
|
|
6250
6455
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
6251
6456
|
|
@@ -6347,6 +6552,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
6347
6552
|
|
6348
6553
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
6349
6554
|
|
6555
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
6350
6556
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
6351
6557
|
|
6352
6558
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -6371,7 +6577,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
6371
6577
|
|
6372
6578
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
6373
6579
|
|
6374
|
-
|
6375
6580
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
6376
6581
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
6377
6582
|
|
@@ -6592,7 +6797,8 @@ OC_ALGEBRA_GENERATE(create, OC_ALGEBRA_CREATE_NODES_MEMBERS)
|
|
6592
6797
|
|
6593
6798
|
#define OC_ALGEBRA_MATCH_NODES_MEMBERS(_KLASS_NAME_, F) \
|
6594
6799
|
F(_KLASS_NAME_, std::vector<alternative<GQLITE_LIST(graph_node, graph_edge)>>, patterns) \
|
6595
|
-
F(_KLASS_NAME_, node_csp, where)
|
6800
|
+
F(_KLASS_NAME_, node_csp, where) \
|
6801
|
+
F(_KLASS_NAME_, bool, optional)
|
6596
6802
|
|
6597
6803
|
OC_ALGEBRA_GENERATE(match, OC_ALGEBRA_MATCH_NODES_MEMBERS)
|
6598
6804
|
|
@@ -6694,6 +6900,7 @@ OC_ALGEBRA_GENERATE(edit_labels, OC_ALGEBRA_EDIT_LABELS_MEMBERS)
|
|
6694
6900
|
|
6695
6901
|
#define OC_ALGEBRA_NO_MEMBERS(_KLASS_NAME_, F)
|
6696
6902
|
|
6903
|
+
OC_ALGEBRA_GENERATE(all, OC_ALGEBRA_NO_MEMBERS)
|
6697
6904
|
OC_ALGEBRA_GENERATE(end_of_list, OC_ALGEBRA_NO_MEMBERS)
|
6698
6905
|
|
6699
6906
|
#define OC_ALGEBRA_GRAPH_NODE_MEMBERS(_KLASS_NAME_, F) \
|
@@ -6718,7 +6925,6 @@ OC_ALGEBRA_GENERATE(graph_edge, OC_ALGEBRA_GRAPH_EDGE_MEMBERS)
|
|
6718
6925
|
|
6719
6926
|
OC_ALGEBRA_GENERATE(value, OC_ALGEBRA_VALUE_MEMBERS)
|
6720
6927
|
|
6721
|
-
|
6722
6928
|
#define OC_ALGEBRA_MAP_MEMBERS(_KLASS_NAME_, F) \
|
6723
6929
|
F(_KLASS_NAME_, std::unordered_map<GQLITE_LIST(std::string, node_csp)>, map)
|
6724
6930
|
|
@@ -7233,11 +7439,17 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7233
7439
|
struct sql_query_builder
|
7234
7440
|
{
|
7235
7441
|
std::size_t uid = 0;
|
7236
|
-
std::size_t table_count = 0;
|
7237
7442
|
std::string variables;
|
7238
|
-
std::string
|
7443
|
+
std::string group_variables;
|
7444
|
+
bool has_aggregation_result = false;
|
7445
|
+
struct table
|
7446
|
+
{
|
7447
|
+
sql_join join;
|
7448
|
+
std::string table, name;
|
7449
|
+
};
|
7450
|
+
std::vector<table> tables;
|
7239
7451
|
std::string join_conditions;
|
7240
|
-
std::string where_conditions;
|
7452
|
+
// std::string where_conditions;
|
7241
7453
|
std::string modifiers;
|
7242
7454
|
std::map<int, value> bindings;
|
7243
7455
|
std::size_t next_uid()
|
@@ -7253,40 +7465,35 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7253
7465
|
/**
|
7254
7466
|
* Add a new variable with a generic name format.
|
7255
7467
|
*/
|
7256
|
-
std::string add_variable(const std::string& _expression, const char* _format = "var_{}")
|
7468
|
+
std::string add_variable(const std::string& _expression, bool _is_aggregation_result, const char* _format = "var_{}")
|
7257
7469
|
{
|
7258
7470
|
std::string name = format_string(_format, next_uid());
|
7259
|
-
return add_variable_with_name(_expression, name);
|
7471
|
+
return add_variable_with_name(_expression, name, _is_aggregation_result);
|
7260
7472
|
}
|
7261
7473
|
/**
|
7262
7474
|
* Add a new variable with the given name.
|
7263
7475
|
*/
|
7264
|
-
std::string add_variable_with_name(const std::string& _expression, const std::string& _name)
|
7476
|
+
std::string add_variable_with_name(const std::string& _expression, const std::string& _name, bool _is_aggregation_result)
|
7265
7477
|
{
|
7478
|
+
has_aggregation_result = has_aggregation_result or _is_aggregation_result;
|
7266
7479
|
if(not variables.empty()) variables += ", ";
|
7267
7480
|
variables += format_string("{} AS {}", _expression, _name);
|
7481
|
+
if(not _is_aggregation_result) group_variables += _name + ", ";
|
7268
7482
|
return _name;
|
7269
7483
|
}
|
7484
|
+
void add_fake_table()
|
7485
|
+
{
|
7486
|
+
errors::check_condition(tables.empty(), exception_stage::runtime, exception_code::internal_error, "Fake table can only be added when the number of table is 0.");
|
7487
|
+
tables.push_back({sql_join::inner, "(SELECT 1 AS fake)", "faketable"});
|
7488
|
+
}
|
7270
7489
|
std::string add_table(const std::string& _table, sql_join _join, const char* _table_name_format= "tbl_{}")
|
7271
7490
|
{
|
7272
|
-
if(
|
7491
|
+
if(tables.empty())
|
7273
7492
|
{
|
7274
7493
|
errors::check_condition(_join == sql_join::inner, exception_stage::runtime, exception_code::internal_error, "Joining with non-inner join on first table.");
|
7275
|
-
tables += " FROM ";
|
7276
|
-
} else {
|
7277
|
-
switch(_join)
|
7278
|
-
{
|
7279
|
-
case sql_join::inner:
|
7280
|
-
tables += " JOIN ";
|
7281
|
-
break;
|
7282
|
-
case sql_join::left:
|
7283
|
-
tables += " LEFT JOIN ";
|
7284
|
-
break;
|
7285
|
-
}
|
7286
7494
|
}
|
7287
|
-
++table_count;
|
7288
7495
|
std::string table_name = format_string(_table_name_format, next_uid());
|
7289
|
-
tables
|
7496
|
+
tables.push_back({_join, _table, table_name});
|
7290
7497
|
return table_name;
|
7291
7498
|
}
|
7292
7499
|
template<typename... _T_>
|
@@ -7299,9 +7506,10 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7299
7506
|
template<typename... _T_>
|
7300
7507
|
void add_where_condition(const std::string& _condition, const _T_&... _args)
|
7301
7508
|
{
|
7302
|
-
|
7303
|
-
|
7304
|
-
where_conditions +=
|
7509
|
+
add_join_condition(_condition, _args...);
|
7510
|
+
// if(_condition.empty()) return;
|
7511
|
+
// where_conditions += where_conditions.empty() ? " WHERE " : " AND ";
|
7512
|
+
// where_conditions += format_string(_condition, _args...);
|
7305
7513
|
}
|
7306
7514
|
void add_modifier(const std::string& _modifier)
|
7307
7515
|
{
|
@@ -7311,10 +7519,38 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7311
7519
|
{
|
7312
7520
|
std::string q = "SELECT ";
|
7313
7521
|
q += variables.empty() ? " null " : variables;
|
7314
|
-
|
7522
|
+
if(not tables.empty())
|
7523
|
+
{
|
7524
|
+
// errors::check_condition(not tables.empty(), exception_stage::runtime, exception_code::internal_error, "Missing tables in query.");
|
7525
|
+
q += format_string(" FROM {} {}", tables[0].table, tables[0].name);
|
7526
|
+
for(std::size_t i = 1; i < tables.size(); ++i)
|
7527
|
+
{
|
7528
|
+
table& tbl = tables[i];
|
7529
|
+
const char* join_type;
|
7530
|
+
switch(tbl.join)
|
7531
|
+
{
|
7532
|
+
case sql_join::inner:
|
7533
|
+
join_type = "JOIN";
|
7534
|
+
break;
|
7535
|
+
case sql_join::left:
|
7536
|
+
join_type = "LEFT JOIN";
|
7537
|
+
break;
|
7538
|
+
}
|
7539
|
+
if(i == tables.size() - 1)
|
7540
|
+
{
|
7541
|
+
q += format_string(" {} {} {}", join_type, tbl.table, tbl.name);
|
7542
|
+
} else {
|
7543
|
+
q += format_string(" {} ({} {}", join_type, tbl.table, tbl.name);
|
7544
|
+
}
|
7545
|
+
}
|
7546
|
+
for(std::size_t i = 1; i < tables.size() - 1; ++i)
|
7547
|
+
{
|
7548
|
+
q += ")";
|
7549
|
+
}
|
7550
|
+
}
|
7315
7551
|
if(not join_conditions.empty())
|
7316
7552
|
{
|
7317
|
-
if(
|
7553
|
+
if(tables.size() == 1)
|
7318
7554
|
{
|
7319
7555
|
q += " WHERE ";
|
7320
7556
|
} else {
|
@@ -7322,7 +7558,11 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7322
7558
|
}
|
7323
7559
|
q += join_conditions;
|
7324
7560
|
}
|
7325
|
-
q += where_conditions;
|
7561
|
+
// q += where_conditions;
|
7562
|
+
if(has_aggregation_result and not group_variables.empty())
|
7563
|
+
{
|
7564
|
+
q += " GROUP BY {}" % std::string_view(group_variables).substr(0, group_variables.size() - 2);
|
7565
|
+
}
|
7326
7566
|
q += modifiers;
|
7327
7567
|
return q;
|
7328
7568
|
}
|
@@ -7341,7 +7581,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7341
7581
|
// std::string view_name;
|
7342
7582
|
oc::algebra::visitors::expression_analyser expression_analyser;
|
7343
7583
|
|
7344
|
-
table prepare(const table& _table, bool _create_new_table)
|
7584
|
+
table prepare(const table& _table, bool _create_new_table, bool _optional)
|
7345
7585
|
{
|
7346
7586
|
expression_analyser.stage = exception_stage::runtime;
|
7347
7587
|
expression_analyser.variables_f = [this](const std::string& _var_name)
|
@@ -7350,8 +7590,13 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7350
7590
|
};
|
7351
7591
|
table new_table;
|
7352
7592
|
if(_create_new_table) new_table.view_name = "__view" + std::to_string(++exec_c->next_view_id);
|
7353
|
-
if(
|
7593
|
+
if(_table.view_name.empty())
|
7354
7594
|
{
|
7595
|
+
if(_optional)
|
7596
|
+
{
|
7597
|
+
query_builder.add_fake_table();
|
7598
|
+
}
|
7599
|
+
} else {
|
7355
7600
|
previous_table_ref = query_builder.add_table(_table.view_name, sql_join::inner, "pt_{}");
|
7356
7601
|
|
7357
7602
|
for(auto const& [k, v] : _table.variables)
|
@@ -7360,7 +7605,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7360
7605
|
variables[k] = { sql_var, v.type };
|
7361
7606
|
if(_create_new_table)
|
7362
7607
|
{
|
7363
|
-
std::string col_name = query_builder.add_variable(sql_var);
|
7608
|
+
std::string col_name = query_builder.add_variable(sql_var, false);
|
7364
7609
|
new_table.variables[k] = { col_name, v.type };
|
7365
7610
|
}
|
7366
7611
|
}
|
@@ -7428,6 +7673,10 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7428
7673
|
{
|
7429
7674
|
return eval_c->query_builder.bind_value(_node->get_value());
|
7430
7675
|
}
|
7676
|
+
std::string visit(algebra::all_csp) override
|
7677
|
+
{
|
7678
|
+
return "*";
|
7679
|
+
}
|
7431
7680
|
std::string visit(algebra::has_labels_csp _node) override
|
7432
7681
|
{
|
7433
7682
|
oc::algebra::expression_type et = eval_c->get_variable_info(_node->get_left()).type;
|
@@ -7463,7 +7712,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7463
7712
|
{
|
7464
7713
|
if(not first)
|
7465
7714
|
{
|
7466
|
-
map += " UNION ";
|
7715
|
+
map += " UNION ALL ";
|
7467
7716
|
}
|
7468
7717
|
map += "SELECT " + eval_c->query_builder.bind_value(k);
|
7469
7718
|
if(first)
|
@@ -7488,7 +7737,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7488
7737
|
{
|
7489
7738
|
if(not first)
|
7490
7739
|
{
|
7491
|
-
array += " UNION ";
|
7740
|
+
array += " UNION ALL ";
|
7492
7741
|
}
|
7493
7742
|
array += "SELECT " + start(v);
|
7494
7743
|
if(first)
|
@@ -7590,7 +7839,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7590
7839
|
return "(SELECT json_group_array(key) FROM json_each({}))" % map_expr;
|
7591
7840
|
} else if(_node->get_name() == "toInteger")
|
7592
7841
|
{
|
7593
|
-
return "
|
7842
|
+
return "gqlite_to_integer({})"s % start(_node->get_arguments()[0]);
|
7594
7843
|
} else if(_node->get_name() == "size")
|
7595
7844
|
{
|
7596
7845
|
return "json_array_length({})"s % start(_node->get_arguments()[0]);
|
@@ -7603,6 +7852,24 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7603
7852
|
} else if(_node->get_name() == "tail")
|
7604
7853
|
{
|
7605
7854
|
return "gqlite_tail({})" % start(_node->get_arguments()[0]);
|
7855
|
+
} else if(_node->get_name() == "avg")
|
7856
|
+
{
|
7857
|
+
return "avg({})" % start(_node->get_arguments()[0]);
|
7858
|
+
} else if(_node->get_name() == "count")
|
7859
|
+
{
|
7860
|
+
return "count({})" % start(_node->get_arguments()[0]);
|
7861
|
+
} else if(_node->get_name() == "collect")
|
7862
|
+
{
|
7863
|
+
return "json_group_array({})" % start(_node->get_arguments()[0]);
|
7864
|
+
} else if(_node->get_name() == "max")
|
7865
|
+
{
|
7866
|
+
return "max({})" % start(_node->get_arguments()[0]);
|
7867
|
+
} else if(_node->get_name() == "min")
|
7868
|
+
{
|
7869
|
+
return "min({})" % start(_node->get_arguments()[0]);
|
7870
|
+
} else if(_node->get_name() == "sum")
|
7871
|
+
{
|
7872
|
+
return "sum({})" % start(_node->get_arguments()[0]);
|
7606
7873
|
}
|
7607
7874
|
throw_exception(exception_stage::runtime, exception_code::unimplemented_error, "Function call to {} is not implemented.", _node->get_name());
|
7608
7875
|
}
|
@@ -7618,8 +7885,8 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7618
7885
|
FILTER_VISITOR_BINARY_OP(relational_different, "!=")
|
7619
7886
|
FILTER_VISITOR_BINARY_OP(relational_inferior, "<")
|
7620
7887
|
FILTER_VISITOR_BINARY_OP(relational_superior, ">")
|
7621
|
-
FILTER_VISITOR_BINARY_OP(relational_inferior_equal, "
|
7622
|
-
FILTER_VISITOR_BINARY_OP(relational_superior_equal, "
|
7888
|
+
FILTER_VISITOR_BINARY_OP(relational_inferior_equal, "<=")
|
7889
|
+
FILTER_VISITOR_BINARY_OP(relational_superior_equal, ">=")
|
7623
7890
|
FILTER_VISITOR_BINARY_OP(substraction, "-")
|
7624
7891
|
FILTER_VISITOR_BINARY_OP(multiplication, "*")
|
7625
7892
|
FILTER_VISITOR_BINARY_OP(division, "/")
|
@@ -7726,8 +7993,9 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7726
7993
|
{
|
7727
7994
|
sql_evaluation_context mc;
|
7728
7995
|
mc.exec_c = &exec_c;
|
7729
|
-
mc.prepare(current_table, false);
|
7996
|
+
mc.prepare(current_table, false, false);
|
7730
7997
|
sql_expression_visitor sev{&mc};
|
7998
|
+
mc.query_builder.add_variable("gqlite_next_uid('nodes')", false);
|
7731
7999
|
|
7732
8000
|
std::string properties_str;
|
7733
8001
|
if(_node->get_properties())
|
@@ -7736,9 +8004,9 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7736
8004
|
} else {
|
7737
8005
|
properties_str = "'{}'";
|
7738
8006
|
}
|
7739
|
-
|
8007
|
+
mc.query_builder.add_variable(properties_str, false);
|
7740
8008
|
std::string query = sqlite_queries::node_create(
|
7741
|
-
|
8009
|
+
exec_c.graph_name, sev.eval_c->query_builder.assemble());
|
7742
8010
|
value res = exec_c.data->execute_sql(query, sev.eval_c->query_builder.bindings);
|
7743
8011
|
value_vector ret_v;
|
7744
8012
|
value_vector res_v = res.to_vector();
|
@@ -7792,13 +8060,13 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7792
8060
|
{
|
7793
8061
|
sql_evaluation_context mc;
|
7794
8062
|
mc.exec_c = &exec_c;
|
7795
|
-
mc.prepare(current_table, false);
|
8063
|
+
mc.prepare(current_table, false, false);
|
7796
8064
|
sql_expression_visitor sev{&mc};
|
7797
|
-
|
8065
|
+
mc.query_builder.add_variable("gqlite_next_uid('edges')", false);
|
7798
8066
|
// Handle label
|
7799
8067
|
std::string label = _edge->get_labels().empty() ? std::string() : _edge->get_labels().front();
|
7800
8068
|
std::string label_binding_idx = sev.eval_c->query_builder.bind_value(exec_c.data->id_for_label(label));
|
7801
|
-
mc.query_builder.add_variable(label_binding_idx, "label_{}");
|
8069
|
+
mc.query_builder.add_variable(label_binding_idx, false, "label_{}");
|
7802
8070
|
|
7803
8071
|
// Handle properties
|
7804
8072
|
std::string properties_str;
|
@@ -7808,18 +8076,18 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7808
8076
|
} else {
|
7809
8077
|
properties_str = "'{}'";
|
7810
8078
|
}
|
7811
|
-
mc.query_builder.add_variable(properties_str, "properties_{}");
|
8079
|
+
mc.query_builder.add_variable(properties_str, false, "properties_{}");
|
7812
8080
|
|
7813
8081
|
// Handle source
|
7814
8082
|
auto const&[left_value, new_left_value, left_expr] = create_node_if_needed(&sev, _edge->get_source(), _new_nodes, "source_node_{}");
|
7815
|
-
mc.query_builder.add_variable(left_expr, "source_{}");
|
8083
|
+
mc.query_builder.add_variable(left_expr, false, "source_{}");
|
7816
8084
|
|
7817
8085
|
// Check if destination == source
|
7818
8086
|
auto const&[right_value, new_right_value, right_expr]
|
7819
8087
|
= (_edge->get_source()->get_variable() == _edge->get_destination()->get_variable()) ?
|
7820
8088
|
std::make_tuple(gqlite::value(), false, left_expr)
|
7821
8089
|
: create_node_if_needed(&sev, _edge->get_destination(), _new_nodes, "destination_node_{}");
|
7822
|
-
mc.query_builder.add_variable(right_expr, "destination_{}");
|
8090
|
+
mc.query_builder.add_variable(right_expr, false, "destination_{}");
|
7823
8091
|
|
7824
8092
|
// Execute queries
|
7825
8093
|
std::string query = sqlite_queries::edge_create(exec_c.graph_name, sev.eval_c->query_builder.assemble());
|
@@ -7881,7 +8149,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7881
8149
|
// 2) Create the resulting table
|
7882
8150
|
sql_evaluation_context mc;
|
7883
8151
|
mc.exec_c = &exec_c;
|
7884
|
-
table new_table = mc.prepare(current_table, true);
|
8152
|
+
table new_table = mc.prepare(current_table, true, false);
|
7885
8153
|
sql_expression_visitor sev{&mc};
|
7886
8154
|
std::string first_table_ref;
|
7887
8155
|
// loop over new things
|
@@ -7901,7 +8169,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7901
8169
|
} else {
|
7902
8170
|
mc.query_builder.add_join_condition("{}.key = {}.key", first_table_ref, table_ref);
|
7903
8171
|
}
|
7904
|
-
mc.query_builder.add_variable_with_name(format_string(" {}.value ", table_ref), table_ref);
|
8172
|
+
mc.query_builder.add_variable_with_name(format_string(" {}.value ", table_ref), table_ref, false);
|
7905
8173
|
new_table.variables[k] = {table_ref, type};
|
7906
8174
|
}
|
7907
8175
|
}
|
@@ -7988,7 +8256,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
7988
8256
|
auto it = _mc->variables.find(_oc_var);
|
7989
8257
|
if(it == _mc->variables.end())
|
7990
8258
|
{
|
7991
|
-
std::string var_name = _mc->query_builder.add_variable(_sql_var, "new_match_{}");
|
8259
|
+
std::string var_name = _mc->query_builder.add_variable(_sql_var, false, "new_match_{}");
|
7992
8260
|
_table->variables[_oc_var] = {var_name, _variable_type};
|
7993
8261
|
_mc->variables[_oc_var] = {_sql_var, _variable_type, _sql_properties_var, _label_var};
|
7994
8262
|
} else {
|
@@ -8002,15 +8270,18 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8002
8270
|
{
|
8003
8271
|
sql_match_evaluation_context mc;
|
8004
8272
|
mc.exec_c = &exec_c;
|
8005
|
-
table new_table = mc.prepare(current_table, true);
|
8273
|
+
table new_table = mc.prepare(current_table, true, _node->get_optional());
|
8006
8274
|
sql_match_expression_visitor sev{&mc};
|
8007
8275
|
|
8276
|
+
const bool is_optional = _node->get_optional();
|
8277
|
+
|
8008
8278
|
// 1) Go through the patterns
|
8009
8279
|
for(const algebra::alternative<algebra::graph_node, algebra::graph_edge>& pattern : _node->get_patterns())
|
8010
8280
|
{
|
8011
|
-
pattern.visit<void>([this, &mc, &sev, &new_table](const algebra::graph_node_csp _node)
|
8281
|
+
pattern.visit<void>([this, &mc, &sev, &new_table, is_optional](const algebra::graph_node_csp _node)
|
8012
8282
|
{
|
8013
|
-
|
8283
|
+
sql_join s_join = is_optional ? sql_join::left : sql_join::inner;
|
8284
|
+
std::string table_ref = sev.eval_c->query_builder.add_table(format_string("gqlite_{}_nodes", exec_c.graph_name), s_join, "node_{}");
|
8014
8285
|
std::string sql_var = format_string("{}.id", table_ref);
|
8015
8286
|
std::string sql_properties_var = format_string("{}.properties", table_ref);
|
8016
8287
|
mc.query_builder.add_join_condition(mc.generate_labels_match(_node->get_labels(), format_string("{}.id", table_ref)));
|
@@ -8020,14 +8291,15 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8020
8291
|
}
|
8021
8292
|
generate_var_match(&mc, &new_table, _node->get_variable(), sql_var, sql_properties_var, std::string(), algebra::expression_type::node);
|
8022
8293
|
},
|
8023
|
-
[this, &mc, &sev, &new_table](const algebra::graph_edge_csp _edge)
|
8294
|
+
[this, &mc, &sev, &new_table, is_optional](const algebra::graph_edge_csp _edge)
|
8024
8295
|
{
|
8296
|
+
sql_join s_join = is_optional ? sql_join::left : sql_join::inner;
|
8025
8297
|
std::string table_ref;
|
8026
8298
|
if(_edge->get_directivity() == algebra::edge_directivity::undirected)
|
8027
8299
|
{
|
8028
|
-
table_ref = sev.eval_c->query_builder.add_table(format_string("gqlite_{}_edges_undirected", exec_c.graph_name),
|
8300
|
+
table_ref = sev.eval_c->query_builder.add_table(format_string("gqlite_{}_edges_undirected", exec_c.graph_name), s_join, "undirected_edge_{}");
|
8029
8301
|
} else {
|
8030
|
-
table_ref = sev.eval_c->query_builder.add_table(format_string("gqlite_{}_edges", exec_c.graph_name),
|
8302
|
+
table_ref = sev.eval_c->query_builder.add_table(format_string("gqlite_{}_edges", exec_c.graph_name), s_join, "edge_{}");
|
8031
8303
|
}
|
8032
8304
|
std::string sql_source_var = format_string("{}.left", table_ref);
|
8033
8305
|
std::string sql_edge_var = format_string("{}.id", table_ref);
|
@@ -8040,7 +8312,13 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8040
8312
|
mc.query_builder.add_where_condition(mc.generate_labels_match(_edge->get_destination()->get_labels(), table_ref + ".right"));
|
8041
8313
|
if(not _edge->get_labels().empty())
|
8042
8314
|
{
|
8043
|
-
std::string label_conds
|
8315
|
+
std::string label_conds;
|
8316
|
+
if(is_optional)
|
8317
|
+
{
|
8318
|
+
label_conds = format_string("({} IS NULL", sql_label_edge_var);
|
8319
|
+
} else {
|
8320
|
+
label_conds = "(FALSE ";
|
8321
|
+
}
|
8044
8322
|
for(const std::string& label : _edge->get_labels())
|
8045
8323
|
{
|
8046
8324
|
label_conds += format_string(" OR {} = {}", sql_label_edge_var, exec_c.data->id_for_label(label));
|
@@ -8099,10 +8377,10 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8099
8377
|
{
|
8100
8378
|
sql_match_evaluation_context mc;
|
8101
8379
|
mc.exec_c = &exec_c;
|
8102
|
-
mc.prepare(current_table, false);
|
8380
|
+
mc.prepare(current_table, false, false);
|
8103
8381
|
sql_match_expression_visitor sev{&mc};
|
8104
8382
|
std::string expr = sev.start(node);
|
8105
|
-
mc.query_builder.add_variable(expr);
|
8383
|
+
mc.query_builder.add_variable(expr, false);
|
8106
8384
|
std::string what = mc.query_builder.assemble();
|
8107
8385
|
|
8108
8386
|
switch(mc.expression_analyser.start(node).type)
|
@@ -8111,8 +8389,15 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8111
8389
|
{
|
8112
8390
|
if(_ds->get_detach())
|
8113
8391
|
{
|
8114
|
-
std::string query = sqlite_queries::
|
8392
|
+
std::string query = sqlite_queries::edge_delete_by_nodes(exec_c.graph_name, what);
|
8115
8393
|
mc.exec_c->data->execute_sql(query, mc.query_builder.bindings);
|
8394
|
+
} else {
|
8395
|
+
std::string query = sqlite_queries::edge_count_by_nodes(exec_c.graph_name, what);
|
8396
|
+
gqlite::value count = mc.exec_c->data->execute_sql(query, mc.query_builder.bindings);
|
8397
|
+
if(count.to_vector().front().to_vector().front().to_integer() > 0)
|
8398
|
+
{
|
8399
|
+
throw_exception(exception_stage::runtime, exception_code::delete_connected_node, "delete connected node not allowed, unless using detach.");
|
8400
|
+
}
|
8116
8401
|
}
|
8117
8402
|
std::string query = sqlite_queries::node_delete(exec_c.graph_name, what);
|
8118
8403
|
mc.exec_c->data->execute_sql(query, mc.query_builder.bindings);
|
@@ -8129,59 +8414,6 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8129
8414
|
}
|
8130
8415
|
}
|
8131
8416
|
return value();
|
8132
|
-
#if 0
|
8133
|
-
evaluation_context eval_c;
|
8134
|
-
eval_c.table = table;
|
8135
|
-
evaluator_visitor eval_v;
|
8136
|
-
eval_v.exec_c = &exec_c;
|
8137
|
-
eval_v.eval_c = &eval_c;
|
8138
|
-
|
8139
|
-
struct deleter
|
8140
|
-
{
|
8141
|
-
statement_visitor* self;
|
8142
|
-
bool detach;
|
8143
|
-
void operator()(const node_ref_sp& _node)
|
8144
|
-
{
|
8145
|
-
if(detach)
|
8146
|
-
{
|
8147
|
-
self->exec_c.data->execute_sql(sqlite_queries::edge_delete_by_node(self->exec_c.graph_name), {{1, _node->id}});
|
8148
|
-
} else {
|
8149
|
-
value result = self->exec_c.data->execute_sql(sqlite_queries::edge_count_by_node(self->exec_c.graph_name), {{1, _node->id}});
|
8150
|
-
value_vector rows = result.to_vector();
|
8151
|
-
errors::check_condition(rows.size() == 1, exception_stage::runtime, exception_code::internal_error, "Invalid number of rows for counting edges got {} expected 1.", rows.size());
|
8152
|
-
value_vector row = rows.front().to_vector();
|
8153
|
-
errors::check_condition(row.size() == 1, exception_stage::runtime, exception_code::internal_error, "Invalid number of columns for counting edges got {} expected 1.", rows.size());
|
8154
|
-
int count = row.front().to_integer();
|
8155
|
-
errors::check_condition(count == 0, exception_stage::runtime, exception_code::unspecified, "Cannot delete node with {} relationships.", count);
|
8156
|
-
}
|
8157
|
-
self->exec_c.data->execute_sql(sqlite_queries::node_delete(self->exec_c.graph_name), {{1, _node->id}});
|
8158
|
-
}
|
8159
|
-
void operator()(const edge_ref_sp& _edge)
|
8160
|
-
{
|
8161
|
-
self->exec_c.data->execute_sql(sqlite_queries::edge_delete(self->exec_c.graph_name), {{1, _edge->id}});
|
8162
|
-
}
|
8163
|
-
void operator()(const value&)
|
8164
|
-
{
|
8165
|
-
throw_exception(exception_stage::runtime, exception_code::invalid_argument_type, "Cannot delete a value.");
|
8166
|
-
}
|
8167
|
-
void operator()(const empty&)
|
8168
|
-
{
|
8169
|
-
throw_exception(exception_stage::runtime, exception_code::invalid_argument_type, "Cannot delete an empty value.");
|
8170
|
-
}
|
8171
|
-
};
|
8172
|
-
|
8173
|
-
for(std::size_t i = 0; i < table.get_rows_count(); ++i)
|
8174
|
-
{
|
8175
|
-
value_vector row;
|
8176
|
-
eval_c.prepare_current_row(table, i, false);
|
8177
|
-
for(const algebra::node_csp& rv : _ds->get_expressions())
|
8178
|
-
{
|
8179
|
-
exec_value ev =eval_v.start(rv);
|
8180
|
-
std::visit(deleter{this, _ds->get_detach()}, ev);
|
8181
|
-
}
|
8182
|
-
}
|
8183
|
-
return value();
|
8184
|
-
#endif
|
8185
8417
|
}
|
8186
8418
|
std::string to_sqlite_path(const std::vector<std::string>& _path)
|
8187
8419
|
{
|
@@ -8209,7 +8441,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8209
8441
|
{
|
8210
8442
|
sql_match_evaluation_context mc;
|
8211
8443
|
mc.exec_c = &self->exec_c;
|
8212
|
-
mc.prepare(self->current_table, false);
|
8444
|
+
mc.prepare(self->current_table, false, false);
|
8213
8445
|
sql_match_expression_visitor sev{&mc};
|
8214
8446
|
sql_variable_info svi = mc.get_variable_info(_property->get_left());
|
8215
8447
|
// mc.query_builder.add_variable(svi.sql_var_name);
|
@@ -8238,7 +8470,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8238
8470
|
{
|
8239
8471
|
sql_match_evaluation_context mc;
|
8240
8472
|
mc.exec_c = &self->exec_c;
|
8241
|
-
mc.prepare(self->current_table, false);
|
8473
|
+
mc.prepare(self->current_table, false, false);
|
8242
8474
|
sql_match_expression_visitor sev{&mc};
|
8243
8475
|
sql_variable_info svi = mc.get_variable_info(_property->get_left());
|
8244
8476
|
std::string expr = sev.start(_property->get_expression());
|
@@ -8266,14 +8498,15 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8266
8498
|
{
|
8267
8499
|
sql_match_evaluation_context mc;
|
8268
8500
|
mc.exec_c = &self->exec_c;
|
8269
|
-
mc.prepare(self->current_table, false);
|
8501
|
+
mc.prepare(self->current_table, false, false);
|
8270
8502
|
sql_match_expression_visitor sev{&mc};
|
8271
8503
|
sql_variable_info svi = mc.get_variable_info(_edit_label->get_target());
|
8272
8504
|
std::vector<std::string> labels = _edit_label->get_labels();
|
8273
8505
|
auto label_ids_view = labels | std::views::transform([this](const std::string& _label) { return value(self->exec_c.data->id_for_label(_label)); });
|
8274
8506
|
std::string labels_ref = mc.query_builder.add_table("json_each({})"s % mc.query_builder.bind_value(value_vector(label_ids_view.begin(), label_ids_view.end())), sql_join::inner);
|
8275
|
-
mc.query_builder.add_variable("{}.value" % labels_ref);
|
8276
|
-
mc.query_builder.add_variable(svi.sql_var_name);
|
8507
|
+
mc.query_builder.add_variable("{}.value" % labels_ref, false);
|
8508
|
+
mc.query_builder.add_variable(svi.sql_var_name, false);
|
8509
|
+
mc.query_builder.add_where_condition("{} IS NOT NULL", svi.sql_var_name);
|
8277
8510
|
std::string what = mc.query_builder.assemble();
|
8278
8511
|
|
8279
8512
|
switch(svi.type)
|
@@ -8312,7 +8545,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8312
8545
|
{
|
8313
8546
|
sql_match_evaluation_context mc;
|
8314
8547
|
mc.exec_c = &self->exec_c;
|
8315
|
-
mc.prepare(self->current_table, false);
|
8548
|
+
mc.prepare(self->current_table, false, false);
|
8316
8549
|
sql_match_expression_visitor sev{&mc};
|
8317
8550
|
sql_variable_info svi = mc.get_variable_info(_property->get_left());
|
8318
8551
|
std::string what = mc.query_builder.assemble().substr(sizeof("SELECT null"));
|
@@ -8339,13 +8572,13 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8339
8572
|
{
|
8340
8573
|
sql_match_evaluation_context mc;
|
8341
8574
|
mc.exec_c = &self->exec_c;
|
8342
|
-
mc.prepare(self->current_table, false);
|
8575
|
+
mc.prepare(self->current_table, false, false);
|
8343
8576
|
sql_match_expression_visitor sev{&mc};
|
8344
8577
|
sql_variable_info svi = mc.get_variable_info(_edit_label->get_target());
|
8345
8578
|
std::vector<std::string> labels = _edit_label->get_labels();
|
8346
8579
|
auto label_ids_view = labels | std::views::transform([this](const std::string& _label) { return std::to_string(self->exec_c.data->id_for_label(_label)); });
|
8347
8580
|
std::string labels_ref = string::join(label_ids_view, ", ");
|
8348
|
-
mc.query_builder.add_variable(svi.sql_var_name);
|
8581
|
+
mc.query_builder.add_variable(svi.sql_var_name, false);
|
8349
8582
|
std::string what = mc.query_builder.assemble();
|
8350
8583
|
|
8351
8584
|
switch(svi.type)
|
@@ -8410,16 +8643,16 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8410
8643
|
|
8411
8644
|
sql_evaluation_context mc;
|
8412
8645
|
mc.exec_c = &exec_c;
|
8413
|
-
table new_table = mc.prepare(current_table, true);
|
8646
|
+
table new_table = mc.prepare(current_table, true, false);
|
8414
8647
|
new_table.variables.clear();
|
8415
8648
|
sql_expression_visitor sev{&mc};
|
8416
8649
|
// Generate SQL Query
|
8417
8650
|
for(const algebra::named_expression_csp& rv : w->get_expressions())
|
8418
8651
|
{
|
8419
|
-
|
8420
|
-
|
8421
|
-
new_table.variables[rv->get_name()] = {var,
|
8422
|
-
mc.variables[rv->get_name()] = {var,
|
8652
|
+
algebra::expression_info expr_info = mc.expression_analyser.start(rv->get_expression());
|
8653
|
+
std::string var = mc.query_builder.add_variable(sev.start(rv->get_expression()), expr_info.aggregation_result);
|
8654
|
+
new_table.variables[rv->get_name()] = {var, expr_info.type};
|
8655
|
+
mc.variables[rv->get_name()] = {var, expr_info.type};
|
8423
8656
|
}
|
8424
8657
|
add_filter_expressions(&sev, w->get_modifiers());
|
8425
8658
|
std::string query = "CREATE TEMPORARY TABLE " + new_table.view_name + " AS " + mc.query_builder.assemble();
|
@@ -8434,10 +8667,10 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8434
8667
|
{
|
8435
8668
|
sql_evaluation_context mc;
|
8436
8669
|
mc.exec_c = &exec_c;
|
8437
|
-
table new_table = mc.prepare(current_table, true);
|
8670
|
+
table new_table = mc.prepare(current_table, true, false);
|
8438
8671
|
sql_expression_visitor sev{&mc};
|
8439
8672
|
std::string table_ref = mc.query_builder.add_table("json_each(" + sev.start(uw->get_expression()) + ")", sql_join::inner, "a_uw_{}");
|
8440
|
-
std::string var = mc.query_builder.add_variable(format_string("{}.value", table_ref));
|
8673
|
+
std::string var = mc.query_builder.add_variable(format_string("{}.value", table_ref), false);
|
8441
8674
|
std::string query = "CREATE TEMPORARY TABLE " + new_table.view_name + " AS " + mc.query_builder.assemble();
|
8442
8675
|
new_table.variables[uw->get_name()] = {var, oc::algebra::expression_type::value};
|
8443
8676
|
exec_c.data->execute_sql(query, mc.query_builder.bindings);
|
@@ -8450,7 +8683,7 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8450
8683
|
{
|
8451
8684
|
sql_evaluation_context mc;
|
8452
8685
|
mc.exec_c = &exec_c;
|
8453
|
-
mc.prepare(current_table, false);
|
8686
|
+
mc.prepare(current_table, false, false);
|
8454
8687
|
sql_expression_visitor sev{&mc};
|
8455
8688
|
std::vector<gqlite::oc::algebra::named_expression_csp> expressions;
|
8456
8689
|
if(_rs->get_all())
|
@@ -8472,14 +8705,14 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8472
8705
|
|
8473
8706
|
for(const algebra::named_expression_csp& rv : expressions)
|
8474
8707
|
{
|
8475
|
-
oc::algebra::
|
8476
|
-
switch(
|
8708
|
+
oc::algebra::expression_info expr_info = mc.expression_analyser.start(rv->get_expression());
|
8709
|
+
switch(expr_info.type)
|
8477
8710
|
{
|
8478
8711
|
case oc::algebra::expression_type::node:
|
8479
8712
|
{
|
8480
8713
|
std::string table_ref = mc.query_builder.add_table(format_string("gqlite_{}_nodes_as_json", exec_c.graph_name), sql_join::inner, "node_{}");
|
8481
|
-
mc.query_builder.add_join_condition("{}.id
|
8482
|
-
std::string var_expr = mc.query_builder.add_variable("{}.node" % table_ref);
|
8714
|
+
mc.query_builder.add_join_condition("{}.id IS {}", table_ref, sev.start(rv->get_expression()));
|
8715
|
+
std::string var_expr = mc.query_builder.add_variable("{}.node" % table_ref, expr_info.aggregation_result);
|
8483
8716
|
variables_extra[rv->get_name()] = {var_expr, oc::algebra::expression_type::node,
|
8484
8717
|
"json_extract({}, '$.properties')" % var_expr, "json_extract({}, '$.labels')" % var_expr};
|
8485
8718
|
break;
|
@@ -8487,8 +8720,8 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8487
8720
|
case oc::algebra::expression_type::edge:
|
8488
8721
|
{
|
8489
8722
|
std::string table_ref = mc.query_builder.add_table(format_string("gqlite_{}_edges_as_json", exec_c.graph_name), sql_join::inner, "edge_{}");
|
8490
|
-
mc.query_builder.add_join_condition("{}.id
|
8491
|
-
std::string var_expr = mc.query_builder.add_variable("{}.edge" % table_ref);
|
8723
|
+
mc.query_builder.add_join_condition("{}.id IS {}", table_ref, sev.start(rv->get_expression()));
|
8724
|
+
std::string var_expr = mc.query_builder.add_variable("{}.edge" % table_ref, expr_info.aggregation_result);
|
8492
8725
|
variables_extra[rv->get_name()] = {var_expr, oc::algebra::expression_type::edge,
|
8493
8726
|
"json_extract({}, '$.properties')" % var_expr, "json_extract({}, '$.label')" % var_expr};
|
8494
8727
|
break;
|
@@ -8499,18 +8732,19 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8499
8732
|
[[fallthrough]];
|
8500
8733
|
default:
|
8501
8734
|
{
|
8502
|
-
std::string var_expr = mc.query_builder.add_variable(sev.start(rv->get_expression()));
|
8503
|
-
variables_extra[rv->get_name()] = {var_expr,
|
8735
|
+
std::string var_expr = mc.query_builder.add_variable(sev.start(rv->get_expression()), expr_info.aggregation_result);
|
8736
|
+
variables_extra[rv->get_name()] = {var_expr, expr_info.type};
|
8504
8737
|
break;
|
8505
8738
|
}
|
8506
8739
|
}
|
8507
8740
|
labels.push_back(rv->get_name());
|
8508
|
-
column_types.push_back(
|
8741
|
+
column_types.push_back(expr_info.type);
|
8509
8742
|
}
|
8510
8743
|
// Execute SQL query
|
8511
8744
|
if(_rs->get_modifiers())
|
8512
8745
|
{
|
8513
|
-
mc.variables
|
8746
|
+
std::swap(mc.variables, variables_extra);
|
8747
|
+
mc.variables.merge(variables_extra);
|
8514
8748
|
add_filter_expressions(&sev, _rs->get_modifiers());
|
8515
8749
|
}
|
8516
8750
|
value res = exec_c.data->execute_sql(mc.query_builder.assemble(), mc.query_builder.bindings);
|
@@ -8524,35 +8758,38 @@ namespace gqlite::backends::sqlite_oc_executor
|
|
8524
8758
|
for(std::size_t c = 0; c < r_v.size(); ++c)
|
8525
8759
|
{
|
8526
8760
|
value& v = r_v[c];
|
8527
|
-
|
8761
|
+
if(v.get_type() != value_type::invalid)
|
8528
8762
|
{
|
8529
|
-
|
8530
|
-
if(v.get_type() != value_type::invalid)
|
8763
|
+
switch(column_types[c])
|
8531
8764
|
{
|
8532
|
-
|
8533
|
-
|
8534
|
-
break;
|
8535
|
-
case oc::algebra::expression_type::map:
|
8536
|
-
case oc::algebra::expression_type::vector:
|
8537
|
-
v = value::from_json(v.to_string());
|
8538
|
-
break;
|
8539
|
-
case oc::algebra::expression_type::node:
|
8540
|
-
case oc::algebra::expression_type::edge:
|
8541
|
-
v = value::from_json(v.to_string());
|
8542
|
-
break;
|
8543
|
-
default:
|
8544
|
-
if(v.get_type() == value_type::string)
|
8545
|
-
{
|
8546
|
-
// Attempt to parse strings as json
|
8547
|
-
try
|
8765
|
+
case oc::algebra::expression_type::boolean:
|
8766
|
+
if(v.get_type() != value_type::invalid)
|
8548
8767
|
{
|
8549
|
-
v =
|
8768
|
+
v = (v.to_integer() == 1);
|
8550
8769
|
}
|
8551
|
-
|
8770
|
+
break;
|
8771
|
+
case oc::algebra::expression_type::map:
|
8772
|
+
case oc::algebra::expression_type::vector:
|
8773
|
+
v = value::from_json(v.to_string());
|
8774
|
+
break;
|
8775
|
+
case oc::algebra::expression_type::node:
|
8776
|
+
case oc::algebra::expression_type::edge:
|
8777
|
+
v = value::from_json(v.to_string());
|
8778
|
+
break;
|
8779
|
+
default:
|
8780
|
+
if(v.get_type() == value_type::string)
|
8552
8781
|
{
|
8553
|
-
//
|
8782
|
+
// Attempt to parse strings as json
|
8783
|
+
try
|
8784
|
+
{
|
8785
|
+
v = value::from_json(v.to_string());
|
8786
|
+
}
|
8787
|
+
catch(const exception&)
|
8788
|
+
{
|
8789
|
+
// ignore, that probably means it is a real string
|
8790
|
+
}
|
8791
|
+
break;
|
8554
8792
|
}
|
8555
|
-
break;
|
8556
8793
|
}
|
8557
8794
|
}
|
8558
8795
|
}
|
@@ -8597,6 +8834,10 @@ sqlite::sqlite(void* _db) : d(new data)
|
|
8597
8834
|
{
|
8598
8835
|
d->execute_sql(sqlite_queries::label_create_table());
|
8599
8836
|
}
|
8837
|
+
if(not d->table_has("gqlite_uids"))
|
8838
|
+
{
|
8839
|
+
d->execute_sql(sqlite_queries::uid_create_table());
|
8840
|
+
}
|
8600
8841
|
if(not d->graph_has("default"))
|
8601
8842
|
{
|
8602
8843
|
d->graph_create("default");
|
@@ -8606,7 +8847,7 @@ sqlite::sqlite(void* _db) : d(new data)
|
|
8606
8847
|
{
|
8607
8848
|
gqlite::value result = d->execute_sql(sqlite_queries::get_debug_stats("default"));
|
8608
8849
|
value_vector rows = result.to_vector();
|
8609
|
-
errors::check_condition(rows.size() ==
|
8850
|
+
errors::check_condition(rows.size() == 9, exception_stage::runtime, exception_code::internal_error, "Invalid number of debug stats got {} expected 7.", rows.size());
|
8610
8851
|
value_map stats;
|
8611
8852
|
stats["nodes_count"] = rows[0].to_vector()[0].to_integer();
|
8612
8853
|
stats["edges_count"] = rows[1].to_vector()[0].to_integer();
|
@@ -8614,6 +8855,8 @@ sqlite::sqlite(void* _db) : d(new data)
|
|
8614
8855
|
stats["properties_count"] = rows[3].to_vector()[0].to_integer() + rows[4].to_vector()[0].to_integer();
|
8615
8856
|
stats["labels_count"] = rows[5].to_vector()[0].to_integer();
|
8616
8857
|
stats["labels_assignment_nodes_count"] = rows[6].to_vector()[0].to_integer();
|
8858
|
+
stats["used_labels_count"] = rows[7].to_vector()[0].to_integer();
|
8859
|
+
stats["used_labels_nodes_count"] = rows[8].to_vector()[0].to_integer();
|
8617
8860
|
return stats;
|
8618
8861
|
};
|
8619
8862
|
}
|
@@ -8667,6 +8910,13 @@ gqlite::value sqlite::execute_oc_query(oc::algebra::node_csp _node)
|
|
8667
8910
|
|
8668
8911
|
|
8669
8912
|
|
8913
|
+
|
8914
|
+
|
8915
|
+
// Older version of SQLITE don*t have SQLITE_RESULT_SUBTYPE
|
8916
|
+
#ifndef SQLITE_RESULT_SUBTYPE
|
8917
|
+
#define SQLITE_RESULT_SUBTYPE 0
|
8918
|
+
#endif
|
8919
|
+
|
8670
8920
|
namespace gqlite::backends
|
8671
8921
|
{
|
8672
8922
|
template<typename... _TArgs_>
|
@@ -8692,6 +8942,15 @@ namespace gqlite::backends
|
|
8692
8942
|
{ \
|
8693
8943
|
report_exception(_context, ex); return; \
|
8694
8944
|
}
|
8945
|
+
|
8946
|
+
#define NULL_CHECK_AT(_ARG_INDEX_) \
|
8947
|
+
{ \
|
8948
|
+
if(sqlite3_value_type(_argv[_ARG_INDEX_]) == SQLITE_NULL) \
|
8949
|
+
{ \
|
8950
|
+
sqlite3_result_null(_context); return ; \
|
8951
|
+
} \
|
8952
|
+
}
|
8953
|
+
|
8695
8954
|
#define NULL_CHECK(_ARGS_COUNT_) \
|
8696
8955
|
for(std::size_t i = 0; i < _ARGS_COUNT_; ++i) \
|
8697
8956
|
{ \
|
@@ -8808,7 +9067,7 @@ namespace gqlite::backends
|
|
8808
9067
|
using enum value_type;
|
8809
9068
|
if(_value.get_type() == invalid)
|
8810
9069
|
{
|
8811
|
-
return comparison_result::compared_null;
|
9070
|
+
return _container.empty() ? comparison_result::false_result : comparison_result::compared_null;
|
8812
9071
|
}
|
8813
9072
|
bool has_compared_to_null = false;
|
8814
9073
|
for(const value& v_c : _container)
|
@@ -8834,7 +9093,232 @@ namespace gqlite::backends
|
|
8834
9093
|
}
|
8835
9094
|
return false;
|
8836
9095
|
}
|
9096
|
+
/**
|
9097
|
+
* @internal
|
9098
|
+
* class use to read json files
|
9099
|
+
*/
|
9100
|
+
struct is_valid_json
|
9101
|
+
{
|
9102
|
+
struct invalid
|
9103
|
+
{};
|
9104
|
+
std::stringstream stream;
|
9105
|
+
int last_char;
|
9106
|
+
/// @brief get the next char
|
9107
|
+
void fetch_next_non_space_char()
|
9108
|
+
{
|
9109
|
+
while(std::isspace(fetch_next_char()))
|
9110
|
+
{
|
9111
|
+
if(last_char == std::stringstream::traits_type::eof())
|
9112
|
+
{
|
9113
|
+
return;
|
9114
|
+
} else if(stream.fail())
|
9115
|
+
{
|
9116
|
+
throw invalid();
|
9117
|
+
}
|
9118
|
+
}
|
9119
|
+
};
|
9120
|
+
int fetch_next_char()
|
9121
|
+
{
|
9122
|
+
return (last_char = stream.get());
|
9123
|
+
}
|
9124
|
+
/// @brief start parsing
|
9125
|
+
/// @throw gqlite::exception
|
9126
|
+
/// @return the parsed value
|
9127
|
+
bool start()
|
9128
|
+
{
|
9129
|
+
try
|
9130
|
+
{
|
9131
|
+
fetch_next_non_space_char();
|
9132
|
+
validate_value();
|
9133
|
+
return true;
|
9134
|
+
} catch(const invalid&)
|
9135
|
+
{
|
9136
|
+
return false;
|
9137
|
+
}
|
9138
|
+
}
|
9139
|
+
static bool validate(const char* _string)
|
9140
|
+
{
|
9141
|
+
is_valid_json ivj{std::stringstream(_string), 0};
|
9142
|
+
return ivj.start();
|
9143
|
+
}
|
9144
|
+
/// @brief read a string
|
9145
|
+
/// @return the string without quotation
|
9146
|
+
void validate_string()
|
9147
|
+
{
|
9148
|
+
is_char('"');
|
9149
|
+
fetch_next_char();
|
9150
|
+
bool keep_nc = false; // this is used to indicate if the last character was a '\' or not
|
9151
|
+
while(keep_nc or last_char != '"')
|
9152
|
+
{
|
9153
|
+
keep_nc = (not keep_nc and last_char == '\\');
|
9154
|
+
fetch_next_char();
|
9155
|
+
}
|
9156
|
+
fetch_next_char(); // eat the '"'
|
9157
|
+
}
|
9158
|
+
/// @brief throw an exception if last_char different from @param _c
|
9159
|
+
void is_char(int _c)
|
9160
|
+
{
|
9161
|
+
if(last_char != _c) throw invalid();
|
9162
|
+
}
|
9163
|
+
/// @brief read the next value
|
9164
|
+
/// @return and return it
|
9165
|
+
void validate_value()
|
9166
|
+
{
|
9167
|
+
switch (last_char)
|
9168
|
+
{
|
9169
|
+
case '{':
|
9170
|
+
{
|
9171
|
+
// Parse object
|
9172
|
+
fetch_next_non_space_char();
|
9173
|
+
while(last_char != '}')
|
9174
|
+
{
|
9175
|
+
validate_string();
|
9176
|
+
is_char(':');
|
9177
|
+
fetch_next_non_space_char();
|
9178
|
+
validate_value();
|
9179
|
+
if(last_char == ',')
|
9180
|
+
{
|
9181
|
+
fetch_next_non_space_char();
|
9182
|
+
} else {
|
9183
|
+
break;
|
9184
|
+
}
|
9185
|
+
}
|
9186
|
+
is_char('}');
|
9187
|
+
fetch_next_non_space_char();
|
9188
|
+
return;
|
9189
|
+
}
|
9190
|
+
case '[':
|
9191
|
+
{
|
9192
|
+
// Parse array
|
9193
|
+
fetch_next_non_space_char();
|
9194
|
+
while(last_char != ']')
|
9195
|
+
{
|
9196
|
+
validate_value();
|
9197
|
+
if(last_char == ',')
|
9198
|
+
{
|
9199
|
+
fetch_next_non_space_char();
|
9200
|
+
} else {
|
9201
|
+
break;
|
9202
|
+
}
|
9203
|
+
}
|
9204
|
+
is_char(']');
|
9205
|
+
fetch_next_non_space_char();
|
9206
|
+
return;
|
9207
|
+
}
|
9208
|
+
case '"':
|
9209
|
+
validate_string();
|
9210
|
+
return;
|
9211
|
+
case 't':
|
9212
|
+
{
|
9213
|
+
// Parse true
|
9214
|
+
fetch_next_non_space_char(); is_char('r');
|
9215
|
+
fetch_next_non_space_char(); is_char('u');
|
9216
|
+
fetch_next_non_space_char(); is_char('e');
|
9217
|
+
fetch_next_non_space_char();
|
9218
|
+
return;
|
9219
|
+
}
|
9220
|
+
case 'f':
|
9221
|
+
{
|
9222
|
+
// Parse false
|
9223
|
+
fetch_next_non_space_char(); is_char('a');
|
9224
|
+
fetch_next_non_space_char(); is_char('l');
|
9225
|
+
fetch_next_non_space_char(); is_char('s');
|
9226
|
+
fetch_next_non_space_char(); is_char('e');
|
9227
|
+
fetch_next_non_space_char();
|
9228
|
+
return;
|
9229
|
+
}
|
9230
|
+
case 'n':
|
9231
|
+
{
|
9232
|
+
// Parse null
|
9233
|
+
fetch_next_non_space_char(); is_char('u');
|
9234
|
+
fetch_next_non_space_char(); is_char('l');
|
9235
|
+
fetch_next_non_space_char(); is_char('l');
|
9236
|
+
fetch_next_non_space_char();
|
9237
|
+
return;
|
9238
|
+
}
|
9239
|
+
// Parse number
|
9240
|
+
case '-':
|
9241
|
+
case '0':
|
9242
|
+
case '1':
|
9243
|
+
case '2':
|
9244
|
+
case '3':
|
9245
|
+
case '4':
|
9246
|
+
case '5':
|
9247
|
+
case '6':
|
9248
|
+
case '7':
|
9249
|
+
case '8':
|
9250
|
+
case '9':
|
9251
|
+
{
|
9252
|
+
fetch_next_non_space_char();
|
9253
|
+
bool is_integer = true;
|
9254
|
+
while((last_char >= '0' and last_char <= '9') or last_char == '.' or last_char == 'e' or last_char == '+' or last_char == '-')
|
9255
|
+
{
|
9256
|
+
is_integer = is_integer and (last_char != '.' and last_char != 'e');
|
9257
|
+
fetch_next_non_space_char();
|
9258
|
+
}
|
9259
|
+
return;
|
9260
|
+
}
|
9261
|
+
default:
|
9262
|
+
throw invalid{};
|
9263
|
+
}
|
9264
|
+
}
|
9265
|
+
};
|
9266
|
+
void gqlite_next_uid(sqlite3_context* _context,int,sqlite3_value** _argv)
|
9267
|
+
{
|
9268
|
+
// We get our db connection from the context
|
9269
|
+
sqlite3 *db = sqlite3_context_db_handle(_context);
|
9270
|
+
const char* label = reinterpret_cast<const char*>(sqlite3_value_text(_argv[0]));
|
9271
|
+
sqlite3_stmt *ps;
|
9272
|
+
int rc = sqlite3_prepare_v2(db, sqlite_queries::uid_next().c_str(), -1, &ps, 0);
|
9273
|
+
if (rc != SQLITE_OK) {
|
9274
|
+
// Something bad happened, we'll come back to look at this later
|
9275
|
+
return;
|
9276
|
+
}
|
9277
|
+
sqlite3_bind_text(ps, 1, label, -1, SQLITE_STATIC);
|
8837
9278
|
|
9279
|
+
rc = sqlite3_step(ps);
|
9280
|
+
if (rc == SQLITE_ROW)
|
9281
|
+
{
|
9282
|
+
sqlite3_result_int64(_context, sqlite3_column_int64(ps, 0));
|
9283
|
+
} else {
|
9284
|
+
report_error(_context, gqlite::exception_code::internal_error, "No uid counter for '{}'.", label);
|
9285
|
+
}
|
9286
|
+
sqlite3_finalize(ps);
|
9287
|
+
}
|
9288
|
+
void gqlite_jsonify(sqlite3_context* _context,int,sqlite3_value** _argv)
|
9289
|
+
{
|
9290
|
+
constexpr int JSON_TYPE = 74;
|
9291
|
+
if(sqlite3_value_subtype(_argv[0]) == JSON_TYPE)
|
9292
|
+
{
|
9293
|
+
sqlite3_result_subtype(_context, JSON_TYPE);
|
9294
|
+
sqlite3_result_text(_context, reinterpret_cast<const char*>(sqlite3_value_text(_argv[0])), -1, SQLITE_TRANSIENT);
|
9295
|
+
} else {
|
9296
|
+
switch(sqlite3_value_type(_argv[0]))
|
9297
|
+
{
|
9298
|
+
case SQLITE_NULL:
|
9299
|
+
sqlite3_result_null(_context);
|
9300
|
+
break;
|
9301
|
+
case SQLITE_INTEGER:
|
9302
|
+
sqlite3_result_int64(_context, sqlite3_value_int64(_argv[0]));
|
9303
|
+
break;
|
9304
|
+
case SQLITE_FLOAT:
|
9305
|
+
sqlite3_result_double(_context, sqlite3_value_double(_argv[0]));
|
9306
|
+
break;
|
9307
|
+
case SQLITE_TEXT:
|
9308
|
+
{
|
9309
|
+
const char* str =reinterpret_cast<const char*>(sqlite3_value_text(_argv[0]));
|
9310
|
+
sqlite3_result_text(_context, str, -1, SQLITE_TRANSIENT);
|
9311
|
+
if(is_valid_json::validate(str))
|
9312
|
+
{
|
9313
|
+
sqlite3_result_subtype(_context, JSON_TYPE);
|
9314
|
+
}
|
9315
|
+
}
|
9316
|
+
break;
|
9317
|
+
default:
|
9318
|
+
report_error(_context, exception_code::invalid_argument_type, "Invalid arguments for addition.");
|
9319
|
+
}
|
9320
|
+
}
|
9321
|
+
}
|
8838
9322
|
void gqlite_range(sqlite3_context* _context,int,sqlite3_value** _argv)
|
8839
9323
|
{
|
8840
9324
|
int start = sqlite3_value_int(_argv[0]);
|
@@ -8893,7 +9377,7 @@ namespace gqlite::backends
|
|
8893
9377
|
}
|
8894
9378
|
break;
|
8895
9379
|
default:
|
8896
|
-
report_error(_context, exception_code::invalid_argument_type, "
|
9380
|
+
report_error(_context, exception_code::invalid_argument_type, "Invalid arguments for addition.");
|
8897
9381
|
}
|
8898
9382
|
} else {
|
8899
9383
|
double left_v = 0.0, right_v = 0.0;
|
@@ -9013,7 +9497,7 @@ namespace gqlite::backends
|
|
9013
9497
|
}
|
9014
9498
|
void gqlite_contains(sqlite3_context* _context,int,sqlite3_value** _argv)
|
9015
9499
|
{
|
9016
|
-
|
9500
|
+
NULL_CHECK_AT(0);
|
9017
9501
|
std::string left = reinterpret_cast<const char*>(sqlite3_value_text(_argv[0]));
|
9018
9502
|
value val_left;
|
9019
9503
|
SAFE(val_left = value::from_json(left));
|
@@ -9022,11 +9506,13 @@ namespace gqlite::backends
|
|
9022
9506
|
{
|
9023
9507
|
case value_type::vector:
|
9024
9508
|
{
|
9025
|
-
std::string right = reinterpret_cast<const char*>(sqlite3_value_text(_argv[1]));
|
9026
|
-
value_vector vv = val_left.to_vector();
|
9027
9509
|
value val_right;
|
9028
|
-
|
9029
|
-
|
9510
|
+
value_vector vv = val_left.to_vector();
|
9511
|
+
if(sqlite3_value_type(_argv[1]) != SQLITE_NULL)
|
9512
|
+
{
|
9513
|
+
std::string right = reinterpret_cast<const char*>(sqlite3_value_text(_argv[1]));
|
9514
|
+
SAFE(val_right = value::from_json(right));
|
9515
|
+
}
|
9030
9516
|
switch(contains(vv, val_right))
|
9031
9517
|
{
|
9032
9518
|
case comparison_result::true_result:
|
@@ -9076,9 +9562,31 @@ namespace gqlite::backends
|
|
9076
9562
|
report_error(_context, exception_code::invalid_argument_type, "Invalid argument to function tail, list was expected.");
|
9077
9563
|
}
|
9078
9564
|
}
|
9079
|
-
|
9565
|
+
void gqlite_to_integer(sqlite3_context* _context,int,sqlite3_value** _argv)
|
9566
|
+
{
|
9567
|
+
int type = sqlite3_value_type(_argv[0]);
|
9568
|
+
switch(type)
|
9569
|
+
{
|
9570
|
+
case SQLITE_INTEGER:
|
9571
|
+
sqlite3_result_int64(_context, sqlite3_value_int64(_argv[0]));
|
9572
|
+
break;
|
9573
|
+
case SQLITE_FLOAT:
|
9574
|
+
sqlite3_result_int64(_context, sqlite3_value_double(_argv[0]));
|
9575
|
+
break;
|
9576
|
+
case SQLITE_TEXT:
|
9577
|
+
{
|
9578
|
+
std::string s(reinterpret_cast<const char*>(sqlite3_value_text(_argv[0])));
|
9579
|
+
sqlite3_result_int64(_context, std::stol(s));
|
9580
|
+
}
|
9581
|
+
break;
|
9582
|
+
default:
|
9583
|
+
report_error(_context, exception_code::invalid_argument_type, "Invalid arguments for toInteger.");
|
9584
|
+
}
|
9585
|
+
}
|
9080
9586
|
void initialise_sqlite_ext(sqlite3* db)
|
9081
9587
|
{
|
9588
|
+
sqlite3_create_function(db, "gqlite_jsonify", 1, SQLITE_SUBTYPE | SQLITE_RESULT_SUBTYPE | SQLITE_UTF8, nullptr, &gqlite_jsonify, nullptr, nullptr);
|
9589
|
+
sqlite3_create_function(db, "gqlite_next_uid", 1, SQLITE_UTF8, nullptr, &gqlite_next_uid, nullptr, nullptr);
|
9082
9590
|
sqlite3_create_function(db, "gqlite_range", 2, SQLITE_DETERMINISTIC | SQLITE_UTF8, nullptr, &gqlite_range, nullptr, nullptr);
|
9083
9591
|
sqlite3_create_function(db, "gqlite_concat", 2, SQLITE_DETERMINISTIC | SQLITE_UTF8, nullptr, &gqlite_concat, nullptr, nullptr);
|
9084
9592
|
sqlite3_create_function(db, "gqlite_addition", 2, SQLITE_DETERMINISTIC | SQLITE_UTF8, nullptr, &gqlite_addition, nullptr, nullptr);
|
@@ -9086,5 +9594,6 @@ namespace gqlite::backends
|
|
9086
9594
|
sqlite3_create_function(db, "gqlite_range_access", 3, SQLITE_DETERMINISTIC | SQLITE_UTF8, nullptr, &gqlite_range_access, nullptr, nullptr);
|
9087
9595
|
sqlite3_create_function(db, "gqlite_contains", 2, SQLITE_DETERMINISTIC | SQLITE_UTF8, nullptr, &gqlite_contains, nullptr, nullptr);
|
9088
9596
|
sqlite3_create_function(db, "gqlite_tail", 1, SQLITE_DETERMINISTIC | SQLITE_UTF8, nullptr, &gqlite_tail, nullptr, nullptr);
|
9597
|
+
sqlite3_create_function(db, "gqlite_to_integer", 1, SQLITE_DETERMINISTIC | SQLITE_UTF8, nullptr, &gqlite_to_integer, nullptr, nullptr);
|
9089
9598
|
}
|
9090
9599
|
}//END backends/sqlite_ext.cpp
|