001import java.io.*; 002import java.nio.charset.StandardCharsets; 003import java.util.*; 004 005import gudusoft.gsqlparser.*; 006import gudusoft.gsqlparser.resolver2.format.DisplayNameMode; 007 008import static gudusoft.gsqlparser.resolver2.format.DisplayNameMode.*; 009 010/** 011 * Standalone executable to compare RESOLVER (old) vs RESOLVER2 (new) results. 012 * 013 * Exit codes: 014 * 0: Both resolvers return the same result (or single resolver ran successfully) 015 * 1: Resolvers return different results 016 * 2: Parse error or file error 017 * 018 * Usage: java compareResolvers [options] <dbvendor> <sqlfile> 019 * 020 * Options: 021 * -v, --verbose Enable detailed output messages 022 * -r1, --resolver1 Only run and print RESOLVER (old) result 023 * -r2, --resolver2 Only run and print RESOLVER2 (new) result 024 * -m, --mode <mode> Set display name mode: DISPLAY, SQL_RENDER, or CANONICAL 025 * Default: SQL_RENDER for -r1, DISPLAY for -r2 026 * 027 * Display Name Modes: 028 * DISPLAY - Strip delimiters, preserve original case ([OrderID] -> OrderID) 029 * SQL_RENDER - Preserve delimiters for valid SQL regeneration ([Order ID] -> [Order ID]) 030 * CANONICAL - Apply vendor-specific case folding (Oracle: MyTable -> MYTABLE) 031 * 032 * Examples: 033 * java compareResolvers oracle /path/to/query.sql 034 * java compareResolvers -v mysql /path/to/query.sql 035 * java compareResolvers -r1 oracle /path/to/query.sql # RESOLVER with SQL_RENDER 036 * java compareResolvers -r2 oracle /path/to/query.sql # RESOLVER2 with DISPLAY 037 * java compareResolvers -r2 -m SQL_RENDER oracle /path/to/query.sql # RESOLVER2 with SQL_RENDER 038 */ 039public class compareResolvers { 040 041 private static boolean verbose = false; 042 private static boolean onlyResolver1 = false; 043 private static boolean onlyResolver2 = false; 044 private static DisplayNameMode displayNameMode = null; // null means use default based on resolver 045 046 public static void main(String[] args) { 047 int exitCode = run(args); 048 System.exit(exitCode); 049 } 050 051 /** 052 * Main entry point that returns an exit code. 053 * @param args command line arguments 054 * @return 0 for same results, 1 for different results, 2 for parse/file error 055 */ 056 public static int run(String[] args) { 057 // Reset static flags (important for multiple calls in same JVM) 058 verbose = false; 059 onlyResolver1 = false; 060 onlyResolver2 = false; 061 displayNameMode = null; 062 063 // Parse arguments 064 List<String> positionalArgs = new ArrayList<>(); 065 for (int i = 0; i < args.length; i++) { 066 String arg = args[i]; 067 if (arg.equals("-v") || arg.equals("--verbose")) { 068 verbose = true; 069 } else if (arg.equals("-r1") || arg.equals("--resolver1")) { 070 onlyResolver1 = true; 071 } else if (arg.equals("-r2") || arg.equals("--resolver2")) { 072 onlyResolver2 = true; 073 } else if (arg.equals("-m") || arg.equals("--mode")) { 074 if (i + 1 >= args.length) { 075 printError("Missing value for " + arg + " option"); 076 printUsage(); 077 return 2; 078 } 079 String modeStr = args[++i].toUpperCase(); 080 displayNameMode = parseDisplayNameMode(modeStr); 081 if (displayNameMode == null) { 082 printError("Invalid display name mode: " + modeStr); 083 printError("Valid modes: DISPLAY, SQL_RENDER, CANONICAL"); 084 return 2; 085 } 086 } else if (arg.startsWith("-")) { 087 printError("Unknown option: " + arg); 088 printUsage(); 089 return 2; 090 } else { 091 positionalArgs.add(arg); 092 } 093 } 094 095 // Validate mutually exclusive options 096 if (onlyResolver1 && onlyResolver2) { 097 printError("Options -r1 and -r2 are mutually exclusive"); 098 printUsage(); 099 return 2; 100 } 101 102 if (positionalArgs.size() < 2) { 103 printError("Missing required arguments"); 104 printUsage(); 105 return 2; 106 } 107 108 String dbVendorStr = positionalArgs.get(0); 109 String sqlFilePath = positionalArgs.get(1); 110 111 // Parse database vendor 112 EDbVendor dbVendor = getDbVendor(dbVendorStr); 113 if (dbVendor == null) { 114 printError("Unknown database vendor: " + dbVendorStr); 115 printSupportedVendors(); 116 return 2; 117 } 118 119 return compareResolvers(dbVendor, sqlFilePath); 120 } 121 122 /** 123 * Compare table and column resolution results between RESOLVER and RESOLVER2. 124 * 125 * @param dbVendor The database vendor 126 * @param sqlFilePath The path to the input SQL file 127 * @return 2 for parse/file error, 0 for same results (or single resolver success), 1 for different results 128 */ 129 public static int compareResolvers(EDbVendor dbVendor, String sqlFilePath) { 130 if (onlyResolver1) { 131 printVerbose(repeatChar('=', 80)); 132 printVerbose("Running RESOLVER (old) only"); 133 printVerbose("Database Vendor: " + dbVendor); 134 printVerbose("SQL File: " + sqlFilePath); 135 printVerbose(repeatChar('=', 80)); 136 printVerbose(""); 137 } else if (onlyResolver2) { 138 printVerbose(repeatChar('=', 80)); 139 printVerbose("Running RESOLVER2 (new) only"); 140 printVerbose("Database Vendor: " + dbVendor); 141 printVerbose("SQL File: " + sqlFilePath); 142 printVerbose(repeatChar('=', 80)); 143 printVerbose(""); 144 } else { 145 printVerbose(repeatChar('=', 80)); 146 printVerbose("Comparing RESOLVER vs RESOLVER2"); 147 printVerbose("Database Vendor: " + dbVendor); 148 printVerbose("SQL File: " + sqlFilePath); 149 printVerbose(repeatChar('=', 80)); 150 printVerbose(""); 151 } 152 153 // Read SQL file content 154 File sqlFile = new File(sqlFilePath); 155 if (!sqlFile.exists()) { 156 printError("SQL file does not exist: " + sqlFilePath); 157 return 2; 158 } 159 160 String sqlContent; 161 try { 162 sqlContent = new String(java.nio.file.Files.readAllBytes( 163 java.nio.file.Paths.get(sqlFilePath)), StandardCharsets.UTF_8); 164 } catch (IOException e) { 165 printError("Failed to read SQL file: " + e.getMessage()); 166 return 2; 167 } 168 169 printVerbose("Input SQL:"); 170 printVerbose(repeatChar('-', 40)); 171 printVerbose(sqlContent); 172 printVerbose(repeatChar('-', 40)); 173 printVerbose(""); 174 175 // Create shared options for both resolvers 176 ResolverComparisonOptions options = new ResolverComparisonOptions(); 177 178 // Single resolver mode: only run the requested resolver 179 if (onlyResolver1) { 180 ResolverResult resolver1Result = getResolver1Result(dbVendor, sqlContent, options); 181 if (resolver1Result.hasError) { 182 return 2; 183 } 184 System.out.println(resolver1Result.result); 185 return 0; 186 } 187 188 if (onlyResolver2) { 189 ResolverResult resolver2Result = getResolver2Result(dbVendor, sqlContent, options); 190 if (resolver2Result.hasError) { 191 return 2; 192 } 193 System.out.println(resolver2Result.result); 194 return 0; 195 } 196 197 // ========== RESOLVER (old) using TGetTableColumn ========== 198 ResolverResult resolver1Result = getResolver1Result(dbVendor, sqlContent, options); 199 if (resolver1Result.hasError) { 200 return 2; 201 } 202 203 // ========== RESOLVER2 (new) using TSQLResolver2ResultFormatter ========== 204 ResolverResult resolver2Result = getResolver2Result(dbVendor, sqlContent, options); 205 if (resolver2Result.hasError) { 206 return 2; 207 } 208 209 // ========== Compare results ========== 210 printVerbose(repeatChar('=', 80)); 211 printVerbose("COMPARISON RESULT"); 212 printVerbose(repeatChar('=', 80)); 213 printVerbose(""); 214 215 // Use semantic comparison (normalized tables and fields) instead of raw string comparison 216 // This handles formatting differences like backticks in RESOLVER vs no backticks in RESOLVER2 217 if (areResultsSemanticallyEqual(resolver1Result.result, resolver2Result.result)) { 218 printVerbose("* RESULTS ARE THE SAME"); 219 printVerbose(""); 220 printVerbose("Result:"); 221 printVerbose(repeatChar('-', 40)); 222 printVerbose(resolver1Result.result); 223 return 0; 224 } else { 225 printVerbose("X RESULTS ARE DIFFERENT"); 226 printVerbose(""); 227 228 // Show differences 229 showDifferences(resolver1Result.result, resolver2Result.result); 230 231 printVerbose(""); 232 printVerbose("RESOLVER (TGetTableColumn) output:"); 233 printVerbose(repeatChar('-', 40)); 234 printVerbose(resolver1Result.result); 235 printVerbose(""); 236 printVerbose("RESOLVER2 (TSQLResolver2ResultFormatter) output:"); 237 printVerbose(repeatChar('-', 40)); 238 printVerbose(resolver2Result.result); 239 return 1; 240 } 241 } 242 243 /** 244 * Check if two results are semantically equal (same tables and fields after normalization). 245 * This handles formatting differences like backticks in RESOLVER vs no backticks in RESOLVER2. 246 */ 247 private static boolean areResultsSemanticallyEqual(String result1, String result2) { 248 // Parse both results into normalized tables and fields 249 Set<String> tables1 = extractSection(result1, "Tables:"); 250 Set<String> tables2 = extractSection(result2, "Tables:"); 251 Set<String> fields1 = extractSection(result1, "Fields:"); 252 Set<String> fields2 = extractSection(result2, "Fields:"); 253 254 // Compare normalized sets 255 return tables1.equals(tables2) && fields1.equals(fields2); 256 } 257 258 /** 259 * Result holder for resolver output. 260 */ 261 private static class ResolverResult { 262 String result; 263 boolean hasError; 264 265 ResolverResult(String result, boolean hasError) { 266 this.result = result; 267 this.hasError = hasError; 268 } 269 } 270 271 /** 272 * Options for resolver comparison. 273 */ 274 private static class ResolverComparisonOptions { 275 boolean showTableEffect = false; 276 boolean showColumnLocation = false; 277 boolean listStarColumn = true; 278 boolean showDatatype = false; 279 boolean linkOrphanColumnToFirstTable = false; 280 boolean showCTE = false; 281 boolean showColumnsOfCTE = false; 282 } 283 284 /** 285 * Get table/column result using RESOLVER (old) with TGetTableColumn. 286 */ 287 private static ResolverResult getResolver1Result(EDbVendor dbVendor, String sqlContent, ResolverComparisonOptions options) { 288 printVerbose("Running RESOLVER (TGetTableColumn)..."); 289 290 gudusoft.gsqlparser.util.TGetTableColumn getTableColumn = 291 new gudusoft.gsqlparser.util.TGetTableColumn(dbVendor); 292 getTableColumn.setResolverType(EResolverType.RESOLVER); 293 getTableColumn.isConsole = false; 294 getTableColumn.showDetail = false; 295 getTableColumn.showSummary = true; 296 297 // Apply shared options 298 getTableColumn.showTableEffect = options.showTableEffect; 299 getTableColumn.showColumnLocation = options.showColumnLocation; 300 getTableColumn.listStarColumn = options.listStarColumn; 301 getTableColumn.showDatatype = options.showDatatype; 302 getTableColumn.linkOrphanColumnToFirstTable = options.linkOrphanColumnToFirstTable; 303 getTableColumn.showCTE = options.showCTE; 304 getTableColumn.showColumnsOfCTE = options.showColumnsOfCTE; 305 306 // Set display name mode (default SQL_RENDER for RESOLVER) 307 DisplayNameMode mode = displayNameMode != null ? displayNameMode : SQL_RENDER; 308 getTableColumn.setDisplayNameMode(mode); 309 printVerbose("Display name mode: " + mode); 310 311 try { 312 getTableColumn.runText(sqlContent); 313 } catch (RuntimeException e) { 314 printError("RESOLVER parse failed: " + e.getMessage()); 315 return new ResolverResult("", true); 316 } 317 318 String result = getTableColumn.outList.toString(); 319 printVerbose("RESOLVER completed."); 320 printVerbose(""); 321 return new ResolverResult(result.trim(), false); 322 } 323 324 /** 325 * Get table/column result using RESOLVER2 (new) with TSQLResolver2ResultFormatter. 326 */ 327 private static ResolverResult getResolver2Result(EDbVendor dbVendor, String sqlContent, ResolverComparisonOptions options) { 328 printVerbose("Running RESOLVER2 (TSQLResolver2ResultFormatter)..."); 329 330 TGSqlParser parser = new TGSqlParser(dbVendor); 331 parser.setResolverType(EResolverType.RESOLVER2); 332 parser.sqltext = sqlContent; 333 334 int ret = parser.parse(); 335 if (ret != 0) { 336 printError("RESOLVER2 parse failed: " + parser.getErrormessage()); 337 return new ResolverResult("", true); 338 } 339 340 // Get resolver2 and format results 341 gudusoft.gsqlparser.resolver2.TSQLResolver2 resolver = parser.getResolver2(); 342 if (resolver == null) { 343 printError("Resolver2 not available after parsing"); 344 return new ResolverResult("", true); 345 } 346 347 gudusoft.gsqlparser.resolver2.TSQLResolver2ResultFormatter formatter = 348 new gudusoft.gsqlparser.resolver2.TSQLResolver2ResultFormatter(resolver); 349 350 // Apply shared options 351 formatter.setShowTableEffect(options.showTableEffect); 352 formatter.setShowColumnLocation(options.showColumnLocation); 353 formatter.setListStarColumn(options.listStarColumn); 354 formatter.setShowDatatype(options.showDatatype); 355 formatter.setLinkOrphanColumnToFirstTable(options.linkOrphanColumnToFirstTable); 356 formatter.setShowCTE(options.showCTE); 357 formatter.setShowColumnsOfCTE(options.showColumnsOfCTE); 358 359 // Set display name mode (default DISPLAY for RESOLVER2) 360 DisplayNameMode mode = displayNameMode != null ? displayNameMode : DISPLAY; 361 formatter.setDisplayNameMode(mode); 362 printVerbose("Display name mode: " + mode); 363 364 String result = formatter.format(); 365 366 printVerbose("RESOLVER2 completed."); 367 printVerbose(""); 368 return new ResolverResult(result.trim(), false); 369 } 370 371 /** 372 * Show detailed differences between two results. 373 */ 374 private static void showDifferences(String result1, String result2) { 375 printVerbose("Differences:"); 376 printVerbose(repeatChar('-', 40)); 377 378 // Parse both results into tables and fields 379 Set<String> tables1 = extractSection(result1, "Tables:"); 380 Set<String> tables2 = extractSection(result2, "Tables:"); 381 Set<String> fields1 = extractSection(result1, "Fields:"); 382 Set<String> fields2 = extractSection(result2, "Fields:"); 383 384 // Compare tables 385 Set<String> tablesOnlyIn1 = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 386 tablesOnlyIn1.addAll(tables1); 387 tablesOnlyIn1.removeAll(tables2); 388 389 Set<String> tablesOnlyIn2 = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 390 tablesOnlyIn2.addAll(tables2); 391 tablesOnlyIn2.removeAll(tables1); 392 393 if (!tablesOnlyIn1.isEmpty()) { 394 printVerbose("Tables only in RESOLVER: " + tablesOnlyIn1); 395 } 396 if (!tablesOnlyIn2.isEmpty()) { 397 printVerbose("Tables only in RESOLVER2: " + tablesOnlyIn2); 398 } 399 400 // Compare fields 401 Set<String> fieldsOnlyIn1 = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 402 fieldsOnlyIn1.addAll(fields1); 403 fieldsOnlyIn1.removeAll(fields2); 404 405 Set<String> fieldsOnlyIn2 = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 406 fieldsOnlyIn2.addAll(fields2); 407 fieldsOnlyIn2.removeAll(fields1); 408 409 if (!fieldsOnlyIn1.isEmpty()) { 410 printVerbose("Fields only in RESOLVER: " + fieldsOnlyIn1); 411 } 412 if (!fieldsOnlyIn2.isEmpty()) { 413 printVerbose("Fields only in RESOLVER2: " + fieldsOnlyIn2); 414 } 415 416 // Show common items 417 Set<String> commonTables = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 418 commonTables.addAll(tables1); 419 commonTables.retainAll(tables2); 420 421 Set<String> commonFields = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 422 commonFields.addAll(fields1); 423 commonFields.retainAll(fields2); 424 425 if (!commonTables.isEmpty() || !commonFields.isEmpty()) { 426 printVerbose(""); 427 printVerbose("Common items:"); 428 if (!commonTables.isEmpty()) { 429 printVerbose(" Tables: " + commonTables); 430 } 431 if (!commonFields.isEmpty()) { 432 printVerbose(" Fields: " + commonFields); 433 } 434 } 435 } 436 437 /** 438 * Extract a section (Tables: or Fields:) from the result string. 439 * Normalizes identifiers by stripping SQL delimiters (backticks, quotes). 440 */ 441 private static Set<String> extractSection(String result, String sectionName) { 442 Set<String> items = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); 443 String[] lines = result.split("\n"); 444 boolean inSection = false; 445 446 for (String line : lines) { 447 line = line.trim(); 448 if (line.isEmpty()) continue; 449 450 if (line.equalsIgnoreCase(sectionName.trim().replace(":", ""))) { 451 inSection = true; 452 continue; 453 } 454 if (line.toLowerCase().startsWith("tables:")) { 455 inSection = sectionName.toLowerCase().contains("tables"); 456 continue; 457 } 458 if (line.toLowerCase().startsWith("fields:")) { 459 inSection = sectionName.toLowerCase().contains("fields"); 460 continue; 461 } 462 if (line.toLowerCase().startsWith("ctes:")) { 463 inSection = false; 464 continue; 465 } 466 467 if (inSection && !line.isEmpty()) { 468 // Normalize the identifier by stripping SQL delimiters 469 items.add(normalizeIdentifier(line)); 470 } 471 } 472 473 return items; 474 } 475 476 /** 477 * Normalize an identifier by stripping SQL delimiters (backticks, double quotes). 478 * This allows fair comparison between RESOLVER (preserves delimiters) and 479 * RESOLVER2 (strips delimiters). 480 * 481 * Examples: 482 * `schema`.`table`.column -> schema.table.column 483 * "schema"."table"."column" -> schema.table.column 484 * schema.table.column -> schema.table.column (unchanged) 485 */ 486 private static String normalizeIdentifier(String identifier) { 487 if (identifier == null || identifier.isEmpty()) { 488 return identifier; 489 } 490 491 StringBuilder result = new StringBuilder(); 492 boolean inBacktick = false; 493 boolean inDoubleQuote = false; 494 495 for (int i = 0; i < identifier.length(); i++) { 496 char c = identifier.charAt(i); 497 498 if (c == '`' && !inDoubleQuote) { 499 // Toggle backtick state, don't add the backtick to result 500 inBacktick = !inBacktick; 501 } else if (c == '"' && !inBacktick) { 502 // Toggle double quote state, don't add the quote to result 503 inDoubleQuote = !inDoubleQuote; 504 } else { 505 result.append(c); 506 } 507 } 508 509 // Trim leading/trailing spaces that may have been inside quotes 510 return result.toString().trim(); 511 } 512 513 /** 514 * Helper method to repeat a character (Java 8 compatible). 515 */ 516 private static String repeatChar(char c, int count) { 517 StringBuilder sb = new StringBuilder(count); 518 for (int i = 0; i < count; i++) { 519 sb.append(c); 520 } 521 return sb.toString(); 522 } 523 524 /** 525 * Print message only if verbose mode is enabled. 526 */ 527 private static void printVerbose(String message) { 528 if (verbose) { 529 System.out.println(message); 530 } 531 } 532 533 /** 534 * Print error message (always printed). 535 */ 536 private static void printError(String message) { 537 System.err.println("ERROR: " + message); 538 } 539 540 /** 541 * Print usage information. 542 */ 543 private static void printUsage() { 544 System.err.println(); 545 System.err.println("Usage: java compareResolvers [options] <dbvendor> <sqlfile>"); 546 System.err.println(); 547 System.err.println("Options:"); 548 System.err.println(" -v, --verbose Enable detailed output messages"); 549 System.err.println(" -r1, --resolver1 Only run and print RESOLVER (old) result"); 550 System.err.println(" -r2, --resolver2 Only run and print RESOLVER2 (new) result"); 551 System.err.println(" -m, --mode <mode> Set display name mode: DISPLAY, SQL_RENDER, or CANONICAL"); 552 System.err.println(" Default: SQL_RENDER for -r1, DISPLAY for -r2"); 553 System.err.println(); 554 System.err.println("Display Name Modes:"); 555 System.err.println(" DISPLAY - Strip delimiters, preserve original case"); 556 System.err.println(" SQL_RENDER - Preserve delimiters for valid SQL regeneration"); 557 System.err.println(" CANONICAL - Apply vendor-specific case folding"); 558 System.err.println(); 559 System.err.println("Exit codes:"); 560 System.err.println(" 0: Both resolvers return the same result (or single resolver success)"); 561 System.err.println(" 1: Resolvers return different results"); 562 System.err.println(" 2: Parse error or file error"); 563 System.err.println(); 564 System.err.println("Examples:"); 565 System.err.println(" java compareResolvers oracle /path/to/query.sql"); 566 System.err.println(" java compareResolvers -v mysql /path/to/query.sql"); 567 System.err.println(" java compareResolvers -r1 oracle /path/to/query.sql"); 568 System.err.println(" java compareResolvers -r2 oracle /path/to/query.sql"); 569 System.err.println(" java compareResolvers -r2 -m SQL_RENDER oracle /path/to/query.sql"); 570 } 571 572 /** 573 * Parse display name mode from string. 574 * @return DisplayNameMode or null if invalid 575 */ 576 private static DisplayNameMode parseDisplayNameMode(String modeStr) { 577 if (modeStr == null) return null; 578 switch (modeStr.toUpperCase()) { 579 case "DISPLAY": return DISPLAY; 580 case "SQL_RENDER": return SQL_RENDER; 581 case "CANONICAL": return CANONICAL; 582 default: return null; 583 } 584 } 585 586 /** 587 * Print supported database vendors. 588 */ 589 private static void printSupportedVendors() { 590 System.err.println(); 591 System.err.println("Supported database vendors:"); 592 System.err.println(" oracle, mysql, mssql, postgresql, db2, teradata,"); 593 System.err.println(" informix, sybase, netezza, greenplum, hive, redshift,"); 594 System.err.println(" snowflake, bigquery, athena, sparksql, vertica, impala,"); 595 System.err.println(" couchbase, dax, mdx, gaussdb, openedge, etc."); 596 } 597 598 /** 599 * Convert database vendor string to EDbVendor enum. 600 */ 601 private static EDbVendor getDbVendor(String vendorStr) { 602 String vendor = vendorStr.toLowerCase().trim(); 603 switch (vendor) { 604 case "oracle": return EDbVendor.dbvoracle; 605 case "mysql": return EDbVendor.dbvmysql; 606 case "mssql": 607 case "sqlserver": return EDbVendor.dbvmssql; 608 case "postgresql": 609 case "postgres": return EDbVendor.dbvpostgresql; 610 case "db2": return EDbVendor.dbvdb2; 611 case "teradata": return EDbVendor.dbvteradata; 612 case "informix": return EDbVendor.dbvinformix; 613 case "sybase": return EDbVendor.dbvsybase; 614 case "netezza": return EDbVendor.dbvnetezza; 615 case "greenplum": return EDbVendor.dbvgreenplum; 616 case "hive": return EDbVendor.dbvhive; 617 case "redshift": return EDbVendor.dbvredshift; 618 case "snowflake": return EDbVendor.dbvsnowflake; 619 case "bigquery": return EDbVendor.dbvbigquery; 620 case "athena": return EDbVendor.dbvathena; 621 case "sparksql": 622 case "spark": return EDbVendor.dbvsparksql; 623 case "vertica": return EDbVendor.dbvvertica; 624 case "impala": return EDbVendor.dbvimpala; 625 case "couchbase": return EDbVendor.dbvcouchbase; 626 case "dax": return EDbVendor.dbvdax; 627 case "mdx": return EDbVendor.dbvmdx; 628 case "gaussdb": return EDbVendor.dbvgaussdb; 629 case "openedge": return EDbVendor.dbvopenedge; 630 case "databricks": return EDbVendor.dbvdatabricks; 631 case "hana": return EDbVendor.dbvhana; 632 default: return null; 633 } 634 } 635}