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 org.simantics.db.RelationInfo;
15 import org.simantics.db.Resource;
16 import org.simantics.db.common.exception.DebugException;
17 import org.simantics.db.common.utils.Logger;
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.IntProcedureAdapter;
22 import org.simantics.db.impl.procedure.InternalProcedure;
23 import org.simantics.db.procedure.AsyncMultiProcedure;
24 import org.simantics.db.request.RequestFlags;
26 import gnu.trove.procedure.TIntProcedure;
32 * statusOrException 4 byte
34 * p2OrParents = 4 byte
41 final public class Objects extends CollectionBinaryQuery<IntProcedure> {
43 public Objects(final int r1, final int r2) {
48 final public void removeEntry(QueryProcessor provider) {
49 provider.cache.remove(this);
52 final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Objects entry) throws DatabaseException {
54 class AssertionMapProc implements IntProcedure {
58 private IntArray result;
60 public void addStatement(int s, int p, int o) {
62 if(result.size() == 0) {
67 for(int i = 0;i < result.sizeOrData ; i+=3) {
68 int existingP = result.data[i+1];
70 int existingO = result.data[i+2];
71 if(existingO == o) return;
82 public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
84 result = QueryCacheBase.resultAssertedStatements(graph, type, r2, entry, null);
88 result = new IntArray();
90 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
94 IntArray ia = QueryCacheBase.resultAssertedStatements(graph, type, r2, entry, null);
96 for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
102 public void finished(ReadGraphImpl graph) {
106 public void exception(ReadGraphImpl graph, Throwable throwable) {
111 AssertionMapProc amp = new AssertionMapProc();
113 // This dependency could be cut
114 QueryCache.runnerPrincipalTypes(graph, r1, entry, null, amp);
120 final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) throws DatabaseException {
122 IntArray map = getAssertionMap(graph, r1, r2, entry);
124 if(entry != null) entry.finish(graph, procedure);
125 else procedure.finished(graph);
129 int size = map.size();
132 int value = map.data[2];
135 entry.addOrSetFunctional(value);
136 entry.finish(graph, procedure);
138 procedure.execute(graph, value);
139 procedure.finished(graph);
142 } else if(size == 0) {
144 if(entry != null) entry.finish(graph, procedure);
145 else procedure.finished(graph);
149 int candidateS = map.data[0];
150 int candidateO = map.data[2];
152 IntSet candidateIs = null;
154 candidateIs = QueryCache.resultSuperTypes(graph, candidateS, entry, null);
155 } catch (DatabaseException e) {
156 if(entry != null) entry.except(e);
157 procedure.exception(graph, e);
161 for(int i=3;i<map.size();i+=3) {
163 int nextS = map.data[i];
164 int nextO = map.data[i+2];
166 if(nextS != candidateS) {
168 if(candidateIs.contains(nextS)) {
170 // Next is a super type of candidate => ignore next
174 IntSet nextIs = null;
176 nextIs = QueryCache.resultSuperTypes(graph, nextS, entry, null);
177 } catch (DatabaseException e) {
178 if(entry != null) entry.except(e);
179 procedure.exception(graph, e);
183 // SuperTypes next = SuperTypes.queryEach(graph, nextS, graph.processor, entry, null, NOP);
184 // if(next.isExcepted()) {
185 // if(entry != null) entry.except((Throwable)next.getResult());
186 // procedure.exception(graph, (Throwable)next.getResult());
189 // IntSet nextIs = next.getResult();
191 if(nextIs.contains(candidateS)) {
193 // Candidate is a super type of next => next is the new candidate
197 candidateIs = nextIs;
201 // candidate and next are unrelated => error
202 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions " + r1 + ", " + r2 + " " + map , r1);
204 if(entry != null) entry.except(exception);
205 procedure.exception(graph, exception);
217 entry.addOrSetFunctional(candidateO);
218 entry.finish(graph, procedure);
220 procedure.execute(graph, candidateO);
221 procedure.finished(graph);
228 final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
231 public void execute(ReadGraphImpl graph, IntSet result) {
235 public void exception(ReadGraphImpl graph, Throwable throwable) {
240 final static TripleIntProcedure NOPT = new TripleIntProcedure() {
244 public void exception(ReadGraphImpl graph, Throwable throwable) {
248 public void execute(ReadGraphImpl graph, int s, int p, int o) {
252 public void finished(ReadGraphImpl graph) {
257 // Search for one statement
258 final public void computeFunctionalIndex(ReadGraphImpl graph, final QueryProcessor provider, final RelationInfo ri, final IntProcedure procedure) throws DatabaseException {
259 computeFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
262 // Search for one statement
263 final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final RelationInfo ri, final IntProcedure procedure) throws DatabaseException {
267 int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
271 // Check for assertions
272 forSingleAssertion(graph, r1, r2, entry, procedure);
274 } else if (result == -1) {
276 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
279 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
280 if(entry != null) entry.addOrSetFunctional(i);
281 else procedure.execute(graph, i);
285 public void exception(ReadGraphImpl graph, Throwable t) {
286 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
290 public void finished(ReadGraphImpl graph) {
295 // Check for assertions
296 forSingleAssertion(graph, r1, r2, entry, procedure);
300 // If functional relation was found there is no need to check assertions
302 entry.addOrSetFunctional(result);
303 entry.finish(graph, procedure);
305 procedure.execute(graph, result);
306 procedure.finished(graph);
314 // Note! The dependency is intentionally cut!
315 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
316 direct.forEach(graph, new SyncIntProcedure() {
318 boolean found = false;
321 public void run(ReadGraphImpl graph) throws DatabaseException {
324 if(entry != null) entry.finish(graph, procedure);
325 else procedure.finished(graph);
328 // Check for assertions
329 forSingleAssertion(graph, r1, r2, entry, procedure);
336 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
342 // Note! The dependency is intentionally cut!
343 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
346 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
350 if(entry != null) entry.addOrSetFunctional(i);
351 else procedure.execute(graph, i);
357 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
358 if(entry != null) entry.except(exception);
359 procedure.exception(graph, exception);
366 public void finished(ReadGraphImpl graph) {
370 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
371 procedure.exception(graph, t);
378 QueryCache.runnerSuperRelations(graph, pred, entry, null, new InternalProcedure<IntSet>() {
381 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
385 if(result.contains(r2)) {
387 // Note! The dependency is intentionally cut!
388 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
391 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
395 if(entry != null) entry.addOrSetFunctional(i);
396 else procedure.execute(graph, i);
402 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
403 if(entry != null) entry.except(exception);
404 procedure.exception(graph, exception);
411 public void finished(ReadGraphImpl graph) {
415 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
416 procedure.exception(graph, t);
426 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
427 procedure.exception(graph, t);
437 public void finished(ReadGraphImpl graph) throws DatabaseException {
450 final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) throws DatabaseException {
452 // Note! The dependency is intentionally cut!
453 QueryCache.runnerPrincipalTypes(graph, r1, null, null, new SyncIntProcedure() {
456 public void run(ReadGraphImpl graph) throws DatabaseException {
458 if(entry != null) entry.finish(graph, procedure);
459 else procedure.finished(graph);
463 TripleIntProcedure proc = new TripleIntProcedure() {
466 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
467 if(entry != null) entry.addOrSet(o);
468 else procedure.execute(graph, o);
472 public void finished(ReadGraphImpl graph) throws DatabaseException {
477 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
478 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
479 procedure.exception(graph, t);
486 public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
489 QueryCache.runnerAssertedStatements(graph, type, r2, entry, null, proc);
494 public void finished(ReadGraphImpl graph) throws DatabaseException {
503 final public static void computeNotFunctionalFinalIndex(ReadGraphImpl graph, final int r1, final int r2, final QueryProcessor provider, RelationInfo ri, AsyncMultiProcedure<Resource> procedure) {
509 final public void computeNotFunctionalIndex(ReadGraphImpl graph, RelationInfo ri, final IntProcedure procedure) throws DatabaseException {
510 computeNotFunctionalIndex(graph, r1(), r2(), this, ri, procedure);
513 final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, RelationInfo ri, final IntProcedure procedure) throws DatabaseException {
517 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
520 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
521 if(entry != null) entry.addOrSet(i);
522 else procedure.execute(graph, i);
526 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
527 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
528 procedure.exception(graph, t);
532 public void finished(ReadGraphImpl graph) {
538 forAssertions(graph, r1, r2, entry, procedure);
540 if(entry != null) entry.finish(graph, procedure);
541 else procedure.finished(graph);
546 // Note! The dependency is intentionally cut!
547 IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
548 direct.forEach(graph, new SyncIntProcedure() {
551 public void run(ReadGraphImpl graph) throws DatabaseException {
553 forAssertions(graph, r1, r2, entry, procedure);
558 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
564 // Note! The dependency is intentionally cut!
565 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
568 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
569 if(entry != null) entry.addOrSet(i);
570 else procedure.execute(graph, i);
574 public void finished(ReadGraphImpl graph) throws DatabaseException {
579 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
580 procedure.exception(graph, t);
590 QueryCache.runnerSuperRelations(graph, pred, entry, null, new InternalProcedure<IntSet>() {
593 public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
595 if(result.contains(r2)) {
599 // Note! The dependency is intentionally cut!
600 QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
603 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
604 if(entry != null) entry.addOrSet(i);
605 else procedure.execute(graph, i);
609 public void finished(ReadGraphImpl graph) throws DatabaseException {
614 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
615 if(DebugException.DEBUG) new DebugException(t).printStackTrace();
616 procedure.exception(graph, t);
629 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
630 procedure.exception(graph, t);
641 public void finished(ReadGraphImpl graph) throws DatabaseException {
652 public Object compute(ReadGraphImpl graph, final IntProcedure procedure) throws DatabaseException {
653 computeForEach(graph, r1(), r2(), this, procedure);
657 public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Objects entry, final IntProcedure procedure) throws DatabaseException {
659 RelationInfo ri = QueryCache.resultRelationInfoQuery(graph, r2, entry, null);
660 graph.ensureLoaded(r1, r2);
661 if(ri.isFunctional) {
662 computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
664 computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
670 public String toString() {
671 return "Objects[" + r1() + " - " + r2() + "]";
674 final private void finish(ReadGraphImpl graph, IntProcedure procedure) throws DatabaseException {
676 assert(assertPending());
682 IntArray v = (IntArray)getResult();
685 if(v.sizeOrData != IntArray.NO_DATA) {
686 procedure.execute(graph, v.sizeOrData);
689 for(int i = 0;i < v.sizeOrData ; i++) {
690 procedure.execute(graph, v.data[i]);
694 procedure.finished(graph);
698 final public void addOrSet(int add) {
700 assert(assertPending());
702 IntArray value = (IntArray)getResult();
703 synchronized(value) {
709 final public void addOrSetFunctional(int add) {
713 IntArray value = (IntArray)getResult();
719 public Object performFromCache(ReadGraphImpl graph, final IntProcedure procedure) throws DatabaseException {
723 if(handleException(graph, procedure)) return getResult();
725 final IntArray value = (IntArray)getResult();
726 if(value.data == null) {
727 if(value.sizeOrData != IntArray.NO_DATA) procedure.execute(graph, value.sizeOrData);
729 for(int i = 0;i < value.sizeOrData ; i++) procedure.execute(graph, value.data[i]);
732 procedure.finished(graph);
739 public void recompute(ReadGraphImpl graph) throws DatabaseException {
741 compute(graph, new IntProcedureAdapter() {
744 public void finished(ReadGraphImpl graph) {
748 public void exception(ReadGraphImpl graph, Throwable t) {
749 new Error("Error in recompute.", t).printStackTrace();
758 return RequestFlags.IMMEDIATE_UPDATE;
762 boolean isImmutable(ReadGraphImpl graph) {
763 return graph.processor.isImmutable(r1());