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