001package gudusoft.gsqlparser.dlineage.dataflow.model;
002
003import java.nio.charset.StandardCharsets;
004import java.security.MessageDigest;
005import java.security.NoSuchAlgorithmException;
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.List;
009
010/**
011 * An immutable value projection of what one dlineage analysis observed and built, for the SQL-LR producer (plan
012 * {@code docs/designs/data-lineage/09-sqllr-v2-runtime-driven-coverage-plan-zh.md}, Section 3.1).
013 *
014 * <p>The snapshot holds values only: strings, numbers, flags and handles. It never holds a runtime model object, a
015 * parse tree node, a token, a parser, a resolver namespace, a catalog, a {@code Throwable} or anything that reads a
016 * {@code ThreadLocal}, so it stays readable after the analyzer is disposed and from any thread. Records refer to each
017 * other by handle: every object of the analysis (statement, name reference, model node, relationship, parse text) gets
018 * one handle, the first time the recorder sees it, and keeps it. Handle 0 means none.</p>
019 *
020 * <p>Two kinds of values are kept apart. Events ({@link ElementEvent}, {@link ReferenceEvent}, {@link Name},
021 * {@link Statement}) are copied when they happen, before the analysis de-duplicates or rewrites anything:
022 * {@code a + a} is two element events. The topology ({@link Node}, {@link Relation}, {@link Contribution}) is copied
023 * once, when the analysis is complete and before output materialization changes the model: {@code a + a} is one
024 * contribution, which lists both of its events.</p>
025 *
026 * <p>Internal API of the SQL-LR producer.</p>
027 *
028 * @since 4.2.17
029 */
030public final class SqllrSnapshot {
031
032    static <T> List<T> copy(List<T> list) {
033        return list == null || list.isEmpty() ? Collections.<T>emptyList()
034                : Collections.unmodifiableList(new ArrayList<T>(list));
035    }
036
037    private static void field(StringBuilder out, String name, Object value) {
038        out.append(name).append('=');
039        if (value == null) {
040            out.append('~');
041        } else if (value instanceof String) {
042            String s = (String) value;
043            out.append(s.length()).append(':').append(s);
044        } else if (value instanceof Writable) {
045            out.append('{');
046            ((Writable) value).write(out);
047            out.append('}');
048        } else if (value instanceof List) {
049            out.append('[');
050            for (Object o : (List<?>) value) {
051                field(out, "", o);
052                out.append(',');
053            }
054            out.append(']');
055        } else {
056            out.append(value);
057        }
058        out.append(';');
059    }
060
061    /** A record that writes itself canonically, for {@link #digest()}. */
062    interface Writable {
063        void write(StringBuilder out);
064    }
065
066    // ---------------------------------------------------------------------------------------------
067    // Positions in parse texts
068    // ---------------------------------------------------------------------------------------------
069
070    /** A source token as the parse left it when it was copied. */
071    public static final class Token implements Writable {
072        private final long text;
073        private final int position;
074        private final long line;
075        private final long column;
076        private final long offset;
077        private final String spelling;
078        private final String type;
079
080        Token(long text, int position, long line, long column, long offset, String spelling, String type) {
081            this.text = text;
082            this.position = position;
083            this.line = line;
084            this.column = column;
085            this.offset = offset;
086            this.spelling = spelling;
087            this.type = type;
088        }
089
090        /** The handle of the parse text ({@link Text}) the token belongs to, or 0. */
091        public long getText() {
092            return text;
093        }
094
095        /** The index of the token in its parse text. */
096        public int getPosition() {
097            return position;
098        }
099
100        public long getLine() {
101            return line;
102        }
103
104        public long getColumn() {
105            return column;
106        }
107
108        /** The offset of the token in its parse text, as the lexer counted it. */
109        public long getOffset() {
110            return offset;
111        }
112
113        /** The token as written. */
114        public String getSpelling() {
115            return spelling;
116        }
117
118        /** The token type ({@code ETokenType} name). */
119        public String getType() {
120            return type;
121        }
122
123        @Override
124        public void write(StringBuilder out) {
125            field(out, "x", Long.valueOf(text));
126            field(out, "p", Integer.valueOf(position));
127            field(out, "l", Long.valueOf(line));
128            field(out, "c", Long.valueOf(column));
129            field(out, "o", Long.valueOf(offset));
130            field(out, "s", spelling);
131            field(out, "t", type);
132        }
133    }
134
135    /** Where a parse tree node lies: its class and its first and last tokens. */
136    public static final class Anchor implements Writable {
137        private final String nodeClass;
138        private final Token start;
139        private final Token end;
140
141        Anchor(String nodeClass, Token start, Token end) {
142            this.nodeClass = nodeClass;
143            this.start = start;
144            this.end = end;
145        }
146
147        /** The simple name of the node's class. */
148        public String getNodeClass() {
149            return nodeClass;
150        }
151
152        public Token getStart() {
153            return start;
154        }
155
156        public Token getEnd() {
157            return end;
158        }
159
160        @Override
161        public void write(StringBuilder out) {
162            field(out, "k", nodeClass);
163            field(out, "s", start);
164            field(out, "e", end);
165        }
166    }
167
168    /** One parse text (a token list): an input unit's, or one the analysis parsed from dynamic SQL. */
169    public static final class Text implements Writable {
170        private final long handle;
171        private final int unit;
172        private final String text;
173
174        Text(long handle, int unit, String text) {
175            this.handle = handle;
176            this.unit = unit;
177            this.text = text;
178        }
179
180        public long getHandle() {
181            return handle;
182        }
183
184        /** The input unit whose parse made the text, or -1 for a text the analysis parsed itself. */
185        public int getUnit() {
186            return unit;
187        }
188
189        /** The text: its tokens, concatenated. */
190        public String getText() {
191            return text;
192        }
193
194        @Override
195        public void write(StringBuilder out) {
196            field(out, "h", Long.valueOf(handle));
197            field(out, "u", Integer.valueOf(unit));
198            field(out, "t", text);
199        }
200    }
201
202    /** A syntax error of a parsed unit. */
203    public static final class SyntaxError implements Writable {
204        private final String token;
205        private final long line;
206        private final long column;
207        private final String errorType;
208        private final int errorNo;
209        private final String hint;
210
211        SyntaxError(String token, long line, long column, String errorType, int errorNo, String hint) {
212            this.token = token;
213            this.line = line;
214            this.column = column;
215            this.errorType = errorType;
216            this.errorNo = errorNo;
217            this.hint = hint;
218        }
219
220        public String getToken() {
221            return token;
222        }
223
224        public long getLine() {
225            return line;
226        }
227
228        public long getColumn() {
229            return column;
230        }
231
232        public String getErrorType() {
233            return errorType;
234        }
235
236        public int getErrorNo() {
237            return errorNo;
238        }
239
240        public String getHint() {
241            return hint;
242        }
243
244        @Override
245        public void write(StringBuilder out) {
246            field(out, "t", token);
247            field(out, "l", Long.valueOf(line));
248            field(out, "c", Long.valueOf(column));
249            field(out, "k", errorType);
250            field(out, "n", Integer.valueOf(errorNo));
251            field(out, "h", hint);
252        }
253    }
254
255    /** One parsed input unit. */
256    public static final class Unit implements Writable {
257        private final int index;
258        private final int parseResult;
259        private final long text;
260        private final List<Long> statements;
261        private final List<SyntaxError> syntaxErrors;
262        private final List<SyntaxError> recoveredSyntaxErrors;
263
264        Unit(int index, int parseResult, long text, List<Long> statements, List<SyntaxError> syntaxErrors,
265                List<SyntaxError> recoveredSyntaxErrors) {
266            this.index = index;
267            this.parseResult = parseResult;
268            this.text = text;
269            this.statements = copy(statements);
270            this.syntaxErrors = copy(syntaxErrors);
271            this.recoveredSyntaxErrors = copy(recoveredSyntaxErrors);
272        }
273
274        public int getIndex() {
275            return index;
276        }
277
278        public int getParseResult() {
279            return parseResult;
280        }
281
282        /** The handle of the parse text the parser read for the unit. */
283        public long getText() {
284            return text;
285        }
286
287        /** The handles of the unit's top-level statements, in text order. */
288        public List<Long> getStatements() {
289            return statements;
290        }
291
292        public List<SyntaxError> getSyntaxErrors() {
293            return syntaxErrors;
294        }
295
296        public List<SyntaxError> getRecoveredSyntaxErrors() {
297            return recoveredSyntaxErrors;
298        }
299
300        @Override
301        public void write(StringBuilder out) {
302            field(out, "i", Integer.valueOf(index));
303            field(out, "r", Integer.valueOf(parseResult));
304            field(out, "x", Long.valueOf(text));
305            field(out, "s", statements);
306            field(out, "e", syntaxErrors);
307            field(out, "v", recoveredSyntaxErrors);
308        }
309    }
310
311    // ---------------------------------------------------------------------------------------------
312    // Statements and name references (events: copied when first seen)
313    // ---------------------------------------------------------------------------------------------
314
315    /** A statement the analysis worked in, copied when first seen. */
316    public static final class Statement implements Writable {
317        private final long handle;
318        private final String statementClass;
319        private final String statementType;
320        private final long stackParent;
321        private final long parent;
322        private final Anchor anchor;
323        private final int entries;
324        private final boolean analysed;
325        private final int unit;
326        private final boolean primary;
327        private final boolean finished;
328        private final String failureClass;
329        private final String failureMessage;
330
331        Statement(long handle, String statementClass, String statementType, long stackParent, long parent,
332                Anchor anchor, int entries, boolean analysed, int unit, boolean primary, boolean finished,
333                String failureClass, String failureMessage) {
334            this.handle = handle;
335            this.statementClass = statementClass;
336            this.statementType = statementType;
337            this.stackParent = stackParent;
338            this.parent = parent;
339            this.anchor = anchor;
340            this.entries = entries;
341            this.analysed = analysed;
342            this.unit = unit;
343            this.primary = primary;
344            this.finished = finished;
345            this.failureClass = failureClass;
346            this.failureMessage = failureMessage;
347        }
348
349        public long getHandle() {
350            return handle;
351        }
352
353        public String getStatementClass() {
354            return statementClass;
355        }
356
357        /** The statement type ({@code ESqlStatementType} name). */
358        public String getStatementType() {
359            return statementType;
360        }
361
362        /**
363         * The statement the analysis was working in when it entered this one (the entry below it on the analysis's
364         * statement stack), or 0 for a statement analysed at the top.
365         */
366        public long getStackParent() {
367            return stackParent;
368        }
369
370        /** The parse tree's parent statement, or 0. */
371        public long getParent() {
372            return parent;
373        }
374
375        public Anchor getAnchor() {
376            return anchor;
377        }
378
379        /**
380         * How many times the analysis entered the statement ({@code analyzeCustomSqlStmt}), nested statements and
381         * statements of dynamic SQL included; 0 for a statement it only reached (a parse parent, a query's SELECT).
382         */
383        public int getEntries() {
384            return entries;
385        }
386
387        /** Whether the analysis analysed the statement as a top-level statement of its own. */
388        public boolean isAnalysed() {
389            return analysed;
390        }
391
392        /** For an analysed statement, the input unit it was parsed from, or -1. */
393        public int getUnit() {
394            return unit;
395        }
396
397        /** For an analysed statement, whether it is one of its unit's parsed top-level statements. */
398        public boolean isPrimary() {
399            return primary;
400        }
401
402        /** For an analysed statement, whether its analysis ended. */
403        public boolean isFinished() {
404            return finished;
405        }
406
407        /** For an analysed statement whose analysis failed, the exception's class name, else null. */
408        public String getFailureClass() {
409            return failureClass;
410        }
411
412        public String getFailureMessage() {
413            return failureMessage;
414        }
415
416        @Override
417        public void write(StringBuilder out) {
418            field(out, "h", Long.valueOf(handle));
419            field(out, "c", statementClass);
420            field(out, "t", statementType);
421            field(out, "sp", Long.valueOf(stackParent));
422            field(out, "p", Long.valueOf(parent));
423            field(out, "a", anchor);
424            field(out, "en", Integer.valueOf(entries));
425            field(out, "an", Boolean.valueOf(analysed));
426            field(out, "u", Integer.valueOf(unit));
427            field(out, "pr", Boolean.valueOf(primary));
428            field(out, "f", Boolean.valueOf(finished));
429            field(out, "fc", failureClass);
430            field(out, "fm", failureMessage);
431        }
432    }
433
434    /** A name reference the analysis read, copied when first seen. */
435    public static final class Name implements Writable {
436        private final long handle;
437        private final String objectType;
438        private final Anchor anchor;
439        private final String spelling;
440        private final Token server;
441        private final Token database;
442        private final Token schema;
443        private final Token object;
444        private final Token part;
445        private final Token pkg;
446        private final boolean wildcard;
447        private final String resolution;
448        private final String sourceNamespace;
449
450        Name(long handle, String objectType, Anchor anchor, String spelling, Token server, Token database,
451                Token schema, Token object, Token part, Token pkg, boolean wildcard, String resolution,
452                String sourceNamespace) {
453            this.handle = handle;
454            this.objectType = objectType;
455            this.anchor = anchor;
456            this.spelling = spelling;
457            this.server = server;
458            this.database = database;
459            this.schema = schema;
460            this.object = object;
461            this.part = part;
462            this.pkg = pkg;
463            this.wildcard = wildcard;
464            this.resolution = resolution;
465            this.sourceNamespace = sourceNamespace;
466        }
467
468        public long getHandle() {
469            return handle;
470        }
471
472        /** The object type the parse gave the name ({@code EDbObjectType} name). */
473        public String getObjectType() {
474            return objectType;
475        }
476
477        public Anchor getAnchor() {
478            return anchor;
479        }
480
481        /** The name as written: the text of its tokens. */
482        public String getSpelling() {
483            return spelling;
484        }
485
486        public Token getServer() {
487            return server;
488        }
489
490        public Token getDatabase() {
491            return database;
492        }
493
494        public Token getSchema() {
495            return schema;
496        }
497
498        public Token getObject() {
499            return object;
500        }
501
502        public Token getPart() {
503            return part;
504        }
505
506        public Token getPackage() {
507            return pkg;
508        }
509
510        /** Whether the name's column part is a wildcard, decided by the parse (its token type). */
511        public boolean isWildcard() {
512            return wildcard;
513        }
514
515        /** The resolver's status for the name ({@code ResolutionStatus} name), or null when it has none. */
516        public String getResolution() {
517            return resolution;
518        }
519
520        /** For an exact match, the simple class name of the namespace the column comes from, else null. */
521        public String getSourceNamespace() {
522            return sourceNamespace;
523        }
524
525        @Override
526        public void write(StringBuilder out) {
527            field(out, "h", Long.valueOf(handle));
528            field(out, "t", objectType);
529            field(out, "a", anchor);
530            field(out, "s", spelling);
531            field(out, "sv", server);
532            field(out, "db", database);
533            field(out, "sc", schema);
534            field(out, "ob", object);
535            field(out, "pt", part);
536            field(out, "pk", pkg);
537            field(out, "w", Boolean.valueOf(wildcard));
538            field(out, "r", resolution);
539            field(out, "ns", sourceNamespace);
540        }
541    }
542
543    // ---------------------------------------------------------------------------------------------
544    // Topology (copied at the freeze)
545    // ---------------------------------------------------------------------------------------------
546
547    /** A {@code Pair3<Long, Long, String>} position of the model. */
548    public static final class Position implements Writable {
549        private final Long line;
550        private final Long column;
551        private final String hash;
552
553        Position(Long line, Long column, String hash) {
554            this.line = line;
555            this.column = column;
556            this.hash = hash;
557        }
558
559        public Long getLine() {
560            return line;
561        }
562
563        public Long getColumn() {
564            return column;
565        }
566
567        public String getHash() {
568            return hash;
569        }
570
571        @Override
572        public void write(StringBuilder out) {
573            field(out, "l", line);
574            field(out, "c", column);
575            field(out, "h", hash);
576        }
577    }
578
579    /** A function or CASE the analysis built a result set for, described by its parse. */
580    public static final class Call implements Writable {
581        private final Anchor anchor;
582        private final String vendor;
583        private final Token nameToken;
584        private final boolean qualified;
585        private final boolean windowed;
586        private final int arguments;
587        private final boolean starArgument;
588        private final List<Anchor> conditions;
589
590        Call(Anchor anchor, String vendor, Token nameToken, boolean qualified, boolean windowed, int arguments,
591                boolean starArgument, List<Anchor> conditions) {
592            this.anchor = anchor;
593            this.vendor = vendor;
594            this.nameToken = nameToken;
595            this.qualified = qualified;
596            this.windowed = windowed;
597            this.arguments = arguments;
598            this.starArgument = starArgument;
599            this.conditions = copy(conditions);
600        }
601
602        public Anchor getAnchor() {
603            return anchor;
604        }
605
606        public String getVendor() {
607            return vendor;
608        }
609
610        /** The token of the function's own name (its part token, else its object token), or null. */
611        public Token getNameToken() {
612            return nameToken;
613        }
614
615        /** Whether the function name is written with a qualifier (schema, database, server or package). */
616        public boolean isQualified() {
617            return qualified;
618        }
619
620        /** Whether the call has an OVER clause. */
621        public boolean isWindowed() {
622            return windowed;
623        }
624
625        /** The number of arguments, or -1 when the call has no argument list. */
626        public int getArguments() {
627            return arguments;
628        }
629
630        /** Whether the only argument is a wildcard ({@code COUNT(*)}), decided by its token type. */
631        public boolean isStarArgument() {
632            return starArgument;
633        }
634
635        /** For a CASE: the operand of a simple CASE, then each WHEN condition, in order. */
636        public List<Anchor> getConditions() {
637            return conditions;
638        }
639
640        @Override
641        public void write(StringBuilder out) {
642            field(out, "a", anchor);
643            field(out, "v", vendor);
644            field(out, "n", nameToken);
645            field(out, "q", Boolean.valueOf(qualified));
646            field(out, "w", Boolean.valueOf(windowed));
647            field(out, "ar", Integer.valueOf(arguments));
648            field(out, "st", Boolean.valueOf(starArgument));
649            field(out, "cd", conditions);
650        }
651    }
652
653    /**
654     * A node of the runtime model: a table, view, variable, result set, function, column, relation-rows pseudo column,
655     * process or routine, as it stood at the freeze.
656     */
657    public static final class Node implements Writable {
658        private final long handle;
659        private final String modelClass;
660        private final long modelId;
661        private final String kind;
662        private final String setOperator;
663        private final String name;
664        private final String alias;
665        private final String fullName;
666        private final long owner;
667        private final List<Long> members;
668        private final List<String> flags;
669        private final Anchor anchor;
670        private final Anchor columnAnchor;
671        private final Call call;
672        private final long selectStatement;
673        private final Anchor cte;
674        private final Position start;
675        private final Position end;
676        private final boolean wildcard;
677
678        Node(long handle, String modelClass, long modelId, String kind, String setOperator, String name, String alias,
679                String fullName, long owner, List<Long> members, List<String> flags, Anchor anchor,
680                Anchor columnAnchor, Call call, long selectStatement, Anchor cte, Position start, Position end,
681                boolean wildcard) {
682            this.handle = handle;
683            this.modelClass = modelClass;
684            this.modelId = modelId;
685            this.kind = kind;
686            this.setOperator = setOperator;
687            this.name = name;
688            this.alias = alias;
689            this.fullName = fullName;
690            this.owner = owner;
691            this.members = copy(members);
692            this.flags = copy(flags);
693            this.anchor = anchor;
694            this.columnAnchor = columnAnchor;
695            this.call = call;
696            this.selectStatement = selectStatement;
697            this.cte = cte;
698            this.start = start;
699            this.end = end;
700            this.wildcard = wildcard;
701        }
702
703        public long getHandle() {
704            return handle;
705        }
706
707        /** The simple name of the model class ({@code Table}, {@code QueryTable}, {@code ResultColumn}, ...). */
708        public String getModelClass() {
709            return modelClass;
710        }
711
712        /** The model's own id, or -1 when the model has none. */
713        public long getModelId() {
714            return modelId;
715        }
716
717        /**
718         * For a result set, its {@link ResultSetClassifier.Kind} name; for a table, its sub type
719         * ({@code SubType} name) or null; else null.
720         */
721        public String getKind() {
722            return kind;
723        }
724
725        /** For a set operation, its operator ({@code ESetOperatorType} name), else null. */
726        public String getSetOperator() {
727            return setOperator;
728        }
729
730        /** The model's name, as the model holds it (a display value, never an identity). */
731        public String getName() {
732            return name;
733        }
734
735        public String getAlias() {
736            return alias;
737        }
738
739        public String getFullName() {
740            return fullName;
741        }
742
743        /** For a column, the handle of the table or result set holding it; for relation rows, of their holder. */
744        public long getOwner() {
745            return owner;
746        }
747
748        /** For a table or result set, the handles of its columns at the freeze, in order. */
749        public List<Long> getMembers() {
750            return members;
751        }
752
753        /** Boolean properties that hold, by name ({@code constant}, {@code variable}, {@code star}, ...), sorted. */
754        public List<String> getFlags() {
755            return flags;
756        }
757
758        /** The parse tree node the model was built for ({@code getGspObject()}, the table object, ...), or null. */
759        public Anchor getAnchor() {
760            return anchor;
761        }
762
763        /** For a column, its column object, or null. */
764        public Anchor getColumnAnchor() {
765            return columnAnchor;
766        }
767
768        /** For a function result set, its function or CASE, else null. */
769        public Call getCall() {
770            return call;
771        }
772
773        /** For a select result set or set operation, the handle of its SELECT statement, else 0. */
774        public long getSelectStatement() {
775            return selectStatement;
776        }
777
778        /** For a query table over a CTE, the CTE's name, else null. */
779        public Anchor getCte() {
780            return cte;
781        }
782
783        /** For a table column, its start position, else null. */
784        public Position getStart() {
785            return start;
786        }
787
788        public Position getEnd() {
789            return end;
790        }
791
792        /** For a result column, whether its column object is a wildcard, decided by the parse. */
793        public boolean isWildcard() {
794            return wildcard;
795        }
796
797        @Override
798        public void write(StringBuilder out) {
799            field(out, "h", Long.valueOf(handle));
800            field(out, "c", modelClass);
801            field(out, "id", Long.valueOf(modelId));
802            field(out, "k", kind);
803            field(out, "op", setOperator);
804            field(out, "n", name);
805            field(out, "al", alias);
806            field(out, "fn", fullName);
807            field(out, "ow", Long.valueOf(owner));
808            field(out, "m", members);
809            field(out, "f", flags);
810            field(out, "a", anchor);
811            field(out, "ca", columnAnchor);
812            field(out, "call", call);
813            field(out, "sel", Long.valueOf(selectStatement));
814            field(out, "cte", cte);
815            field(out, "s", start);
816            field(out, "e", end);
817            field(out, "w", Boolean.valueOf(wildcard));
818        }
819    }
820
821    /** A transform the analysis attached to a relationship element. */
822    public static final class TransformValue implements Writable {
823        private final String type;
824        private final Anchor code;
825
826        TransformValue(String type, Anchor code) {
827            this.type = type;
828            this.code = code;
829        }
830
831        public String getType() {
832            return type;
833        }
834
835        public Anchor getCode() {
836            return code;
837        }
838
839        @Override
840        public void write(StringBuilder out) {
841            field(out, "t", type);
842            field(out, "c", code);
843        }
844    }
845
846    /** A relationship element: the node it stands for and how the relationship reads it. */
847    public static final class Element implements Writable {
848        private final long node;
849        private final String elementClass;
850        private final String clause;
851        private final int starIndex;
852        private final Integer columnIndex;
853        private final String tableAlias;
854        private final boolean positionUnproven;
855        private final long columnName;
856        private final Position referenceStart;
857        private final Position referenceEnd;
858        private final List<TransformValue> transforms;
859
860        Element(long node, String elementClass, String clause, int starIndex, Integer columnIndex, String tableAlias,
861                boolean positionUnproven, long columnName, Position referenceStart, Position referenceEnd,
862                List<TransformValue> transforms) {
863            this.node = node;
864            this.elementClass = elementClass;
865            this.clause = clause;
866            this.starIndex = starIndex;
867            this.columnIndex = columnIndex;
868            this.tableAlias = tableAlias;
869            this.positionUnproven = positionUnproven;
870            this.columnName = columnName;
871            this.referenceStart = referenceStart;
872            this.referenceEnd = referenceEnd;
873            this.transforms = copy(transforms);
874        }
875
876        /** The handle of the model node, or 0. */
877        public long getNode() {
878            return node;
879        }
880
881        /** The simple name of the element class. */
882        public String getElementClass() {
883            return elementClass;
884        }
885
886        /** Where the relationship reads the element ({@code ESqlClause} name), or null. */
887        public String getClause() {
888            return clause;
889        }
890
891        public int getStarIndex() {
892            return starIndex;
893        }
894
895        public Integer getColumnIndex() {
896            return columnIndex;
897        }
898
899        public String getTableAlias() {
900            return tableAlias;
901        }
902
903        public boolean isPositionUnproven() {
904            return positionUnproven;
905        }
906
907        /** The handle of the name the element carries ({@link Name}), or 0. */
908        public long getColumnName() {
909            return columnName;
910        }
911
912        public Position getReferenceStart() {
913            return referenceStart;
914        }
915
916        public Position getReferenceEnd() {
917            return referenceEnd;
918        }
919
920        /** The transforms; copied only at the freeze (an event carries none). */
921        public List<TransformValue> getTransforms() {
922            return transforms;
923        }
924
925        @Override
926        public void write(StringBuilder out) {
927            field(out, "n", Long.valueOf(node));
928            field(out, "c", elementClass);
929            field(out, "cl", clause);
930            field(out, "si", Integer.valueOf(starIndex));
931            field(out, "ci", columnIndex);
932            field(out, "ta", tableAlias);
933            field(out, "pu", Boolean.valueOf(positionUnproven));
934            field(out, "cn", Long.valueOf(columnName));
935            field(out, "rs", referenceStart);
936            field(out, "re", referenceEnd);
937            field(out, "t", transforms);
938        }
939    }
940
941    /** One element of a frozen relationship (its target, or one de-duplicated source) with the events that gave it. */
942    public static final class Contribution implements Writable {
943        private final Element element;
944        private final List<Long> events;
945
946        Contribution(Element element, List<Long> events) {
947            this.element = element;
948            this.events = copy(events);
949        }
950
951        public Element getElement() {
952            return element;
953        }
954
955        /**
956         * The sequence numbers of the element events ({@link ElementEvent#getSequence()}) the contribution stands for:
957         * a source read twice has two; a target set again has every setting; empty when no event gave the element.
958         */
959        public List<Long> getEvents() {
960            return events;
961        }
962
963        @Override
964        public void write(StringBuilder out) {
965            field(out, "el", element);
966            field(out, "ev", events);
967        }
968    }
969
970    /** A relationship as it stood at the freeze. */
971    public static final class Relation implements Writable {
972        private final long handle;
973        private final long modelId;
974        private final String relationClass;
975        private final String type;
976        private final String effectType;
977        private final String function;
978        private final Contribution target;
979        private final List<Contribution> sources;
980        private final List<Long> supersededTargetEvents;
981
982        Relation(long handle, long modelId, String relationClass, String type, String effectType, String function,
983                Contribution target, List<Contribution> sources, List<Long> supersededTargetEvents) {
984            this.supersededTargetEvents = copy(supersededTargetEvents);
985            this.handle = handle;
986            this.modelId = modelId;
987            this.relationClass = relationClass;
988            this.type = type;
989            this.effectType = effectType;
990            this.function = function;
991            this.target = target;
992            this.sources = copy(sources);
993        }
994
995        public long getHandle() {
996            return handle;
997        }
998
999        public long getModelId() {
1000            return modelId;
1001        }
1002
1003        /** The simple name of the relationship class ({@code DataFlowRelationship}, {@code ImpactRelationship}, ...). */
1004        public String getRelationClass() {
1005            return relationClass;
1006        }
1007
1008        /** The relationship type ({@code RelationshipType} name), or null. */
1009        public String getType() {
1010            return type;
1011        }
1012
1013        public String getEffectType() {
1014            return effectType;
1015        }
1016
1017        public String getFunction() {
1018            return function;
1019        }
1020
1021        /** The target, or null when the relationship has none. */
1022        public Contribution getTarget() {
1023            return target;
1024        }
1025
1026        /** The de-duplicated sources, in the order the relationship holds them. */
1027        public List<Contribution> getSources() {
1028            return sources;
1029        }
1030
1031        /**
1032         * The sequences of target events that set a target the relationship no longer has: a later setting replaced
1033         * it. Their own element is in the event ({@link ElementEvent#getElement()}).
1034         */
1035        public List<Long> getSupersededTargetEvents() {
1036            return supersededTargetEvents;
1037        }
1038
1039        @Override
1040        public void write(StringBuilder out) {
1041            field(out, "h", Long.valueOf(handle));
1042            field(out, "id", Long.valueOf(modelId));
1043            field(out, "c", relationClass);
1044            field(out, "t", type);
1045            field(out, "ef", effectType);
1046            field(out, "fn", function);
1047            field(out, "tg", target);
1048            field(out, "s", sources);
1049            field(out, "sup", supersededTargetEvents);
1050        }
1051    }
1052
1053    // ---------------------------------------------------------------------------------------------
1054    // Events
1055    // ---------------------------------------------------------------------------------------------
1056
1057    /** An element added as a source of a relationship, or set as its target, copied when it happened. */
1058    public static final class ElementEvent implements Writable {
1059        private final long sequence;
1060        private final long relation;
1061        private final boolean target;
1062        private final Element element;
1063        private final long reference;
1064        private final Resolution resolution;
1065        private final long statement;
1066        private final long topStatement;
1067
1068        ElementEvent(long sequence, long relation, boolean target, Element element, long reference,
1069                Resolution resolution, long statement, long topStatement) {
1070            this.sequence = sequence;
1071            this.relation = relation;
1072            this.target = target;
1073            this.element = element;
1074            this.reference = reference;
1075            this.resolution = resolution;
1076            this.statement = statement;
1077            this.topStatement = topStatement;
1078        }
1079
1080        /** How the reference stood when the event happened (it can change later), or null without a reference. */
1081        public Resolution getResolution() {
1082            return resolution;
1083        }
1084
1085        /** The recording order, shared with {@link ReferenceEvent}. */
1086        public long getSequence() {
1087            return sequence;
1088        }
1089
1090        /** The handle of the relationship. */
1091        public long getRelation() {
1092            return relation;
1093        }
1094
1095        public boolean isTarget() {
1096            return target;
1097        }
1098
1099        /** The element as it was when the event happened; it carries no transforms. */
1100        public Element getElement() {
1101            return element;
1102        }
1103
1104        /** The handle of the name reference the analysis was processing ({@link Name}), or 0. */
1105        public long getReference() {
1106            return reference;
1107        }
1108
1109        /** The handle of the innermost statement being analysed, or 0. */
1110        public long getStatement() {
1111            return statement;
1112        }
1113
1114        /** The handle of its top-level statement, or 0. */
1115        public long getTopStatement() {
1116            return topStatement;
1117        }
1118
1119        @Override
1120        public void write(StringBuilder out) {
1121            field(out, "q", Long.valueOf(sequence));
1122            field(out, "r", Long.valueOf(relation));
1123            field(out, "t", Boolean.valueOf(target));
1124            field(out, "el", element);
1125            field(out, "rf", Long.valueOf(reference));
1126            field(out, "res", resolution);
1127            field(out, "s", Long.valueOf(statement));
1128            field(out, "ts", Long.valueOf(topStatement));
1129        }
1130    }
1131
1132    /** A name reference the analysis read for a target, whether or not it added a source. */
1133    public static final class ReferenceEvent implements Writable {
1134        private final long sequence;
1135        private final long reference;
1136        private final Resolution resolution;
1137        private final long target;
1138        private final long statement;
1139        private final long topStatement;
1140
1141        ReferenceEvent(long sequence, long reference, Resolution resolution, long target, long statement,
1142                long topStatement) {
1143            this.sequence = sequence;
1144            this.reference = reference;
1145            this.resolution = resolution;
1146            this.target = target;
1147            this.statement = statement;
1148            this.topStatement = topStatement;
1149        }
1150
1151        /** How the reference stood when it was read. */
1152        public Resolution getResolution() {
1153            return resolution;
1154        }
1155
1156        public long getSequence() {
1157            return sequence;
1158        }
1159
1160        /** The handle of the name ({@link Name}). */
1161        public long getReference() {
1162            return reference;
1163        }
1164
1165        /** The handle of the model node the reference was read for, or 0. */
1166        public long getTarget() {
1167            return target;
1168        }
1169
1170        public long getStatement() {
1171            return statement;
1172        }
1173
1174        public long getTopStatement() {
1175            return topStatement;
1176        }
1177
1178        @Override
1179        public void write(StringBuilder out) {
1180            field(out, "q", Long.valueOf(sequence));
1181            field(out, "rf", Long.valueOf(reference));
1182            field(out, "res", resolution);
1183            field(out, "tg", Long.valueOf(target));
1184            field(out, "s", Long.valueOf(statement));
1185            field(out, "ts", Long.valueOf(topStatement));
1186        }
1187    }
1188
1189    /** A statement of dynamic SQL text, with the statement whose analysis parsed it. */
1190    public static final class Derived implements Writable {
1191        private final long statement;
1192        private final long site;
1193
1194        Derived(long statement, long site) {
1195            this.statement = statement;
1196            this.site = site;
1197        }
1198
1199        public long getStatement() {
1200            return statement;
1201        }
1202
1203        public long getSite() {
1204            return site;
1205        }
1206
1207        @Override
1208        public void write(StringBuilder out) {
1209            field(out, "s", Long.valueOf(statement));
1210            field(out, "site", Long.valueOf(site));
1211        }
1212    }
1213
1214    /** A column built for a field of a STRUCT that a select item constructs. */
1215    public static final class StructField implements Writable {
1216        private final long column;
1217        private final Anchor item;
1218
1219        StructField(long column, Anchor item) {
1220            this.column = column;
1221            this.item = item;
1222        }
1223
1224        public long getColumn() {
1225            return column;
1226        }
1227
1228        public Anchor getItem() {
1229            return item;
1230        }
1231
1232        @Override
1233        public void write(StringBuilder out) {
1234            field(out, "c", Long.valueOf(column));
1235            field(out, "i", item);
1236        }
1237    }
1238
1239
1240    // ---------------------------------------------------------------------------------------------
1241    // Resolution evidence and decisions (events)
1242    // ---------------------------------------------------------------------------------------------
1243
1244    /** One alternative the resolver gave a name: where its column comes from, unflattened. */
1245    public static final class Alternative implements Writable {
1246        private final String namespaceClass;
1247        private final Anchor range;
1248        private final String exposedName;
1249        private final Anchor definition;
1250        private final Anchor override;
1251        private final String confidence;
1252        private final String evidenceType;
1253        private final String evidence;
1254
1255        Alternative(String namespaceClass, Anchor range, String exposedName, Anchor definition, Anchor override,
1256                String confidence, String evidenceType, String evidence) {
1257            this.namespaceClass = namespaceClass;
1258            this.range = range;
1259            this.exposedName = exposedName;
1260            this.definition = definition;
1261            this.override = override;
1262            this.confidence = confidence;
1263            this.evidenceType = evidenceType;
1264            this.evidence = evidence;
1265        }
1266
1267        /** The simple class name of the namespace the column comes from ({@code TableNamespace}, ...). */
1268        public String getNamespaceClass() {
1269            return namespaceClass;
1270        }
1271
1272        /**
1273         * The range variable as written: the table of a table namespace, the FROM item that reads a CTE (else the
1274         * CTE's query), the query of a derived table; null for another namespace.
1275         */
1276        public Anchor getRange() {
1277            return range;
1278        }
1279
1280        /** The column name the namespace exposes. */
1281        public String getExposedName() {
1282            return exposedName;
1283        }
1284
1285        /** Where the column is defined (a select item, a column definition), or null. */
1286        public Anchor getDefinition() {
1287            return definition;
1288        }
1289
1290        /** The table the resolver set over the namespace's own, or null. */
1291        public Anchor getOverride() {
1292            return override;
1293        }
1294
1295        /** The resolver's confidence, as written by {@code String.valueOf(double)}. */
1296        public String getConfidence() {
1297            return confidence;
1298        }
1299
1300        /** The evidence type ({@code EvidenceType} name), or null. */
1301        public String getEvidenceType() {
1302            return evidenceType;
1303        }
1304
1305        public String getEvidence() {
1306            return evidence;
1307        }
1308
1309        @Override
1310        public void write(StringBuilder out) {
1311            field(out, "ns", namespaceClass);
1312            field(out, "r", range);
1313            field(out, "x", exposedName);
1314            field(out, "d", definition);
1315            field(out, "o", override);
1316            field(out, "c", confidence);
1317            field(out, "et", evidenceType);
1318            field(out, "e", evidence);
1319        }
1320    }
1321
1322    /** A name's resolution as it stood at one moment: status, every alternative and the table linked to it. */
1323    public static final class Resolution implements Writable {
1324        private final String status;
1325        private final List<Alternative> alternatives;
1326        private final Anchor sourceTable;
1327
1328        Resolution(String status, List<Alternative> alternatives, Anchor sourceTable) {
1329            this.status = status;
1330            this.alternatives = copy(alternatives);
1331            this.sourceTable = sourceTable;
1332        }
1333
1334        /** The resolver's status ({@code ResolutionStatus} name), or null when the resolver left no result. */
1335        public String getStatus() {
1336            return status;
1337        }
1338
1339        /** The exact match's source, or every candidate of an ambiguous name, in the resolver's order. */
1340        public List<Alternative> getAlternatives() {
1341            return alternatives;
1342        }
1343
1344        /** The table the name was linked to ({@code TObjectName.getSourceTable()}), or null. */
1345        public Anchor getSourceTable() {
1346            return sourceTable;
1347        }
1348
1349        @Override
1350        public void write(StringBuilder out) {
1351            field(out, "s", status);
1352            field(out, "a", alternatives);
1353            field(out, "t", sourceTable);
1354        }
1355    }
1356
1357    /**
1358     * A binding the analysis decided by a fallback (plan 06, Section 3.3, decision points), recorded before it acts on
1359     * it: the reference as it stood, what was selected and why.
1360     */
1361    public static final class Decision implements Writable {
1362        private final long sequence;
1363        private final String id;
1364        private final long reference;
1365        private final Resolution resolution;
1366        private final Anchor selected;
1367        private final long selectedNode;
1368        private final String reason;
1369        private final long statement;
1370
1371        Decision(long sequence, String id, long reference, Resolution resolution, Anchor selected, long selectedNode,
1372                String reason, long statement) {
1373            this.sequence = sequence;
1374            this.id = id;
1375            this.reference = reference;
1376            this.resolution = resolution;
1377            this.selected = selected;
1378            this.selectedNode = selectedNode;
1379            this.reason = reason;
1380            this.statement = statement;
1381        }
1382
1383        /** The recording order, shared with the element and reference events. */
1384        public long getSequence() {
1385            return sequence;
1386        }
1387
1388        /** The decision point ({@code SqllrObservations.DECISION_*}). */
1389        public String getId() {
1390            return id;
1391        }
1392
1393        /** The handle of the name decided for ({@link Name}), or 0. */
1394        public long getReference() {
1395            return reference;
1396        }
1397
1398        /** The name's resolution just before the decision. */
1399        public Resolution getResolution() {
1400            return resolution;
1401        }
1402
1403        /** The parse tree node selected (a FROM item), or null. */
1404        public Anchor getSelected() {
1405            return selected;
1406        }
1407
1408        /** The model node selected, or 0. */
1409        public long getSelectedNode() {
1410            return selectedNode;
1411        }
1412
1413        public String getReason() {
1414            return reason;
1415        }
1416
1417        public long getStatement() {
1418            return statement;
1419        }
1420
1421        @Override
1422        public void write(StringBuilder out) {
1423            field(out, "q", Long.valueOf(sequence));
1424            field(out, "id", id);
1425            field(out, "rf", Long.valueOf(reference));
1426            field(out, "res", resolution);
1427            field(out, "sel", selected);
1428            field(out, "sn", Long.valueOf(selectedNode));
1429            field(out, "why", reason);
1430            field(out, "s", Long.valueOf(statement));
1431        }
1432    }
1433
1434    /** The members of one model registry, in the registry's order (processes, packages, routines, tables, ...). */
1435    public static final class RegistryEntry implements Writable {
1436        private final String category;
1437        private final List<Long> nodes;
1438
1439        RegistryEntry(String category, List<Long> nodes) {
1440            this.category = category;
1441            this.nodes = copy(nodes);
1442        }
1443
1444        public String getCategory() {
1445            return category;
1446        }
1447
1448        public List<Long> getNodes() {
1449            return nodes;
1450        }
1451
1452        @Override
1453        public void write(StringBuilder out) {
1454            field(out, "c", category);
1455            field(out, "n", nodes);
1456        }
1457    }
1458
1459    // ---------------------------------------------------------------------------------------------
1460    // What has no relationship: declarations, layouts, written rows (copied from the parse at the freeze)
1461    // ---------------------------------------------------------------------------------------------
1462
1463    /** A declared parameter or variable, used or not. */
1464    public static final class Declaration implements Writable {
1465        private final long statement;
1466        private final String kind;
1467        private final Anchor name;
1468        private final String mode;
1469        private final Anchor dataType;
1470        private final Anchor defaultValue;
1471        private final Anchor declaration;
1472
1473        Declaration(long statement, String kind, Anchor name, String mode, Anchor dataType, Anchor defaultValue,
1474                Anchor declaration) {
1475            this.statement = statement;
1476            this.kind = kind;
1477            this.name = name;
1478            this.mode = mode;
1479            this.dataType = dataType;
1480            this.defaultValue = defaultValue;
1481            this.declaration = declaration;
1482        }
1483
1484        /** The handle of the statement whose parse holds the declaration. */
1485        public long getStatement() {
1486            return statement;
1487        }
1488
1489        /** {@code PARAMETER} or {@code VARIABLE}. */
1490        public String getKind() {
1491            return kind;
1492        }
1493
1494        public Anchor getName() {
1495            return name;
1496        }
1497
1498        /** A parameter's mode ({@code EParameterMode} name), else null. */
1499        public String getMode() {
1500            return mode;
1501        }
1502
1503        public Anchor getDataType() {
1504            return dataType;
1505        }
1506
1507        /** The default or initial value, or null. */
1508        public Anchor getDefaultValue() {
1509            return defaultValue;
1510        }
1511
1512        /** The whole declaration. */
1513        public Anchor getDeclaration() {
1514            return declaration;
1515        }
1516
1517        @Override
1518        public void write(StringBuilder out) {
1519            field(out, "s", Long.valueOf(statement));
1520            field(out, "k", kind);
1521            field(out, "n", name);
1522            field(out, "m", mode);
1523            field(out, "t", dataType);
1524            field(out, "d", defaultValue);
1525            field(out, "a", declaration);
1526        }
1527    }
1528
1529    /** The output layout of one query block: its items, also when there are none. */
1530    public static final class Layout implements Writable {
1531        private final long statement;
1532        private final Anchor select;
1533        private final String setOperator;
1534        private final int columns;
1535        private final List<String> kinds;
1536        private final List<Anchor> items;
1537        private final boolean into;
1538
1539        Layout(long statement, Anchor select, String setOperator, int columns, List<String> kinds, List<Anchor> items,
1540                boolean into) {
1541            this.statement = statement;
1542            this.select = select;
1543            this.setOperator = setOperator;
1544            this.columns = columns;
1545            this.kinds = copy(kinds);
1546            this.items = copy(items);
1547            this.into = into;
1548        }
1549
1550        /** The handle of the statement whose parse holds the query. */
1551        public long getStatement() {
1552            return statement;
1553        }
1554
1555        public Anchor getSelect() {
1556            return select;
1557        }
1558
1559        /** For a set operation, its operator ({@code ESetOperatorType} name); its operands have their own layouts. */
1560        public String getSetOperator() {
1561            return setOperator;
1562        }
1563
1564        /** The number of select items: 0 for {@code SELECT FROM t} (complete and empty), -1 for a set operation. */
1565        public int getColumns() {
1566            return columns;
1567        }
1568
1569        /** Per item: {@code WILDCARD} (decided by the parse) or the expression type ({@code EExpressionType}). */
1570        public List<String> getKinds() {
1571            return kinds;
1572        }
1573
1574        public List<Anchor> getItems() {
1575            return items;
1576        }
1577
1578        /** Whether the query has an INTO clause. */
1579        public boolean isInto() {
1580            return into;
1581        }
1582
1583        @Override
1584        public void write(StringBuilder out) {
1585            field(out, "s", Long.valueOf(statement));
1586            field(out, "q", select);
1587            field(out, "op", setOperator);
1588            field(out, "n", Integer.valueOf(columns));
1589            field(out, "k", kinds);
1590            field(out, "i", items);
1591            field(out, "into", Boolean.valueOf(into));
1592        }
1593    }
1594
1595    /** One row an INSERT writes from a VALUES list (or DEFAULT VALUES), item by item. */
1596    public static final class WriteRow implements Writable {
1597        private final long statement;
1598        private final Anchor target;
1599        private final String insertSource;
1600        private final int targetColumns;
1601        private final int row;
1602        private final List<String> kinds;
1603        private final List<Anchor> items;
1604
1605        WriteRow(long statement, Anchor target, String insertSource, int targetColumns, int row, List<String> kinds,
1606                List<Anchor> items) {
1607            this.statement = statement;
1608            this.target = target;
1609            this.insertSource = insertSource;
1610            this.targetColumns = targetColumns;
1611            this.row = row;
1612            this.kinds = copy(kinds);
1613            this.items = copy(items);
1614        }
1615
1616        public long getStatement() {
1617            return statement;
1618        }
1619
1620        /** The target table as written. */
1621        public Anchor getTarget() {
1622            return target;
1623        }
1624
1625        /** The kind of source ({@code EInsertSource} name). */
1626        public String getInsertSource() {
1627            return insertSource;
1628        }
1629
1630        /** The number of target columns listed, or -1 when the statement lists none. */
1631        public int getTargetColumns() {
1632            return targetColumns;
1633        }
1634
1635        /** The row's position in the VALUES list, from 0; -1 for DEFAULT VALUES. */
1636        public int getRow() {
1637            return row;
1638        }
1639
1640        /** Per item: {@code DEFAULT} (the keyword) or the expression type ({@code EExpressionType}). */
1641        public List<String> getKinds() {
1642            return kinds;
1643        }
1644
1645        public List<Anchor> getItems() {
1646            return items;
1647        }
1648
1649        @Override
1650        public void write(StringBuilder out) {
1651            field(out, "s", Long.valueOf(statement));
1652            field(out, "t", target);
1653            field(out, "src", insertSource);
1654            field(out, "tc", Integer.valueOf(targetColumns));
1655            field(out, "r", Integer.valueOf(row));
1656            field(out, "k", kinds);
1657            field(out, "i", items);
1658        }
1659    }
1660
1661    /**
1662     * A column reference of the parse, whether the analysis read it or not (a failed read leaves no event): its name
1663     * and its resolution at the freeze.
1664     */
1665    public static final class ColumnReference implements Writable {
1666        private final long statement;
1667        private final long name;
1668        private final Resolution resolution;
1669
1670        ColumnReference(long statement, long name, Resolution resolution) {
1671            this.statement = statement;
1672            this.name = name;
1673            this.resolution = resolution;
1674        }
1675
1676        public long getStatement() {
1677            return statement;
1678        }
1679
1680        /** The handle of the name ({@link Name}). */
1681        public long getName() {
1682            return name;
1683        }
1684
1685        public Resolution getResolution() {
1686            return resolution;
1687        }
1688
1689        @Override
1690        public void write(StringBuilder out) {
1691            field(out, "s", Long.valueOf(statement));
1692            field(out, "n", Long.valueOf(name));
1693            field(out, "res", resolution);
1694        }
1695    }
1696
1697    // ---------------------------------------------------------------------------------------------
1698
1699    private final List<Text> texts;
1700    private final List<Unit> units;
1701    private final List<Statement> statements;
1702    private final List<Name> names;
1703    private final List<Node> nodes;
1704    private final List<Relation> relations;
1705    private final List<ElementEvent> elementEvents;
1706    private final List<ReferenceEvent> referenceEvents;
1707    private final List<Derived> derived;
1708    private final List<StructField> structFields;
1709    private final List<Decision> decisions;
1710    private final List<RegistryEntry> registry;
1711    private final List<Declaration> declarations;
1712    private final List<Layout> layouts;
1713    private final List<WriteRow> writeRows;
1714    private final List<ColumnReference> columnReferences;
1715    private final String projectionFailure;
1716
1717    SqllrSnapshot(List<Text> texts, List<Unit> units, List<Statement> statements, List<Name> names, List<Node> nodes,
1718            List<Relation> relations, List<ElementEvent> elementEvents, List<ReferenceEvent> referenceEvents,
1719            List<Derived> derived, List<StructField> structFields, List<Decision> decisions,
1720            List<RegistryEntry> registry, List<Declaration> declarations, List<Layout> layouts,
1721            List<WriteRow> writeRows, List<ColumnReference> columnReferences, String projectionFailure) {
1722        this.columnReferences = copy(columnReferences);
1723        this.decisions = copy(decisions);
1724        this.registry = copy(registry);
1725        this.declarations = copy(declarations);
1726        this.layouts = copy(layouts);
1727        this.writeRows = copy(writeRows);
1728        this.projectionFailure = projectionFailure;
1729        this.texts = copy(texts);
1730        this.units = copy(units);
1731        this.statements = copy(statements);
1732        this.names = copy(names);
1733        this.nodes = copy(nodes);
1734        this.relations = copy(relations);
1735        this.elementEvents = copy(elementEvents);
1736        this.referenceEvents = copy(referenceEvents);
1737        this.derived = copy(derived);
1738        this.structFields = copy(structFields);
1739    }
1740
1741    /** Every parse text a copied token belongs to, by handle. */
1742    public List<Text> getTexts() {
1743        return texts;
1744    }
1745
1746    /** The parsed units, in analysis order. */
1747    public List<Unit> getUnits() {
1748        return units;
1749    }
1750
1751    /** Every statement the analysis worked in, in handle order. */
1752    public List<Statement> getStatements() {
1753        return statements;
1754    }
1755
1756    /** Every name reference an event carries, in handle order. */
1757    public List<Name> getNames() {
1758        return names;
1759    }
1760
1761    /**
1762     * Every model node: those the model registers for output (processes, routines, tables, views, result sets), then
1763     * any other node an element or member reaches, in handle order.
1764     */
1765    public List<Node> getNodes() {
1766        return nodes;
1767    }
1768
1769    /** Every relationship at the freeze, in creation order. */
1770    public List<Relation> getRelations() {
1771        return relations;
1772    }
1773
1774    /** Every element event, in recording order. */
1775    public List<ElementEvent> getElementEvents() {
1776        return elementEvents;
1777    }
1778
1779    /** Every reference event, in recording order. */
1780    public List<ReferenceEvent> getReferenceEvents() {
1781        return referenceEvents;
1782    }
1783
1784    public List<Derived> getDerived() {
1785        return derived;
1786    }
1787
1788    public List<StructField> getStructFields() {
1789        return structFields;
1790    }
1791
1792    /** Every fallback decision, in recording order. */
1793    public List<Decision> getDecisions() {
1794        return decisions;
1795    }
1796
1797    /** The model's registries, each in its own order; a node may also be reached only through a relationship. */
1798    public List<RegistryEntry> getRegistry() {
1799        return registry;
1800    }
1801
1802    /** Every declared parameter and variable of the analysed statements, used or not, in text order. */
1803    public List<Declaration> getDeclarations() {
1804        return declarations;
1805    }
1806
1807    /** The output layout of every query block of the analysed statements, in text order. */
1808    public List<Layout> getLayouts() {
1809        return layouts;
1810    }
1811
1812    /** Every row an INSERT of the analysed statements writes from VALUES (or DEFAULT VALUES), in text order. */
1813    public List<WriteRow> getWriteRows() {
1814        return writeRows;
1815    }
1816
1817    /** Every column reference of the analysed statements' parse, read or not, in text order. */
1818    public List<ColumnReference> getColumnReferences() {
1819        return columnReferences;
1820    }
1821
1822    /**
1823     * Why copying the declarations, layouts, written rows and column references from the parse stopped (they are then
1824     * incomplete), or null.
1825     */
1826    public String getProjectionFailure() {
1827        return projectionFailure;
1828    }
1829
1830    /** The snapshot written canonically: equal snapshots, and only equal ones, write the same text. */
1831    public String canonical() {
1832        StringBuilder out = new StringBuilder();
1833        field(out, "texts", texts);
1834        field(out, "units", units);
1835        field(out, "statements", statements);
1836        field(out, "names", names);
1837        field(out, "nodes", nodes);
1838        field(out, "relations", relations);
1839        field(out, "elementEvents", elementEvents);
1840        field(out, "referenceEvents", referenceEvents);
1841        field(out, "derived", derived);
1842        field(out, "structFields", structFields);
1843        field(out, "decisions", decisions);
1844        field(out, "registry", registry);
1845        field(out, "declarations", declarations);
1846        field(out, "layouts", layouts);
1847        field(out, "writeRows", writeRows);
1848        field(out, "columnReferences", columnReferences);
1849        field(out, "projectionFailure", projectionFailure);
1850        return out.toString();
1851    }
1852
1853    /** The SHA-256 of {@link #canonical()}, in lower-case hex. */
1854    public String digest() {
1855        try {
1856            byte[] d = MessageDigest.getInstance("SHA-256").digest(canonical().getBytes(StandardCharsets.UTF_8));
1857            StringBuilder hex = new StringBuilder();
1858            for (byte b : d) {
1859                hex.append(Character.forDigit((b >> 4) & 0xF, 16)).append(Character.forDigit(b & 0xF, 16));
1860            }
1861            return hex.toString();
1862        } catch (NoSuchAlgorithmException e) {
1863            throw new IllegalStateException(e);
1864        }
1865    }
1866}