001package gudusoft.gsqlparser.catalog.input; 002 003import gudusoft.gsqlparser.EDbVendor; 004import gudusoft.gsqlparser.catalog.diagnostic.CatalogDiagnosticSink; 005import gudusoft.gsqlparser.catalog.input.model.IdentifierConfig; 006import gudusoft.gsqlparser.catalog.runtime.CatalogSearchPath; 007 008import java.util.Collections; 009import java.util.LinkedHashMap; 010import java.util.Map; 011 012/** 013 * Caller-supplied knobs that drive both the input reader and the runtime provider. 014 * 015 * <p>Plan ยง7.1. Immutable; build via {@link #builder()}.</p> 016 * 017 * <p>Defaults match the Phase 1 reference paths: {@code loadingMode=EAGER}, 018 * {@code strict=false}, {@code normalizeOnLoad=true}, includes columns / views / 019 * routines, no caps. {@code identifierConfig} defaults to 020 * {@link IdentifierConfig#defaultsFor(EDbVendor) defaultsFor(vendor)} when unset.</p> 021 */ 022public final class CatalogLoadOptions { 023 024 private final EDbVendor vendor; 025 private final String defaultCatalog; 026 private final String defaultSchema; 027 private final String defaultServer; 028 private final CatalogSearchPath searchPath; 029 private final CatalogLoadingMode loadingMode; 030 private final boolean strict; 031 private final boolean normalizeOnLoad; 032 private final long ttlMillis; 033 private final int maxEagerObjects; 034 private final int maxFetchesPerAnalysis; 035 private final boolean includeColumns; 036 private final boolean includeViews; 037 private final boolean includeRoutines; 038 private final IdentifierConfig identifierConfig; 039 private final boolean explicitIdentifierConfig; 040 private final CatalogDiagnosticSink diagnosticSink; 041 private final Map<String, Object> providerProperties; 042 043 private CatalogLoadOptions(Builder b) { 044 if (b.vendor == null) { 045 throw new IllegalArgumentException("CatalogLoadOptions.vendor is required"); 046 } 047 if (b.ttlMillis < 0) { 048 throw new IllegalArgumentException( 049 "CatalogLoadOptions.ttlMillis must be >= 0 (got " + b.ttlMillis + ")"); 050 } 051 if (b.maxEagerObjects < 0) { 052 throw new IllegalArgumentException( 053 "CatalogLoadOptions.maxEagerObjects must be >= 0 (got " + b.maxEagerObjects + ")"); 054 } 055 if (b.maxFetchesPerAnalysis < 0) { 056 throw new IllegalArgumentException( 057 "CatalogLoadOptions.maxFetchesPerAnalysis must be >= 0 (got " 058 + b.maxFetchesPerAnalysis + ")"); 059 } 060 this.vendor = b.vendor; 061 this.defaultCatalog = b.defaultCatalog; 062 this.defaultSchema = b.defaultSchema; 063 this.defaultServer = b.defaultServer; 064 this.searchPath = b.searchPath != null ? b.searchPath : CatalogSearchPath.empty(); 065 this.loadingMode = b.loadingMode != null ? b.loadingMode : CatalogLoadingMode.EAGER; 066 this.strict = b.strict; 067 this.normalizeOnLoad = b.normalizeOnLoad; 068 this.ttlMillis = b.ttlMillis; 069 this.maxEagerObjects = b.maxEagerObjects; 070 this.maxFetchesPerAnalysis = b.maxFetchesPerAnalysis; 071 this.includeColumns = b.includeColumns; 072 this.includeViews = b.includeViews; 073 this.includeRoutines = b.includeRoutines; 074 // Only auto-default when the caller did not explicitly pass an identifierConfig. 075 // The caller-explicit flag matters because the validator and downstream consumers 076 // need to know whether to prefer the model's IdentifierConfig (when no override was 077 // supplied) or this one. When the caller did supply an explicit config we still 078 // validate vendor consistency. 079 this.explicitIdentifierConfig = b.identifierConfig != null; 080 this.identifierConfig = b.identifierConfig != null 081 ? b.identifierConfig : IdentifierConfig.defaultsFor(b.vendor); 082 if (this.identifierConfig.vendor() != b.vendor) { 083 throw new IllegalArgumentException( 084 "CatalogLoadOptions: identifierConfig.vendor=" + this.identifierConfig.vendor() 085 + " does not match vendor=" + b.vendor); 086 } 087 this.diagnosticSink = b.diagnosticSink; 088 this.providerProperties = Collections.unmodifiableMap( 089 new LinkedHashMap<String, Object>(b.providerProperties)); 090 } 091 092 public static Builder builder() { 093 return new Builder(); 094 } 095 096 public EDbVendor vendor() { 097 return vendor; 098 } 099 100 public String defaultCatalog() { 101 return defaultCatalog; 102 } 103 104 public String defaultSchema() { 105 return defaultSchema; 106 } 107 108 public String defaultServer() { 109 return defaultServer; 110 } 111 112 public CatalogSearchPath searchPath() { 113 return searchPath; 114 } 115 116 public CatalogLoadingMode loadingMode() { 117 return loadingMode; 118 } 119 120 public boolean strict() { 121 return strict; 122 } 123 124 public boolean normalizeOnLoad() { 125 return normalizeOnLoad; 126 } 127 128 public long ttlMillis() { 129 return ttlMillis; 130 } 131 132 public int maxEagerObjects() { 133 return maxEagerObjects; 134 } 135 136 public int maxFetchesPerAnalysis() { 137 return maxFetchesPerAnalysis; 138 } 139 140 public boolean includeColumns() { 141 return includeColumns; 142 } 143 144 public boolean includeViews() { 145 return includeViews; 146 } 147 148 public boolean includeRoutines() { 149 return includeRoutines; 150 } 151 152 public IdentifierConfig identifierConfig() { 153 return identifierConfig; 154 } 155 156 /** 157 * {@code true} when the caller passed an explicit {@link IdentifierConfig} via 158 * {@link Builder#identifierConfig(IdentifierConfig)}; {@code false} when the value 159 * returned by {@link #identifierConfig()} is the auto-filled vendor default. 160 * Consumers that already have a model-supplied {@link IdentifierConfig} can use 161 * this flag to decide whether to prefer the model's value over the auto-fill. 162 */ 163 public boolean hasExplicitIdentifierConfig() { 164 return explicitIdentifierConfig; 165 } 166 167 public CatalogDiagnosticSink diagnosticSink() { 168 return diagnosticSink; 169 } 170 171 public Map<String, Object> providerProperties() { 172 return providerProperties; 173 } 174 175 public static final class Builder { 176 177 private EDbVendor vendor; 178 private String defaultCatalog; 179 private String defaultSchema; 180 private String defaultServer; 181 private CatalogSearchPath searchPath; 182 private CatalogLoadingMode loadingMode; 183 private boolean strict; 184 private boolean normalizeOnLoad = true; 185 private long ttlMillis; 186 private int maxEagerObjects; 187 private int maxFetchesPerAnalysis; 188 private boolean includeColumns = true; 189 private boolean includeViews = true; 190 private boolean includeRoutines = true; 191 private IdentifierConfig identifierConfig; 192 private CatalogDiagnosticSink diagnosticSink; 193 private final Map<String, Object> providerProperties = new LinkedHashMap<String, Object>(); 194 195 private Builder() { 196 } 197 198 public Builder vendor(EDbVendor v) { 199 this.vendor = v; 200 return this; 201 } 202 203 public Builder defaultCatalog(String v) { 204 this.defaultCatalog = v; 205 return this; 206 } 207 208 public Builder defaultSchema(String v) { 209 this.defaultSchema = v; 210 return this; 211 } 212 213 public Builder defaultServer(String v) { 214 this.defaultServer = v; 215 return this; 216 } 217 218 public Builder searchPath(CatalogSearchPath v) { 219 this.searchPath = v; 220 return this; 221 } 222 223 public Builder loadingMode(CatalogLoadingMode v) { 224 this.loadingMode = v; 225 return this; 226 } 227 228 public Builder strict(boolean v) { 229 this.strict = v; 230 return this; 231 } 232 233 public Builder normalizeOnLoad(boolean v) { 234 this.normalizeOnLoad = v; 235 return this; 236 } 237 238 public Builder ttlMillis(long v) { 239 this.ttlMillis = v; 240 return this; 241 } 242 243 public Builder maxEagerObjects(int v) { 244 this.maxEagerObjects = v; 245 return this; 246 } 247 248 public Builder maxFetchesPerAnalysis(int v) { 249 this.maxFetchesPerAnalysis = v; 250 return this; 251 } 252 253 public Builder includeColumns(boolean v) { 254 this.includeColumns = v; 255 return this; 256 } 257 258 public Builder includeViews(boolean v) { 259 this.includeViews = v; 260 return this; 261 } 262 263 public Builder includeRoutines(boolean v) { 264 this.includeRoutines = v; 265 return this; 266 } 267 268 public Builder identifierConfig(IdentifierConfig v) { 269 this.identifierConfig = v; 270 return this; 271 } 272 273 public Builder diagnosticSink(CatalogDiagnosticSink v) { 274 this.diagnosticSink = v; 275 return this; 276 } 277 278 public Builder providerProperty(String key, Object value) { 279 if (key == null) { 280 throw new IllegalArgumentException("providerProperty key may not be null"); 281 } 282 this.providerProperties.put(key, value); 283 return this; 284 } 285 286 public CatalogLoadOptions build() { 287 return new CatalogLoadOptions(this); 288 } 289 } 290}