1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 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 final public class Statements extends CollectionBinaryQuery<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 entry, final TripleIntProcedure procedure) throws DatabaseException {
139 assert(entry.isPending());
142 IntArray map = getAssertionMap(graph, r1, r2, entry);
144 if(entry != null) entry.finish(graph, procedure);
145 else procedure.finished(graph);
149 int size = map.size();
157 entry.addOrSetFunctional(s,p,o);
158 entry.finish(graph, procedure);
160 procedure.execute(graph, s,p,o);
161 procedure.finished(graph);
164 } else if(size == 0) {
166 if(entry != null) entry.finish(graph, procedure);
167 else procedure.finished(graph);
171 int candidateS = map.data[0];
172 int candidateP = map.data[1];
173 int candidateO = map.data[2];
175 IntSet candidateIs = null;
177 candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null);
178 } catch (DatabaseException e) {
179 if(entry != null) entry.except(e);
180 procedure.exception(graph, e);
185 // SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
186 // if(candidate.isExcepted()) {
187 // if(entry != null) entry.except((Throwable)candidate.getResult());
188 // procedure.exception(graph, (Throwable)candidate.getResult());
191 // IntSet candidateIs = candidate.getResult();
193 for(int i=3;i<map.size();i+=3) {
195 int nextS = map.data[i];
196 int nextP = map.data[i+1];
197 int nextO = map.data[i+2];
199 if(nextS != candidateS) {
201 if(candidateIs.contains(nextS)) {
203 // Next is a super type of candidate => ignore next
207 IntSet nextIs = null;
209 nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null);
210 } catch (DatabaseException e) {
211 if(entry != null) entry.except(e);
212 procedure.exception(graph, e);
216 // SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
217 // if(next.isExcepted()) {
218 // if(entry != null) entry.except((Throwable)next.getResult());
219 // procedure.exception(graph, (Throwable)next.getResult());
222 // IntSet nextIs = next.getResult();
224 if(nextIs.contains(candidateS)) {
226 // Candidate is a super type of next => next is the new candidate
231 candidateIs = nextIs;
235 // candidate and next are unrelated => error
236 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
238 if(entry != null) entry.except(exception);
239 procedure.exception(graph, exception);
251 entry.addOrSetFunctional(candidateS, candidateP, candidateO);
252 entry.finish(graph, procedure);
254 procedure.execute(graph, candidateS, candidateP, candidateO);
255 procedure.finished(graph);
262 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
265 public void execute(ReadGraphImpl graph, IntSet result) {
269 public void exception(ReadGraphImpl graph, Throwable throwable) {
274 // Search for one statement
275 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
279 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
283 // Check for assertions
284 forSingleAssertion(graph, r1, r2, entry, procedure);
286 } else if(result == -1) {
288 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
291 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
292 if(entry != null) entry.addOrSetFunctional(r1, r2, i);
293 else procedure.execute(graph, r1, r2, i);
297 public void exception(ReadGraphImpl graph, Throwable t) {
298 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
302 public void finished(ReadGraphImpl graph) {
307 // Check for assertions
308 forSingleAssertion(graph, r1, r2, entry, procedure);
312 // If functional relation was found there is no need to check assertions
314 entry.addOrSetFunctional(r1, r2, result);
315 entry.finish(graph, procedure);
317 procedure.execute(graph, r1, r2, result);
318 procedure.finished(graph);
326 final AtomicBoolean found = new AtomicBoolean(false);
328 // Note! The dependency is intentionally cut!
329 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
330 direct.forEach(graph, new SyncIntProcedure() {
333 public void run(ReadGraphImpl graph) throws DatabaseException {
336 if(entry != null) entry.finish(graph, procedure);
337 else procedure.finished(graph);
340 // Check for assertions
341 forSingleAssertion(graph, r1, r2, entry, procedure);
348 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
350 if(found.get()) return;
356 // Note! The dependency is intentionally cut!
357 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
360 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
362 if(found.compareAndSet(false, true)) {
364 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
365 else procedure.execute(graph, r1, pred, i);
369 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
370 if(entry != null) entry.except(exception);
371 procedure.exception(graph, exception);
378 public void finished(ReadGraphImpl graph) throws DatabaseException {
383 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
384 procedure.exception(graph, t);
394 QueryCache.runnerSuperRelations(graph, pred, entry, null, new InternalProcedure<IntSet>() {
397 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
404 if(result.contains(r2)) {
408 // Note! The dependency is intentionally cut!
409 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
412 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
414 if(found.compareAndSet(false, true)) {
416 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
417 else procedure.execute(graph, r1, pred, i);
421 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
422 if(entry != null) entry.except(exception);
423 procedure.exception(graph, exception);
430 public void finished(ReadGraphImpl graph) throws DatabaseException {
435 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
436 procedure.exception(graph, t);
449 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
450 procedure.exception(graph, t);
461 public void finished(ReadGraphImpl graph) throws DatabaseException {
471 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) throws DatabaseException {
473 QueryCache.runnerPrincipalTypes(graph, r1, entry, null, new SyncIntProcedure() {
476 public void run(ReadGraphImpl graph) throws DatabaseException {
478 if(entry != null) entry.finish(graph, procedure);
479 else procedure.finished(graph);
483 TripleIntProcedure proc = new TripleIntProcedureAdapter() {
486 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
487 if(entry != null) entry.addOrSet(s, p, o);
488 else procedure.execute(graph, s, p, o);
492 public void finished(ReadGraphImpl graph) throws DatabaseException {
497 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
499 procedure.exception(graph, t);
505 public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
508 QueryCache.runnerAssertedStatements(graph, type, r2, entry, null, proc);
513 public void finished(ReadGraphImpl graph) throws DatabaseException {
518 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
527 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
531 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
534 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
535 if(entry != null) entry.addOrSet(r1, r2, i);
536 else procedure.execute(graph, r1, r2, i);
540 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
541 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
542 procedure.exception(graph, t);
546 public void finished(ReadGraphImpl graph) {
552 forAssertions(graph, r1, r2, entry, procedure);
554 if(entry != null) entry.finish(graph, procedure);
555 else procedure.finished(graph);
560 // Note! The dependency is intentionally cut!
561 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
562 direct.forEach(graph, new SyncIntProcedure() {
565 public void run(ReadGraphImpl graph) throws DatabaseException {
567 forAssertions(graph, r1, r2, entry, procedure);
572 public void execute(ReadGraphImpl graph, final int pred2) throws DatabaseException {
578 // Note! The dependency is intentionally cut!
579 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
582 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
583 if(entry != null) entry.addOrSet(r1, pred2, i);
584 else procedure.execute(graph, r1, pred2, i);
588 public void finished(ReadGraphImpl graph) throws DatabaseException {
593 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
594 procedure.exception(graph, t);
606 IntSet result = QueryCache.resultSuperRelations(graph, pred2, entry, null);
607 if(result.contains(r2)) {
611 // Note! The dependency is intentionally cut!
612 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
615 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
616 if(entry != null) entry.addOrSet(r1, pred2, i);
617 else procedure.execute(graph, r1, pred2, i);
622 public void finished(ReadGraphImpl graph) throws DatabaseException {
627 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
628 procedure.exception(graph, t);
636 } catch (Throwable e) {
637 procedure.exception(graph, e);
645 public void finished(ReadGraphImpl graph) throws DatabaseException {
655 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) throws DatabaseException {
658 assert(entry.isPending());
661 QueryCache.runnerRelationInfoQuery(graph, r2, entry, null, new InternalProcedure<RelationInfo>() {
664 public void execute(ReadGraphImpl graph, final RelationInfo ri) throws DatabaseException {
666 graph.ensureLoaded(r1, r2);
667 if(ri.isFunctional) {
668 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
670 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
676 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
677 procedure.exception(graph, t);
685 public String toString() {
686 return "Statements[" + r1() + " - " + r2() + "]";
689 final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) throws DatabaseException {
691 assert(assertPending());
695 //new Exception(toString() + " is READY").printStackTrace();
698 IntArray v = (IntArray)getResult();
699 final IntArray value = (IntArray)getResult();
701 for(int i=0;i<value.size();i+=3) {
702 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
705 procedure.finished(graph);
709 synchronized public void addOrSet(int s, int p, int o) {
711 assert(assertPending());
713 IntArray value = (IntArray)getResult();
720 final static public int r1(long id) {
721 return (int)(id>>>32);
724 final static public int r2(long id) {
728 final public void addOrSetFunctional(int s, long po) {
730 addOrSetFunctional(s, r1(po), r2(po));
734 final public void addOrSetFunctional(int s, int p, int o) {
736 assert(assertPending());
738 IntArray value = (IntArray)getResult();
746 public Object performFromCache(ReadGraphImpl graph, final TripleIntProcedure procedure) throws DatabaseException {
750 final IntArray value = (IntArray)getResult();
752 if(handleException(graph, procedure)) return value;
754 for(int i=0;i<value.size();i+=3) {
755 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
758 procedure.finished(graph);
765 public void recompute(ReadGraphImpl graph) throws DatabaseException {
767 computeForEach(graph, r1(), r2(), this, new TripleIntProcedureAdapter() {
770 public void finished(ReadGraphImpl graph) {
774 public void exception(ReadGraphImpl graph, Throwable t) {
775 new Error("Error in recompute.", t).printStackTrace();
784 return RequestFlags.IMMEDIATE_UPDATE;
789 boolean isImmutable(ReadGraphImpl graph) {
790 return graph.processor.isImmutable(r1());