gqlite 1.2.0 → 1.2.3

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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/ext/gqliterb/.cargo/config.toml +2 -0
  3. data/ext/gqliterb/Cargo.lock +152 -135
  4. data/ext/gqliterb/Cargo.toml +4 -6
  5. data/ext/gqliterb/src/lib.rs +8 -2
  6. data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +2115 -0
  7. data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +138 -0
  8. data/ext/gqliterb/vendor/gqlitedb/askama.toml +3 -0
  9. data/ext/gqliterb/vendor/gqlitedb/benches/common/mod.rs +25 -0
  10. data/ext/gqliterb/vendor/gqlitedb/benches/common/pokec.rs +185 -0
  11. data/ext/gqliterb/vendor/gqlitedb/benches/pokec_divan.rs +137 -0
  12. data/ext/gqliterb/vendor/gqlitedb/benches/pokec_iai.rs +122 -0
  13. data/ext/gqliterb/vendor/gqlitedb/release.toml +7 -0
  14. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/arithmetic.rs +96 -0
  15. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/containers.rs +33 -0
  16. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/count.rs +35 -0
  17. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/stats.rs +168 -0
  18. data/ext/gqliterb/vendor/gqlitedb/src/aggregators.rs +74 -0
  19. data/ext/gqliterb/vendor/gqlitedb/src/capi.rs +259 -0
  20. data/ext/gqliterb/vendor/gqlitedb/src/compiler/expression_analyser.rs +431 -0
  21. data/ext/gqliterb/vendor/gqlitedb/src/compiler/variables_manager.rs +621 -0
  22. data/ext/gqliterb/vendor/gqlitedb/src/compiler.rs +1115 -0
  23. data/ext/gqliterb/vendor/gqlitedb/src/connection.rs +342 -0
  24. data/ext/gqliterb/vendor/gqlitedb/src/consts.rs +10 -0
  25. data/ext/gqliterb/vendor/gqlitedb/src/error.rs +613 -0
  26. data/ext/gqliterb/vendor/gqlitedb/src/functions/containers.rs +115 -0
  27. data/ext/gqliterb/vendor/gqlitedb/src/functions/edge.rs +20 -0
  28. data/ext/gqliterb/vendor/gqlitedb/src/functions/math.rs +44 -0
  29. data/ext/gqliterb/vendor/gqlitedb/src/functions/node.rs +16 -0
  30. data/ext/gqliterb/vendor/gqlitedb/src/functions/path.rs +80 -0
  31. data/ext/gqliterb/vendor/gqlitedb/src/functions/scalar.rs +86 -0
  32. data/ext/gqliterb/vendor/gqlitedb/src/functions/string.rs +28 -0
  33. data/ext/gqliterb/vendor/gqlitedb/src/functions/value.rs +99 -0
  34. data/ext/gqliterb/vendor/gqlitedb/src/functions.rs +410 -0
  35. data/ext/gqliterb/vendor/gqlitedb/src/graph.rs +283 -0
  36. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/evaluators.rs +1776 -0
  37. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/instructions.rs +267 -0
  38. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/mod.rs +4 -0
  39. data/ext/gqliterb/vendor/gqlitedb/src/lib.rs +41 -0
  40. data/ext/gqliterb/vendor/gqlitedb/src/parser/ast.rs +611 -0
  41. data/ext/gqliterb/vendor/gqlitedb/src/parser/gql.pest +196 -0
  42. data/ext/gqliterb/vendor/gqlitedb/src/parser/parser.rs +1183 -0
  43. data/ext/gqliterb/vendor/gqlitedb/src/parser.rs +4 -0
  44. data/ext/gqliterb/vendor/gqlitedb/src/prelude.rs +8 -0
  45. data/ext/gqliterb/vendor/gqlitedb/src/serialize_with.rs +94 -0
  46. data/ext/gqliterb/vendor/gqlitedb/src/store/pgql.rs +121 -0
  47. data/ext/gqliterb/vendor/gqlitedb/src/store/redb.rs +1262 -0
  48. data/ext/gqliterb/vendor/gqlitedb/src/store/sqlite.rs +1026 -0
  49. data/ext/gqliterb/vendor/gqlitedb/src/store.rs +439 -0
  50. data/ext/gqliterb/vendor/gqlitedb/src/tests/compiler.rs +92 -0
  51. data/ext/gqliterb/vendor/gqlitedb/src/tests/evaluators.rs +227 -0
  52. data/ext/gqliterb/vendor/gqlitedb/src/tests/parser.rs +81 -0
  53. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/redb.rs +46 -0
  54. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/sqlite.rs +46 -0
  55. data/ext/gqliterb/vendor/gqlitedb/src/tests/store.rs +470 -0
  56. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/ast.rs +356 -0
  57. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/programs.rs +455 -0
  58. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates.rs +2 -0
  59. data/ext/gqliterb/vendor/gqlitedb/src/tests.rs +39 -0
  60. data/ext/gqliterb/vendor/gqlitedb/src/utils.rs +28 -0
  61. data/ext/gqliterb/vendor/gqlitedb/src/value/compare.rs +212 -0
  62. data/ext/gqliterb/vendor/gqlitedb/src/value/contains.rs +47 -0
  63. data/ext/gqliterb/vendor/gqlitedb/src/value/value_map.rs +298 -0
  64. data/ext/gqliterb/vendor/gqlitedb/src/value.rs +609 -0
  65. data/ext/gqliterb/vendor/gqlitedb/src/value_table.rs +610 -0
  66. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/call_stats.sql +22 -0
  67. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_count_for_node.sql +3 -0
  68. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_create.sql +6 -0
  69. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete.sql +1 -0
  70. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete_by_nodes.sql +2 -0
  71. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_select.sql +139 -0
  72. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_update.sql +4 -0
  73. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_create.sql +16 -0
  74. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_delete.sql +3 -0
  75. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_create_table.sql +1 -0
  76. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_get.sql +1 -0
  77. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_set.sql +1 -0
  78. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_create.sql +1 -0
  79. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_delete.sql +1 -0
  80. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_select.sql +42 -0
  81. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_update.sql +4 -0
  82. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/table_exists.sql +5 -0
  83. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_from_1_01.sql +2 -0
  84. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_graph_from_1_01.sql +65 -0
  85. metadata +82 -2
