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}