gqlite 1.1.0 → 1.2.2

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