gqlite 1.5.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/Cargo.toml +10 -4
- data/ext/db-index/Cargo.toml +29 -0
- data/ext/db-index/src/hnsw/error.rs +66 -0
- data/ext/db-index/src/hnsw/graph_store.rs +272 -0
- data/ext/db-index/src/hnsw/id.rs +36 -0
- data/ext/db-index/src/hnsw/implementation.rs +1517 -0
- data/ext/db-index/src/hnsw/kernels.rs +1228 -0
- data/ext/db-index/src/hnsw/metric.rs +244 -0
- data/ext/db-index/src/hnsw/scalar.rs +72 -0
- data/ext/db-index/src/hnsw/simple_store.rs +140 -0
- data/ext/db-index/src/hnsw/store.rs +472 -0
- data/ext/db-index/src/hnsw/vector.rs +105 -0
- data/ext/db-index/src/hnsw/vectors.rs +568 -0
- data/ext/db-index/src/hnsw.rs +42 -0
- data/ext/db-index/src/lib.rs +3 -0
- data/ext/gqlitedb/Cargo.toml +19 -9
- data/ext/gqlitedb/benches/common/pokec.rs +62 -2
- data/ext/gqlitedb/benches/pokec_divan.rs +66 -2
- data/ext/gqlitedb/benches/pokec_iai.rs +60 -3
- data/ext/gqlitedb/release.toml +2 -2
- data/ext/gqlitedb/src/aggregators/arithmetic.rs +3 -1
- data/ext/gqlitedb/src/aggregators/containers.rs +1 -1
- data/ext/gqlitedb/src/aggregators/stats.rs +21 -12
- data/ext/gqlitedb/src/capi.rs +1 -1
- data/ext/gqlitedb/src/compiler/expression_analyser.rs +28 -20
- data/ext/gqlitedb/src/compiler/variables_manager.rs +97 -29
- data/ext/gqlitedb/src/compiler.rs +505 -225
- data/ext/gqlitedb/src/connection.rs +149 -11
- data/ext/gqlitedb/src/consts.rs +1 -2
- data/ext/gqlitedb/src/error.rs +123 -61
- data/ext/gqlitedb/src/functions/common.rs +39 -2
- data/ext/gqlitedb/src/functions/math.rs +8 -3
- data/ext/gqlitedb/src/functions/path.rs +48 -11
- data/ext/gqlitedb/src/functions/value.rs +1 -1
- data/ext/gqlitedb/src/functions.rs +23 -7
- data/ext/gqlitedb/src/graph.rs +1 -9
- data/ext/gqlitedb/src/interpreter/evaluators.rs +968 -130
- data/ext/gqlitedb/src/interpreter/instructions.rs +39 -2
- data/ext/gqlitedb/src/lib.rs +5 -4
- data/ext/gqlitedb/src/planner.rs +329 -0
- data/ext/gqlitedb/src/prelude.rs +3 -3
- data/ext/gqlitedb/src/store/pgrx.rs +1 -1
- data/ext/gqlitedb/src/store/postgres.rs +735 -7
- data/ext/gqlitedb/src/store/redb/hnsw_store.rs +702 -0
- data/ext/gqlitedb/src/store/redb/index.rs +274 -0
- data/ext/gqlitedb/src/store/redb.rs +1268 -113
- data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +28 -0
- data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +103 -0
- data/ext/gqlitedb/src/store/sqlbase.rs +146 -16
- data/ext/gqlitedb/src/store/sqlite.rs +569 -5
- data/ext/gqlitedb/src/store/vector_extract.rs +56 -0
- data/ext/gqlitedb/src/store.rs +123 -3
- data/ext/gqlitedb/src/tests/compiler.rs +207 -10
- data/ext/gqlitedb/src/tests/connection/postgres.rs +38 -3
- data/ext/gqlitedb/src/tests/connection/redb.rs +23 -0
- data/ext/gqlitedb/src/tests/connection/sqlite.rs +31 -0
- data/ext/gqlitedb/src/tests/connection.rs +61 -1
- data/ext/gqlitedb/src/tests/evaluators.rs +162 -7
- data/ext/gqlitedb/src/tests/parser.rs +54 -23
- data/ext/gqlitedb/src/tests/planner.rs +511 -0
- data/ext/gqlitedb/src/tests/store/postgres.rs +7 -0
- data/ext/gqlitedb/src/tests/store/redb.rs +8 -0
- data/ext/gqlitedb/src/tests/store/sqlite.rs +8 -0
- data/ext/gqlitedb/src/tests/store/vector_index/postgres.rs +182 -0
- data/ext/gqlitedb/src/tests/store/vector_index/redb.rs +386 -0
- data/ext/gqlitedb/src/tests/store/vector_index/sqlite.rs +166 -0
- data/ext/gqlitedb/src/tests/store/vector_index.rs +2313 -0
- data/ext/gqlitedb/src/tests/store.rs +78 -14
- data/ext/gqlitedb/src/tests/templates/ast.rs +92 -16
- data/ext/gqlitedb/src/tests/templates/programs.rs +14 -7
- data/ext/gqlitedb/src/tests.rs +15 -9
- data/ext/gqlitedb/src/utils.rs +6 -1
- data/ext/gqlitedb/src/value/compare.rs +61 -3
- data/ext/gqlitedb/src/value.rs +136 -7
- data/ext/gqlitedb/templates/sql/postgres/metadata_delete.sql +1 -0
- data/ext/gqlitedb/templates/sql/postgres/node_select.sql +1 -1
- data/ext/gqlitedb/templates/sql/sqlite/metadata_delete.sql +1 -0
- data/ext/gqliterb/src/lib.rs +53 -8
- data/ext/gqlparser/Cargo.toml +25 -0
- data/ext/gqlparser/README.MD +9 -0
- data/ext/gqlparser/benches/pokec_divan.rs +34 -0
- data/ext/gqlparser/src/common.rs +69 -0
- data/ext/gqlparser/src/gqls/ast.rs +69 -0
- data/ext/gqlparser/src/gqls/constraint.rs +79 -0
- data/ext/gqlparser/src/gqls/error.rs +22 -0
- data/ext/gqlparser/src/gqls/parser.rs +813 -0
- data/ext/gqlparser/src/gqls/prelude.rs +8 -0
- data/ext/gqlparser/src/gqls/properties.rs +115 -0
- data/ext/gqlparser/src/gqls/resolve.rs +207 -0
- data/ext/gqlparser/src/gqls.rs +265 -0
- data/ext/gqlparser/src/lib.rs +7 -0
- data/ext/gqlparser/src/oc/ast.rs +680 -0
- data/ext/gqlparser/src/oc/error.rs +172 -0
- data/ext/gqlparser/src/oc/lexer.rs +429 -0
- data/ext/gqlparser/src/oc/parser/tests.rs +2284 -0
- data/ext/gqlparser/src/oc/parser.rs +2005 -0
- data/ext/gqlparser/src/oc.rs +33 -0
- data/ext/gqlparser/src/prelude.rs +3 -0
- data/ext/graphcore/Cargo.toml +1 -0
- data/ext/graphcore/src/error.rs +26 -0
- data/ext/graphcore/src/graph.rs +177 -51
- data/ext/graphcore/src/lib.rs +4 -2
- data/ext/graphcore/src/open_cypher.rs +12 -0
- data/ext/graphcore/src/table.rs +50 -2
- data/ext/graphcore/src/timestamp.rs +127 -104
- data/ext/graphcore/src/value/tensor.rs +739 -0
- data/ext/graphcore/src/value/value_map.rs +1 -1
- data/ext/graphcore/src/value.rs +343 -19
- metadata +90 -22
- data/ext/gqlitedb/src/parser/ast.rs +0 -604
- data/ext/gqlitedb/src/parser/parser_impl.rs +0 -1213
- data/ext/gqlitedb/src/parser.rs +0 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
use std::{collections::HashSet, fs};
|
|
2
2
|
|
|
3
3
|
use ccutils::temporary::TemporaryFile;
|
|
4
|
-
use gqlitedb::{
|
|
5
|
-
use rand::{seq::IndexedRandom
|
|
4
|
+
use gqlitedb::{Connection, value_map};
|
|
5
|
+
use rand::{Rng, seq::IndexedRandom};
|
|
6
6
|
use regex::Regex;
|
|
7
7
|
|
|
8
8
|
/// Marker trait to keep backend-specific resources alive for the benchmark lifetime.
|
|
@@ -244,4 +244,64 @@ impl Pokec
|
|
|
244
244
|
)
|
|
245
245
|
.unwrap();
|
|
246
246
|
}
|
|
247
|
+
pub(crate) fn scan_limit_1(&self)
|
|
248
|
+
{
|
|
249
|
+
self
|
|
250
|
+
.connection
|
|
251
|
+
.execute_oc_query("MATCH (n:User) RETURN n LIMIT 1", Default::default())
|
|
252
|
+
.unwrap();
|
|
253
|
+
}
|
|
254
|
+
pub(crate) fn scan_limit_10(&self)
|
|
255
|
+
{
|
|
256
|
+
self
|
|
257
|
+
.connection
|
|
258
|
+
.execute_oc_query("MATCH (n:User) RETURN n LIMIT 10", Default::default())
|
|
259
|
+
.unwrap();
|
|
260
|
+
}
|
|
261
|
+
pub(crate) fn scan_limit_100(&self)
|
|
262
|
+
{
|
|
263
|
+
self
|
|
264
|
+
.connection
|
|
265
|
+
.execute_oc_query("MATCH (n:User) RETURN n LIMIT 100", Default::default())
|
|
266
|
+
.unwrap();
|
|
267
|
+
}
|
|
268
|
+
pub(crate) fn recursive_1_2<R>(&self, rng: &mut R)
|
|
269
|
+
where
|
|
270
|
+
R: Rng + ?Sized,
|
|
271
|
+
{
|
|
272
|
+
let random_id = self.ids.choose(rng).unwrap();
|
|
273
|
+
self
|
|
274
|
+
.connection
|
|
275
|
+
.execute_oc_query(
|
|
276
|
+
"MATCH (s:User {id: $id})-[*1..2]->(n:User) RETURN n.id",
|
|
277
|
+
value_map!("$id" => *random_id),
|
|
278
|
+
)
|
|
279
|
+
.unwrap();
|
|
280
|
+
}
|
|
281
|
+
pub(crate) fn recursive_1_3<R>(&self, rng: &mut R)
|
|
282
|
+
where
|
|
283
|
+
R: Rng + ?Sized,
|
|
284
|
+
{
|
|
285
|
+
let random_id = self.ids.choose(rng).unwrap();
|
|
286
|
+
self
|
|
287
|
+
.connection
|
|
288
|
+
.execute_oc_query(
|
|
289
|
+
"MATCH (s:User {id: $id})-[*1..3]->(n:User) RETURN n.id",
|
|
290
|
+
value_map!("$id" => *random_id),
|
|
291
|
+
)
|
|
292
|
+
.unwrap();
|
|
293
|
+
}
|
|
294
|
+
pub(crate) fn recursive_1_2_filter<R>(&self, rng: &mut R)
|
|
295
|
+
where
|
|
296
|
+
R: Rng + ?Sized,
|
|
297
|
+
{
|
|
298
|
+
let random_id = self.ids.choose(rng).unwrap();
|
|
299
|
+
self
|
|
300
|
+
.connection
|
|
301
|
+
.execute_oc_query(
|
|
302
|
+
"MATCH (s:User {id: $id})-[*1..2]->(n:User) WHERE n.age >= 18 RETURN n.id",
|
|
303
|
+
value_map!("$id" => *random_id),
|
|
304
|
+
)
|
|
305
|
+
.unwrap();
|
|
306
|
+
}
|
|
247
307
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use divan::Bencher;
|
|
2
|
-
use rand::{rngs::StdRng
|
|
2
|
+
use rand::{SeedableRng, rngs::StdRng};
|
|
3
3
|
|
|
4
4
|
mod common;
|
|
5
5
|
|
|
@@ -8,6 +8,8 @@ use common::pokec::{Pokec, PokecSize};
|
|
|
8
8
|
const FRIEND_OF_COUNT: u32 = 100;
|
|
9
9
|
const SINGLE_VERTEX_COUNT: u32 = 100;
|
|
10
10
|
const IMPORT_COUNT: u32 = 30;
|
|
11
|
+
const LIMIT_COUNT: u32 = 200;
|
|
12
|
+
const RECURSIVE_COUNT: u32 = 100;
|
|
11
13
|
|
|
12
14
|
fn main()
|
|
13
15
|
{
|
|
@@ -125,7 +127,6 @@ fn aggregate_count_filter(bencher: Bencher, backend: &str)
|
|
|
125
127
|
tiny_pokec.aggregate_count_filter();
|
|
126
128
|
});
|
|
127
129
|
}
|
|
128
|
-
|
|
129
130
|
#[divan::bench(args = ["postgres", "sqlite", "redb"])]
|
|
130
131
|
fn aggregate_min_max_avg(bencher: Bencher, backend: &str)
|
|
131
132
|
{
|
|
@@ -135,3 +136,66 @@ fn aggregate_min_max_avg(bencher: Bencher, backend: &str)
|
|
|
135
136
|
tiny_pokec.aggregate_min_max_avg();
|
|
136
137
|
});
|
|
137
138
|
}
|
|
139
|
+
|
|
140
|
+
#[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = LIMIT_COUNT)]
|
|
141
|
+
fn scan_limit_1(bencher: Bencher, backend: &str)
|
|
142
|
+
{
|
|
143
|
+
let pokec = load_pokec(backend);
|
|
144
|
+
|
|
145
|
+
bencher.bench_local(move || {
|
|
146
|
+
pokec.scan_limit_1();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = LIMIT_COUNT)]
|
|
151
|
+
fn scan_limit_10(bencher: Bencher, backend: &str)
|
|
152
|
+
{
|
|
153
|
+
let pokec = load_pokec(backend);
|
|
154
|
+
|
|
155
|
+
bencher.bench_local(move || {
|
|
156
|
+
pokec.scan_limit_10();
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
#[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = LIMIT_COUNT)]
|
|
161
|
+
fn scan_limit_100(bencher: Bencher, backend: &str)
|
|
162
|
+
{
|
|
163
|
+
let pokec = load_pokec(backend);
|
|
164
|
+
|
|
165
|
+
bencher.bench_local(move || {
|
|
166
|
+
pokec.scan_limit_100();
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = RECURSIVE_COUNT)]
|
|
171
|
+
fn recursive_1_2(bencher: Bencher, backend: &str)
|
|
172
|
+
{
|
|
173
|
+
let pokec = load_pokec(backend).read_ids();
|
|
174
|
+
let mut rng = StdRng::seed_from_u64(991173);
|
|
175
|
+
|
|
176
|
+
bencher.bench_local(move || {
|
|
177
|
+
pokec.recursive_1_2(&mut rng);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
#[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = RECURSIVE_COUNT)]
|
|
182
|
+
fn recursive_1_3(bencher: Bencher, backend: &str)
|
|
183
|
+
{
|
|
184
|
+
let pokec = load_pokec(backend).read_ids();
|
|
185
|
+
let mut rng = StdRng::seed_from_u64(991173);
|
|
186
|
+
|
|
187
|
+
bencher.bench_local(move || {
|
|
188
|
+
pokec.recursive_1_3(&mut rng);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
#[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = RECURSIVE_COUNT)]
|
|
193
|
+
fn recursive_1_2_filter(bencher: Bencher, backend: &str)
|
|
194
|
+
{
|
|
195
|
+
let pokec = load_pokec(backend).read_ids();
|
|
196
|
+
let mut rng = StdRng::seed_from_u64(991173);
|
|
197
|
+
|
|
198
|
+
bencher.bench_local(move || {
|
|
199
|
+
pokec.recursive_1_2_filter(&mut rng);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use std::hint::black_box;
|
|
2
2
|
|
|
3
3
|
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
|
|
4
|
-
use rand::{rngs::StdRng
|
|
4
|
+
use rand::{SeedableRng, rngs::StdRng};
|
|
5
5
|
|
|
6
6
|
mod common;
|
|
7
7
|
|
|
@@ -123,11 +123,68 @@ fn aggregate_min_max_avg(micro_pokec: Pokec)
|
|
|
123
123
|
micro_pokec.aggregate_min_max_avg();
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
#[library_benchmark(setup = load_pokec)]
|
|
127
|
+
#[bench::postgres("postgres")]
|
|
128
|
+
#[bench::redb("redb")]
|
|
129
|
+
#[bench::sqlite("sqlite")]
|
|
130
|
+
fn scan_limit_1(micro_pokec: Pokec)
|
|
131
|
+
{
|
|
132
|
+
micro_pokec.scan_limit_1();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#[library_benchmark(setup = load_pokec)]
|
|
136
|
+
#[bench::postgres("postgres")]
|
|
137
|
+
#[bench::redb("redb")]
|
|
138
|
+
#[bench::sqlite("sqlite")]
|
|
139
|
+
fn scan_limit_10(micro_pokec: Pokec)
|
|
140
|
+
{
|
|
141
|
+
micro_pokec.scan_limit_10();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#[library_benchmark(setup = load_pokec)]
|
|
145
|
+
#[bench::postgres("postgres")]
|
|
146
|
+
#[bench::redb("redb")]
|
|
147
|
+
#[bench::sqlite("sqlite")]
|
|
148
|
+
fn scan_limit_100(micro_pokec: Pokec)
|
|
149
|
+
{
|
|
150
|
+
micro_pokec.scan_limit_100();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
#[library_benchmark(setup = load_with_ids)]
|
|
154
|
+
#[bench::postgres("postgres")]
|
|
155
|
+
#[bench::redb("redb")]
|
|
156
|
+
#[bench::sqlite("sqlite")]
|
|
157
|
+
fn recursive_1_2(micro_pokec: Pokec)
|
|
158
|
+
{
|
|
159
|
+
let mut rng = StdRng::seed_from_u64(991173);
|
|
160
|
+
micro_pokec.recursive_1_2(&mut rng);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#[library_benchmark(setup = load_with_ids)]
|
|
164
|
+
#[bench::postgres("postgres")]
|
|
165
|
+
#[bench::redb("redb")]
|
|
166
|
+
#[bench::sqlite("sqlite")]
|
|
167
|
+
fn recursive_1_3(micro_pokec: Pokec)
|
|
168
|
+
{
|
|
169
|
+
let mut rng = StdRng::seed_from_u64(991173);
|
|
170
|
+
micro_pokec.recursive_1_3(&mut rng);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#[library_benchmark(setup = load_with_ids)]
|
|
174
|
+
#[bench::postgres("postgres")]
|
|
175
|
+
#[bench::redb("redb")]
|
|
176
|
+
#[bench::sqlite("sqlite")]
|
|
177
|
+
fn recursive_1_2_filter(micro_pokec: Pokec)
|
|
178
|
+
{
|
|
179
|
+
let mut rng = StdRng::seed_from_u64(991173);
|
|
180
|
+
micro_pokec.recursive_1_2_filter(&mut rng);
|
|
181
|
+
}
|
|
182
|
+
|
|
126
183
|
library_benchmark_group!(
|
|
127
184
|
name = bench_micro_pokec_group;
|
|
128
|
-
benchmarks = import_micro_pokec, single_vertex, single_vertex_where, friend_of, friend_of_filter, friend_of_friend_of, friend_of_friend_of_filter, reciprocal_friends, aggregate_count, aggregate_count_filter, aggregate_min_max_avg
|
|
185
|
+
benchmarks = recursive_1_2, import_micro_pokec, single_vertex, single_vertex_where, friend_of, friend_of_filter, friend_of_friend_of, friend_of_friend_of_filter, reciprocal_friends, aggregate_count, aggregate_count_filter, aggregate_min_max_avg, scan_limit_1, scan_limit_10, scan_limit_100, recursive_1_3, recursive_1_2_filter
|
|
129
186
|
);
|
|
130
187
|
|
|
131
188
|
main!(
|
|
132
|
-
setup = common::get_bench_data();
|
|
189
|
+
setup = common::get_bench_data();
|
|
133
190
|
library_benchmark_groups = bench_micro_pokec_group);
|
data/ext/gqlitedb/release.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
pre-release-replacements = [
|
|
2
2
|
{ file = "../../CHANGELOG.md", search = "Unreleased", replace = "{{version}}" },
|
|
3
|
-
{ file = "../../CHANGELOG.md", search = "\\.\\.\\.dev/1", replace = "...{{
|
|
3
|
+
{ file = "../../CHANGELOG.md", search = "\\.\\.\\.dev/1", replace = "...gqlitedb-v{{version}}", exactly = 1 },
|
|
4
4
|
{ file = "../../CHANGELOG.md", search = "ReleaseDate", replace = "{{date}}" },
|
|
5
5
|
{ file = "../../CHANGELOG.md", search = "<!-- next-header -->", replace = "<!-- next-header -->\n\n## [Unreleased] - ReleaseDate", exactly = 1 },
|
|
6
|
-
{ file = "../../CHANGELOG.md", search = "<!-- next-url -->", replace = "<!-- next-url -->\n[Unreleased]: https://gitlab.com/
|
|
6
|
+
{ file = "../../CHANGELOG.md", search = "<!-- next-url -->", replace = "<!-- next-url -->\n[Unreleased]: https://gitlab.com/auksys/gqlite/compare/gqlitedb-v{{version}}...dev/1", exactly = 1 },
|
|
7
7
|
]
|
|
@@ -2,7 +2,7 @@ use std::fmt::Debug;
|
|
|
2
2
|
|
|
3
3
|
use super::AggregatorState;
|
|
4
4
|
|
|
5
|
-
use crate::{error::RunTimeError, value::Value
|
|
5
|
+
use crate::{Result, error::RunTimeError, value::Value};
|
|
6
6
|
|
|
7
7
|
trait Op
|
|
8
8
|
{
|
|
@@ -45,9 +45,11 @@ where
|
|
|
45
45
|
| Value::Node(..)
|
|
46
46
|
| Value::Edge(..)
|
|
47
47
|
| Value::Array(..)
|
|
48
|
+
| Value::Tensor(..)
|
|
48
49
|
| Value::String(..)
|
|
49
50
|
| Value::TimeStamp(..)
|
|
50
51
|
| Value::Map(..)
|
|
52
|
+
| Value::SinglePath(..)
|
|
51
53
|
| Value::Path(..) => Err(RunTimeError::InvalidBinaryOperands)?,
|
|
52
54
|
Value::Null =>
|
|
53
55
|
{
|
|
@@ -26,17 +26,17 @@ impl AggregatorState for AvgState
|
|
|
26
26
|
{
|
|
27
27
|
fn next(&mut self, value: value::Value) -> crate::Result<()>
|
|
28
28
|
{
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
self.value = value;
|
|
32
|
-
}
|
|
33
|
-
else
|
|
29
|
+
match value
|
|
34
30
|
{
|
|
35
|
-
|
|
31
|
+
value::Value::Null => Ok(()),
|
|
32
|
+
value::Value::Integer(i) =>
|
|
36
33
|
{
|
|
37
|
-
value
|
|
38
|
-
{
|
|
39
|
-
|
|
34
|
+
if self.value.is_null()
|
|
35
|
+
{
|
|
36
|
+
self.value = value::Value::Integer(i);
|
|
37
|
+
self.count = 1;
|
|
38
|
+
}
|
|
39
|
+
else
|
|
40
40
|
{
|
|
41
41
|
self.count += 1;
|
|
42
42
|
match self.value
|
|
@@ -46,7 +46,16 @@ impl AggregatorState for AvgState
|
|
|
46
46
|
_ => Err(InternalError::InvalidAggregationState)?,
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
Ok(())
|
|
50
|
+
}
|
|
51
|
+
value::Value::Float(f) =>
|
|
52
|
+
{
|
|
53
|
+
if self.value.is_null()
|
|
54
|
+
{
|
|
55
|
+
self.value = value::Value::Float(f);
|
|
56
|
+
self.count = 1;
|
|
57
|
+
}
|
|
58
|
+
else
|
|
50
59
|
{
|
|
51
60
|
self.count += 1;
|
|
52
61
|
match self.value
|
|
@@ -56,10 +65,10 @@ impl AggregatorState for AvgState
|
|
|
56
65
|
_ => Err(InternalError::InvalidAggregationState)?,
|
|
57
66
|
}
|
|
58
67
|
}
|
|
59
|
-
|
|
68
|
+
Ok(())
|
|
60
69
|
}
|
|
70
|
+
_ => Err(RunTimeError::InvalidArgumentType)?,
|
|
61
71
|
}
|
|
62
|
-
Ok(())
|
|
63
72
|
}
|
|
64
73
|
fn finalise(self: Box<Self>) -> crate::Result<crate::value::Value>
|
|
65
74
|
{
|
data/ext/gqlitedb/src/capi.rs
CHANGED
|
@@ -41,7 +41,7 @@ fn check_error(context: *mut GqliteApiContextT)
|
|
|
41
41
|
{
|
|
42
42
|
let context = unsafe { Box::from_raw(context) };
|
|
43
43
|
let stri = context.string.to_str().unwrap();
|
|
44
|
-
|
|
44
|
+
log::error!("Error message '{stri:?}' was not cleared from context!");
|
|
45
45
|
let _ = Box::into_raw(context);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
use
|
|
1
|
+
use gqlparser::oc::ast;
|
|
2
|
+
|
|
3
|
+
use crate::{compiler::variables_manager::VariablesManager, prelude::*};
|
|
2
4
|
|
|
3
5
|
// __ __ _ _ _ _____
|
|
4
6
|
// \ \ / /_ _ _ __(_) __ _| |__ | | __|_ _| _ _ __ ___
|
|
@@ -23,6 +25,8 @@ pub(crate) enum ExpressionType
|
|
|
23
25
|
String,
|
|
24
26
|
TimeStamp,
|
|
25
27
|
Variant,
|
|
28
|
+
#[expect(dead_code)]
|
|
29
|
+
Tensor,
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
// _ _ _ _
|
|
@@ -34,7 +38,7 @@ pub(crate) enum ExpressionType
|
|
|
34
38
|
|
|
35
39
|
mod validators
|
|
36
40
|
{
|
|
37
|
-
use crate::{
|
|
41
|
+
use crate::{Result, error};
|
|
38
42
|
|
|
39
43
|
use super::{ExpressionInfo, ExpressionType};
|
|
40
44
|
|
|
@@ -136,15 +140,15 @@ where
|
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
|
|
139
|
-
impl<VT> ExpressionAnalyser for (&ast::Expression, VT)
|
|
140
|
-
where
|
|
141
|
-
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
143
|
+
// impl<VT> ExpressionAnalyser for (&ast::Expression, VT)
|
|
144
|
+
// where
|
|
145
|
+
// VT: Fn(ExpressionInfo) -> Result<ExpressionInfo>,
|
|
146
|
+
// {
|
|
147
|
+
// fn analyse<'b>(self, analyser: &Analyser<'b>) -> Result<Vec<ExpressionInfo>>
|
|
148
|
+
// {
|
|
149
|
+
// Ok(vec![self.1(analyser.analyse(self.0)?)?])
|
|
150
|
+
// }
|
|
151
|
+
// }
|
|
148
152
|
|
|
149
153
|
impl<'a, VT0, VT1> ExpressionAnalyser for ((&'a ast::Expression, &'a ast::Expression), (VT0, VT1))
|
|
150
154
|
where
|
|
@@ -154,8 +158,8 @@ where
|
|
|
154
158
|
fn analyse<'b>(self, analyser: &Analyser<'b>) -> Result<Vec<ExpressionInfo>>
|
|
155
159
|
{
|
|
156
160
|
Ok(vec![
|
|
157
|
-
self.1
|
|
158
|
-
self.1
|
|
161
|
+
self.1.0(analyser.analyse(self.0.0)?)?,
|
|
162
|
+
self.1.1(analyser.analyse(self.0.1)?)?,
|
|
159
163
|
])
|
|
160
164
|
}
|
|
161
165
|
}
|
|
@@ -171,17 +175,21 @@ where
|
|
|
171
175
|
pub(crate) struct ExpressionInfo
|
|
172
176
|
{
|
|
173
177
|
pub(crate) expression_type: ExpressionType,
|
|
174
|
-
|
|
178
|
+
/// runtime constant indicates a constant that can be evaluated during compilation, but
|
|
179
|
+
/// that might not always be deterministic. For instance, `toInteger(rand()*9)` is such
|
|
180
|
+
/// a contant.
|
|
181
|
+
pub(crate) runtime_constant: bool,
|
|
175
182
|
pub(crate) aggregation_result: bool,
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
impl ExpressionInfo
|
|
179
186
|
{
|
|
180
|
-
fn new(expression_type: ExpressionType,
|
|
187
|
+
fn new(expression_type: ExpressionType, runtime_constant: bool, aggregation_result: bool)
|
|
188
|
+
-> Self
|
|
181
189
|
{
|
|
182
190
|
Self {
|
|
183
191
|
expression_type,
|
|
184
|
-
|
|
192
|
+
runtime_constant,
|
|
185
193
|
aggregation_result,
|
|
186
194
|
}
|
|
187
195
|
}
|
|
@@ -190,7 +198,7 @@ impl ExpressionInfo
|
|
|
190
198
|
let dependents = dependents.into();
|
|
191
199
|
Self {
|
|
192
200
|
expression_type,
|
|
193
|
-
|
|
201
|
+
runtime_constant: dependents.iter().all(|x| x.runtime_constant),
|
|
194
202
|
aggregation_result: dependents.into_iter().any(|x| x.aggregation_result),
|
|
195
203
|
}
|
|
196
204
|
}
|
|
@@ -254,8 +262,7 @@ impl<'b> Analyser<'b>
|
|
|
254
262
|
&call.name,
|
|
255
263
|
arguments.iter().map(|x| x.expression_type).collect(),
|
|
256
264
|
)?,
|
|
257
|
-
|
|
258
|
-
&& arguments.iter().all(|x| x.constant),
|
|
265
|
+
arguments.iter().all(|x| x.runtime_constant),
|
|
259
266
|
self.functions_manager.is_aggregate(&call.name)?,
|
|
260
267
|
))
|
|
261
268
|
}
|
|
@@ -410,6 +417,7 @@ impl<'b> Analyser<'b>
|
|
|
410
417
|
match val.value
|
|
411
418
|
{
|
|
412
419
|
value::Value::Array(_) => ExpressionType::Array,
|
|
420
|
+
value::Value::Tensor(_) => ExpressionType::Array,
|
|
413
421
|
value::Value::Key(_) => ExpressionType::Key,
|
|
414
422
|
value::Value::Boolean(_) => ExpressionType::Boolean,
|
|
415
423
|
value::Value::Edge(_) => ExpressionType::Edge,
|
|
@@ -418,7 +426,7 @@ impl<'b> Analyser<'b>
|
|
|
418
426
|
value::Value::Integer(_) => ExpressionType::Integer,
|
|
419
427
|
value::Value::Null => ExpressionType::Null,
|
|
420
428
|
value::Value::Map(_) => ExpressionType::Map,
|
|
421
|
-
value::Value::Path(_) => ExpressionType::Path,
|
|
429
|
+
value::Value::SinglePath(_) | value::Value::Path(_) => ExpressionType::Path,
|
|
422
430
|
value::Value::String(_) => ExpressionType::String,
|
|
423
431
|
value::Value::TimeStamp(_) => ExpressionType::TimeStamp,
|
|
424
432
|
},
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
|
|
3
|
-
use
|
|
3
|
+
use gqlparser::oc::ast;
|
|
4
|
+
|
|
5
|
+
use crate::{planner::LogicalPlan, prelude::*};
|
|
4
6
|
|
|
5
7
|
use compiler::expression_analyser::{self, ExpressionType};
|
|
6
|
-
use parser::ast;
|
|
7
8
|
|
|
8
9
|
fn unknown_variable_error(name: &ast::VariableIdentifier) -> ErrorType
|
|
9
10
|
{
|
|
10
|
-
|
|
11
|
+
CompileTimeError::UndefinedVariable {
|
|
11
12
|
name: name.name().clone(),
|
|
12
13
|
}
|
|
13
14
|
.into()
|
|
@@ -77,7 +78,8 @@ impl Variable
|
|
|
77
78
|
labels: ast::LabelExpression::None,
|
|
78
79
|
properties: None,
|
|
79
80
|
},
|
|
80
|
-
directivity:
|
|
81
|
+
directivity: graphcore::EdgeDirectivity::Directed,
|
|
82
|
+
recursive_range: None,
|
|
81
83
|
}),
|
|
82
84
|
variable_type: ExpressionType::Edge,
|
|
83
85
|
col_id,
|
|
@@ -253,7 +255,7 @@ impl VariablesManager
|
|
|
253
255
|
}
|
|
254
256
|
}
|
|
255
257
|
_ => Err(
|
|
256
|
-
|
|
258
|
+
CompileTimeError::ExpectedNode {
|
|
257
259
|
context: "validate_node",
|
|
258
260
|
}
|
|
259
261
|
.into(),
|
|
@@ -358,7 +360,7 @@ impl VariablesManager
|
|
|
358
360
|
}
|
|
359
361
|
}
|
|
360
362
|
_ => Err(
|
|
361
|
-
|
|
363
|
+
CompileTimeError::ExpectedNode {
|
|
362
364
|
context: "is_valid_existing_node",
|
|
363
365
|
}
|
|
364
366
|
.into(),
|
|
@@ -413,7 +415,7 @@ impl VariablesManager
|
|
|
413
415
|
}
|
|
414
416
|
}
|
|
415
417
|
_ => Err(
|
|
416
|
-
|
|
418
|
+
CompileTimeError::ExpectedEdge {
|
|
417
419
|
context: "is_valid_existing_edge",
|
|
418
420
|
}
|
|
419
421
|
.into(),
|
|
@@ -459,7 +461,7 @@ impl VariablesManager
|
|
|
459
461
|
fn analyse_edge_path(
|
|
460
462
|
&mut self,
|
|
461
463
|
path_variable: Option<ast::VariableIdentifier>,
|
|
462
|
-
edge: &
|
|
464
|
+
edge: &gqlparser::oc::ast::EdgePattern,
|
|
463
465
|
is_create: bool,
|
|
464
466
|
) -> Result<()>
|
|
465
467
|
{
|
|
@@ -538,7 +540,7 @@ impl VariablesManager
|
|
|
538
540
|
self.variables = new_variables;
|
|
539
541
|
Ok(())
|
|
540
542
|
}
|
|
541
|
-
pub(crate) fn analyse(&mut self,
|
|
543
|
+
pub(crate) fn analyse(&mut self, logical_plan: &LogicalPlan) -> Result<()>
|
|
542
544
|
{
|
|
543
545
|
if self.variables.iter().any(|(_, var)| !var.is_set)
|
|
544
546
|
{
|
|
@@ -559,17 +561,17 @@ impl VariablesManager
|
|
|
559
561
|
.into(),
|
|
560
562
|
);
|
|
561
563
|
}
|
|
562
|
-
match
|
|
564
|
+
match logical_plan
|
|
563
565
|
{
|
|
564
|
-
|
|
566
|
+
LogicalPlan::CreateGraph { .. } =>
|
|
565
567
|
{}
|
|
566
|
-
|
|
568
|
+
LogicalPlan::DropGraph { .. } =>
|
|
567
569
|
{}
|
|
568
|
-
|
|
570
|
+
LogicalPlan::UseGraph { .. } =>
|
|
569
571
|
{}
|
|
570
|
-
|
|
572
|
+
LogicalPlan::Create { patterns } =>
|
|
571
573
|
{
|
|
572
|
-
for pattern in
|
|
574
|
+
for pattern in patterns.iter()
|
|
573
575
|
{
|
|
574
576
|
if let ast::Pattern::Node(n) = &pattern
|
|
575
577
|
&& self.has_variable(&n.variable)
|
|
@@ -584,31 +586,97 @@ impl VariablesManager
|
|
|
584
586
|
self.analyse_pattern(pattern, true)?;
|
|
585
587
|
}
|
|
586
588
|
}
|
|
587
|
-
|
|
589
|
+
LogicalPlan::NodeScan { patterns, .. } =>
|
|
588
590
|
{
|
|
589
|
-
for pattern in
|
|
591
|
+
for pattern in patterns.iter()
|
|
590
592
|
{
|
|
591
593
|
self.analyse_pattern(pattern, false)?;
|
|
592
594
|
}
|
|
593
595
|
}
|
|
594
|
-
|
|
595
|
-
{}
|
|
596
|
-
|
|
596
|
+
LogicalPlan::Filter { source, .. }
|
|
597
|
+
| LogicalPlan::Sort { source, .. }
|
|
598
|
+
| LogicalPlan::Skip { source, .. }
|
|
599
|
+
| LogicalPlan::Limit { source, .. } => self.analyse(source.as_ref())?,
|
|
600
|
+
LogicalPlan::Projection { .. } =>
|
|
597
601
|
{}
|
|
598
|
-
|
|
602
|
+
LogicalPlan::Call { .. } =>
|
|
599
603
|
{}
|
|
600
|
-
|
|
604
|
+
LogicalPlan::Unwind { identifier, .. } =>
|
|
601
605
|
{
|
|
602
|
-
self.declare_variable(
|
|
603
|
-
|
|
604
|
-
expression_analyser::ExpressionType::Variant,
|
|
605
|
-
)?;
|
|
606
|
-
self.mark_variables_as_set(&unwind.identifier)?;
|
|
606
|
+
self.declare_variable(identifier, expression_analyser::ExpressionType::Variant)?;
|
|
607
|
+
self.mark_variables_as_set(identifier)?;
|
|
607
608
|
}
|
|
608
|
-
|
|
609
|
+
LogicalPlan::Delete { .. } =>
|
|
609
610
|
{}
|
|
610
|
-
|
|
611
|
+
LogicalPlan::Update { .. } =>
|
|
611
612
|
{}
|
|
613
|
+
LogicalPlan::Merge { patterns, .. } =>
|
|
614
|
+
{
|
|
615
|
+
for pattern in patterns.iter()
|
|
616
|
+
{
|
|
617
|
+
match pattern
|
|
618
|
+
{
|
|
619
|
+
ast::Pattern::Node(n) =>
|
|
620
|
+
{
|
|
621
|
+
if self.has_variable(&n.variable)
|
|
622
|
+
{
|
|
623
|
+
return Err(
|
|
624
|
+
CompileTimeError::VariableAlreadyBound {
|
|
625
|
+
name: n.variable.as_ref().unwrap().name().clone(),
|
|
626
|
+
}
|
|
627
|
+
.into(),
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
ast::Pattern::Edge(e) =>
|
|
632
|
+
{
|
|
633
|
+
if self.has_variable(&e.variable)
|
|
634
|
+
{
|
|
635
|
+
return Err(
|
|
636
|
+
CompileTimeError::VariableAlreadyBound {
|
|
637
|
+
name: e.variable.as_ref().unwrap().name().clone(),
|
|
638
|
+
}
|
|
639
|
+
.into(),
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
ast::Pattern::Path(p) =>
|
|
644
|
+
{
|
|
645
|
+
if self.has_variable(&Some(p.variable.clone()))
|
|
646
|
+
{
|
|
647
|
+
return Err(
|
|
648
|
+
CompileTimeError::VariableAlreadyBound {
|
|
649
|
+
name: p.variable.name().clone(),
|
|
650
|
+
}
|
|
651
|
+
.into(),
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
self.analyse_pattern(pattern, false)?;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
LogicalPlan::VectorSearch {
|
|
660
|
+
result_var,
|
|
661
|
+
score_var,
|
|
662
|
+
..
|
|
663
|
+
} =>
|
|
664
|
+
{
|
|
665
|
+
// Declare the result variable as a Node
|
|
666
|
+
self.declare_variable(result_var, expression_analyser::ExpressionType::Node)?;
|
|
667
|
+
self.mark_variables_as_set(result_var)?;
|
|
668
|
+
|
|
669
|
+
// Declare the score variable if present
|
|
670
|
+
if let Some(score_var_id) = score_var
|
|
671
|
+
{
|
|
672
|
+
self.declare_variable(score_var_id, expression_analyser::ExpressionType::Float)?;
|
|
673
|
+
self.mark_variables_as_set(score_var_id)?;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
LogicalPlan::CreateVectorIndex { .. } =>
|
|
677
|
+
{
|
|
678
|
+
// Schema operation - no variable analysis needed
|
|
679
|
+
}
|
|
612
680
|
}
|
|
613
681
|
Ok(())
|
|
614
682
|
}
|