]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/Statements.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / Statements.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2018 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.impl.query;
13
14 import org.simantics.db.RelationInfo;
15 import org.simantics.db.common.exception.DebugException;
16 import org.simantics.db.exception.DatabaseException;
17 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
18 import org.simantics.db.impl.graph.ReadGraphImpl;
19 import org.simantics.db.impl.procedure.InternalProcedure;
20 import org.simantics.db.impl.procedure.TripleIntProcedureAdapter;
21 import org.simantics.db.procedure.ListenerBase;
22 import org.simantics.db.request.RequestFlags;
23
24 public final class Statements extends CollectionBinaryQuery<TripleIntProcedure> implements TripleIntProcedure {
25
26     public Statements(final int r1, final int r2) {
27         super(r1, r2);
28     }
29
30     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 {
31
32         assert(r1 != 0);
33         assert(r2 != 0);
34
35         if(parent == null && listener == null) {
36             Statements.computeForEach(graph, r1, r2, null, procedure);
37             return;
38         }
39
40         QueryCache.runnerStatements(graph, r1, r2, parent, listener, procedure);
41
42     }
43
44     @Override
45     final public void removeEntry(QueryProcessor provider) {
46         provider.cache.remove(this);
47     }
48
49     final static TripleIntProcedure NOPT = new TripleIntProcedure() {
50
51
52         @Override
53         public void exception(ReadGraphImpl graph, Throwable throwable) {
54         }
55
56         @Override
57         public void execute(ReadGraphImpl graph, int s, int p, int o) {
58         }
59
60         @Override
61         public void finished(ReadGraphImpl graph) {
62         }
63
64     };
65
66     final static private IntArray getAssertionMap(ReadGraphImpl graph, final int r1, final int r2, final Statements entry) throws DatabaseException {
67
68         class AssertionMapProc implements IntProcedure {
69
70             boolean first = true;
71
72             private IntArray result;
73
74             public void addStatement(int s, int p, int o) {
75
76                 if(result.size() == 0) {
77                     result.add(s);
78                     result.add(p);
79                     result.add(o);
80                 } else {
81                     for(int i = 0;i < result.sizeOrData ; i+=3) {
82                         int existingP = result.data[i+1];
83                         if(p == existingP) {
84                             int existingO = result.data[i+2];
85                             if(existingO == o) return;
86                         }
87                     }
88                     result.add(s);
89                     result.add(p);
90                     result.add(o);
91                 }
92
93             }
94
95             @Override
96             public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
97                 if(result == null) {
98                     result = QueryCache.resultAssertedStatements(graph, type, r2, entry, null);
99                 } else {
100                     if (first) {
101                         IntArray ia = result;
102                         result = new IntArray();
103                         if(ia.data != null) {
104                             for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
105                         }
106                         first = false;
107                     }
108                     IntArray ia = QueryCache.resultAssertedStatements(graph, type, r2, entry, null);
109                     if(ia.data != null) {
110                         for(int i = 0;i < ia.sizeOrData ; i+=3) addStatement(ia.data[i],ia.data[i+1],ia.data[i+2]);
111                     }
112                 }
113             }
114
115             @Override
116             public void finished(ReadGraphImpl graph) {
117             }
118
119             @Override
120             public void exception(ReadGraphImpl graph, Throwable throwable) {
121             }
122
123         }
124
125         AssertionMapProc amp = new AssertionMapProc();
126
127         // This dependency could be cut
128         QueryCache.runnerPrincipalTypes(graph, r1, entry, null, amp);
129
130         return amp.result;
131
132     }
133
134     final static private void forSingleAssertion(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final TripleIntProcedure procedure) throws DatabaseException {
135
136         IntArray map = getAssertionMap(graph, r1, r2, parent);
137         if(map == null) {
138             procedure.finished(graph);
139             return;
140         }
141
142         int size = map.size();
143         if(size == 3) {
144
145             int s = map.data[0];
146             int p = map.data[1];
147             int o = map.data[2];
148
149             procedure.execute(graph, s,p,o);
150             procedure.finished(graph);
151
152         } else if(size == 0) {
153
154             procedure.finished(graph);
155
156         } else {
157
158             int candidateS = map.data[0];
159             int candidateP = map.data[1];
160             int candidateO = map.data[2];
161
162             IntSet candidateIs = null;
163             try {
164                 candidateIs = QueryCache.resultSuperTypes(graph, candidateS, parent, null);
165             } catch (DatabaseException e) {
166                 procedure.exception(graph, e);
167                 return;
168             }
169
170             for(int i=3;i<map.size();i+=3) {
171
172                 int nextS = map.data[i];
173                 int nextP = map.data[i+1];
174                 int nextO = map.data[i+2];
175
176                 if(nextS != candidateS) {
177
178                     if(candidateIs.contains(nextS)) {
179
180                         // Next is a super type of candidate => ignore next
181
182                     } else {
183
184                         IntSet nextIs = null;
185                         try {
186                             nextIs = QueryCache.resultSuperTypes(graph, nextS, parent, null);
187                         } catch (DatabaseException e) {
188                             procedure.exception(graph, e);
189                             return;
190                         }
191
192                         if(nextIs.contains(candidateS)) {
193
194                             // Candidate is a super type of next => next is the new candidate
195
196                             candidateS = nextS;
197                             candidateP = nextP;
198                             candidateO = nextO;
199                             candidateIs = nextIs;
200
201                         } else {
202                             // candidate and next are unrelated => error
203                             ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has conflicting assertions.", r1);
204                             procedure.exception(graph, exception);
205                             return;                                             
206                         }
207
208                     }
209
210                 }
211
212             }
213
214             procedure.execute(graph, candidateS, candidateP, candidateO);
215             procedure.finished(graph);
216
217         }
218
219     }
220
221     final static InternalProcedure<IntSet> NOP = new InternalProcedure<IntSet>() {
222
223         @Override
224         public void execute(ReadGraphImpl graph, IntSet result) {
225         }
226
227         @Override
228         public void exception(ReadGraphImpl graph, Throwable throwable) {
229         }
230
231     };
232
233     // Search for one statement
234     final static public void computeFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
235
236         if(ri.isFinal) {
237
238             int result = graph.processor.querySupport.getFunctionalObject(r1, r2);
239
240             if(result == 0) {
241
242                 // Check for assertions
243                 forSingleAssertion(graph, r1, r2, parent, procedure);
244
245             } else if(result == -1) {
246
247                 graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
248
249                     @Override
250                     public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
251                         procedure.execute(graph, r1, r2, i);
252                     }
253
254                     @Override
255                     public void exception(ReadGraphImpl graph, Throwable t) {
256                         if(DebugException.DEBUG) new DebugException(t).printStackTrace();
257                     }
258
259                     @Override
260                     public void finished(ReadGraphImpl graph) {
261                     }
262
263                 });
264
265                 // Check for assertions
266                 forSingleAssertion(graph, r1, r2, parent, procedure);
267
268             } else {
269
270                 // If functional relation was found there is no need to check assertions
271                 procedure.execute(graph, r1, r2, result);
272                 procedure.finished(graph);
273
274             }
275
276
277         } else {
278
279             // Note! The dependency is intentionally cut!
280             IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
281             direct.forEach(graph, new SyncIntProcedure() {
282
283                 /*
284                  * 0 = not found
285                  * 1 = found
286                  * 2 = exception
287                  */
288                 int found = 0;
289
290                 @Override
291                 public void run(ReadGraphImpl graph) throws DatabaseException {
292
293                     if(found == 1) {
294
295                         procedure.finished(graph);
296
297                     } else if(found == 0) {
298
299                         // Check for assertions
300                         forSingleAssertion(graph, r1, r2, parent, procedure);
301
302                     }
303
304                 }
305
306                 @Override
307                 public void execute(ReadGraphImpl graph, final int pred) throws DatabaseException {
308
309                     if(found > 0)
310                         return;
311
312                     if(pred == r2) {
313
314                         // Note! The dependency is intentionally cut!
315                         QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
316
317                             @Override
318                             public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
319
320                                 if(found == 0) {
321
322                                     procedure.execute(graph, r1, pred, i);
323                                     found = 1;
324
325                                 } else {
326
327                                     ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement.", r1);
328                                     procedure.exception(graph, exception);
329                                     found = 2;
330
331                                 }
332
333                             }
334
335                             @Override
336                             public void finished(ReadGraphImpl graph) throws DatabaseException {
337                             }
338
339                             @Override
340                             public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
341
342                                 procedure.exception(graph, t);
343                                 found = 2;
344
345                             }
346
347                         });
348
349                     } else {
350
351                         QueryCache.runnerSuperRelations(graph, pred, parent, null, new InternalProcedure<IntSet>() {
352
353                             @Override
354                             public void execute(ReadGraphImpl graph, IntSet result) throws DatabaseException {
355
356                                 if(found > 0)
357                                     return;
358
359                                 if(result.contains(r2)) {
360
361                                     inc();
362
363                                     // Note! The dependency is intentionally cut!
364                                     QueryCache.runnerDirectObjects(graph, r1, pred, null, null, new IntProcedure() {
365
366                                         @Override
367                                         public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
368
369                                             if(found == 0) {
370
371                                                 procedure.execute(graph, r1, pred, i);
372                                                 found = 1;
373
374                                             } else {
375
376                                                 ManyObjectsForFunctionalRelationException exception = new ManyObjectsForFunctionalRelationException("Functional relation has more than one statement (r1=" + r1 + ", r2=" + r2 + ").", r1);
377                                                 procedure.exception(graph, exception);
378                                                 found = 2;
379
380                                             }
381
382                                         }
383
384                                         @Override
385                                         public void finished(ReadGraphImpl graph) throws DatabaseException {
386                                         }
387
388                                         @Override
389                                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
390                                             procedure.exception(graph, t);
391                                             found = 2;
392                                         }
393
394                                     });
395
396                                 }
397
398                             }
399
400                             @Override
401                             public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
402                                 procedure.exception(graph, t);
403                                 found = 2;
404                             }
405
406                         });
407
408                     }
409
410                 }
411
412                 @Override
413                 public void finished(ReadGraphImpl graph) throws DatabaseException {
414                     dec(graph);
415                 }
416
417             });
418
419         }
420
421     }
422
423     final static private void forAssertions(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final TripleIntProcedure procedure) throws DatabaseException {
424
425         QueryCache.runnerPrincipalTypes(graph, r1, parent, null, new SyncIntProcedure() {
426
427             @Override
428             public void run(ReadGraphImpl graph) throws DatabaseException {
429                 procedure.finished(graph);
430             }
431
432             TripleIntProcedure proc = new TripleIntProcedureAdapter() {
433
434                 @Override
435                 public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
436                     procedure.execute(graph, s, p, o);
437                 }
438
439                 @Override
440                 public void finished(ReadGraphImpl graph) throws DatabaseException {
441                     dec(graph);
442                 }
443
444                 @Override
445                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
446                     dec(graph);
447                     procedure.exception(graph, t);
448                 }
449
450             }; 
451
452             @Override
453             public void execute(ReadGraphImpl graph, int type) throws DatabaseException {
454                 inc();
455                 QueryCache.runnerAssertedStatements(graph, type, r2, parent, null, proc);
456             }
457
458             @Override
459             public void finished(ReadGraphImpl graph) throws DatabaseException {
460                 dec(graph);       
461             }
462
463             @Override
464             public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
465                 dec(graph);
466             }
467
468         });
469
470
471     }
472
473     final static public void computeNotFunctionalIndex(ReadGraphImpl graph, final int r1, final int r2, final Statements parent, final RelationInfo ri, final TripleIntProcedure procedure) throws DatabaseException {
474
475         if(ri.isFinal) {
476
477             graph.processor.querySupport.getObjects(graph, r1, r2, new IntProcedure() {
478
479                 @Override
480                 public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
481                     procedure.execute(graph, r1, r2, i);
482                 }
483
484                 @Override
485                 public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
486                     if(DebugException.DEBUG) new DebugException(t).printStackTrace();
487                     procedure.exception(graph, t);
488                 }
489
490                 @Override
491                 public void finished(ReadGraphImpl graph) {
492                 }
493
494             });
495
496             if(ri.isAsserted) {
497                 forAssertions(graph, r1, r2, parent, procedure);
498             } else {
499                 procedure.finished(graph);
500             }
501
502         } else {
503
504             // Note! The dependency is intentionally cut!
505             IntSet direct = QueryCache.resultDirectPredicates(graph, r1, null, null);
506             direct.forEach(graph, new SyncIntProcedure() {
507
508                 @Override
509                 public void run(ReadGraphImpl graph) throws DatabaseException {
510                     forAssertions(graph, r1, r2, parent, procedure);
511                 }
512
513                 @Override
514                 public void execute(ReadGraphImpl graph, final int pred2) throws DatabaseException {
515
516                     if(pred2 == r2) {
517
518                         // Note! The dependency is intentionally cut!
519                         QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
520
521                             @Override
522                             public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
523                                 procedure.execute(graph, r1, pred2, i);
524                             }
525
526                             @Override
527                             public void finished(ReadGraphImpl graph) throws DatabaseException {
528                             }
529
530                             @Override
531                             public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
532                                 procedure.exception(graph, t);
533                             }
534
535                         });
536
537                     } else {
538
539                         try {
540
541                             IntSet result = QueryCache.resultSuperRelations(graph, pred2, parent, null);
542                             if(result.contains(r2)) {
543
544                                 inc();
545
546                                 // Note! The dependency is intentionally cut!
547                                 QueryCache.runnerDirectObjects(graph, r1, pred2, null, null, new IntProcedure() {
548
549                                     @Override
550                                     public void execute(ReadGraphImpl graph, int i) throws DatabaseException {
551                                         procedure.execute(graph, r1, pred2, i);
552
553                                     }
554
555                                     @Override
556                                     public void finished(ReadGraphImpl graph) throws DatabaseException {
557                                         dec(graph);
558                                     }
559
560                                     @Override
561                                     public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
562                                         procedure.exception(graph, t);
563                                         dec(graph);
564                                     }
565
566                                 });
567
568                             }
569
570                         } catch (Throwable e) {
571                             procedure.exception(graph, e);
572                         }
573
574                     }
575
576                 }
577
578                 @Override
579                 public void finished(ReadGraphImpl graph) throws DatabaseException {
580                     dec(graph);
581                 }
582
583             });
584
585         }
586
587     }
588
589     public static void computeForEach(ReadGraphImpl graph, final int r1, final int r2, final Statements entry, final TripleIntProcedure procedure_) throws DatabaseException {
590
591         TripleIntProcedure procedure = entry != null ? entry : procedure_;
592
593         RelationInfo ri = QueryCache.resultRelationInfoQuery(graph, r2, entry, null);
594         graph.ensureLoaded(r1, r2);
595         if(ri.isFunctional) {
596             computeFunctionalIndex(graph, r1, r2, entry, ri, procedure);
597         } else {
598             computeNotFunctionalIndex(graph, r1, r2, entry, ri, procedure);
599         }
600
601         if(entry != null) entry.performFromCache(graph, procedure_);
602
603     }
604
605     @Override
606     public String toString() {
607         return "Statements[" + r1() + " - " + r2() + "]";
608     }
609
610     final private void finish(ReadGraphImpl graph, TripleIntProcedure procedure) throws DatabaseException {
611
612         assert(assertPending());
613
614         synchronized(this) {
615             setReady();
616             //new Exception(toString() + " is READY").printStackTrace();
617         }
618
619         IntArray v = (IntArray)getResult();
620         final IntArray value = (IntArray)getResult();
621
622         for(int i=0;i<value.size();i+=3) {
623             procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
624         }
625
626         procedure.finished(graph);
627
628     }
629
630     synchronized public void addOrSet(int s, int p, int o) {
631
632         assert(assertPending());
633
634         IntArray value = (IntArray)getResult();
635         value.add(s);
636         value.add(p);
637         value.add(o);
638
639     }
640
641     final static public int r1(long id) {
642         return (int)(id>>>32);
643     }
644
645     final static public int r2(long id) {
646         return (int)id;
647     }
648
649     final public void addOrSetFunctional(int s, long po) {
650
651         addOrSetFunctional(s, r1(po), r2(po));
652
653     }
654
655     final public void addOrSetFunctional(int s, int p, int o) {
656
657         assert(assertPending());
658
659         IntArray value = (IntArray)getResult();
660         value.add(s);
661         value.add(p);
662         value.add(o);
663
664     }
665
666     @Override
667     public Object performFromCache(ReadGraphImpl graph, final TripleIntProcedure procedure) throws DatabaseException {
668
669         assert(isReady());
670
671         final IntArray value = (IntArray)getResult();
672
673         if(handleException(graph, procedure)) return value;
674
675         for(int i=0;i<value.size();i+=3) {
676             procedure.execute(graph, value.data[i], value.data[i+1], value.data[i+2]);
677         }
678
679         procedure.finished(graph);
680
681         return value;
682
683     }
684
685     @Override
686     public void recompute(ReadGraphImpl graph) throws DatabaseException {
687
688         computeForEach(graph, r1(), r2(), this, new TripleIntProcedureAdapter() {
689
690             @Override
691             public void finished(ReadGraphImpl graph) {
692             }
693
694             @Override
695             public void exception(ReadGraphImpl graph, Throwable t) {
696                 new Error("Error in recompute.", t).printStackTrace();
697             }
698
699         });
700
701     }
702
703     @Override
704     public int type() {
705         return RequestFlags.IMMEDIATE_UPDATE;
706     }
707
708
709     @Override
710     boolean isImmutable(ReadGraphImpl graph) {
711         return graph.processor.isImmutable(r1());
712     }
713
714     @Override
715     public void execute(ReadGraphImpl graph, int s, int p, int o) throws DatabaseException {
716         addOrSet(s, p, o);
717     }
718
719     @Override
720     public void finished(ReadGraphImpl graph) throws DatabaseException {
721         setReady();
722     }
723
724     @Override
725     public void exception(ReadGraphImpl graph, Throwable throwable) throws DatabaseException {
726         except(throwable);
727     }
728
729 }