1 /*******************************************************************************
2 * Copyright (c) 2007, 2018 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.impl.query;
14 import java.util.concurrent.atomic.AtomicBoolean;
16 import org.simantics.db.RelationInfo;
17 import org.simantics.db.common.exception.DebugException;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
20 import org.simantics.db.impl.graph.ReadGraphImpl;
21 import org.simantics.db.impl.procedure.InternalProcedure;
22 import org.simantics.db.impl.procedure.TripleIntProcedureAdapter;
23 import org.simantics.db.procedure.ListenerBase;
24 import org.simantics.db.request.RequestFlags;
26 public final class Statements extends CollectionBinaryQuery<TripleIntProcedure> implements TripleIntProcedure {
28 public Statements(final int r1, final int r2) {
32 final public static void queryEach(ReadGraphImpl graph, final int r1, final int r2, final QueryProcessor provider, final CacheEntry parent, final ListenerBase listener, final TripleIntProcedure procedure) throws DatabaseException {
37 if(parent == null && listener == null) {
38 Statements.computeForEach(graph, r1, r2, null, procedure);
42 QueryCache.runnerStatements(graph, r1, r2, parent, listener, procedure);
47 final public void removeEntry(QueryProcessor provider) {
48 provider.cache.remove(this);
51 final static TripleIntProcedure NOPT = new TripleIntProcedure() {
55 public void exception(ReadGraphImpl graph, Throwable throwable) {
59 public void execute(ReadGraphImpl graph, int s, int p, int o) {
63 public void finished(ReadGraphImpl graph) {
68 final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Statements entry) throws DatabaseException {
70 class AssertionMapProc implements IntProcedure {
74 private IntArray result;
76 public void addStatement(int s, int p, int o) {
78 if(result.size() == 0) {
83 for(int i = 0;i < result.sizeOrData ; i+=3) {
84 int existingP = result.data[i+1];
86 int existingO = result.data[i+2];
87 if(existingO == o) return;
98 public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
100 result = QueryCache.resultAssertedStatements(graph, type, r2, entry, null);
103 IntArray ia = result;
104 result = new IntArray();
105 if(ia.data != null) {
106 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
110 IntArray ia = QueryCache.resultAssertedStatements(graph, type, r2, entry, null);
111 if(ia.data != null) {
112 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
118 public void finished(ReadGraphImpl graph) {
122 public void exception(ReadGraphImpl graph, Throwable throwable) {
127 AssertionMapProc amp = new AssertionMapProc();
129 // This dependency could be cut
130 QueryCache.runnerPrincipalTypes(graph, r1, entry, null, amp);
136 final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final TripleIntProcedure procedure) throws DatabaseException {
138 IntArray map = getAssertionMap(graph, r1, r2, parent);
140 procedure.finished(graph);
144 int size = map.size();
151 procedure.execute(graph, s,p,o);
152 procedure.finished(graph);
154 } else if(size == 0) {
156 procedure.finished(graph);
160 int candidateS = map.data[0];
161 int candidateP = map.data[1];
162 int candidateO = map.data[2];
164 IntSet candidateIs = null;
166 candidateIs = QueryCache.resultSuperTypes(graph, candidateS, parent, null);
167 } catch (DatabaseException e) {
168 procedure.exception(graph, e);
172 for(int i=3;i<map.size();i+=3) {
174 int nextS = map.data[i];
175 int nextP = map.data[i+1];
176 int nextO = map.data[i+2];
178 if(nextS != candidateS) {
180 if(candidateIs.contains(nextS)) {
182 // Next is a super type of candidate => ignore next
186 IntSet nextIs = null;
188 nextIs = QueryCache.resultSuperTypes(graph, nextS, parent, null);
189 } catch (DatabaseException e) {
190 procedure.exception(graph, e);
194 if(nextIs.contains(candidateS)) {
196 // Candidate is a super type of next => next is the new candidate
201 candidateIs = nextIs;
204 // candidate and next are unrelated => error
205 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
206 procedure.exception(graph, exception);
216 procedure.execute(graph, candidateS, candidateP, candidateO);
217 procedure.finished(graph);
223 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
226 public void execute(ReadGraphImpl graph, IntSet result) {
230 public void exception(ReadGraphImpl graph, Throwable throwable) {
235 // Search for one statement
236 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
240 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
244 // Check for assertions
245 forSingleAssertion(graph, r1, r2, parent, procedure);
247 } else if(result == -1) {
249 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
252 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
253 procedure.execute(graph, r1, r2, i);
257 public void exception(ReadGraphImpl graph, Throwable t) {
258 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
262 public void finished(ReadGraphImpl graph) {
267 // Check for assertions
268 forSingleAssertion(graph, r1, r2, parent, procedure);
272 // If functional relation was found there is no need to check assertions
273 procedure.execute(graph, r1, r2, result);
274 procedure.finished(graph);
281 final AtomicBoolean found = new AtomicBoolean(false);
283 // Note! The dependency is intentionally cut!
284 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
285 direct.forEach(graph, new SyncIntProcedure() {
288 public void run(ReadGraphImpl graph) throws DatabaseException {
291 procedure.finished(graph);
293 // Check for assertions
294 forSingleAssertion(graph, r1, r2, parent, procedure);
300 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
302 if(found.get()) return;
308 // Note! The dependency is intentionally cut!
309 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
312 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
314 if(found.compareAndSet(false, true)) {
315 procedure.execute(graph, r1, pred, i);
317 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
318 procedure.exception(graph, exception);
324 public void finished(ReadGraphImpl graph) throws DatabaseException {
329 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
330 procedure.exception(graph, t);
340 QueryCache.runnerSuperRelations(graph, pred, parent, null, new InternalProcedure<IntSet>() {
343 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
350 if(result.contains(r2)) {
354 // Note! The dependency is intentionally cut!
355 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
358 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
360 if(found.compareAndSet(false, true)) {
361 procedure.execute(graph, r1, pred, i);
363 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
364 procedure.exception(graph, exception);
370 public void finished(ReadGraphImpl graph) throws DatabaseException {
375 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
376 procedure.exception(graph, t);
389 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
390 procedure.exception(graph, t);
401 public void finished(ReadGraphImpl graph) throws DatabaseException {
411 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final TripleIntProcedure procedure) throws DatabaseException {
413 QueryCache.runnerPrincipalTypes(graph, r1, parent, null, new SyncIntProcedure() {
416 public void run(ReadGraphImpl graph) throws DatabaseException {
417 procedure.finished(graph);
420 TripleIntProcedure proc = new TripleIntProcedureAdapter() {
423 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
424 procedure.execute(graph, s, p, o);
428 public void finished(ReadGraphImpl graph) throws DatabaseException {
433 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
435 procedure.exception(graph, t);
441 public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
443 QueryCache.runnerAssertedStatements(graph, type, r2, parent, null, proc);
447 public void finished(ReadGraphImpl graph) throws DatabaseException {
452 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
461 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
465 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
468 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
469 procedure.execute(graph, r1, r2, i);
473 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
474 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
475 procedure.exception(graph, t);
479 public void finished(ReadGraphImpl graph) {
485 forAssertions(graph, r1, r2, parent, procedure);
487 procedure.finished(graph);
492 // Note! The dependency is intentionally cut!
493 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
494 direct.forEach(graph, new SyncIntProcedure() {
497 public void run(ReadGraphImpl graph) throws DatabaseException {
498 forAssertions(graph, r1, r2, parent, procedure);
502 public void execute(ReadGraphImpl graph, final int pred2) throws DatabaseException {
508 // Note! The dependency is intentionally cut!
509 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
512 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
513 procedure.execute(graph, r1, pred2, i);
517 public void finished(ReadGraphImpl graph) throws DatabaseException {
522 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
523 procedure.exception(graph, t);
535 IntSet result = QueryCache.resultSuperRelations(graph, pred2, parent, null);
536 if(result.contains(r2)) {
540 // Note! The dependency is intentionally cut!
541 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
544 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
545 procedure.execute(graph, r1, pred2, i);
550 public void finished(ReadGraphImpl graph) throws DatabaseException {
555 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
556 procedure.exception(graph, t);
564 } catch (Throwable e) {
565 procedure.exception(graph, e);
573 public void finished(ReadGraphImpl graph) throws DatabaseException {
583 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure_) throws DatabaseException {
585 TripleIntProcedure procedure = entry != null ? entry : procedure_;
587 RelationInfo ri = QueryCache.resultRelationInfoQuery(graph, r2, entry, null);
588 graph.ensureLoaded(r1, r2);
589 if(ri.isFunctional) {
590 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
592 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
595 if(entry != null) entry.performFromCache(graph, procedure_);
600 public String toString() {
601 return "Statements[" + r1() + " - " + r2() + "]";
604 final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) throws DatabaseException {
606 assert(assertPending());
610 //new Exception(toString() + " is READY").printStackTrace();
613 IntArray v = (IntArray)getResult();
614 final IntArray value = (IntArray)getResult();
616 for(int i=0;i<value.size();i+=3) {
617 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
620 procedure.finished(graph);
624 synchronized public void addOrSet(int s, int p, int o) {
626 assert(assertPending());
628 IntArray value = (IntArray)getResult();
635 final static public int r1(long id) {
636 return (int)(id>>>32);
639 final static public int r2(long id) {
643 final public void addOrSetFunctional(int s, long po) {
645 addOrSetFunctional(s, r1(po), r2(po));
649 final public void addOrSetFunctional(int s, int p, int o) {
651 assert(assertPending());
653 IntArray value = (IntArray)getResult();
661 public Object performFromCache(ReadGraphImpl graph, final TripleIntProcedure procedure) throws DatabaseException {
665 final IntArray value = (IntArray)getResult();
667 if(handleException(graph, procedure)) return value;
669 for(int i=0;i<value.size();i+=3) {
670 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
673 procedure.finished(graph);
680 public void recompute(ReadGraphImpl graph) throws DatabaseException {
682 computeForEach(graph, r1(), r2(), this, new TripleIntProcedureAdapter() {
685 public void finished(ReadGraphImpl graph) {
689 public void exception(ReadGraphImpl graph, Throwable t) {
690 new Error("Error in recompute.", t).printStackTrace();
699 return RequestFlags.IMMEDIATE_UPDATE;
704 boolean isImmutable(ReadGraphImpl graph) {
705 return graph.processor.isImmutable(r1());
709 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
714 public void finished(ReadGraphImpl graph) throws DatabaseException {
719 public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {