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 {
138 IntArray map = getAssertionMap(graph, r1, r2, entry);
140 if(entry != null) entry.finish(graph, procedure);
141 else procedure.finished(graph);
145 int size = map.size();
153 entry.addOrSetFunctional(s,p,o);
154 entry.finish(graph, procedure);
156 procedure.execute(graph, s,p,o);
157 procedure.finished(graph);
160 } else if(size == 0) {
162 if(entry != null) entry.finish(graph, procedure);
163 else procedure.finished(graph);
167 int candidateS = map.data[0];
168 int candidateP = map.data[1];
169 int candidateO = map.data[2];
171 IntSet candidateIs = null;
173 candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null);
174 } catch (DatabaseException e) {
175 if(entry != null) entry.except(e);
176 procedure.exception(graph, e);
181 // SuperTypes candidate = SuperTypes.queryEach(graph, candidateS, graph.processor, entry, null, NOP);
182 // if(candidate.isExcepted()) {
183 // if(entry != null) entry.except((Throwable)candidate.getResult());
184 // procedure.exception(graph, (Throwable)candidate.getResult());
187 // IntSet candidateIs = candidate.getResult();
189 for(int i=3;i<map.size();i+=3) {
191 int nextS = map.data[i];
192 int nextP = map.data[i+1];
193 int nextO = map.data[i+2];
195 if(nextS != candidateS) {
197 if(candidateIs.contains(nextS)) {
199 // Next is a super type of candidate => ignore next
203 IntSet nextIs = null;
205 nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null);
206 } catch (DatabaseException e) {
207 if(entry != null) entry.except(e);
208 procedure.exception(graph, e);
212 // SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
213 // if(next.isExcepted()) {
214 // if(entry != null) entry.except((Throwable)next.getResult());
215 // procedure.exception(graph, (Throwable)next.getResult());
218 // IntSet nextIs = next.getResult();
220 if(nextIs.contains(candidateS)) {
222 // Candidate is a super type of next => next is the new candidate
227 candidateIs = nextIs;
231 // candidate and next are unrelated => error
232 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
234 if(entry != null) entry.except(exception);
235 procedure.exception(graph, exception);
247 entry.addOrSetFunctional(candidateS, candidateP, candidateO);
248 entry.finish(graph, procedure);
250 procedure.execute(graph, candidateS, candidateP, candidateO);
251 procedure.finished(graph);
258 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
261 public void execute(ReadGraphImpl graph, IntSet result) {
265 public void exception(ReadGraphImpl graph, Throwable throwable) {
270 // Search for one statement
271 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
275 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
279 // Check for assertions
280 forSingleAssertion(graph, r1, r2, entry, procedure);
282 } else if(result == -1) {
284 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
287 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
288 if(entry != null) entry.addOrSetFunctional(r1, r2, i);
289 else procedure.execute(graph, r1, r2, i);
293 public void exception(ReadGraphImpl graph, Throwable t) {
294 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
298 public void finished(ReadGraphImpl graph) {
303 // Check for assertions
304 forSingleAssertion(graph, r1, r2, entry, procedure);
308 // If functional relation was found there is no need to check assertions
310 entry.addOrSetFunctional(r1, r2, result);
311 entry.finish(graph, procedure);
313 procedure.execute(graph, r1, r2, result);
314 procedure.finished(graph);
322 final AtomicBoolean found = new AtomicBoolean(false);
324 // Note! The dependency is intentionally cut!
325 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
326 direct.forEach(graph, new SyncIntProcedure() {
329 public void run(ReadGraphImpl graph) throws DatabaseException {
332 if(entry != null) entry.finish(graph, procedure);
333 else procedure.finished(graph);
336 // Check for assertions
337 forSingleAssertion(graph, r1, r2, entry, procedure);
344 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
346 if(found.get()) return;
352 // Note! The dependency is intentionally cut!
353 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
356 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
358 if(found.compareAndSet(false, true)) {
360 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
361 else procedure.execute(graph, r1, pred, i);
365 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
366 if(entry != null) entry.except(exception);
367 procedure.exception(graph, exception);
374 public void finished(ReadGraphImpl graph) throws DatabaseException {
379 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
380 procedure.exception(graph, t);
390 QueryCache.runnerSuperRelations(graph, pred, entry, null, new InternalProcedure<IntSet>() {
393 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
400 if(result.contains(r2)) {
404 // Note! The dependency is intentionally cut!
405 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
408 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
410 if(found.compareAndSet(false, true)) {
412 if(entry != null) entry.addOrSetFunctional(r1, pred, i);
413 else procedure.execute(graph, r1, pred, i);
417 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
418 if(entry != null) entry.except(exception);
419 procedure.exception(graph, exception);
426 public void finished(ReadGraphImpl graph) throws DatabaseException {
431 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
432 procedure.exception(graph, t);
445 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
446 procedure.exception(graph, t);
457 public void finished(ReadGraphImpl graph) throws DatabaseException {
467 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) throws DatabaseException {
469 QueryCache.runnerPrincipalTypes(graph, r1, entry, null, new SyncIntProcedure() {
472 public void run(ReadGraphImpl graph) throws DatabaseException {
474 if(entry != null) entry.finish(graph, procedure);
475 else procedure.finished(graph);
479 TripleIntProcedure proc = new TripleIntProcedureAdapter() {
482 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
483 if(entry != null) entry.addOrSet(s, p, o);
484 else procedure.execute(graph, s, p, o);
488 public void finished(ReadGraphImpl graph) throws DatabaseException {
493 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
495 procedure.exception(graph, t);
501 public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
504 QueryCache.runnerAssertedStatements(graph, type, r2, entry, null, proc);
509 public void finished(ReadGraphImpl graph) throws DatabaseException {
514 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
523 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
527 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
530 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
531 if(entry != null) entry.addOrSet(r1, r2, i);
532 else procedure.execute(graph, r1, r2, i);
536 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
537 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
538 procedure.exception(graph, t);
542 public void finished(ReadGraphImpl graph) {
548 forAssertions(graph, r1, r2, entry, procedure);
550 if(entry != null) entry.finish(graph, procedure);
551 else procedure.finished(graph);
556 // Note! The dependency is intentionally cut!
557 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
558 direct.forEach(graph, new SyncIntProcedure() {
561 public void run(ReadGraphImpl graph) throws DatabaseException {
563 forAssertions(graph, r1, r2, entry, procedure);
568 public void execute(ReadGraphImpl graph, final int pred2) throws DatabaseException {
574 // Note! The dependency is intentionally cut!
575 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
578 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
579 if(entry != null) entry.addOrSet(r1, pred2, i);
580 else procedure.execute(graph, r1, pred2, i);
584 public void finished(ReadGraphImpl graph) throws DatabaseException {
589 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
590 procedure.exception(graph, t);
602 IntSet result = QueryCache.resultSuperRelations(graph, pred2, entry, null);
603 if(result.contains(r2)) {
607 // Note! The dependency is intentionally cut!
608 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
611 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
612 if(entry != null) entry.addOrSet(r1, pred2, i);
613 else procedure.execute(graph, r1, pred2, i);
618 public void finished(ReadGraphImpl graph) throws DatabaseException {
623 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
624 procedure.exception(graph, t);
632 } catch (Throwable e) {
633 procedure.exception(graph, e);
641 public void finished(ReadGraphImpl graph) throws DatabaseException {
652 public Object compute(ReadGraphImpl graph, final TripleIntProcedure procedure) throws DatabaseException {
653 computeForEach(graph, r1(), r2(), this, procedure);
657 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure) throws DatabaseException {
659 QueryCache.runnerRelationInfoQuery(graph, r2, entry, null, new InternalProcedure<RelationInfo>() {
662 public void execute(ReadGraphImpl graph, final RelationInfo ri) throws DatabaseException {
664 graph.ensureLoaded(r1, r2);
665 if(ri.isFunctional) {
666 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
668 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
674 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
675 procedure.exception(graph, t);
683 public String toString() {
684 return "Statements[" + r1() + " - " + r2() + "]";
687 final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) throws DatabaseException {
689 assert(assertPending());
695 IntArray v = (IntArray)getResult();
696 final IntArray value = (IntArray)getResult();
698 for(int i=0;i<value.size();i+=3) {
699 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
702 procedure.finished(graph);
706 synchronized public void addOrSet(int s, int p, int o) {
708 assert(assertPending());
710 IntArray value = (IntArray)getResult();
717 final static public int r1(long id) {
718 return (int)(id>>>32);
721 final static public int r2(long id) {
725 final public void addOrSetFunctional(int s, long po) {
727 addOrSetFunctional(s, r1(po), r2(po));
731 final public void addOrSetFunctional(int s, int p, int o) {
733 assert(assertPending());
735 IntArray value = (IntArray)getResult();
743 public Object performFromCache(ReadGraphImpl graph, final TripleIntProcedure procedure) throws DatabaseException {
747 final IntArray value = (IntArray)getResult();
749 if(handleException(graph, procedure)) return value;
751 for(int i=0;i<value.size();i+=3) {
752 procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
755 procedure.finished(graph);
762 public void recompute(ReadGraphImpl graph) throws DatabaseException {
764 compute(graph, new TripleIntProcedureAdapter() {
767 public void finished(ReadGraphImpl graph) {
771 public void exception(ReadGraphImpl graph, Throwable t) {
772 new Error("Error in recompute.", t).printStackTrace();
781 return RequestFlags.IMMEDIATE_UPDATE;
786 boolean isImmutable(ReadGraphImpl graph) {
787 return graph.processor.isImmutable(r1());