gqlite 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|