001package gudusoft.gsqlparser.dlineage.dynamicsql; 002 003/** 004 * Resource bounds for {@code resolveDynamicSqlLineage}. 005 * 006 * <p>The evaluated dynamic-SQL string is effectively attacker-controlled (it is 007 * built from runtime parameter values), so every dimension that an adversarial 008 * or pathological procedure could blow up is capped. When a bound is exceeded 009 * the affected site fails <em>closed</em> to an unresolved diagnostic — never a 010 * hang, never an OOM, never a fabricated edge. 011 */ 012public final class DynamicLineageOptions { 013 014 private int maxResolvedSqlLength = 1_000_000; // chars in a single materialized statement string 015 private int maxSites = 256; // dynamic-SQL EXEC sites resolved per call 016 private int maxBindings = 1024; // parameter bindings accepted per call 017 private int maxValueSetSize = 8; // correlated constant-relation variants 018 // literal rows retained per table variable or #temp table: a configuration registry a call binds is looked up 019 // by its WHERE, so its size costs little; 64 refused a 100-row registry even when bound (Mantis 4962, spec §9) 020 private int maxConstRelationRows = 1024; 021 private int maxExpansionDepth = 256; // function/CASE nesting depth before failing closed 022 private long timeoutMillis = 10_000; // wall-clock budget for the whole resolve call 023 private boolean showImplicitSchema = true; // qualify unqualified names with currentDatabase/defaultSchema 024 private boolean caseSensitiveCompare = false; // literal relation queries compare strings case-sensitively 025 private DynamicSqlTrustMode trustMode = DynamicSqlTrustMode.LEGACY; 026 027 public static DynamicLineageOptions createDefault() { 028 return new DynamicLineageOptions(); 029 } 030 031 public int getMaxResolvedSqlLength() { 032 return maxResolvedSqlLength; 033 } 034 035 public DynamicLineageOptions setMaxResolvedSqlLength(int v) { 036 this.maxResolvedSqlLength = v; 037 return this; 038 } 039 040 public int getMaxSites() { 041 return maxSites; 042 } 043 044 public DynamicLineageOptions setMaxSites(int v) { 045 this.maxSites = v; 046 return this; 047 } 048 049 public int getMaxBindings() { 050 return maxBindings; 051 } 052 053 public DynamicLineageOptions setMaxBindings(int v) { 054 this.maxBindings = v; 055 return this; 056 } 057 058 /** 059 * Maximum number of distinct statically-enumerated values (or correlated 060 * row tuples) retained by the dynamic-SQL evaluator. An attempted union or 061 * product above this bound widens to today's UNKNOWN result; it is never 062 * silently truncated. 063 */ 064 public int getMaxValueSetSize() { 065 return maxValueSetSize; 066 } 067 068 public DynamicLineageOptions setMaxValueSetSize(int v) { 069 this.maxValueSetSize = v; 070 return this; 071 } 072 073 /** 074 * Maximum number of literal rows retained for one T-SQL table variable or local temporary table (default 1024); 075 * an INSERT beyond it makes the relation opaque. 076 */ 077 public int getMaxConstRelationRows() { 078 return maxConstRelationRows; 079 } 080 081 public DynamicLineageOptions setMaxConstRelationRows(int v) { 082 this.maxConstRelationRows = v; 083 return this; 084 } 085 086 /** Compatibility alias for callers that use the longer relation-cap name. */ 087 public int getMaxConstantRelationRows() { 088 return getMaxConstRelationRows(); 089 } 090 091 public DynamicLineageOptions setMaxConstantRelationRows(int v) { 092 return setMaxConstRelationRows(v); 093 } 094 095 public int getMaxExpansionDepth() { 096 return maxExpansionDepth; 097 } 098 099 public DynamicLineageOptions setMaxExpansionDepth(int v) { 100 this.maxExpansionDepth = v; 101 return this; 102 } 103 104 public long getTimeoutMillis() { 105 return timeoutMillis; 106 } 107 108 public DynamicLineageOptions setTimeoutMillis(long v) { 109 this.timeoutMillis = v; 110 return this; 111 } 112 113 public boolean isShowImplicitSchema() { 114 return showImplicitSchema; 115 } 116 117 public DynamicLineageOptions setShowImplicitSchema(boolean v) { 118 this.showImplicitSchema = v; 119 return this; 120 } 121 122 /** 123 * Whether a query over a literal relation (a table variable or temporary table the procedure fills with literal 124 * rows) compares strings case-sensitively. Default false: SQL Server's default {@code _CI_AS} collations compare 125 * case-insensitively; trailing spaces are ignored either way (Mantis 4962). 126 */ 127 public boolean isCaseSensitiveCompare() { 128 return caseSensitiveCompare; 129 } 130 131 public DynamicLineageOptions setCaseSensitiveCompare(boolean v) { 132 this.caseSensitiveCompare = v; 133 return this; 134 } 135 136 /** 137 * Controls observation of edges from a materialized string that still has 138 * unresolved fragments. Both modes preserve publication; SHADOW adds 139 * diagnostics. The default is {@link DynamicSqlTrustMode#LEGACY} for 140 * backwards compatibility. 141 */ 142 public DynamicSqlTrustMode getTrustMode() { 143 return trustMode; 144 } 145 146 public DynamicLineageOptions setTrustMode(DynamicSqlTrustMode v) { 147 this.trustMode = v == null ? DynamicSqlTrustMode.LEGACY : v; 148 return this; 149 } 150}