| 75 | } |
| 76 | |
| 77 | static Record UpdateConsume |
| 78 | ( |
| 79 | OpBase *opBase |
| 80 | ) { |
| 81 | OpUpdate *op = (OpUpdate *)opBase; |
| 82 | OpBase *child = op->op.children[0]; |
| 83 | Record r; |
| 84 | |
| 85 | // updates already performed |
| 86 | if(op->updates_committed) return _handoff(op); |
| 87 | |
| 88 | while((r = OpBase_Consume(child))) { |
| 89 | Record_PersistScalars(r); |
| 90 | |
| 91 | // evaluate update expressions |
| 92 | raxSeek(&op->it, "^", NULL, 0); |
| 93 | while(raxNext(&op->it)) { |
| 94 | EntityUpdateEvalCtx *ctx = op->it.data; |
| 95 | EvalEntityUpdates(op->gc, op->node_updates, op->edge_updates, r, ctx, true); |
| 96 | } |
| 97 | |
| 98 | array_append(op->records, r); |
| 99 | } |
| 100 | |
| 101 | uint node_updates_count = HashTableElemCount(op->node_updates); |
| 102 | uint edge_updates_count = HashTableElemCount(op->edge_updates); |
| 103 | |
| 104 | if(node_updates_count > 0 || edge_updates_count > 0) { |
| 105 | // done reading; we're not going to call Consume any longer |
| 106 | // there might be operations like "Index Scan" that need to free the |
| 107 | // index R/W lock - as such, free all ExecutionPlan operations up the chain. |
| 108 | OpBase_PropagateReset(child); |
| 109 | |
| 110 | // lock everything |
| 111 | QueryCtx_LockForCommit(); |
| 112 | |
| 113 | CommitUpdates(op->gc, op->node_updates, ENTITY_NODE); |
| 114 | CommitUpdates(op->gc, op->edge_updates, ENTITY_EDGE); |
| 115 | } |
| 116 | |
| 117 | HashTableEmpty(op->node_updates, NULL); |
| 118 | HashTableEmpty(op->edge_updates, NULL); |
| 119 | |
| 120 | op->updates_committed = true; |
| 121 | |
| 122 | return _handoff(op); |
| 123 | } |
| 124 | |
| 125 | static OpBase *UpdateClone(const ExecutionPlan *plan, const OpBase *opBase) { |
| 126 | ASSERT(opBase->type == OPType_UPDATE); |
nothing calls this directly
no test coverage detected