@@ -0,0 +1,1776 @@
1
+ use std::collections::HashMap;
2
+
3
+ use crate::{
4
+ interpreter::instructions::{Block, VariablesSizes},
5
+ prelude::*,
6
+ store::TransactionBoxable,
7
+ value_table::{MutableRowInterface, Row, RowInterface},
8
+ };
9
+ use interpreter::instructions;
10
+
11
+ #[derive(Debug, Clone)]
12
+ enum Value
13
+ {
14
+ GraphValue(value::Value),
15
+ NodeQuery(store::SelectNodeQuery),
16
+ EdgeQuery(store::SelectEdgeQuery),
17
+ }
18
+
19
+ impl<T> From<T> for Value
20
+ where
21
+ T: Into<value::Value>,
22
+ {
23
+ fn from(value: T) -> Self
24
+ {
25
+ Self::GraphValue(value.into())
26
+ }
27
+ }
28
+
29
+ macro_rules! try_into_gv_impl {
30
+ ($vn:ty) => {
31
+ impl TryInto<$vn> for Value
32
+ {
33
+ type Error = ErrorType;
34
+ fn try_into(self) -> crate::Result<$vn>
35
+ {
36
+ let a: value::Value = self.try_into()?;
37
+ a.try_into()
38
+ }
39
+ }
40
+ impl TryPopInto<$vn> for Stack
41
+ {
42
+ fn try_pop_into(&mut self) -> crate::Result<$vn>
43
+ {
44
+ self.try_pop()?.try_into()
45
+ .map_err(|e: ErrorType| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::InvalidArgumentType ))
46
+ }
47
+ fn try_drain_into(&mut self, n: usize) -> Result<Vec<$vn>>
48
+ {
49
+ self.try_drain(n)?.map(|x| x.try_into()).collect::<Result<_>>()
50
+ .map_err(|e| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::InvalidArgumentType ))
51
+ }
52
+ }
53
+ };
54
+ }
55
+
56
+ try_into_gv_impl! {bool}
57
+ try_into_gv_impl! {i64}
58
+ try_into_gv_impl! {f64}
59
+ try_into_gv_impl! {String}
60
+ try_into_gv_impl! {graph::Node}
61
+ try_into_gv_impl! {graph::Edge}
62
+
63
+ macro_rules! try_into_impl {
64
+ ($typename:tt, $type:ty, $errorname:tt) => {
65
+ impl TryInto<$type> for Value
66
+ {
67
+ type Error = ErrorType;
68
+ fn try_into(self) -> std::result::Result<$type, Self::Error>
69
+ {
70
+ match self
71
+ {
72
+ Self::$typename(gv) => Ok(gv),
73
+ _ => Err(
74
+ InternalError::$errorname {
75
+ context: "try_into",
76
+ }
77
+ .into(),
78
+ ),
79
+ }
80
+ }
81
+ }
82
+ impl TryPopInto<$type> for Stack
83
+ {
84
+ fn try_pop_into(&mut self) -> Result<$type>
85
+ {
86
+ self.try_pop()?.try_into()
87
+ .map_err(|e: ErrorType| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::InvalidArgumentType ))
88
+
89
+ }
90
+ fn try_drain_into(&mut self, n: usize) -> Result<Vec<$type>>
91
+ {
92
+ self.try_drain(n)?.map(|x| x.try_into()).collect::<Result<_>>()
93
+ .map_err(|e| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::InvalidArgumentType ))
94
+ }
95
+ }
96
+ };
97
+ }
98
+
99
+ try_into_impl! {GraphValue, value::Value, ExpectedGraphValue}
100
+ try_into_impl! {NodeQuery, store::SelectNodeQuery, ExpectedNodeQuery}
101
+ try_into_impl! {EdgeQuery, store::SelectEdgeQuery, ExpectedEdgeQuery}
102
+
103
+ impl From<store::SelectNodeQuery> for Value
104
+ {
105
+ fn from(value: store::SelectNodeQuery) -> Self
106
+ {
107
+ Self::NodeQuery(value.into())
108
+ }
109
+ }
110
+
111
+ impl From<store::SelectEdgeQuery> for Value
112
+ {
113
+ fn from(value: store::SelectEdgeQuery) -> Self
114
+ {
115
+ Self::EdgeQuery(value.into())
116
+ }
117
+ }
118
+
119
+ #[allow(unused_macros)]
120
+ macro_rules! check_for_null {
121
+ ($a: expr) => {
122
+ if $a.is_null() {
123
+ return Ok(crate::value::Value::Null)
124
+ }
125
+ };
126
+ ($a: expr, $($b:expr), *) => {
127
+ check_for_null!($a);
128
+ check_for_null!($($b),*);
129
+ }
130
+ }
131
+
132
+ macro_rules! ordering_to_value {
133
+ ($expression:expr, $true_pattern:pat, $null_value:expr ) => {
134
+ match $expression
135
+ {
136
+ $true_pattern => true.into(),
137
+ value::Ordering::ComparedNull => value::Value::Null,
138
+ value::Ordering::Null => $null_value,
139
+ _ => false.into(),
140
+ }
141
+ };
142
+ }
143
+
144
+ macro_rules! contain_to_value {
145
+ ($expression:expr, $true_pattern:pat ) => {
146
+ match $expression
147
+ {
148
+ $true_pattern => true.into(),
149
+ value::ContainResult::ComparedNull => value::Value::Null,
150
+ _ => false.into(),
151
+ }
152
+ };
153
+ }
154
+
155
+ #[derive(Default, Debug)]
156
+ struct Stack
157
+ {
158
+ stack: Vec<Value>,
159
+ }
160
+
161
+ impl Stack
162
+ {
163
+ fn push(&mut self, value: impl Into<Value>)
164
+ {
165
+ self.stack.push(value.into());
166
+ }
167
+ fn try_pop(&mut self) -> Result<Value>
168
+ {
169
+ self.stack.pop().ok_or(InternalError::EmptyStack.into())
170
+ }
171
+ fn try_last(&self) -> Result<&Value>
172
+ {
173
+ self.stack.last().ok_or(InternalError::EmptyStack.into())
174
+ }
175
+ fn try_drain(&mut self, len: usize) -> Result<std::vec::Drain<'_, Value>>
176
+ {
177
+ if len > self.stack.len()
178
+ {
179
+ Err(InternalError::EmptyStack.into())
180
+ }
181
+ else
182
+ {
183
+ Ok(self.stack.drain((self.stack.len() - len)..))
184
+ }
185
+ }
186
+ fn to_vec(self) -> Vec<Value>
187
+ {
188
+ self.stack
189
+ }
190
+ fn try_pop_as_boolean(&mut self) -> Result<bool>
191
+ {
192
+ let v = self.try_pop()?;
193
+ match v
194
+ {
195
+ Value::GraphValue(value::Value::Null) | Value::GraphValue(value::Value::Boolean(false)) =>
196
+ {
197
+ Ok(false)
198
+ }
199
+ _ => Ok(true),
200
+ }
201
+ }
202
+ }
203
+
204
+ trait TryPopInto<T>
205
+ {
206
+ fn try_pop_into(&mut self) -> Result<T>;
207
+ fn try_drain_into(&mut self, n: usize) -> Result<Vec<T>>;
208
+ }
209
+
210
+ impl<T> TryPopInto<T> for Stack
211
+ where
212
+ T: TryFrom<Value, Error = ErrorType>,
213
+ {
214
+ fn try_pop_into(&mut self) -> Result<T>
215
+ {
216
+ self.try_pop()?.try_into()
217
+ .map_err(|e: ErrorType| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::InvalidArgumentType ))
218
+ }
219
+ fn try_drain_into(&mut self, n: usize) -> Result<Vec<T>>
220
+ {
221
+ self.try_drain(n)?.map(|x| x.try_into()).collect::<Result<Vec<_>>>()
222
+ .map_err(|e| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::InvalidArgumentType ))
223
+ }
224
+ }
225
+
226
+ fn execute_boolean_operator(
227
+ stack: &mut Stack,
228
+ instruction: &instructions::Instruction,
229
+ ) -> Result<()>
230
+ {
231
+ let a = stack.try_pop()?;
232
+ let b = stack.try_pop()?;
233
+ let a: value::Value = a.try_into()?;
234
+ let b: value::Value = b.try_into()?;
235
+ match instruction
236
+ {
237
+ &instructions::Instruction::AndBinaryOperator =>
238
+ {
239
+ if a.is_null()
240
+ {
241
+ if b.is_null() || <value::Value as TryInto<bool>>::try_into(b)? == true
242
+ {
243
+ stack.push(value::Value::Null);
244
+ }
245
+ else
246
+ {
247
+ stack.push(false);
248
+ }
249
+ }
250
+ else
251
+ {
252
+ let a: bool = a.try_into()?;
253
+ if a
254
+ {
255
+ if b.is_null()
256
+ {
257
+ stack.push(value::Value::Null);
258
+ }
259
+ else
260
+ {
261
+ stack.push(b);
262
+ }
263
+ }
264
+ else
265
+ {
266
+ stack.push(false);
267
+ }
268
+ }
269
+ }
270
+ &instructions::Instruction::OrBinaryOperator =>
271
+ {
272
+ if a.is_null()
273
+ {
274
+ if b.is_null() || <value::Value as TryInto<bool>>::try_into(b)? == false
275
+ {
276
+ stack.push(value::Value::Null);
277
+ }
278
+ else
279
+ {
280
+ stack.push(true);
281
+ }
282
+ }
283
+ else
284
+ {
285
+ let a: bool = a.try_into()?;
286
+ if a
287
+ {
288
+ stack.push(true);
289
+ }
290
+ else
291
+ {
292
+ if b.is_null()
293
+ {
294
+ stack.push(value::Value::Null);
295
+ }
296
+ else
297
+ {
298
+ stack.push(b);
299
+ }
300
+ }
301
+ }
302
+ }
303
+ &instructions::Instruction::XorBinaryOperator =>
304
+ {
305
+ if a.is_null() || b.is_null()
306
+ {
307
+ stack.push(value::Value::Null);
308
+ }
309
+ else
310
+ {
311
+ let a: bool = a.try_into()?;
312
+ let b: bool = b.try_into()?;
313
+ stack.push(a ^ b);
314
+ }
315
+ }
316
+ _ => Err(InternalError::Unreachable {
317
+ context: "evaluator/execute_boolean_operator",
318
+ })?,
319
+ }
320
+
321
+ Ok(())
322
+ }
323
+
324
+ fn execute_binary_operator<T: Into<crate::value::Value>>(
325
+ stack: &mut Stack,
326
+ operand: impl FnOnce(crate::value::Value, crate::value::Value) -> Result<T>,
327
+ ) -> Result<()>
328
+ {
329
+ let a = stack.try_pop()?;
330
+ let b = stack.try_pop()?;
331
+ stack.push(operand(a.try_into()?, b.try_into()?)?.into());
332
+ Ok(())
333
+ }
334
+
335
+ fn eval_instructions(
336
+ stack: &mut Stack,
337
+ row: &impl value_table::RowInterface,
338
+ instructions: &instructions::Instructions,
339
+ parameters: &crate::value::ValueMap,
340
+ ) -> Result<()>
341
+ {
342
+ if crate::consts::SHOW_EVALUATOR_STATE
343
+ {
344
+ println!("----------- eval_instructions");
345
+ }
346
+ for instruction in instructions
347
+ {
348
+ if crate::consts::SHOW_EVALUATOR_STATE
349
+ {
350
+ println!(
351
+ "-- instruction {:#?}\n-- stack {:#?}\n-- row {:#?}",
352
+ instruction, stack, row
353
+ );
354
+ }
355
+ match instruction
356
+ {
357
+ instructions::Instruction::CreateEdgeLiteral { labels } =>
358
+ {
359
+ let props: value::Value = stack.try_pop_into()?;
360
+ let dst: graph::Node = stack.try_pop_into()?;
361
+ let src: graph::Node = stack.try_pop_into()?;
362
+ stack.push(crate::graph::Edge {
363
+ key: graph::Key::default(),
364
+ source: src,
365
+ destination: dst,
366
+ labels: labels.to_owned(),
367
+ properties: props.into_map(),
368
+ });
369
+ }
370
+ instructions::Instruction::CreateNodeLiteral { labels } =>
371
+ {
372
+ let props: value::Value = stack.try_pop_into()?;
373
+ stack.push(crate::graph::Node {
374
+ key: crate::graph::Key::default(),
375
+ labels: labels.clone(),
376
+ properties: props.into_map(),
377
+ });
378
+ }
379
+ instructions::Instruction::CreateEdgeQuery { labels } =>
380
+ {
381
+ let props: value::Value = stack.try_pop_into()?;
382
+ let dst: store::SelectNodeQuery = stack.try_pop_into()?;
383
+ let src: store::SelectNodeQuery = stack.try_pop_into()?;
384
+ match props
385
+ {
386
+ value::Value::Edge(ed) =>
387
+ {
388
+ stack.push(store::SelectEdgeQuery::select_source_destination_keys(
389
+ src,
390
+ [ed.key],
391
+ dst,
392
+ ));
393
+ }
394
+ value::Value::Map(ob) =>
395
+ {
396
+ stack.push(
397
+ store::SelectEdgeQuery::select_source_destination_labels_properties(
398
+ src,
399
+ labels.clone(),
400
+ ob,
401
+ dst,
402
+ ),
403
+ );
404
+ }
405
+ value::Value::Null =>
406
+ {
407
+ stack.push(store::SelectEdgeQuery::select_none());
408
+ }
409
+ _ => Err(InternalError::InvalidValueCast {
410
+ value: props,
411
+ typename: "Edge properties",
412
+ })?,
413
+ }
414
+ }
415
+ instructions::Instruction::CreateNodeQuery { labels } =>
416
+ {
417
+ let props: value::Value = stack.try_pop_into()?;
418
+ match props
419
+ {
420
+ value::Value::Node(no) =>
421
+ {
422
+ stack.push(store::SelectNodeQuery::select_keys([no.key]));
423
+ }
424
+ value::Value::Map(ob) =>
425
+ {
426
+ stack.push(store::SelectNodeQuery::select_labels_properties(
427
+ labels.clone(),
428
+ ob,
429
+ ));
430
+ }
431
+ value::Value::Null =>
432
+ {
433
+ stack.push(store::SelectNodeQuery::select_none());
434
+ }
435
+ _ => Err(InternalError::InvalidValueCast {
436
+ value: props,
437
+ typename: "Node properties",
438
+ })?,
439
+ }
440
+ }
441
+ instructions::Instruction::FunctionCall {
442
+ function,
443
+ arguments_count,
444
+ } =>
445
+ {
446
+ let args: Vec<value::Value> = stack.try_drain_into(*arguments_count)?;
447
+ if args.len() != *arguments_count
448
+ {
449
+ Err(InternalError::MissingStackValue {
450
+ context: "eval_instructions/FunctionCall",
451
+ })?;
452
+ }
453
+ stack.push(function.call(args)?);
454
+ }
455
+ instructions::Instruction::Push { value } =>
456
+ {
457
+ stack.push(value.clone());
458
+ }
459
+ instructions::Instruction::GetVariable { col_id } =>
460
+ {
461
+ stack.push(row.get_owned(*col_id)?);
462
+ }
463
+ instructions::Instruction::GetParameter { name } =>
464
+ {
465
+ if let Some(value) = parameters.get(name)
466
+ {
467
+ stack.push(value.to_owned());
468
+ }
469
+ else
470
+ {
471
+ return Err(
472
+ crate::error::RunTimeError::UnknownParameter {
473
+ name: name.to_owned(),
474
+ }
475
+ .into(),
476
+ );
477
+ }
478
+ }
479
+ instructions::Instruction::CreateArray { length } =>
480
+ {
481
+ let mut m = vec![];
482
+ for _ in 0..*length
483
+ {
484
+ m.push(stack.try_pop_into()?);
485
+ }
486
+ m.reverse();
487
+ stack.push(value::Value::Array(m));
488
+ }
489
+ instructions::Instruction::CreateMap { keys } =>
490
+ {
491
+ let mut m = crate::value::ValueMap::new();
492
+ for k in keys.iter().rev()
493
+ {
494
+ m.insert(k.to_owned(), stack.try_pop_into()?);
495
+ }
496
+ stack.push(value::Value::Map(m));
497
+ }
498
+ instructions::Instruction::MemberAccess { path } =>
499
+ {
500
+ let v: value::Value = stack.try_pop_into()?;
501
+ stack.push(v.access(path.iter()));
502
+ }
503
+ instructions::Instruction::IndexAccess =>
504
+ {
505
+ // Implement access to array or map (edge/node properties).
506
+ // Get the index
507
+ let index: value::Value = stack.try_pop_into()?;
508
+ if index.is_null()
509
+ {
510
+ stack.try_drain(1)?;
511
+ stack.push(value::Value::Null);
512
+ }
513
+ else
514
+ {
515
+ // Get the array/map
516
+ let container: value::Value = stack.try_pop_into()?;
517
+ match container
518
+ {
519
+ value::Value::Array(array) =>
520
+ {
521
+ let idx: i64 = index.try_into()
522
+ .map_err(|e: ErrorType| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::InvalidArgumentType ))?;
523
+ stack.push(
524
+ array
525
+ .get(idx as usize)
526
+ .ok_or(RunTimeError::OutOfBound)?
527
+ .to_owned(),
528
+ );
529
+ }
530
+ value::Value::Map(map)
531
+ | value::Value::Node(graph::Node {
532
+ key: _,
533
+ labels: _,
534
+ properties: map,
535
+ })
536
+ | value::Value::Edge(graph::Edge {
537
+ key: _,
538
+ source: _,
539
+ destination: _,
540
+ labels: _,
541
+ properties: map,
542
+ }) =>
543
+ {
544
+ let idx: String = index.try_into()
545
+ .map_err(|e: ErrorType| error::map_error!(e, Error::Internal(InternalError::InvalidValueCast{..}) => RunTimeError::MapElementAccessByNonString ))?;
546
+ stack.push(map.get(&idx).unwrap_or(&value::Value::Null).to_owned());
547
+ }
548
+ value::Value::Null => stack.push(value::Value::Null),
549
+ _ => Err(error::RunTimeError::InvalidArgumentType)?,
550
+ }
551
+ }
552
+ }
553
+ instructions::Instruction::RangeAccess { start, end } =>
554
+ {
555
+ let end: Option<value::Value> = if *end
556
+ {
557
+ Some(stack.try_pop_into()?)
558
+ }
559
+ else
560
+ {
561
+ None
562
+ };
563
+ let start: Option<value::Value> = if *start
564
+ {
565
+ Some(stack.try_pop_into()?)
566
+ }
567
+ else
568
+ {
569
+ None
570
+ };
571
+ // Get the array out of the stack
572
+ let v: value::Value = stack.try_pop_into()?;
573
+ // if either end or start are null, return null
574
+ if end.as_ref().map_or(false, |e| e.is_null())
575
+ || start.as_ref().map_or(false, |s| s.is_null())
576
+ {
577
+ stack.push(value::Value::Null);
578
+ }
579
+ else
580
+ {
581
+ let mut start: Option<i64> = start.map(|x| x.try_into()).transpose()?;
582
+ let mut end: Option<i64> = end.map(|x| x.try_into()).transpose()?;
583
+ let v: Vec<value::Value> = v.try_into()?;
584
+ // Compute range length
585
+ let length = match (start, end)
586
+ {
587
+ (Some(start), Some(end)) => Some(end - start),
588
+ _ => None,
589
+ };
590
+ if length.map_or(false, |l| l >= v.len() as i64)
591
+ {
592
+ stack.push(v);
593
+ }
594
+ else
595
+ {
596
+ // If start is negative, it should be made into a positive number
597
+ while start.map_or(false, |x| x < 0)
598
+ {
599
+ start = start.map(|x| x + v.len() as i64);
600
+ end = end.map(|x| x + v.len() as i64);
601
+ }
602
+ let end = end.map(|x| x.min(v.len() as i64));
603
+ let v = match (start, end)
604
+ {
605
+ (Some(start), Some(end)) =>
606
+ {
607
+ if end < start
608
+ {
609
+ Vec::<value::Value>::default()
610
+ }
611
+ else
612
+ {
613
+ v[start as usize..end as usize].to_owned()
614
+ }
615
+ }
616
+ (Some(start), None) => v[start as usize..].to_owned(),
617
+ (None, Some(end)) => v[..end as usize].to_owned(),
618
+ (None, None) => v.to_owned(),
619
+ };
620
+ stack.push(v);
621
+ }
622
+ }
623
+ }
624
+ instructions::Instruction::Duplicate => stack.push(stack.try_last()?.clone()),
625
+ &instructions::Instruction::Rot3 =>
626
+ {
627
+ let a = stack.try_pop()?;
628
+ let b = stack.try_pop()?;
629
+ let c = stack.try_pop()?;
630
+ stack.push(a);
631
+ stack.push(c);
632
+ stack.push(b);
633
+ }
634
+ &instructions::Instruction::InverseRot3 =>
635
+ {
636
+ let a = stack.try_pop()?;
637
+ let b = stack.try_pop()?;
638
+ let c = stack.try_pop()?;
639
+ stack.push(b);
640
+ stack.push(a);
641
+ stack.push(c);
642
+ }
643
+ &instructions::Instruction::Swap =>
644
+ {
645
+ let a = stack.try_pop()?;
646
+ let b = stack.try_pop()?;
647
+ stack.push(a);
648
+ stack.push(b);
649
+ }
650
+ &instructions::Instruction::AndBinaryOperator
651
+ | &instructions::Instruction::OrBinaryOperator
652
+ | &instructions::Instruction::XorBinaryOperator =>
653
+ {
654
+ execute_boolean_operator(stack, instruction)?;
655
+ }
656
+ &instructions::Instruction::NotUnaryOperator =>
657
+ {
658
+ let a: value::Value = stack.try_pop_into()?;
659
+ match a
660
+ {
661
+ value::Value::Null => stack.push(value::Value::Null),
662
+ value::Value::Boolean(b) => stack.push(!b),
663
+ _ => Err(RunTimeError::InvalidArgumentType)?,
664
+ }
665
+ }
666
+ &instructions::Instruction::NegationUnaryOperator =>
667
+ {
668
+ let a: crate::value::Value = stack.try_pop_into()?;
669
+ stack.push((-a)?);
670
+ }
671
+ &instructions::Instruction::IsNullUnaryOperator =>
672
+ {
673
+ let a: crate::value::Value = stack.try_pop_into()?;
674
+ stack.push(a.is_null());
675
+ }
676
+ &instructions::Instruction::EqualBinaryOperator =>
677
+ {
678
+ execute_binary_operator(stack, |a, b| {
679
+ Ok(ordering_to_value!(
680
+ a.compare(&b),
681
+ value::Ordering::Equal,
682
+ false.into()
683
+ ))
684
+ })?;
685
+ }
686
+ &instructions::Instruction::NotEqualBinaryOperator =>
687
+ {
688
+ execute_binary_operator(stack, |a, b| {
689
+ Ok(ordering_to_value!(
690
+ a.compare(&b),
691
+ value::Ordering::Less | value::Ordering::Greater | value::Ordering::Different,
692
+ true.into()
693
+ ))
694
+ })?;
695
+ }
696
+ &instructions::Instruction::InferiorBinaryOperator =>
697
+ {
698
+ execute_binary_operator(stack, |a, b| {
699
+ Ok(ordering_to_value!(
700
+ a.compare(&b),
701
+ value::Ordering::Less,
702
+ value::Value::Null
703
+ ))
704
+ })?;
705
+ }
706
+ &instructions::Instruction::SuperiorBinaryOperator =>
707
+ {
708
+ execute_binary_operator(stack, |a, b| {
709
+ Ok(ordering_to_value!(
710
+ a.compare(&b),
711
+ value::Ordering::Greater,
712
+ value::Value::Null
713
+ ))
714
+ })?;
715
+ }
716
+ &instructions::Instruction::InferiorEqualBinaryOperator =>
717
+ {
718
+ execute_binary_operator(stack, |a, b| {
719
+ Ok(ordering_to_value!(
720
+ a.compare(&b),
721
+ value::Ordering::Equal | value::Ordering::Less,
722
+ value::Value::Null
723
+ ))
724
+ })?;
725
+ }
726
+ &instructions::Instruction::SuperiorEqualBinaryOperator =>
727
+ {
728
+ execute_binary_operator(stack, |a, b| {
729
+ Ok(ordering_to_value!(
730
+ a.compare(&b),
731
+ value::Ordering::Equal | value::Ordering::Greater,
732
+ value::Value::Null
733
+ ))
734
+ })?;
735
+ }
736
+ &instructions::Instruction::InBinaryOperator =>
737
+ {
738
+ execute_binary_operator::<value::Value>(stack, |a, b| {
739
+ if b.is_null()
740
+ {
741
+ Ok(value::Value::Null.into())
742
+ }
743
+ else
744
+ {
745
+ let b_arr: Vec<value::Value> = b.try_into()?;
746
+ Ok(contain_to_value!(
747
+ value::contains(&b_arr, &a),
748
+ value::ContainResult::True
749
+ ))
750
+ }
751
+ })?;
752
+ }
753
+ &instructions::Instruction::NotInBinaryOperator =>
754
+ {
755
+ execute_binary_operator::<value::Value>(stack, |a, b| {
756
+ if b.is_null()
757
+ {
758
+ Ok(value::Value::Null.into())
759
+ }
760
+ else
761
+ {
762
+ let b_arr: Vec<value::Value> = b.try_into()?;
763
+ Ok(contain_to_value!(
764
+ value::contains(&b_arr, &a),
765
+ value::ContainResult::False
766
+ ))
767
+ }
768
+ })?;
769
+ }
770
+ &instructions::Instruction::AdditionBinaryOperator =>
771
+ {
772
+ execute_binary_operator(stack, |a, b| a + b)?;
773
+ }
774
+ &instructions::Instruction::SubtractionBinaryOperator =>
775
+ {
776
+ execute_binary_operator(stack, |a, b| a - b)?;
777
+ }
778
+ &instructions::Instruction::MultiplicationBinaryOperator =>
779
+ {
780
+ execute_binary_operator(stack, |a, b| a * b)?;
781
+ }
782
+ &instructions::Instruction::DivisionBinaryOperator =>
783
+ {
784
+ execute_binary_operator(stack, |a, b| a / b)?;
785
+ }
786
+ &instructions::Instruction::ModuloBinaryOperator =>
787
+ {
788
+ execute_binary_operator(stack, |a, b| a % b)?;
789
+ }
790
+ &instructions::Instruction::ExponentBinaryOperator =>
791
+ {
792
+ execute_binary_operator(stack, |a, b| a.pow(b))?;
793
+ }
794
+ }
795
+ }
796
+ Ok(())
797
+ }
798
+
799
+ pub(crate) fn eval_update_property<TStore: store::Store>(
800
+ store: &TStore,
801
+ mut tx: &mut TStore::TransactionBox,
802
+ graph_name: &String,
803
+ row: &mut value_table::Row,
804
+ target: value_table::ColId,
805
+ path: &Vec<String>,
806
+ instructions: &instructions::Instructions,
807
+ parameters: &crate::value::ValueMap,
808
+ set: bool,
809
+ ) -> Result<()>
810
+ {
811
+ let var = row.get(target)?;
812
+ let mut stack = Stack::default();
813
+ eval_instructions(&mut stack, row, &instructions, &parameters)?;
814
+ let value: value::Value = stack.try_pop_into()?;
815
+ let value = match value
816
+ {
817
+ value::Value::Node(n) => n.properties.into(),
818
+ value::Value::Edge(e) => e.properties.into(),
819
+ _ => value,
820
+ };
821
+ let mut piter = path.iter();
822
+ match var
823
+ {
824
+ value::Value::Node(n) =>
825
+ {
826
+ let mut n = n.to_owned();
827
+ if set
828
+ {
829
+ n.properties
830
+ .set_value(piter.next(), piter, value.remove_null())?;
831
+ }
832
+ else
833
+ {
834
+ n.properties
835
+ .add_values(piter.next(), piter, value.try_into()?)?;
836
+ }
837
+ store.update_node(&mut tx, &graph_name, &n)?;
838
+ row.set(target, n.into())?;
839
+ }
840
+ value::Value::Edge(e) =>
841
+ {
842
+ let mut e = e.to_owned();
843
+ if set
844
+ {
845
+ e.properties
846
+ .set_value(piter.next(), piter, value.remove_null())?;
847
+ }
848
+ else
849
+ {
850
+ e.properties
851
+ .add_values(piter.next(), piter, value.try_into()?)?;
852
+ }
853
+ store.update_edge(&mut tx, &graph_name, &e)?;
854
+ row.set(target, e.into())?;
855
+ }
856
+ value::Value::Null =>
857
+ {}
858
+ _ => Err(InternalError::ExpectedEdge {
859
+ context: "evaluator/eval_program",
860
+ })?,
861
+ }
862
+ Ok(())
863
+ }
864
+
865
+ fn handle_asc(o: std::cmp::Ordering, asc: bool) -> std::cmp::Ordering
866
+ {
867
+ if asc
868
+ {
869
+ o
870
+ }
871
+ else
872
+ {
873
+ match o
874
+ {
875
+ std::cmp::Ordering::Equal => std::cmp::Ordering::Equal,
876
+ std::cmp::Ordering::Less => std::cmp::Ordering::Greater,
877
+ std::cmp::Ordering::Greater => std::cmp::Ordering::Less,
878
+ }
879
+ }
880
+ }
881
+
882
+ #[derive(Debug, Default, Clone, Hash, PartialEq)]
883
+ struct RowKey(value_table::Row);
884
+
885
+ impl Eq for RowKey {}
886
+
887
+ fn create_aggregations_states(
888
+ variables: &Vec<&instructions::RWExpression>,
889
+ parameters: &crate::value::ValueMap,
890
+ ) -> Result<Vec<HashMap<usize, Box<dyn aggregators::AggregatorState>>>>
891
+ {
892
+ variables
893
+ .iter()
894
+ .map(|rw_expr| {
895
+ rw_expr
896
+ .aggregations
897
+ .iter()
898
+ .map(|(name, agg)| {
899
+ let mut stack = Stack::default();
900
+
901
+ eval_instructions(
902
+ &mut stack,
903
+ &value_table::Row::default(),
904
+ &agg.init_instructions,
905
+ parameters,
906
+ )?;
907
+ let state = agg.aggregator.create(
908
+ stack
909
+ .to_vec()
910
+ .into_iter()
911
+ .map(|v| v.try_into())
912
+ .collect::<Result<_>>()?,
913
+ )?;
914
+
915
+ Ok((name.to_owned(), state))
916
+ })
917
+ .collect::<Result<HashMap<_, _>>>()
918
+ })
919
+ .collect::<Result<Vec<_>>>()
920
+ }
921
+
922
+ fn compute_return_with_table(
923
+ variables: Vec<&instructions::RWExpression>,
924
+ filter: &instructions::Instructions,
925
+ modifiers: &instructions::Modifiers,
926
+ input_table: value_table::ValueTable<usize>,
927
+ parameters: &crate::value::ValueMap,
928
+ variables_sizes: &VariablesSizes,
929
+ ) -> Result<value_table::ValueTable<usize>>
930
+ {
931
+ let mut output_table = value_table::ValueTable::new(variables_sizes.total_size());
932
+ // Compute table
933
+ if variables.iter().any(|v| v.aggregations.len() > 0)
934
+ {
935
+ // 1) For each row, compute non-aggregated columns, based on those columns, select a vector of aggregator states. and update them
936
+
937
+ let mut aggregation_table =
938
+ HashMap::<RowKey, Vec<HashMap<usize, Box<dyn aggregators::AggregatorState>>>>::default();
939
+
940
+ for row in input_table.into_row_iter()
941
+ {
942
+ // a) compute non-aggregated columns
943
+ let mut row = row.extended(variables_sizes.total_size())?;
944
+ let out_row = variables
945
+ .iter()
946
+ .map(|rw_expr| {
947
+ if rw_expr.aggregations.len() > 0
948
+ {
949
+ Ok(value::Value::Null)
950
+ }
951
+ else
952
+ {
953
+ assert_eq!(rw_expr.aggregations.len(), 0);
954
+ let mut stack = Stack::default();
955
+ eval_instructions(&mut stack, &row, &rw_expr.instructions, &parameters)?;
956
+ let value: value::Value = stack.try_pop_into()?;
957
+ row.set(rw_expr.col_id, value.to_owned())?;
958
+ Ok(value)
959
+ }
960
+ })
961
+ .collect::<Result<Row>>()?;
962
+ // b) initialise aggregations
963
+ use std::collections::hash_map::Entry;
964
+ let aggregations_states = match aggregation_table.entry(RowKey(out_row.clone()))
965
+ {
966
+ Entry::Occupied(entry) => entry.into_mut(),
967
+ Entry::Vacant(entry) =>
968
+ {
969
+ let aggregations_states = create_aggregations_states(&variables, parameters)?;
970
+ entry.insert(aggregations_states)
971
+ }
972
+ };
973
+ // c) update aggregations states
974
+ for (rw_expr, aggregation_states) in variables.iter().zip(aggregations_states.iter_mut())
975
+ {
976
+ for (name, agg) in rw_expr.aggregations.iter()
977
+ {
978
+ let mut stack = Stack::default();
979
+ eval_instructions(&mut stack, &row, &agg.argument_instructions, parameters)?;
980
+ let value: value::Value = stack.try_pop_into()?;
981
+ aggregation_states
982
+ .get_mut(name)
983
+ .ok_or(InternalError::MissingAggregationState)?
984
+ .next(value)?;
985
+ }
986
+ }
987
+ }
988
+
989
+ // Aggregation always return at least once, unless there is a non-aggregated value
990
+ if aggregation_table.is_empty() && variables.iter().all(|v| v.aggregations.len() > 0)
991
+ {
992
+ let row = Row::new(Default::default(), variables_sizes.total_size());
993
+ let aggregations_states = create_aggregations_states(&variables, parameters)?;
994
+ aggregation_table.insert(RowKey(row), aggregations_states);
995
+ }
996
+
997
+ // 2) For each vector of aggregator states, compute the final result
998
+
999
+ for (row, aggregations_states) in aggregation_table
1000
+ {
1001
+ let mut non_null_aggregation = false;
1002
+ let mut out_row = value_table::Row::new(Default::default(), variables_sizes.total_size());
1003
+ for (idx, (rw_expr, aggregation_states)) in variables
1004
+ .iter()
1005
+ .zip(aggregations_states.into_iter())
1006
+ .enumerate()
1007
+ {
1008
+ if rw_expr.aggregations.len() == 0
1009
+ {
1010
+ out_row.set(rw_expr.col_id, row.0.get(idx)?.to_owned())?;
1011
+ }
1012
+ else
1013
+ {
1014
+ for (name, s) in aggregation_states.into_iter()
1015
+ {
1016
+ let value = s.finalise()?;
1017
+ non_null_aggregation = non_null_aggregation | !value.is_null();
1018
+ out_row.set(name, value)?;
1019
+ }
1020
+ let mut stack = Stack::default();
1021
+ eval_instructions(&mut stack, &out_row, &rw_expr.instructions, &parameters)?;
1022
+ let value: value::Value = stack.try_pop_into()?;
1023
+ out_row.set(rw_expr.col_id, value.to_owned())?;
1024
+ }
1025
+ }
1026
+ output_table.add_truncated_row(out_row)?;
1027
+ }
1028
+ }
1029
+ else
1030
+ {
1031
+ output_table = input_table
1032
+ .into_row_iter()
1033
+ .map(|row| {
1034
+ let mut out_row = row.extended(variables_sizes.total_size())?;
1035
+ for rw_expr in variables.iter()
1036
+ {
1037
+ assert_eq!(rw_expr.aggregations.len(), 0);
1038
+ let mut stack = Stack::default();
1039
+ eval_instructions(&mut stack, &out_row, &rw_expr.instructions, &parameters)?;
1040
+ let value: value::Value = stack.try_pop_into()?;
1041
+ out_row.set(rw_expr.col_id, value.to_owned())?;
1042
+ }
1043
+ Ok(out_row)
1044
+ })
1045
+ .collect::<Result<Result<_>>>()??;
1046
+ }
1047
+ // Apply filter
1048
+ if !filter.is_empty()
1049
+ {
1050
+ output_table = filter_rows(output_table.into_row_iter(), &filter, &parameters)?.try_into()?;
1051
+ }
1052
+ // Apply modifiers
1053
+ // Sort the table according to order_by
1054
+ if !modifiers.order_by.is_empty()
1055
+ {
1056
+ let mut table_key = output_table
1057
+ .into_row_iter()
1058
+ .map(|x| {
1059
+ let mut v = Vec::<(value::Value, bool)>::new();
1060
+ for info in modifiers.order_by.iter()
1061
+ {
1062
+ let mut stack = Stack::default();
1063
+ eval_instructions(&mut stack, &x, &info.instructions, &parameters)?;
1064
+ v.push((stack.try_pop_into()?, info.asc));
1065
+ }
1066
+ Ok((x, v))
1067
+ })
1068
+ .collect::<Result<Vec<_>>>()?;
1069
+ table_key.sort_by(|(_, a), (_, b)| {
1070
+ a.iter()
1071
+ .zip(b.iter())
1072
+ .map(|((a, asc), (b, _))| handle_asc(a.orderability(b), *asc))
1073
+ .find(|x| *x != std::cmp::Ordering::Equal)
1074
+ .unwrap_or(std::cmp::Ordering::Equal)
1075
+ });
1076
+ output_table = table_key
1077
+ .into_iter()
1078
+ .map(|(x, _)| x)
1079
+ .collect::<Result<_>>()?;
1080
+ }
1081
+
1082
+ // Skip
1083
+ if let Some(skip) = &modifiers.skip
1084
+ {
1085
+ let mut stack = Stack::default();
1086
+ eval_instructions(&mut stack, &value_table::Row::default(), &skip, &parameters)?;
1087
+ let q: i64 = stack
1088
+ .try_pop_into()
1089
+ .map_err(|_| RunTimeError::InvalidArgumentType)?;
1090
+ if q >= 0
1091
+ {
1092
+ output_table.remove_first_rows(q as usize);
1093
+ }
1094
+ else
1095
+ {
1096
+ Err(RunTimeError::NegativeIntegerArgument)?
1097
+ }
1098
+ }
1099
+
1100
+ // Limit
1101
+ if let Some(limit) = &modifiers.limit
1102
+ {
1103
+ let mut stack = Stack::default();
1104
+ eval_instructions(
1105
+ &mut stack,
1106
+ &value_table::Row::default(),
1107
+ &limit,
1108
+ &parameters,
1109
+ )?;
1110
+ let q: i64 = stack
1111
+ .try_pop_into()
1112
+ .map_err(|_| RunTimeError::InvalidArgumentType)?;
1113
+ if q >= 0
1114
+ {
1115
+ output_table.truncate(q as usize);
1116
+ }
1117
+ else
1118
+ {
1119
+ Err(RunTimeError::NegativeIntegerArgument)?
1120
+ }
1121
+ }
1122
+
1123
+ output_table
1124
+ .into_row_iter()
1125
+ .map(|mut row| {
1126
+ Ok(Row::new(
1127
+ variables
1128
+ .iter()
1129
+ .map(|rw_expr| row.take(rw_expr.col_id))
1130
+ .collect::<Result<_>>()?,
1131
+ 0,
1132
+ ))
1133
+ })
1134
+ .map(|r| value_table::RowResult(r))
1135
+ .collect()
1136
+ }
1137
+
1138
+ fn filter_rows(
1139
+ current_rows: impl Iterator<Item = value_table::Row>,
1140
+ filter: &instructions::Instructions,
1141
+ parameters: &crate::value::ValueMap,
1142
+ ) -> Result<Vec<value_table::Row>>
1143
+ {
1144
+ current_rows
1145
+ .filter_map(|row| {
1146
+ let res: Result<bool> = (|| {
1147
+ let mut stack = Stack::default();
1148
+ eval_instructions(&mut stack, &row, &filter, &parameters)?;
1149
+ stack.try_pop_as_boolean()
1150
+ })();
1151
+ match res
1152
+ {
1153
+ Err(x) => Some(Err(x)),
1154
+ Ok(v) =>
1155
+ {
1156
+ if v
1157
+ {
1158
+ Some(Ok(row))
1159
+ }
1160
+ else
1161
+ {
1162
+ None
1163
+ }
1164
+ }
1165
+ }
1166
+ })
1167
+ .collect()
1168
+ }
1169
+
1170
+ fn is_write_program(program: &super::Program) -> bool
1171
+ {
1172
+ program.iter().any(|b| match b
1173
+ {
1174
+ Block::UseGraph { .. }
1175
+ | Block::BlockMatch { .. }
1176
+ | Block::Return { .. }
1177
+ | Block::Unwind { .. }
1178
+ | Block::Call { .. }
1179
+ | Block::With { .. } => false,
1180
+ Block::CreateGraph { .. }
1181
+ | Block::DropGraph { .. }
1182
+ | Block::Create { .. }
1183
+ | Block::Update { .. }
1184
+ | Block::Delete { .. } => true,
1185
+ })
1186
+ }
1187
+
1188
+ ///
1189
+ pub(crate) fn eval_program<TStore: store::Store>(
1190
+ store: &TStore,
1191
+ program: &super::Program,
1192
+ parameters: &crate::value::ValueMap,
1193
+ ) -> crate::Result<crate::value::Value>
1194
+ {
1195
+ let mut graph_name: String = "default".into();
1196
+ let mut input_table = value_table::ValueTable::new(0);
1197
+ input_table.add_full_row(value_table::Row::default())?;
1198
+ let mut tx = if is_write_program(program)
1199
+ {
1200
+ store.begin_write()?
1201
+ }
1202
+ else
1203
+ {
1204
+ store.begin_read()?
1205
+ };
1206
+ let mut stack = Default::default();
1207
+ for block in program
1208
+ {
1209
+ if crate::consts::SHOW_EVALUATOR_STATE
1210
+ {
1211
+ println!("--- block {:#?}", block);
1212
+ println!("input_table: {:#?}", input_table);
1213
+ }
1214
+ match block
1215
+ {
1216
+ instructions::Block::CreateGraph { name } =>
1217
+ {
1218
+ store
1219
+ .create_graph(&mut tx, name, false)
1220
+ .map_err(|e|
1221
+ error::map_error!(e, Error::StoreError(StoreError::DuplicatedGraph { graph_name }) => RunTimeError::DuplicatedGraph {
1222
+ graph_name: graph_name.clone(),
1223
+ } ))?;
1224
+ graph_name = name.to_owned();
1225
+ }
1226
+ instructions::Block::DropGraph { name, if_exists } =>
1227
+ {
1228
+ store
1229
+ .drop_graph(&mut tx, name, *if_exists)
1230
+ .map_err(|e|
1231
+ error::map_error!(e, Error::StoreError(StoreError::UnknownGraph { graph_name }) => RunTimeError::UnknownGraph {
1232
+ graph_name: graph_name.clone(),
1233
+ } ))?;
1234
+ graph_name = name.to_owned();
1235
+ }
1236
+ instructions::Block::UseGraph { name } =>
1237
+ {
1238
+ graph_name = name.to_owned();
1239
+ if !store.graphs_list(&mut tx)?.contains(&graph_name)
1240
+ {
1241
+ Err(RunTimeError::UnknownGraph {
1242
+ graph_name: graph_name.to_owned(),
1243
+ })?;
1244
+ }
1245
+ }
1246
+ instructions::Block::Create {
1247
+ actions,
1248
+ variables_size,
1249
+ } =>
1250
+ {
1251
+ let mut output_table = value_table::ValueTable::new(variables_size.total_size());
1252
+ for row in input_table.into_row_iter()
1253
+ {
1254
+ let mut new_row = row.extended(variables_size.total_size())?;
1255
+ for action in actions.iter()
1256
+ {
1257
+ eval_instructions(&mut stack, &new_row, &action.instructions, &parameters)?;
1258
+ for (v, var) in stack
1259
+ .try_drain_into(action.variables.len())?
1260
+ .into_iter()
1261
+ .zip(action.variables.iter())
1262
+ {
1263
+ match v
1264
+ {
1265
+ crate::value::Value::Node(n) =>
1266
+ {
1267
+ store.create_nodes(&mut tx, &graph_name, vec![n.to_owned()].iter())?;
1268
+ if let Some(var) = var
1269
+ {
1270
+ new_row.set_if_unset(*var, crate::value::Value::Node(n))?;
1271
+ }
1272
+ }
1273
+ crate::value::Value::Edge(e) =>
1274
+ {
1275
+ store.create_edges(&mut tx, &graph_name, vec![e.to_owned()].iter())?;
1276
+ if let Some(var) = var
1277
+ {
1278
+ new_row.set(*var, crate::value::Value::Edge(e))?;
1279
+ }
1280
+ }
1281
+ _ =>
1282
+ {
1283
+ return Err(InternalError::Unimplemented("executor/eval/create").into());
1284
+ }
1285
+ }
1286
+ }
1287
+ }
1288
+ output_table.add_truncated_row(new_row)?;
1289
+ }
1290
+ input_table = output_table;
1291
+ }
1292
+ instructions::Block::BlockMatch {
1293
+ blocks,
1294
+ filter,
1295
+ optional,
1296
+ variables_size,
1297
+ } =>
1298
+ {
1299
+ let mut output_table = value_table::ValueTable::new(variables_size.persistent_variables);
1300
+ for row in input_table.into_row_iter()
1301
+ {
1302
+ let mut current_rows: Vec<_> = vec![row.clone().extended(variables_size.total_size())?];
1303
+ for block in blocks.iter()
1304
+ {
1305
+ let mut new_rows = Vec::<value_table::Row>::default();
1306
+ for row in current_rows
1307
+ {
1308
+ match block
1309
+ {
1310
+ instructions::BlockMatch::MatchNode {
1311
+ instructions,
1312
+ variable,
1313
+ filter,
1314
+ } =>
1315
+ {
1316
+ eval_instructions(&mut stack, &row, &instructions, &parameters)?;
1317
+ let query: store::SelectNodeQuery = stack.try_pop_into()?;
1318
+ let nodes = store.select_nodes(&mut tx, &graph_name, query)?;
1319
+
1320
+ for node in nodes.iter()
1321
+ {
1322
+ let mut new_row = row.clone();
1323
+ match &variable
1324
+ {
1325
+ Some(variable) =>
1326
+ {
1327
+ new_row.set_if_unset(*variable, node.to_owned().into())?;
1328
+ }
1329
+ None =>
1330
+ {}
1331
+ }
1332
+ let should_add_row = if filter.is_empty()
1333
+ {
1334
+ true
1335
+ }
1336
+ else
1337
+ {
1338
+ let mut stack = Stack::default();
1339
+ stack.push(true);
1340
+ stack.push(node.to_owned());
1341
+ eval_instructions(&mut stack, &new_row, &filter, &parameters)?;
1342
+ stack.try_pop()?; // Get rid of the edge
1343
+ stack.try_pop_into()?
1344
+ };
1345
+ if should_add_row
1346
+ {
1347
+ new_rows.push(new_row);
1348
+ }
1349
+ }
1350
+ }
1351
+ instructions::BlockMatch::MatchEdge {
1352
+ instructions,
1353
+ left_variable,
1354
+ edge_variable,
1355
+ right_variable,
1356
+ path_variable,
1357
+ filter,
1358
+ directivity,
1359
+ } =>
1360
+ {
1361
+ eval_instructions(&mut stack, &row, &instructions, &parameters)?;
1362
+ let query = stack.try_pop_into()?;
1363
+
1364
+ let edges = store.select_edges(&mut tx, &graph_name, query, *directivity)?;
1365
+
1366
+ for edge in edges.iter()
1367
+ {
1368
+ let mut new_row = row.clone();
1369
+ if let Some(left_variable) = left_variable.to_owned()
1370
+ {
1371
+ new_row.set(
1372
+ left_variable,
1373
+ if edge.reversed
1374
+ {
1375
+ edge.edge.destination.to_owned()
1376
+ }
1377
+ else
1378
+ {
1379
+ edge.edge.source.to_owned()
1380
+ }
1381
+ .into(),
1382
+ )?;
1383
+ }
1384
+ if let Some(right_variable) = right_variable.to_owned()
1385
+ {
1386
+ new_row.set(
1387
+ right_variable,
1388
+ if edge.reversed
1389
+ {
1390
+ edge.edge.source.to_owned()
1391
+ }
1392
+ else
1393
+ {
1394
+ edge.edge.destination.to_owned()
1395
+ }
1396
+ .into(),
1397
+ )?;
1398
+ }
1399
+ if let Some(edge_variable) = edge_variable.to_owned()
1400
+ {
1401
+ new_row.set(edge_variable, edge.edge.to_owned().into())?;
1402
+ }
1403
+ if let Some(path_variable) = path_variable.to_owned()
1404
+ {
1405
+ new_row.set(
1406
+ path_variable,
1407
+ crate::value::Value::Path(edge.edge.to_owned().into()),
1408
+ )?;
1409
+ }
1410
+ let should_add_row = if filter.is_empty()
1411
+ {
1412
+ true
1413
+ }
1414
+ else
1415
+ {
1416
+ let mut stack = Stack::default();
1417
+ stack.push(true);
1418
+ stack.push(edge.edge.to_owned());
1419
+ eval_instructions(&mut stack, &new_row, &filter, &parameters)?;
1420
+ stack.try_pop()?; // Get rid of the edge
1421
+ stack.try_pop_into()?
1422
+ };
1423
+ if should_add_row
1424
+ {
1425
+ new_rows.push(new_row);
1426
+ }
1427
+ }
1428
+ }
1429
+ }
1430
+ }
1431
+ current_rows = new_rows;
1432
+ }
1433
+ if !filter.is_empty()
1434
+ {
1435
+ current_rows = filter_rows(current_rows.into_iter(), &filter, &parameters)?;
1436
+ }
1437
+ if current_rows.is_empty() && *optional
1438
+ {
1439
+ output_table.add_truncated_row(row.extended(variables_size.persistent_variables)?)?;
1440
+ }
1441
+ else
1442
+ {
1443
+ output_table.add_truncated_rows(current_rows)?;
1444
+ }
1445
+ }
1446
+ input_table = output_table;
1447
+ }
1448
+ instructions::Block::Return {
1449
+ variables,
1450
+ filter,
1451
+ modifiers,
1452
+ variables_size,
1453
+ } =>
1454
+ {
1455
+ let (names, variables): (Vec<_>, Vec<_>) =
1456
+ variables.into_iter().map(|(s, e)| (s, e)).unzip();
1457
+ let output_table = compute_return_with_table(
1458
+ variables,
1459
+ &filter,
1460
+ &modifiers,
1461
+ input_table,
1462
+ &parameters,
1463
+ &variables_size,
1464
+ )?;
1465
+ let mut r = Vec::<crate::value::Value>::new();
1466
+ r.push(crate::value::Value::Array(
1467
+ names
1468
+ .into_iter()
1469
+ .map(|name| crate::value::Value::String(name.to_owned()))
1470
+ .collect(),
1471
+ ));
1472
+ for row in output_table.into_row_iter()
1473
+ {
1474
+ r.push(row.into());
1475
+ }
1476
+ tx.close()?;
1477
+ return Ok(r.into());
1478
+ }
1479
+ instructions::Block::With {
1480
+ variables,
1481
+ filter,
1482
+ modifiers,
1483
+ variables_size,
1484
+ } =>
1485
+ {
1486
+ input_table = compute_return_with_table(
1487
+ variables.iter().collect(),
1488
+ &filter,
1489
+ &modifiers,
1490
+ input_table,
1491
+ &parameters,
1492
+ &variables_size,
1493
+ )?;
1494
+ }
1495
+ instructions::Block::Unwind {
1496
+ col_id,
1497
+ instructions,
1498
+ variables_size,
1499
+ } =>
1500
+ {
1501
+ let mut output_table = value_table::ValueTable::new(variables_size.persistent_variables);
1502
+ for row in input_table.into_row_iter()
1503
+ {
1504
+ let mut stack = Stack::default();
1505
+ eval_instructions(&mut stack, &row, &instructions, &parameters)?;
1506
+ let value = stack.try_pop_into()?;
1507
+ match value
1508
+ {
1509
+ value::Value::Array(arr) =>
1510
+ {
1511
+ for v in arr.into_iter()
1512
+ {
1513
+ let mut out_row = row.clone().extended(variables_size.total_size())?;
1514
+ out_row.set(*col_id, v)?;
1515
+ output_table.add_truncated_row(out_row)?;
1516
+ }
1517
+ }
1518
+ value::Value::Null =>
1519
+ {}
1520
+ _ =>
1521
+ {
1522
+ let mut out_row = row.extended(variables_size.total_size())?;
1523
+ out_row.set(*col_id, value)?;
1524
+ output_table.add_truncated_row(out_row)?;
1525
+ }
1526
+ }
1527
+ }
1528
+ input_table = output_table;
1529
+ }
1530
+ instructions::Block::Delete {
1531
+ detach,
1532
+ instructions,
1533
+ } =>
1534
+ {
1535
+ let mut nodes_keys = Vec::<graph::Key>::new();
1536
+ let mut edges_keys = Vec::<graph::Key>::new();
1537
+ for row in input_table.row_iter()
1538
+ {
1539
+ for instructions in instructions.iter()
1540
+ {
1541
+ let mut stack = Stack::default();
1542
+ eval_instructions(&mut stack, &row, &instructions, &parameters)?;
1543
+ let value: value::Value = stack.try_pop_into()?;
1544
+ match value
1545
+ {
1546
+ value::Value::Node(node) => nodes_keys.push(node.key),
1547
+ value::Value::Edge(edge) => edges_keys.push(edge.key),
1548
+ value::Value::Null =>
1549
+ {}
1550
+ _ => return Err(RunTimeError::InvalidDelete.into()),
1551
+ }
1552
+ }
1553
+ }
1554
+
1555
+ store.delete_edges(
1556
+ &mut tx,
1557
+ &graph_name,
1558
+ store::SelectEdgeQuery::select_keys(edges_keys),
1559
+ graph::EdgeDirectivity::Directed,
1560
+ )?;
1561
+ store.delete_nodes(
1562
+ &mut tx,
1563
+ &graph_name,
1564
+ store::SelectNodeQuery::select_keys(nodes_keys),
1565
+ *detach,
1566
+ )?;
1567
+ }
1568
+ instructions::Block::Update {
1569
+ updates,
1570
+ variables_size,
1571
+ } =>
1572
+ {
1573
+ let mut output_table = value_table::ValueTable::new(variables_size.persistent_variables);
1574
+ for row in input_table.into_row_iter()
1575
+ {
1576
+ let mut out_row = row.extended(variables_size.total_size())?;
1577
+ for update in updates.iter()
1578
+ {
1579
+ match update
1580
+ {
1581
+ instructions::UpdateOne::SetProperty {
1582
+ target,
1583
+ path,
1584
+ instructions,
1585
+ } =>
1586
+ {
1587
+ eval_update_property(
1588
+ store,
1589
+ &mut tx,
1590
+ &graph_name,
1591
+ &mut out_row,
1592
+ *target,
1593
+ path,
1594
+ instructions,
1595
+ &parameters,
1596
+ true,
1597
+ )?;
1598
+ }
1599
+ instructions::UpdateOne::AddProperty {
1600
+ target,
1601
+ path,
1602
+ instructions,
1603
+ } =>
1604
+ {
1605
+ eval_update_property(
1606
+ store,
1607
+ &mut tx,
1608
+ &graph_name,
1609
+ &mut out_row,
1610
+ *target,
1611
+ path,
1612
+ instructions,
1613
+ &parameters,
1614
+ false,
1615
+ )?;
1616
+ }
1617
+ instructions::UpdateOne::RemoveProperty { target, path } =>
1618
+ {
1619
+ let var = out_row.get(*target)?;
1620
+ let mut piter = path.iter();
1621
+ match var
1622
+ {
1623
+ value::Value::Node(n) =>
1624
+ {
1625
+ let mut n = n.to_owned();
1626
+ n.properties.remove_value(piter.next(), piter)?;
1627
+ store.update_node(&mut tx, &graph_name, &n)?;
1628
+ out_row.set(*target, n.into())?;
1629
+ }
1630
+ value::Value::Edge(e) =>
1631
+ {
1632
+ let mut e = e.to_owned();
1633
+ e.properties.remove_value(piter.next(), piter)?;
1634
+ store.update_edge(&mut tx, &graph_name, &e)?;
1635
+ out_row.set(*target, e.into())?;
1636
+ }
1637
+ value::Value::Null =>
1638
+ {}
1639
+ _ => Err(InternalError::ExpectedEdge {
1640
+ context: "evaluator/eval_program",
1641
+ })?,
1642
+ }
1643
+ }
1644
+ instructions::UpdateOne::AddLabels { target, labels }
1645
+ | instructions::UpdateOne::RemoveLabels { target, labels } =>
1646
+ {
1647
+ let add_labels = match update
1648
+ {
1649
+ instructions::UpdateOne::AddLabels { .. } => true,
1650
+ instructions::UpdateOne::RemoveLabels { .. } => false,
1651
+ _ => Err(InternalError::Unreachable {
1652
+ context: "evaluator/eval_program/add_remove_labels",
1653
+ })?,
1654
+ };
1655
+
1656
+ let var = out_row.get(*target)?;
1657
+ match var
1658
+ {
1659
+ value::Value::Node(n) =>
1660
+ {
1661
+ let mut n = n.to_owned();
1662
+ if add_labels
1663
+ {
1664
+ n.labels.append(&mut labels.clone());
1665
+ }
1666
+ else
1667
+ {
1668
+ n.labels = n
1669
+ .labels
1670
+ .into_iter()
1671
+ .filter(|x| !labels.contains(x))
1672
+ .collect();
1673
+ }
1674
+ store.update_node(&mut tx, &graph_name, &n)?;
1675
+ out_row.set(*target, n.into())?;
1676
+ }
1677
+ value::Value::Edge(e) =>
1678
+ {
1679
+ let mut e = e.to_owned();
1680
+ if add_labels
1681
+ {
1682
+ e.labels.append(&mut labels.clone());
1683
+ }
1684
+ else
1685
+ {
1686
+ e.labels = e
1687
+ .labels
1688
+ .into_iter()
1689
+ .filter(|x| !labels.contains(x))
1690
+ .collect();
1691
+ }
1692
+ store.update_edge(&mut tx, &graph_name, &e)?;
1693
+ out_row.set(*target, e.into())?;
1694
+ }
1695
+ value::Value::Null =>
1696
+ {}
1697
+ _ => Err(InternalError::ExpectedEdge {
1698
+ context: "evaluator/eval_program",
1699
+ })?,
1700
+ }
1701
+ }
1702
+ }
1703
+ }
1704
+ output_table.add_truncated_row(out_row)?;
1705
+ }
1706
+ input_table = output_table;
1707
+ }
1708
+ instructions::Block::Call { arguments: _, name } =>
1709
+ {
1710
+ if name == "gqlite.internal.stats"
1711
+ {
1712
+ let stats = store.compute_statistics(&mut tx)?;
1713
+ let mut res = value::ValueMap::new();
1714
+ res.insert("nodes_count".into(), (stats.nodes_count as i64).into());
1715
+ res.insert("edges_count".into(), (stats.edges_count as i64).into());
1716
+ res.insert(
1717
+ "labels_nodes_count".into(),
1718
+ (stats.labels_nodes_count as i64).into(),
1719
+ );
1720
+ res.insert(
1721
+ "properties_count".into(),
1722
+ (stats.properties_count as i64).into(),
1723
+ );
1724
+ return Ok(crate::value::Value::Map(res));
1725
+ }
1726
+ else
1727
+ {
1728
+ return Err(InternalError::Unimplemented("call for any other function").into());
1729
+ }
1730
+ }
1731
+ }
1732
+ }
1733
+ tx.close()?;
1734
+ Ok(crate::value::Value::Null)
1735
+ }
1736
+
1737
+ #[cfg(test)]
1738
+ mod tests
1739
+ {
1740
+ use crate::{
1741
+ interpreter::instructions::Instruction::{AndBinaryOperator, OrBinaryOperator},
1742
+ prelude::*,
1743
+ };
1744
+
1745
+ use super::{execute_boolean_operator, TryPopInto};
1746
+
1747
+ fn test_execute_boolean_operator_(
1748
+ instruction: &interpreter::instructions::Instruction,
1749
+ a: impl Into<super::Value>,
1750
+ b: impl Into<super::Value>,
1751
+ g: impl Into<value::Value>,
1752
+ )
1753
+ {
1754
+ let mut stack = super::Stack::default();
1755
+ stack.push(b.into());
1756
+ stack.push(a.into());
1757
+ execute_boolean_operator(&mut stack, instruction).unwrap();
1758
+ let r: value::Value = stack.try_pop_into().unwrap();
1759
+ assert_eq!(r, g.into());
1760
+ }
1761
+
1762
+ #[test]
1763
+ fn test_execute_boolean_operator()
1764
+ {
1765
+ test_execute_boolean_operator_(&AndBinaryOperator, true, true, true);
1766
+ test_execute_boolean_operator_(&AndBinaryOperator, true, false, false);
1767
+ test_execute_boolean_operator_(&AndBinaryOperator, false, true, false);
1768
+ test_execute_boolean_operator_(&AndBinaryOperator, false, value::Value::Null, false);
1769
+ test_execute_boolean_operator_(
1770
+ &OrBinaryOperator,
1771
+ value::Value::Null,
1772
+ false,
1773
+ value::Value::Null,
1774
+ );
1775
+ }
1776
+ }