001package gudusoft.gsqlparser.dlineage.dynamicsql; 002 003/** 004 * Immutable rollout and resource options for interprocedural stored-procedure 005 * lineage. 006 * 007 * <p>The default is deliberately {@link Mode#LEGACY}: constructing an option 008 * object can never opt a caller into summary extraction or change the existing 009 * {@code DataFlowAnalyzer} result. {@link Mode#SHADOW} computes the isolated 010 * summary side model for comparison. {@link Mode#ENHANCED} retains the public 011 * rollout shape but currently exposes the same observation-only candidates; 012 * no mode publishes applicable additions until call validity is proven. 013 */ 014public final class ProceduralLineageOptions { 015 016 public enum Mode { 017 /** Do not extract or consult routine summaries. */ 018 LEGACY, 019 /** Compute summaries in an isolated side model; apply nothing. */ 020 SHADOW, 021 /** Compute the enhanced candidate pipeline; publication remains 022 * observation-only until the application gate is proven. */ 023 ENHANCED 024 } 025 026 private static final int DEFAULT_MAX_OBSERVED_FUNCTIONS = 16; 027 028 private final Mode mode; 029 /** Zero means the design formula: max(4, 2 * SCC size). */ 030 private final int maxSccIterations; 031 private final int maxObservedFunctions; 032 033 private ProceduralLineageOptions(Builder builder) { 034 this.mode = builder.mode; 035 this.maxSccIterations = builder.maxSccIterations; 036 this.maxObservedFunctions = builder.maxObservedFunctions; 037 } 038 039 /** Safe default: no summary work and no change to legacy behavior. */ 040 public static ProceduralLineageOptions legacy() { 041 return builder().mode(Mode.LEGACY).build(); 042 } 043 044 public static ProceduralLineageOptions shadow() { 045 return builder().mode(Mode.SHADOW).build(); 046 } 047 048 public static ProceduralLineageOptions enhanced() { 049 return builder().mode(Mode.ENHANCED).build(); 050 } 051 052 public static Builder builder() { 053 return new Builder(); 054 } 055 056 public Mode getMode() { return mode; } 057 058 /** 059 * Configured hard cap, or zero when the SCC-size formula is used. 060 * Explicit positive caps are primarily for bounded deployments and tests; 061 * hitting one keeps accumulated summary-local observation candidates and 062 * marks the component partial. It does not certify application safety. 063 */ 064 public int getMaxSccIterations() { return maxSccIterations; } 065 066 /** Maximum advisory observed function names before widening to TOP. */ 067 public int getMaxObservedFunctions() { return maxObservedFunctions; } 068 069 /** @deprecated the metadata is an unordered observed-function set, not 070 * an ordered transform descriptor. */ 071 @Deprecated 072 public int getMaxTransformDescriptors() { return maxObservedFunctions; } 073 074 int iterationCapForScc(int size) { 075 if (maxSccIterations > 0) { 076 return maxSccIterations; 077 } 078 return Math.max(4, 2 * Math.max(1, size)); 079 } 080 081 public static final class Builder { 082 private Mode mode = Mode.LEGACY; 083 private int maxSccIterations; 084 private int maxObservedFunctions = DEFAULT_MAX_OBSERVED_FUNCTIONS; 085 086 private Builder() { 087 } 088 089 public Builder mode(Mode mode) { 090 if (mode == null) { 091 throw new IllegalArgumentException("mode must not be null"); 092 } 093 this.mode = mode; 094 return this; 095 } 096 097 /** 098 * Set an explicit positive cap; zero restores the SCC-size formula. 099 */ 100 public Builder maxSccIterations(int maxSccIterations) { 101 if (maxSccIterations < 0) { 102 throw new IllegalArgumentException( 103 "maxSccIterations must be zero or positive"); 104 } 105 this.maxSccIterations = maxSccIterations; 106 return this; 107 } 108 109 public Builder maxObservedFunctions(int maxObservedFunctions) { 110 if (maxObservedFunctions < 1) { 111 throw new IllegalArgumentException( 112 "maxObservedFunctions must be positive"); 113 } 114 this.maxObservedFunctions = maxObservedFunctions; 115 return this; 116 } 117 118 /** @deprecated use {@link #maxObservedFunctions(int)}. */ 119 @Deprecated 120 public Builder maxTransformDescriptors(int maxTransformDescriptors) { 121 return maxObservedFunctions(maxTransformDescriptors); 122 } 123 124 public ProceduralLineageOptions build() { 125 return new ProceduralLineageOptions(this); 126 } 127 } 128}