001package gudusoft.gsqlparser.dlineage.dynamicsql; 002 003/** 004 * Where the parameter values a materialized dynamic SQL site was evaluated with came from (Mantis 4962): none (the 005 * procedure on its own, literal defaults only), the caller of the explicit API, a preset in the catalog, or a call 006 * of the procedure in its own file or in another unit of a multi-file analysis. When the bindings cover every call of 007 * the procedure in the analysis, a site is published with the bound values only: the unbound evaluation is then what 008 * a caller nobody wrote would see. 009 */ 010public final class BindingSource { 011 012 public enum Kind { EXPLICIT, PRESET, SAME_FILE, CROSS_FILE, NONE } 013 014 /** The procedure evaluated on its own. */ 015 public static final BindingSource NONE = new BindingSource(Kind.NONE, null, -1L, null, null); 016 017 private final Kind kind; 018 private final String callerUnit; 019 private final long callerLine; 020 private final String bindingHash; 021 private final String description; 022 023 private BindingSource(Kind kind, String callerUnit, long callerLine, String bindingHash, String description) { 024 this.kind = kind; 025 this.callerUnit = callerUnit; 026 this.callerLine = callerLine; 027 this.bindingHash = bindingHash; 028 this.description = description; 029 } 030 031 /** Bindings the caller of the explicit API supplied. */ 032 public static BindingSource explicit(String bindingHash) { 033 return new BindingSource(Kind.EXPLICIT, null, -1L, bindingHash, "parameters bound by the caller"); 034 } 035 036 /** Values preset in the catalog for the parameters of {@code routine} ({@code TSQLEnv}, metadata JSON). */ 037 public static BindingSource preset(String routine, String bindingHash) { 038 return new BindingSource(Kind.PRESET, null, -1L, bindingHash, 039 "parameters preset in the catalog for " + routine); 040 } 041 042 /** Bindings a call of the procedure in its own file supplied. */ 043 public static BindingSource sameFile(long callerLine, String bindingHash) { 044 return new BindingSource(Kind.SAME_FILE, null, callerLine, bindingHash, 045 "parameters bound by the call in the same file at line " + callerLine); 046 } 047 048 /** Bindings a call of the procedure in another unit of the analysis supplied. */ 049 public static BindingSource crossFile(String callerUnit, long callerLine, String bindingHash) { 050 return new BindingSource(Kind.CROSS_FILE, callerUnit, callerLine, bindingHash, 051 "parameters bound by the call in " + callerUnit + " at line " + callerLine); 052 } 053 054 /** 055 * {@link #sameFile(long, String)} for a call in the body of {@code routine} (null: in a batch), which may not run 056 * on the path its values come from when {@code mayNotRun} (Mantis 4962). 057 */ 058 public static BindingSource sameFile(long callerLine, String bindingHash, String routine, boolean mayNotRun) { 059 return new BindingSource(Kind.SAME_FILE, null, callerLine, bindingHash, 060 "parameters bound by the call in the same file at line " + callerLine + where(routine, mayNotRun)); 061 } 062 063 /** {@link #crossFile(String, long, String)} for a call in the body of {@code routine}, or one that may not run. */ 064 public static BindingSource crossFile(String callerUnit, long callerLine, String bindingHash, String routine, 065 boolean mayNotRun) { 066 return new BindingSource(Kind.CROSS_FILE, callerUnit, callerLine, bindingHash, 067 "parameters bound by the call in " + callerUnit + " at line " + callerLine + where(routine, mayNotRun)); 068 } 069 070 private static String where(String routine, boolean mayNotRun) { 071 return (routine == null ? "" : ", in " + routine) + (mayNotRun ? " (the call may not run)" : ""); 072 } 073 074 /** 075 * This binding, also supplied by {@code other} (two calls with the same values): the same values, a description 076 * that names both. 077 */ 078 public BindingSource alsoAt(BindingSource other) { 079 if (other == null || other.description == null || other == this) { 080 return this; 081 } 082 if (description == null) { 083 return new BindingSource(kind, callerUnit, callerLine, bindingHash, other.description); 084 } 085 java.util.List<String> named = new java.util.ArrayList<String>(java.util.Arrays.asList(description.split("; "))); 086 for (String part : other.description.split("; ")) { 087 if (!named.contains(part)) { 088 named.add(part); 089 } 090 } 091 String combined = String.join("; ", named); 092 return combined.equals(description) ? this 093 : new BindingSource(kind, callerUnit, callerLine, bindingHash, combined); 094 } 095 096 public Kind getKind() { 097 return kind; 098 } 099 100 /** The analysis unit of the call, for {@link Kind#CROSS_FILE}; null otherwise. */ 101 public String getCallerUnit() { 102 return callerUnit; 103 } 104 105 /** The line of the call, for {@link Kind#SAME_FILE} and {@link Kind#CROSS_FILE}; -1 otherwise. */ 106 public long getCallerLine() { 107 return callerLine; 108 } 109 110 /** A digest of the bound values; null for {@link Kind#NONE}. */ 111 public String getBindingHash() { 112 return bindingHash; 113 } 114 115 /** What a site's diagnostic says of the binding; null for {@link Kind#NONE}. */ 116 public String getDescription() { 117 return description; 118 } 119 120 @Override 121 public String toString() { 122 return description == null ? "no binding" : description; 123 } 124}