001package gudusoft.gsqlparser.dlineage.dataflow.model; 002 003import java.util.Arrays; 004import java.util.HashSet; 005import java.util.Set; 006 007import gudusoft.gsqlparser.EDbVendor; 008import gudusoft.gsqlparser.dlineage.dataflow.listener.DataFlowHandleListener; 009import gudusoft.gsqlparser.dlineage.dynamicsql.DynamicSqlTrustMode; 010 011public class Option implements Cloneable { 012 013 private EDbVendor vendor; 014 private EDbVendor powerQueryInnerVendor; 015 private DataFlowHandleListener handleListener; 016 private boolean simpleOutput; 017 private boolean textFormat = false; 018 private boolean showJoin = false; 019 private boolean ignoreRecordSet = false; 020 private boolean ignoreTemporaryTable = false; 021 private boolean ignoreTopSelect = false; 022 private boolean ignoreUnusedSynonym = true; 023 private boolean showCallRelation = false; 024 private boolean simpleShowFunction = false; 025 private boolean simpleShowSynonym = false; 026 private boolean simpleShowUdfFunctionOnly = false; 027 private boolean simpleShowCursor = false; 028 private boolean simpleShowVariable = false; 029 private boolean simpleRetainIntermediate = false; 030 private boolean simpleShowTopSelectResultSet = false; 031 private boolean linkOrphanColumnToFirstTable = false; 032 private boolean ignoreCoordinate = false; 033 private boolean transform = false; 034 private boolean transformCoordinate = false; 035 /** 036 * Whether SQL Server parsers created by {@code DataFlowAnalyzer} accept 037 * colon-prefixed bind variables such as {@code :name}, {@code :1}, and 038 * {@code :@name}. This compatibility extension is disabled by default. 039 */ 040 private boolean enableMssqlColonBindVariables = false; 041 /** 042 * Whether {@code DataFlowAnalyzer} should collect the immutable semantic 043 * sidecar consumed by the SLPC adapter. 044 * 045 * <p>This is deliberately opt-in. The established dlineage XML/JSON model 046 * remains the default execution path, with no AST traversal or sidecar 047 * bookkeeping added for callers that do not request SLPC projection. 048 * Parallel analysis currently forces this option off because merged legacy 049 * IDs are remapped and cannot yet be correlated safely to worker evidence.</p> 050 */ 051 private boolean collectAuthoritativeLineageEvidence = false; 052 private boolean showImplicitSchema = false; 053 private boolean showCountTableColumn = true; 054 private boolean showConstantTable = false; 055 private boolean showCaseWhenAsDirect = true; 056 private String filePathDatabase; 057 private String filePathSchema; 058 private long startId = 0; 059 private boolean output = true; 060 private boolean traceSQL = false; 061 private boolean traceProcedure = false; 062 private int parallel = Runtime.getRuntime().availableProcessors() / 2 - 1; 063 private String defaultServer; 064 private String defaultDatabase; 065 private String defaultSchema; 066 private boolean showERDiagram = false; 067 private Set<ResultSetType> targetResultSetTypes = new HashSet<ResultSetType>(); 068 private Set<String> filterRelationTypes = new HashSet<String>(); 069 private Set<String> simpleShowRelationTypes = new HashSet<String>(); 070 private boolean sqlflowIgnoreFunction = false; 071 private DynamicSqlTrustMode dynamicSqlTrustMode = DynamicSqlTrustMode.LEGACY; 072 /** Whether execution statements may analyze embedded/generated SQL text. 073 * Defaults true for compatibility. Routine-summary extraction disables 074 * it so dynamic relationships cannot lose their site provenance when 075 * collapsed into an ordinary base-summary edge. */ 076 private boolean analyzeDynamicSql = true; 077 078 private Set<String> excludedProcedureNames = new HashSet<String>(); 079 080 /** 081 * Wildcard patterns to exclude procedures from analysis. 082 * <p> 083 * Supports the following wildcard characters: 084 * <ul> 085 * <li><code>*</code> - Matches any sequence of characters (e.g., <code>SCHEMA1.*</code> matches all procedures in SCHEMA1)</li> 086 * <li><code>?</code> - Matches any single character (e.g., <code>SCHEMA?.PROC?</code> matches SCHEMA1.PROC1, SCHEMA2.PROC2, etc.)</li> 087 * <li><code>.</code> - Reserved as schema/procedure name separator (e.g., <code>SCHEMA.PROC</code> matches a two-segment qualified name)</li> 088 * </ul> 089 * <p> 090 * Examples: 091 * <ul> 092 * <li><code>"SCHEMA1.*"</code> - Excludes all procedures in SCHEMA1</li> 093 * <li><code>"*.SP_*"</code> - Excludes all procedures starting with SP_ in any schema</li> 094 * <li><code>"*_TEST"</code> - Excludes all procedures ending with _TEST in any schema</li> 095 * <li><code>"SCHEMA?.PROC?"</code> - Excludes procedures like SCHEMA1.PROC1, SCHEMA2.PROC2, etc.</li> 096 * <li><code>"DB.SCHEMA.PROC"</code> - Excludes a specific three-segment procedure</li> 097 * </ul> 098 * <p> 099 * Note: Pattern matching is case-insensitive. Quoted identifiers (double quotes, square brackets, backticks, single quotes) 100 * will be automatically stripped before matching. 101 */ 102 private Set<String> excludedProcedurePatterns = new HashSet<String>(); 103 private boolean showCandidateTable = true; 104 private boolean ignoreInsertIntoValues = true; 105 private boolean normalizeOutput = false; 106 /* 107 * Whether to trace all table positions. Default is false. 108 */ 109 private boolean traceTablePosition = false; 110 111 private boolean enablePipelinedStitching = true; 112 113 /** 114 * B3 (routine-summary-scc-design §3): object-level per-overload variable 115 * pools — the identity-first createVariable path. OFF by default: LEGACY 116 * keeps the historical shared-key merge of same-named overload formals; 117 * only the SHADOW/ENHANCED pipelines switch this on. Folds into 118 * ProceduralLineageOptions in B6. 119 */ 120 private boolean identityFirstVariablePools = false; 121 private int maxPipelinedExpansionDepth = 8; 122 private int maxStitchedSourcesPerColumn = 64; 123 124 private AnalyzeMode analyzeMode; 125 126 public EDbVendor getVendor() { 127 return vendor; 128 } 129 130 public void setVendor(EDbVendor vendor) { 131 this.vendor = vendor; 132 } 133 134 /** 135 * Explicit SQL dialect for the inner SQL embedded in Power Query 136 * {@code Value.NativeQuery()} calls and for navigation-chain synthetic 137 * SELECTs. When set, this takes precedence over the connector-based 138 * inference performed by {@code TPowerQueryAnalyzer}; when {@code null} 139 * (default), inference is used. 140 */ 141 public EDbVendor getPowerQueryInnerVendor() { 142 return powerQueryInnerVendor; 143 } 144 145 public void setPowerQueryInnerVendor(EDbVendor powerQueryInnerVendor) { 146 this.powerQueryInnerVendor = powerQueryInnerVendor; 147 } 148 149 public DataFlowHandleListener getHandleListener() { 150 return handleListener; 151 } 152 153 public void setHandleListener(DataFlowHandleListener handleListener) { 154 this.handleListener = handleListener; 155 } 156 157 public boolean isSimpleOutput() { 158 return simpleOutput; 159 } 160 161 public void setSimpleOutput(boolean simpleOutput) { 162 this.simpleOutput = simpleOutput; 163 } 164 165 public boolean isTextFormat() { 166 return textFormat; 167 } 168 169 public void setTextFormat(boolean textFormat) { 170 this.textFormat = textFormat; 171 } 172 173 public boolean isShowJoin() { 174 return showJoin; 175 } 176 177 public void setShowJoin(boolean showJoin) { 178 this.showJoin = showJoin; 179 } 180 181 /** 182 * When true, every non-RESOLVED dynamic-SQL site (including SHADOW's PARTIAL sites) is also 183 * mirrored into an {@link ErrorInfo} (type {@link ErrorInfo#DYNAMIC_SQL_UNRESOLVED}) so callers reading 184 * {@code getErrorMessages()} can see them. Default false, so existing callers are unaffected; 185 * the structured list is always available via {@code DataFlowAnalyzer.getDynamicSqlSites()}. 186 */ 187 private boolean reportDynamicSqlSitesAsErrors = false; 188 189 public boolean isReportDynamicSqlSitesAsErrors() { 190 return reportDynamicSqlSitesAsErrors; 191 } 192 193 public void setReportDynamicSqlSitesAsErrors(boolean reportDynamicSqlSitesAsErrors) { 194 this.reportDynamicSqlSitesAsErrors = reportDynamicSqlSitesAsErrors; 195 } 196 197 /** 198 * Observation policy for incompletely materialized dynamic SQL. The default 199 * {@link DynamicSqlTrustMode#LEGACY} retains historical output. SHADOW keeps 200 * the exact same model and adds incompleteness diagnostics. 201 */ 202 public DynamicSqlTrustMode getDynamicSqlTrustMode() { 203 return dynamicSqlTrustMode; 204 } 205 206 public void setDynamicSqlTrustMode(DynamicSqlTrustMode dynamicSqlTrustMode) { 207 this.dynamicSqlTrustMode = dynamicSqlTrustMode == null 208 ? DynamicSqlTrustMode.LEGACY : dynamicSqlTrustMode; 209 } 210 211 /** 212 * Controls inner analysis of dynamic SQL text. When false, ordinary 213 * static statements and static routine calls are still analyzed, but 214 * EXEC-string, sp_executesql, EXECUTE IMMEDIATE, DBMS_SQL.PARSE, and 215 * similar embedded-text expansions publish no relationships. 216 */ 217 public boolean isAnalyzeDynamicSql() { 218 return analyzeDynamicSql; 219 } 220 221 public void setAnalyzeDynamicSql(boolean analyzeDynamicSql) { 222 this.analyzeDynamicSql = analyzeDynamicSql; 223 } 224 225 public boolean isIgnoreRecordSet() { 226 return ignoreRecordSet; 227 } 228 229 public void setIgnoreRecordSet(boolean ignoreRecordSet) { 230 this.ignoreRecordSet = ignoreRecordSet; 231 } 232 233 public boolean isLinkOrphanColumnToFirstTable() { 234 return linkOrphanColumnToFirstTable; 235 } 236 237 public void setLinkOrphanColumnToFirstTable(boolean linkOrphanColumnToFirstTable) { 238 this.linkOrphanColumnToFirstTable = linkOrphanColumnToFirstTable; 239 } 240 241 /** 242 * When true, dlineage ASSUMES that an external script 243 * ({@code sp_execute_external_script}) passes its input dataset through to the 244 * declared {@code WITH RESULT SETS} output positionally, emitting 245 * {@link gudusoft.gsqlparser.dlineage.dataflow.model.EffectType#external_script_passthrough} 246 * edges from each @input_data_1 column to the corresponding output column. 247 * 248 * <p>The script body (Python/R/…) is opaque and may reorder, drop or 249 * synthesize columns, so these edges are an assumption, not proven lineage — 250 * hence the dedicated effect type. Default {@code true}: column-level lineage 251 * flows THROUGH the script (e.g. across an {@code INSERT ... EXEC} that 252 * consumes the procedure's result set), with every assumed edge marked 253 * {@code external_script_passthrough} so it stays distinguishable from proven 254 * lineage. Set to {@code false} to suppress the assumption: the input query's 255 * source lineage is still emitted, but it stops at the script boundary (it is 256 * not connected to the output columns). 257 */ 258 private boolean assumeExternalScriptPassthrough = true; 259 260 public boolean isAssumeExternalScriptPassthrough() { 261 return assumeExternalScriptPassthrough; 262 } 263 264 public void setAssumeExternalScriptPassthrough(boolean assumeExternalScriptPassthrough) { 265 this.assumeExternalScriptPassthrough = assumeExternalScriptPassthrough; 266 } 267 268 public boolean isIgnoreCoordinate() { 269 return ignoreCoordinate; 270 } 271 272 public void setIgnoreCoordinate(boolean ignoreCoordinate) { 273 this.ignoreCoordinate = ignoreCoordinate; 274 } 275 276 public boolean isTransform() { 277 return transform; 278 } 279 280 public void setTransform(boolean transform) { 281 this.transform = transform; 282 } 283 284 public boolean isTransformCoordinate() { 285 return transformCoordinate; 286 } 287 288 public void setTransformCoordinate(boolean transformCoordinate) { 289 this.transformCoordinate = transformCoordinate; 290 } 291 292 public boolean isMssqlColonBindVariablesEnabled() { 293 return enableMssqlColonBindVariables; 294 } 295 296 public void setEnableMssqlColonBindVariables(boolean enabled) { 297 this.enableMssqlColonBindVariables = enabled; 298 } 299 300 public boolean isCollectAuthoritativeLineageEvidence() { 301 return collectAuthoritativeLineageEvidence; 302 } 303 304 public void setCollectAuthoritativeLineageEvidence(boolean collectAuthoritativeLineageEvidence) { 305 this.collectAuthoritativeLineageEvidence = collectAuthoritativeLineageEvidence; 306 } 307 308 public boolean isSimpleShowFunction() { 309 return simpleShowFunction; 310 } 311 312 public void setSimpleShowFunction(boolean simpleShowFunction) { 313 this.simpleShowFunction = simpleShowFunction; 314 } 315 316 public boolean isSimpleShowSynonym() { 317 return simpleShowSynonym; 318 } 319 320 public void setSimpleShowSynonym(boolean simpleShowSynonym) { 321 this.simpleShowSynonym = simpleShowSynonym; 322 } 323 324 public boolean isSimpleShowTopSelectResultSet() { 325 return simpleShowTopSelectResultSet; 326 } 327 328 public void setSimpleShowTopSelectResultSet(boolean simpleShowTopSelectResultSet) { 329 this.simpleShowTopSelectResultSet = simpleShowTopSelectResultSet; 330 } 331 332 public boolean isShowImplicitSchema() { 333 return showImplicitSchema; 334 } 335 336 public void setShowImplicitSchema(boolean showImplicitSchema) { 337 this.showImplicitSchema = showImplicitSchema; 338 } 339 340 public boolean isShowCountTableColumn() { 341 return showCountTableColumn; 342 } 343 344 public void setShowCountTableColumn(boolean showCountTableColumn) { 345 this.showCountTableColumn = showCountTableColumn; 346 } 347 348 public boolean isShowConstantTable() { 349 return showConstantTable; 350 } 351 352 public void setShowConstantTable(boolean showConstantTable) { 353 this.showConstantTable = showConstantTable; 354 } 355 356 public long getStartId() { 357 return startId; 358 } 359 360 public void setStartId(long startId) { 361 this.startId = startId; 362 } 363 364 public boolean isOutput() { 365 return output; 366 } 367 368 public void setOutput(boolean output) { 369 this.output = output; 370 } 371 372 public int getParallel() { 373 return parallel; 374 } 375 376 public void setParallel(int parallel) { 377 this.parallel = parallel; 378 } 379 380 public boolean isTraceSQL() { 381 return traceSQL; 382 } 383 384 public void setTraceSQL(boolean traceSQL) { 385 this.traceSQL = traceSQL; 386 } 387 388 public boolean isIgnoreTopSelect() { 389 return ignoreTopSelect; 390 } 391 392 public void setIgnoreTopSelect(boolean ignoreTopSelect) { 393 this.ignoreTopSelect = ignoreTopSelect; 394 } 395 396 public void setShowCallRelation(boolean showCallRelation) { 397 this.showCallRelation = showCallRelation; 398 } 399 400 public boolean isShowCallRelation() { 401 return showCallRelation; 402 } 403 404 public String getFilePathDatabase() { 405 return filePathDatabase; 406 } 407 408 public void setFilePathDatabase(String filePathDatabase) { 409 this.filePathDatabase = filePathDatabase; 410 } 411 412 public String getFilePathSchema() { 413 return filePathSchema; 414 } 415 416 public void setFilePathSchema(String filePathSchema) { 417 this.filePathSchema = filePathSchema; 418 } 419 420 public String getDefaultServer() { 421 return defaultServer; 422 } 423 424 public void setDefaultServer(String defaultServer) { 425 this.defaultServer = defaultServer; 426 } 427 428 public String getDefaultDatabase() { 429 return defaultDatabase; 430 } 431 432 public void setDefaultDatabase(String defaultDatabase) { 433 this.defaultDatabase = defaultDatabase; 434 } 435 436 public String getDefaultSchema() { 437 return defaultSchema; 438 } 439 440 public void setDefaultSchema(String defaultSchema) { 441 this.defaultSchema = defaultSchema; 442 } 443 444 public boolean isShowERDiagram() { 445 return showERDiagram; 446 } 447 448 public void setShowERDiagram(boolean showERDiagram) { 449 this.showERDiagram = showERDiagram; 450 } 451 452 public boolean isIgnoreTemporaryTable() { 453 return ignoreTemporaryTable; 454 } 455 456 public void setIgnoreTemporaryTable(boolean ignoreTemporaryTable) { 457 this.ignoreTemporaryTable = ignoreTemporaryTable; 458 } 459 460 public void showResultSetTypes(ResultSetType... types) { 461 if(types!=null) { 462 targetResultSetTypes.addAll(Arrays.asList(types)); 463 } 464 } 465 466 public void showResultSetTypes(String... types) { 467 if (types != null) { 468 for (String type : types) { 469 ResultSetType resultSetType = ResultSetType.of(type); 470 if (resultSetType != null) { 471 targetResultSetTypes.add(resultSetType); 472 } 473 } 474 } 475 } 476 477 public boolean containsResultSetType(ResultSetType type) { 478 return targetResultSetTypes.contains(type); 479 } 480 481 @Override 482 public Object clone() throws CloneNotSupportedException { 483 return super.clone(); 484 } 485 486 public void filterRelationTypes(String... types) { 487 if (types != null) { 488 for (String type : types) { 489 RelationshipType relationshipType = RelationshipType.of(type); 490 if (relationshipType != null) { 491 filterRelationTypes.add(relationshipType.name()); 492 } 493 } 494 } 495 } 496 497 public Set<String> getFilterRelationTypes() { 498 return filterRelationTypes; 499 } 500 501 public boolean isSimpleShowCursor() { 502 return simpleShowCursor; 503 } 504 505 public void setSimpleShowCursor(boolean simpleShowCursor) { 506 this.simpleShowCursor = simpleShowCursor; 507 } 508 509 public boolean isSimpleShowVariable() { 510 return simpleShowVariable; 511 } 512 513 public void setSimpleShowVariable(boolean simpleShowVariable) { 514 this.simpleShowVariable = simpleShowVariable; 515 } 516 517 public boolean isSimpleRetainIntermediate() { 518 return simpleRetainIntermediate; 519 } 520 521 public void setSimpleRetainIntermediate(boolean simpleRetainIntermediate) { 522 this.simpleRetainIntermediate = simpleRetainIntermediate; 523 } 524 525 public boolean isSimpleShowUdfFunctionOnly() { 526 return simpleShowUdfFunctionOnly; 527 } 528 529 public void setSimpleShowUdfFunctionOnly(boolean simpleShowUdfFunctionOnly) { 530 this.simpleShowUdfFunctionOnly = simpleShowUdfFunctionOnly; 531 } 532 533 public boolean isTraceProcedure() { 534 return traceProcedure; 535 } 536 537 public void setTraceProcedure(boolean traceProcedure) { 538 this.traceProcedure = traceProcedure; 539 } 540 541 public boolean isSqlflowIgnoreFunction() { 542 return sqlflowIgnoreFunction; 543 } 544 545 public void setSqlflowIgnoreFunction(boolean sqlflowIgnoreFunction) { 546 this.sqlflowIgnoreFunction = sqlflowIgnoreFunction; 547 } 548 549 public boolean isShowCaseWhenAsDirect() { 550 return showCaseWhenAsDirect; 551 } 552 553 public void setShowCaseWhenAsDirect(boolean showCaseWhenAsDirect) { 554 this.showCaseWhenAsDirect = showCaseWhenAsDirect; 555 } 556 557 public boolean isIgnoreUnusedSynonym() { 558 return ignoreUnusedSynonym; 559 } 560 561 public void setIgnoreUnusedSynonym(boolean ignoreUnusedSynonym) { 562 this.ignoreUnusedSynonym = ignoreUnusedSynonym; 563 } 564 565 public boolean isShowCandidateTable() { 566 return showCandidateTable; 567 } 568 569 public void setShowCandidateTable(boolean showCandidateTable) { 570 this.showCandidateTable = showCandidateTable; 571 } 572 573 public Set<String> getSimpleShowRelationTypes() { 574 return simpleShowRelationTypes; 575 } 576 577 public void setSimpleShowRelationTypes(String... types) { 578 if (types != null) { 579 for (String type : types) { 580 RelationshipType relationshipType = RelationshipType.of(type); 581 if (relationshipType != null) { 582 simpleShowRelationTypes.add(relationshipType.name()); 583 } 584 } 585 } 586 } 587 588 public void setSimpleShowRelationTypes(RelationshipType... types) { 589 if (types != null) { 590 for (RelationshipType relationshipType : types) { 591 simpleShowRelationTypes.add(relationshipType.name()); 592 } 593 } 594 } 595 596 public AnalyzeMode getAnalyzeMode() { 597 return analyzeMode; 598 } 599 600 public void setAnalyzeMode(AnalyzeMode analyzeMode) { 601 this.analyzeMode = analyzeMode; 602 } 603 604 public boolean isIgnoreInsertIntoValues() { 605 return ignoreInsertIntoValues; 606 } 607 608 public void setIgnoreInsertIntoValues(boolean ignoreInsertIntoValues) { 609 this.ignoreInsertIntoValues = ignoreInsertIntoValues; 610 } 611 612 public boolean isNormalizeOutput() { 613 return normalizeOutput; 614 } 615 616 public void setNormalizeOutput(boolean normalizeOutput) { 617 this.normalizeOutput = normalizeOutput; 618 } 619 620 public boolean isTraceTablePosition() { 621 return traceTablePosition; 622 } 623 624 public void setTraceTablePosition(boolean traceTablePosition) { 625 this.traceTablePosition = traceTablePosition; 626 } 627 628 public boolean isEnablePipelinedStitching() { 629 return enablePipelinedStitching; 630 } 631 632 public boolean isIdentityFirstVariablePools() { 633 return identityFirstVariablePools; 634 } 635 636 public void setIdentityFirstVariablePools(boolean identityFirstVariablePools) { 637 this.identityFirstVariablePools = identityFirstVariablePools; 638 } 639 640 public void setEnablePipelinedStitching(boolean enablePipelinedStitching) { 641 this.enablePipelinedStitching = enablePipelinedStitching; 642 } 643 644 public int getMaxPipelinedExpansionDepth() { 645 return maxPipelinedExpansionDepth; 646 } 647 648 public void setMaxPipelinedExpansionDepth(int maxPipelinedExpansionDepth) { 649 this.maxPipelinedExpansionDepth = maxPipelinedExpansionDepth; 650 } 651 652 public int getMaxStitchedSourcesPerColumn() { 653 return maxStitchedSourcesPerColumn; 654 } 655 656 public void setMaxStitchedSourcesPerColumn(int maxStitchedSourcesPerColumn) { 657 this.maxStitchedSourcesPerColumn = maxStitchedSourcesPerColumn; 658 } 659 660 public Set<String> getExcludedProcedureNames() { 661 return excludedProcedureNames; 662 } 663 664 public void setExcludedProcedureNames(Set<String> excludedProcedureNames) { 665 this.excludedProcedureNames = excludedProcedureNames; 666 } 667 668 public void addExcludedProcedureName(String name) { 669 if (name != null && !name.isEmpty()) { 670 this.excludedProcedureNames.add(name); 671 } 672 } 673 674 public void addExcludedProcedureNames(String... names) { 675 if (names != null) { 676 for (String name : names) { 677 addExcludedProcedureName(name); 678 } 679 } 680 } 681 682 /** 683 * @see #excludedProcedurePatterns 684 */ 685 public Set<String> getExcludedProcedurePatterns() { 686 return excludedProcedurePatterns; 687 } 688 689 /** 690 * @see #excludedProcedurePatterns 691 */ 692 public void setExcludedProcedurePatterns(Set<String> excludedProcedurePatterns) { 693 this.excludedProcedurePatterns = excludedProcedurePatterns; 694 } 695 696 /** 697 * Adds a wildcard pattern to exclude procedures from analysis. 698 * @param pattern A wildcard pattern (e.g., "SCHEMA1.*", "*.SP_*", "*_TEST") 699 * @see #excludedProcedurePatterns 700 */ 701 public void addExcludedProcedurePattern(String pattern) { 702 if (pattern != null && !pattern.isEmpty()) { 703 this.excludedProcedurePatterns.add(pattern); 704 } 705 } 706 707 /** 708 * Adds multiple wildcard patterns to exclude procedures from analysis. 709 * @param patterns Variable number of wildcard patterns 710 * @see #excludedProcedurePatterns 711 */ 712 public void addExcludedProcedurePatterns(String... patterns) { 713 if (patterns != null) { 714 for (String pattern : patterns) { 715 addExcludedProcedurePattern(pattern); 716 } 717 } 718 } 719 720 /** 721 * Whether to automatically detect large files and delegate to 722 * {@link gudusoft.gsqlparser.dlineage.ParallelDataFlowAnalyzer} for parallel 723 * processing. When enabled, the {@link gudusoft.gsqlparser.dlineage.util.LargeFileDetector} 724 * checks the input scale against the configured thresholds and may split large 725 * files or route sharded manifests to the parallel analyzer. Default {@code false}. 726 */ 727 private boolean autoDetectLargeFile = false; 728 729 public boolean isAutoDetectLargeFile() { 730 return autoDetectLargeFile; 731 } 732 733 public void setAutoDetectLargeFile(boolean autoDetectLargeFile) { 734 this.autoDetectLargeFile = autoDetectLargeFile; 735 } 736 737 /** 738 * Threshold for the number of {@link SqlInfo} entries that triggers large-file 739 * delegation. When the total SqlInfo count reaches this value, the analyzer 740 * delegates to parallel processing. Default {@code 1000}. 741 */ 742 private int largeSqlInfoCountThreshold = 1000; 743 744 public int getLargeSqlInfoCountThreshold() { 745 return largeSqlInfoCountThreshold; 746 } 747 748 public void setLargeSqlInfoCountThreshold(int largeSqlInfoCountThreshold) { 749 this.largeSqlInfoCountThreshold = largeSqlInfoCountThreshold; 750 } 751 752 /** 753 * Threshold for the total SQL content size (in bytes) that triggers large-file 754 * delegation. When the sum of all SQL string lengths reaches this value, the 755 * analyzer delegates to parallel processing. Default {@code 25 * 1024 * 1024} (25 MB). 756 */ 757 private long largeSqlTotalSizeThreshold = 25 * 1024 * 1024L; 758 759 public long getLargeSqlTotalSizeThreshold() { 760 return largeSqlTotalSizeThreshold; 761 } 762 763 public void setLargeSqlTotalSizeThreshold(long largeSqlTotalSizeThreshold) { 764 this.largeSqlTotalSizeThreshold = largeSqlTotalSizeThreshold; 765 } 766 767 /** 768 * Threshold for the number of queries in a sqlflow/grabit manifest that triggers 769 * large-file delegation. When the manifest contains this many queries, the analyzer 770 * delegates to parallel processing. Default {@code 1000}. 771 */ 772 private int largeQueryCountThreshold = 1000; 773 774 public int getLargeQueryCountThreshold() { 775 return largeQueryCountThreshold; 776 } 777 778 public void setLargeQueryCountThreshold(int largeQueryCountThreshold) { 779 this.largeQueryCountThreshold = largeQueryCountThreshold; 780 } 781 782 /** 783 * Threshold for the number of shards in a sqlflow-sharded manifest that triggers 784 * large-file delegation. When the manifest references this many shard source files, 785 * the analyzer delegates to parallel processing. Default {@code 10}. 786 */ 787 private int largeShardCountThreshold = 10; 788 789 public int getLargeShardCountThreshold() { 790 return largeShardCountThreshold; 791 } 792 793 public void setLargeShardCountThreshold(int largeShardCountThreshold) { 794 this.largeShardCountThreshold = largeShardCountThreshold; 795 } 796 797 /** 798 * Maximum size in MB for a single file before it is split into smaller chunks 799 * for parallel processing. Files larger than this threshold are split using 800 * {@link gudusoft.gsqlparser.util.FileSplitter}. Default {@code 5} (5 MB). 801 */ 802 private int largeFileSplitSizeMB = 5; 803 804 public int getLargeFileSplitSizeMB() { 805 return largeFileSplitSizeMB; 806 } 807 808 public void setLargeFileSplitSizeMB(int largeFileSplitSizeMB) { 809 this.largeFileSplitSizeMB = largeFileSplitSizeMB; 810 } 811 812 /** 813 * Multiplier applied to {@link #largeFileSplitSizeMB} to calculate the 814 * byte threshold in {@link #isLargeSql(String)}. Default {@code 1.5}. 815 */ 816 private double largeSqlThresholdMultiplier = 1.5; 817 818 public double getLargeSqlThresholdMultiplier() { 819 return largeSqlThresholdMultiplier; 820 } 821 822 public void setLargeSqlThresholdMultiplier(double largeSqlThresholdMultiplier) { 823 this.largeSqlThresholdMultiplier = largeSqlThresholdMultiplier; 824 } 825 826 public boolean isLargeSql(String sql) { 827 if (!autoDetectLargeFile || sql == null) { 828 return false; 829 } 830 return sql.length() > getLargeSqlThresholdBytes(); 831 } 832 833 public long getLargeSqlThresholdBytes() { 834 return (long) (largeFileSplitSizeMB * largeSqlThresholdMultiplier * 1024 * 1024); 835 } 836 837 /** 838 * Estimated memory consumption per parallel task in MB, used to calculate the 839 * thread pool size in {@code ParallelDataFlowAnalyzer}. The pool size is capped 840 * so that {@code poolSize * estimatedMemoryPerTaskMB} does not exceed the JVM's 841 * available memory. Default {@code 2560} (2.5 GB). 842 */ 843 private long estimatedMemoryPerTaskMB = 2560L; 844 845 public long getEstimatedMemoryPerTaskMB() { 846 return estimatedMemoryPerTaskMB; 847 } 848 849 public void setEstimatedMemoryPerTaskMB(long estimatedMemoryPerTaskMB) { 850 this.estimatedMemoryPerTaskMB = estimatedMemoryPerTaskMB; 851 } 852 853}