001package gudusoft.gsqlparser.util; 002 003import gudusoft.gsqlparser.EDbVendor; 004import gudusoft.gsqlparser.TGSqlParser; 005import gudusoft.gsqlparser.dlineage.dataflow.model.ModelBindingManager; 006import gudusoft.gsqlparser.dlineage.dataflow.model.SubType; 007import gudusoft.gsqlparser.dlineage.dataflow.model.xml.table; 008import gudusoft.gsqlparser.pp.para.GFmtOpt; 009import gudusoft.gsqlparser.pp.para.GFmtOptFactory; 010import gudusoft.gsqlparser.pp.para.styleenums.TCaseOption; 011import gudusoft.gsqlparser.pp.stmtformatter.FormatterFactory; 012import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 013import gudusoft.gsqlparser.sqlenv.IdentifierService; 014import gudusoft.gsqlparser.sqlenv.TSQLEnv; 015 016import java.io.*; 017import java.nio.charset.Charset; 018import java.security.MessageDigest; 019import java.util.*; 020import java.util.stream.Collectors; 021 022public class SQLUtil { 023 private static final Logger logger = LoggerFactory.getLogger(SQLUtil.class); 024 025 026 public static String formatSql( EDbVendor dbVendor, String inputQuery ) 027 { 028 String Result = inputQuery; 029 TGSqlParser sqlparser = new TGSqlParser( dbVendor ); 030 sqlparser.sqltext = inputQuery; 031 int ret = sqlparser.parse( ); 032 if ( ret == 0 ) 033 { 034 GFmtOpt option = GFmtOptFactory.newInstance(); 035 option.caseFuncname = TCaseOption.CoNoChange; 036 Result = FormatterFactory.pp(sqlparser, option); 037 } 038 return Result; 039 } 040 041 public static boolean isEmpty(String value) { 042 return value == null || value.trim().length() == 0; 043 } 044 045 public static String getFileContent(File file) { 046 String charset = null; 047 String sqlfilename = file.getAbsolutePath(); 048 int read = 0; 049 try { 050 FileInputStream fr = new FileInputStream(sqlfilename); 051 byte[] bom = new byte[4]; 052 fr.read(bom, 0, bom.length); 053 054 if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) 055 && (bom[3] == (byte) 0xFF)) { 056 charset = "UTF-32BE"; 057 read = 4; 058 } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) 059 && (bom[3] == (byte) 0x00)) { 060 charset = "UTF-32LE"; 061 read = 4; 062 } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { 063 charset = "UTF-8"; 064 read = 3; 065 } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { 066 charset = "UTF-16BE"; 067 read = 2; 068 } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { 069 charset = "UTF-16LE"; 070 read = 2; 071 } else { 072 charset = "UTF-8"; 073 read = 0; 074 } 075 076 fr.close(); 077 } catch (IOException e) { 078 logger.error("Check file encoding failed.", e); 079 } 080 081 Long filelength = file.length(); 082 byte[] filecontent = new byte[filelength.intValue()]; 083 try { 084 InputStream in = new BufferedInputStream(new FileInputStream(sqlfilename)); 085 in.read(filecontent); 086 in.close(); 087 } catch (IOException e) { 088 logger.error("read file content failed.", e); 089 } 090 091 byte[] content = new byte[filelength.intValue() - read]; 092 System.arraycopy(filecontent, read, content, 0, content.length); 093 094 try { 095 String fileContent = new String(content, charset == null ? Charset.defaultCharset().name() : charset); 096 return fileContent.replace((char) 160, (char) 32); 097 } catch (UnsupportedEncodingException e) { 098 logger.error("The OS does not support " + charset == null ? Charset.defaultCharset().name() : charset, e); 099 return null; 100 } 101 } 102 103 public static String getInputStreamContent(InputStream is, boolean close) { 104 try { 105 ByteArrayOutputStream out = new ByteArrayOutputStream(4096); 106 byte[] tmp = new byte[4096]; 107 while (true) { 108 int r = is.read(tmp); 109 if (r == -1) 110 break; 111 out.write(tmp, 0, r); 112 } 113 byte[] bytes = out.toByteArray(); 114 if (close) { 115 is.close(); 116 } 117 out.close(); 118 String content = new String(bytes); 119 return content; 120 } catch (IOException e) { 121 logger.error("read inputStream failed.", e); 122 } 123 return null; 124 } 125 126 public static String getFileContent(String filePath) { 127 if (filePath == null) 128 return ""; 129 File file = new File(filePath); 130 if (!file.exists() || file.isDirectory()) 131 return ""; 132 return getFileContent(file); 133 } 134 135 public static String trimColumnStringQuote(String string) { 136 try { 137 if (string == null) 138 return string; 139 140 if (string.indexOf('.') != -1) { 141 List<String> splits = parseNames(string); 142 if (splits.size() > 1) { 143 StringBuilder buffer = new StringBuilder(); 144 for (int i = 0; i < splits.size(); i++) { 145 String segment = splits.get(i); 146 if (parseNames(trimColumnStringQuote(segment)).size() > 1) { 147 buffer.append(segment); 148 } else { 149 buffer.append(trimColumnStringQuote(segment)); 150 } 151 if (i < splits.size() - 1) { 152 buffer.append("."); 153 } 154 } 155 string = buffer.toString(); 156 return string; 157 } 158 } 159 if (string.length() < 2) { 160 return string; 161 } 162 if (string.startsWith("'") && string.endsWith("'")) 163 return string.substring(1, string.length() - 1); 164 else if (string.startsWith("\"") && string.endsWith("\"")) 165 return string.substring(1, string.length() - 1); 166 else if (string.startsWith("`") && string.endsWith("`")) 167 return string.substring(1, string.length() - 1); 168 else if (string.startsWith("[") && string.endsWith("]")) 169 return string.substring(1, string.length() - 1); 170 return string; 171 }catch (Exception e){ 172 return string; 173 } 174 } 175 176// public static List<String> parseNames(String nameString, EDbVendor vendor) { 177// List<String> names = new ArrayList<String>(); 178// if (nameString.startsWith("`") && nameString.endsWith("`")){ 179// nameString = nameString.substring(1,nameString.length()-1); 180// } 181// String[] splits = nameString.trim().split("\\."); 182// 183// for (int i = 0; i < splits.length; i++) { 184// String split = splits[i].trim(); 185// if (TSQLEnv.isDelimitedIdentifier(vendor, split) && !TSQLEnv.endsWithDelimitedIdentifier(vendor, split)) { 186// StringBuilder buffer = new StringBuilder(); 187// buffer.append(splits[i]); 188// while (i < splits.length - 1 189// && !TSQLEnv.endsWithDelimitedIdentifier(vendor, split = splits[++i].trim())) { 190// buffer.append("."); 191// buffer.append(splits[i]); 192// } 193// 194// buffer.append("."); 195// buffer.append(splits[i]); 196// 197// names.add(buffer.toString()); 198// continue; 199// } 200// names.add(splits[i]); 201// } 202// return names; 203// } 204 205 public static List<String> parseNames(String nameString) { 206 return parseNames(nameString, null); 207 } 208 209 // Pre-compiled patterns for better performance 210 private static final java.util.regex.Pattern DOT_PATTERN = java.util.regex.Pattern.compile("\\s*\\.\\s*"); 211 212// // LRU Cache for parseNames results - thread-safe with limited size 213 private static final java.util.Map<String, List<String>> PARSE_NAMES_CACHE = 214 Collections.synchronizedMap(new java.util.LinkedHashMap<String, List<String>>(256, 0.75f, true) { 215 @Override 216 protected boolean removeEldestEntry(java.util.Map.Entry<String, List<String>> eldest) { 217 return size() > 10000; // Keep cache under 10000 entries 218 } 219 }); 220 221 /** 222 * 解析以点号分隔的 SQL 标识符或表达式,并返回各层级片段。 223 * <p> 224 * 用途: 225 * <ul> 226 * <li>将类似 catalog.schema.table.column 的全限定名拆分为有序片段;</li> 227 * <li>在拆分时识别并保留引号/括号内的点号,不做误分割;</li> 228 * <li>根据不同数据库厂商(如 BigQuery)的定界符规则进行处理。</li> 229 * </ul> 230 * 工作机制: 231 * <ol> 232 * <li>按「可选空格 + '.' + 可选空格」初步切分;</li> 233 * <li>对以下情况进行片段合并直至遇到闭合符号: 234 * <ul> 235 * <li>单引号字符串:'...'</li> 236 * <li>双引号定界标识符:"..."</li> 237 * <li>反引号定界标识符:`...`</li> 238 * <li>方括号定界标识符:[...]</li> 239 * <li>函数/表达式括号:(...)</li> 240 * </ul> 241 * </li> 242 * <li>BigQuery(vendor == dbvbigquery)且包含反引号时,会先去除反引号再进行切分。</li> 243 * <li>入参为 null 返回空列表;发生异常时返回仅包含原始字符串的列表。</li> 244 * </ol> 245 * 示例: 246 * <pre> 247 * "dbo.Employee.Name" -> ["dbo", "Employee", "Name"] 248 * "[Sales DB].[Employee].[Name]" -> ["[Sales DB]", "[Employee]", "[Name]"] 249 * "\"My.Schema\".\"My.Table\"" -> ["\"My.Schema\"", "\"My.Table\""] 250 * "`project.dataset.table`" (BigQuery) -> ["project", "dataset", "table"] 251 * "OPENJSON(aptd.test.ActiviteTypeIDs)" -> ["OPENJSON(aptd.test.ActiviteTypeIDs)"] 252 * </pre> 253 * 254 * @param nameString 待解析的标识符或表达式字符串 255 * @param vendor 数据库厂商(用于处理厂商特定定界符,如 BigQuery 的反引号),可为 null 256 * @return 解析后的片段列表;顺序与层级一致 257 */ 258 public static List<String> parseNames(String nameString, EDbVendor vendor) { 259 if(nameString == null){ 260 return Collections.emptyList(); 261 } 262 263 // Cache lookup - use a simple cache key 264 String cacheKey = vendor == null ? nameString : (vendor.ordinal() + ":" + nameString); 265 List<String> cached = PARSE_NAMES_CACHE.get(cacheKey); 266 if (cached != null) { 267 return new ArrayList<String>(cached); 268 } 269 270 String name = nameString.trim(); 271 272 // Fast path: simple names without special characters 273 // Check once for all special characters in a single pass 274 boolean hasSpecialChar = false; 275 boolean hasSingleQuote = false; 276 boolean hasDoubleQuote = false; 277 boolean hasBacktick = false; 278 boolean hasParenthesis = false; 279 boolean hasBracket = false; 280 281 for (int i = 0, len = name.length(); i < len; i++) { 282 char c = name.charAt(i); 283 switch (c) { 284 case '\'': 285 hasSingleQuote = true; 286 hasSpecialChar = true; 287 break; 288 case '"': 289 hasDoubleQuote = true; 290 hasSpecialChar = true; 291 break; 292 case '`': 293 hasBacktick = true; 294 hasSpecialChar = true; 295 break; 296 case '(': 297 case ')': 298 hasParenthesis = true; 299 hasSpecialChar = true; 300 break; 301 case '[': 302 case ']': 303 hasBracket = true; 304 hasSpecialChar = true; 305 break; 306 } 307 } 308 309 List<String> names = new ArrayList<String>(4); // Pre-size for typical case 310 311 // Handle BigQuery special case 312 if (vendor == EDbVendor.dbvbigquery && hasBacktick) { 313 String[] parts = DOT_PATTERN.split(name.replace("`", "")); 314 for (String part : parts) { 315 names.add(part); 316 } 317 putCache(cacheKey, names); 318 return names; 319 } 320 321 try { 322 String[] splits = DOT_PATTERN.split(nameString); 323 324 // Fast path: no special characters 325 if (!hasSpecialChar) { 326 for (String split : splits) { 327 names.add(split); 328 } 329 putCache(cacheKey, names); 330 return names; 331 } 332 333 // Handle special character cases 334 if (hasSingleQuote) { 335 if ("'.'".equals(name)) { 336 names = Arrays.asList("."); 337 putCache(cacheKey, names); 338 return names; 339 } 340 parseWithDelimiter(splits, names, '\'', '\''); 341 } else if (hasParenthesis) { 342 parseWithParenthesis(splits, names); 343 } else if (hasBacktick) { 344 if ("`.`".equals(name)) { 345 names = Arrays.asList("."); 346 putCache(cacheKey, names); 347 return names; 348 } 349 parseWithDelimiter(splits, names, '`', '`'); 350 } else if (hasDoubleQuote) { 351 if ("\".\"".equals(name)) { 352 names = Arrays.asList("."); 353 putCache(cacheKey, names); 354 return names; 355 } 356 parseWithDelimiter(splits, names, '"', '"'); 357 } else if (hasBracket) { 358 if ("[.]".equals(name)) { 359 names = Arrays.asList("."); 360 putCache(cacheKey, names); 361 return names; 362 } 363 parseWithDelimiter(splits, names, '[', ']'); 364 } else { 365 for (String split : splits) { 366 names.add(split); 367 } 368 } 369 } catch (Throwable e) { 370 names.clear(); 371 names.add(nameString); 372 } 373 374 putCache(cacheKey, names); 375 return names; 376 } 377 378 protected static List<String> putCache(String cacheKey, List<String> names) { 379 return PARSE_NAMES_CACHE.put(cacheKey, new ArrayList<String>(names)); 380 } 381 382 /** 383 * Helper method to parse name segments with paired delimiters (quotes, brackets, etc.) 384 */ 385 private static void parseWithDelimiter(String[] splits, List<String> names, char startDelim, char endDelim) { 386 for (int i = 0; i < splits.length; i++) { 387 String split = splits[i].trim(); 388 if (split.length() > 0 && split.charAt(0) == startDelim && 389 (split.length() == 1 || split.charAt(split.length() - 1) != endDelim)) { 390 // Found start delimiter without matching end - need to merge segments 391 StringBuilder buffer = new StringBuilder(split.length() * 2); 392 buffer.append(splits[i]); 393 394 while (i < splits.length - 1) { 395 split = splits[++i].trim(); 396 buffer.append(".").append(splits[i]); 397 if (split.length() > 0 && split.charAt(split.length() - 1) == endDelim) { 398 break; 399 } 400 } 401 names.add(buffer.toString()); 402 } else { 403 names.add(splits[i]); 404 } 405 } 406 } 407 408 /** 409 * Helper method to parse name segments with parentheses 410 */ 411 private static void parseWithParenthesis(String[] splits, List<String> names) { 412 for (int i = 0; i < splits.length; i++) { 413 String split = splits[i].trim(); 414 int openParen = split.indexOf('('); 415 int closeParen = split.indexOf(')'); 416 417 if (openParen != -1 && closeParen == -1) { 418 // Found opening parenthesis without closing - need to merge segments 419 StringBuilder buffer = new StringBuilder(split.length() * 2); 420 buffer.append(splits[i]); 421 422 while (i < splits.length - 1) { 423 split = splits[++i].trim(); 424 buffer.append(".").append(splits[i]); 425 if (split.indexOf(')') != -1) { 426 break; 427 } 428 } 429 names.add(buffer.toString()); 430 } else { 431 names.add(splits[i]); 432 } 433 } 434 } 435 436 public static void main(String[] args) { 437 SQLUtil.parseNames("OPENJSON(aptd.test.ActiviteTypeIDs)"); 438 } 439 440 public static void writeToFile(File file, InputStream source, boolean close) { 441 BufferedInputStream bis = null; 442 BufferedOutputStream fouts = null; 443 try { 444 bis = new BufferedInputStream(source); 445 if (!file.exists()) { 446 if (!file.getParentFile().exists()) { 447 file.getParentFile().mkdirs(); 448 } 449 file.createNewFile(); 450 } 451 fouts = new BufferedOutputStream(new FileOutputStream(file)); 452 byte b[] = new byte[1024]; 453 int i = 0; 454 while ((i = bis.read(b)) != -1) { 455 fouts.write(b, 0, i); 456 } 457 fouts.flush(); 458 fouts.close(); 459 if (close) 460 bis.close(); 461 } catch (IOException e) { 462 logger.error("Write file failed.", e); 463 try { 464 if (fouts != null) 465 fouts.close(); 466 } catch (IOException f) { 467 logger.error("Close output stream failed.", f); 468 } 469 if (close) { 470 try { 471 if (bis != null) 472 bis.close(); 473 } catch (IOException f) { 474 logger.error("Close input stream failed.", f); 475 } 476 } 477 } 478 } 479 480 public static void writeToFile(File file, String string) throws IOException { 481 482 if (!file.exists()) { 483 if (!file.getParentFile().exists()) { 484 file.getParentFile().mkdirs(); 485 } 486 file.createNewFile(); 487 } 488 PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file))); 489 if (string != null) 490 out.print(string); 491 out.close(); 492 } 493 494 public static void appendToFile(File file, String string) throws IOException { 495 496 if (!file.exists()) { 497 if (!file.getParentFile().exists()) { 498 file.getParentFile().mkdirs(); 499 } 500 file.createNewFile(); 501 } 502 PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file, true))); 503 if (string != null) 504 out.println(string); 505 out.close(); 506 } 507 508 public static void deltree(File root) { 509 if (root == null || !root.exists()) { 510 return; 511 } 512 513 if (root.isFile()) { 514 root.delete(); 515 return; 516 } 517 518 File[] children = root.listFiles(); 519 if (children != null) { 520 for (int i = 0; i < children.length; i++) { 521 deltree(children[i]); 522 } 523 } 524 525 root.delete(); 526 } 527 528 public static InputStream getInputStreamWithoutBom(String file) throws IOException { 529 UnicodeInputStream stream = null; 530 FileInputStream fis = new FileInputStream(file); 531 stream = new UnicodeInputStream(fis, null); 532 return stream; 533 } 534 535 public static class UnicodeInputStream extends InputStream { 536 PushbackInputStream internalIn; 537 boolean isInited = false; 538 String defaultEnc; 539 String encoding; 540 541 private static final int BOM_SIZE = 4; 542 543 public UnicodeInputStream(InputStream in, String defaultEnc) { 544 internalIn = new PushbackInputStream(in, BOM_SIZE); 545 this.defaultEnc = defaultEnc; 546 } 547 548 public String getDefaultEncoding() { 549 return defaultEnc; 550 } 551 552 public String getEncoding() { 553 if (!isInited) { 554 try { 555 init(); 556 } catch (IOException ex) { 557 IllegalStateException ise = new IllegalStateException("Init method failed."); 558 ise.initCause(ise); 559 throw ise; 560 } 561 } 562 return encoding; 563 } 564 565 protected void init() throws IOException { 566 if (isInited) 567 return; 568 569 byte bom[] = new byte[BOM_SIZE]; 570 int n, unread; 571 n = internalIn.read(bom, 0, bom.length); 572 573 if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) 574 && (bom[3] == (byte) 0xFF)) { 575 encoding = "UTF-32BE"; 576 unread = n - 4; 577 } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) 578 && (bom[3] == (byte) 0x00)) { 579 encoding = "UTF-32LE"; 580 unread = n - 4; 581 } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { 582 encoding = "UTF-8"; 583 unread = n - 3; 584 } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { 585 encoding = "UTF-16BE"; 586 unread = n - 2; 587 } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { 588 encoding = "UTF-16LE"; 589 unread = n - 2; 590 } else { 591 encoding = defaultEnc; 592 unread = n; 593 } 594 595 if (unread > 0) 596 internalIn.unread(bom, (n - unread), unread); 597 598 isInited = true; 599 } 600 601 public void close() throws IOException { 602 internalIn.close(); 603 } 604 605 public int read() throws IOException { 606 return internalIn.read(); 607 } 608 } 609 610 public static boolean compareIdentifier(EDbVendor dbVendor, ESQLDataObjectType sqlDataObjectType, 611 String identifier1, String identifier2) { 612 List<String> segments1 = parseNames(identifier1); 613 List<String> segments2 = parseNames(identifier2); 614 615 if (segments1.size() != segments2.size()) 616 return false; 617 618 boolean supportCatalog = TSQLEnv.supportCatalog(dbVendor); 619 boolean supportSchema = TSQLEnv.supportSchema(dbVendor); 620 621 if(supportCatalog && supportSchema) { 622 if (sqlDataObjectType == ESQLDataObjectType.dotColumn) { 623 if (segments1.size() > 4) { 624 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 625 segments2.get(0)) 626 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(1), 627 segments2.get(1)) 628 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(2), 629 segments2.get(2)) 630 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, mergeSegments(segments1, 3), 631 mergeSegments(segments2, 3)); 632 } else if (segments1.size() == 4) { 633 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 634 segments2.get(0)) 635 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(1), 636 segments2.get(1)) 637 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(2), 638 segments2.get(2)) 639 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(3), 640 segments2.get(3)); 641 } else if (segments1.size() == 3) { 642 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(0), 643 segments2.get(0)) 644 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(1), 645 segments2.get(1)) 646 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(2), 647 segments2.get(2)); 648 } else if (segments1.size() == 2) { 649 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(0), 650 segments2.get(0)) 651 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(1), 652 segments2.get(1)); 653 } else if (segments1.size() == 1) { 654 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(0), 655 segments2.get(0)); 656 } 657 } else if (sqlDataObjectType == ESQLDataObjectType.dotTable 658 || sqlDataObjectType == ESQLDataObjectType.dotOraclePackage 659 || sqlDataObjectType == ESQLDataObjectType.dotFunction 660 || sqlDataObjectType == ESQLDataObjectType.dotProcedure 661 || sqlDataObjectType == ESQLDataObjectType.dotTrigger) { 662 if (segments1.size() > 3) { 663 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 664 segments2.get(0)) 665 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(1), 666 segments2.get(1)) 667 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments1, 2), mergeSegments(segments2, 2)); 668 } else if (segments1.size() == 3) { 669 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 670 segments2.get(0)) 671 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(1), 672 segments2.get(1)) 673 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(2), segments2.get(2)); 674 } else if (segments1.size() == 2) { 675 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(0), 676 segments2.get(0)) 677 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(1), segments2.get(1)); 678 } else if (segments1.size() == 1) { 679 return TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(0), segments2.get(0)); 680 } 681 } else if (sqlDataObjectType == ESQLDataObjectType.dotSchema) { 682 if (segments1.size() > 2) { 683 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 684 segments2.get(0)) 685 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments1, 1), mergeSegments(segments2, 1)); 686 } else if (segments1.size() == 2) { 687 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 688 segments2.get(0)) 689 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(1), segments2.get(1)); 690 } else if (segments1.size() == 1) { 691 return TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(0), segments2.get(0)); 692 } 693 } else if (sqlDataObjectType == ESQLDataObjectType.dotCatalog) { 694 if (segments1.size() > 1) { 695 return TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments1, 0), mergeSegments(segments2, 0)); 696 } else if (segments1.size() == 1) { 697 return TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(0), segments2.get(0)); 698 } 699 } 700 } 701 else if(supportCatalog){ 702 if (sqlDataObjectType == ESQLDataObjectType.dotColumn) { 703 if (segments1.size() > 3) { 704 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 705 segments2.get(0)) 706 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(1), 707 segments2.get(1)) 708 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, mergeSegments(segments1, 2), 709 mergeSegments(segments2, 2)); 710 } else if (segments1.size() == 3) { 711 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 712 segments2.get(0)) 713 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(1), 714 segments2.get(1)) 715 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(2), 716 segments2.get(2)); 717 } else if (segments1.size() == 2) { 718 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(0), 719 segments2.get(0)) 720 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(1), 721 segments2.get(1)); 722 } else if (segments1.size() == 1) { 723 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(0), 724 segments2.get(0)); 725 } 726 } else if (sqlDataObjectType == ESQLDataObjectType.dotTable 727 || sqlDataObjectType == ESQLDataObjectType.dotOraclePackage 728 || sqlDataObjectType == ESQLDataObjectType.dotFunction 729 || sqlDataObjectType == ESQLDataObjectType.dotProcedure 730 || sqlDataObjectType == ESQLDataObjectType.dotTrigger) { 731 if (segments1.size() > 2) { 732 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 733 segments2.get(0)) 734 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments1, 1), mergeSegments(segments2, 1)); 735 } else if (segments1.size() == 2) { 736 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), 737 segments2.get(0)) 738 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(1), segments2.get(1)); 739 } else if (segments1.size() == 1) { 740 return TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(0), segments2.get(0)); 741 } 742 } else if (sqlDataObjectType == ESQLDataObjectType.dotCatalog || sqlDataObjectType == ESQLDataObjectType.dotSchema) { 743 if (segments1.size() > 1) { 744 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, mergeSegments(segments1, 0), mergeSegments(segments2, 0)); 745 } else if (segments1.size() == 1) { 746 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments1.get(0), segments2.get(0)); 747 } 748 } 749 } 750 else if(supportSchema){ 751 if (sqlDataObjectType == ESQLDataObjectType.dotColumn) { 752 if (segments1.size() > 3) { 753 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(0), 754 segments2.get(0)) 755 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(1), 756 segments2.get(1)) 757 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, mergeSegments(segments1, 2), 758 mergeSegments(segments2, 2)); 759 } else if (segments1.size() == 3) { 760 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(0), 761 segments2.get(0)) 762 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(1), 763 segments2.get(1)) 764 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(2), 765 segments2.get(2)); 766 } else if (segments1.size() == 2) { 767 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments1.get(0), 768 segments2.get(0)) 769 && TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(1), 770 segments2.get(1)); 771 } else if (segments1.size() == 1) { 772 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments1.get(0), 773 segments2.get(0)); 774 } 775 } else if (sqlDataObjectType == ESQLDataObjectType.dotTable 776 || sqlDataObjectType == ESQLDataObjectType.dotOraclePackage 777 || sqlDataObjectType == ESQLDataObjectType.dotFunction 778 || sqlDataObjectType == ESQLDataObjectType.dotProcedure 779 || sqlDataObjectType == ESQLDataObjectType.dotTrigger) { 780 if (segments1.size() > 2) { 781 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(0), 782 segments2.get(0)) 783 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments1, 1), mergeSegments(segments2, 1)); 784 } else if (segments1.size() == 2) { 785 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(0), 786 segments2.get(0)) 787 && TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(1), segments2.get(1)); 788 } else if (segments1.size() == 1) { 789 return TSQLEnv.compareIdentifier(dbVendor, sqlDataObjectType, segments1.get(0), segments2.get(0)); 790 } 791 } else if (sqlDataObjectType == ESQLDataObjectType.dotCatalog || sqlDataObjectType == ESQLDataObjectType.dotSchema) { 792 if (segments1.size() > 1) { 793 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, mergeSegments(segments1, 0), mergeSegments(segments2, 0)); 794 } else if (segments1.size() == 1) { 795 return TSQLEnv.compareIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments1.get(0), segments2.get(0)); 796 } 797 } 798 } 799 return false; 800 } 801 802 public static String normalizeIdentifier(EDbVendor dbVendor, ESQLDataObjectType objectType, String identifier) { 803 if (identifier == null) 804 return null; 805 String originIdentifier = identifier; 806 identifier = IdentifierService.normalizeStatic(dbVendor, objectType, identifier); 807 boolean collationSensitive = false; 808 switch (objectType) { 809 case dotCatalog: 810 case dotSchema: 811 collationSensitive = TSQLEnv.catalogCollationCaseSensitive.get(dbVendor); 812 break; 813 case dotFunction: 814 case dotProcedure: 815 case dotTrigger: 816 case dotTable: 817 case dotOraclePackage: 818 collationSensitive = TSQLEnv.tableCollationCaseSensitive.get(dbVendor); 819 break; 820 case dotColumn: 821 collationSensitive = TSQLEnv.columnCollationCaseSensitive.get(dbVendor); 822 break; 823 default: 824 collationSensitive = TSQLEnv.defaultCollationCaseSensitive.get(dbVendor); 825 break; 826 } 827 if(parseNames(identifier).size()>1) { 828 return collationSensitive ? originIdentifier : originIdentifier.toUpperCase(); 829 } 830 else { 831 return collationSensitive ? identifier : identifier.toUpperCase(); 832 } 833 } 834 835 public static String getIdentifierNormalColumnName(EDbVendor dbVendor, String name) { 836 return getIdentifierNormalName(dbVendor, name, ESQLDataObjectType.dotColumn); 837 } 838 839 public static String getIdentifierNormalTableName(String name) { 840 return getIdentifierNormalName(ModelBindingManager.getGlobalVendor(), name, ESQLDataObjectType.dotTable); 841 } 842 843 public static String getIdentifierNormalTableName(EDbVendor dbVendor, String name) { 844 return getIdentifierNormalName(dbVendor, name, ESQLDataObjectType.dotTable); 845 } 846 847 /** 848 * 规范化多段限定名(Multi-Segment Qualified Name)并返回规范化后的完整限定名。 849 * 850 * <h3>核心功能</h3> 851 * <p>本方法是 SQL 标识符规范化的<b>多段名处理版本</b>,接受包含多段(catalog.schema.table.column)的限定名, 852 * 根据数据库厂商特性、层级支持能力和对象类型,智能解析和规范化每个段,最后返回用点号连接的完整规范化名称。</p> 853 * 854 * <h3>处理流程</h3> 855 * <ol> 856 * <li><b>厂商特定语法展开</b>: 857 * <ul> 858 * <li>MSSQL/Azure SQL: 将 ".." 语法展开为 ".dbo." 或全局配置的 schema</li> 859 * <li>示例:{@code "db..table"} → {@code "db.dbo.table"}</li> 860 * </ul> 861 * </li> 862 * <li><b>解析多段名</b>:使用 {@link #parseNames(String)} 将限定名按点号分割成段列表</li> 863 * <li><b>智能段类型推断</b>:根据以下因素决定每段的实际类型: 864 * <ul> 865 * <li>数据库厂商的层级支持能力(supportCatalog/supportSchema)</li> 866 * <li>目标对象类型({@code sqlDataObjectType})</li> 867 * <li>实际段数</li> 868 * </ul> 869 * </li> 870 * <li><b>逐段规范化</b>:对每段调用 {@link #normalizeIdentifier(EDbVendor, ESQLDataObjectType, String)}, 871 * 应用厂商特定的大小写规则、引号处理等</li> 872 * <li><b>重组限定名</b>:用点号连接所有规范化后的段,返回完整的规范化限定名</li> 873 * </ol> 874 * 875 * <h3>智能段类型推断示例</h3> 876 * <p>假设数据库<b>同时支持 catalog 和 schema</b>,目标类型为 {@code dotTable}:</p> 877 * <ul> 878 * <li>3段名 {@code "a.b.c"} → 解析为 {@code catalog.schema.table}</li> 879 * <li>2段名 {@code "a.b"} → 解析为 {@code schema.table}</li> 880 * <li>1段名 {@code "a"} → 解析为 {@code table}</li> 881 * </ul> 882 * 883 * <p>假设数据库<b>仅支持 catalog</b>(如 MySQL),目标类型为 {@code dotTable}:</p> 884 * <ul> 885 * <li>2段名 {@code "a.b"} → 解析为 {@code catalog.table}</li> 886 * <li>1段名 {@code "a"} → 解析为 {@code table}</li> 887 * </ul> 888 * 889 * <p>假设数据库<b>仅支持 schema</b>(如 PostgreSQL),目标类型为 {@code dotTable}:</p> 890 * <ul> 891 * <li>2段名 {@code "a.b"} → 解析为 {@code schema.table}</li> 892 * <li>1段名 {@code "a"} → 解析为 {@code table}</li> 893 * </ul> 894 * 895 * <h3>对于 dotColumn 类型的特殊处理</h3> 896 * <p>列名可能有4段(catalog.schema.table.column),方法会根据实际段数自动调整解析策略:</p> 897 * <ul> 898 * <li>4段名 {@code "db.sch.tbl.col"} → {@code catalog.schema.table.column}</li> 899 * <li>3段名 {@code "sch.tbl.col"} → {@code schema.table.column}</li> 900 * <li>2段名 {@code "tbl.col"} → {@code table.column}</li> 901 * <li>1段名 {@code "col"} → {@code column}</li> 902 * </ul> 903 * 904 * <h3>处理超长限定名</h3> 905 * <p>当段数超过标准层级时(如表名有4段或更多),方法会使用 {@link #mergeSegments(List, int)} 906 * 将多余的尾部段合并为单个段(保留点号),然后作为最后一段进行规范化。</p> 907 * <p>示例:5段列名 {@code "db.sch.tbl.nested.col"} → 合并后4段处理: 908 * {@code "db.sch.tbl.nested.col"} (最后两段合并为 {@code "nested.col"})</p> 909 * 910 * <h3>方法目的与使用场景</h3> 911 * <ul> 912 * <li><b>目的</b>:为多段限定名提供统一的规范化接口,生成可用于比较、索引和查找的标准化名称</li> 913 * <li><b>输出特性</b>:返回<b>多段名</b>(用点号连接),保留层级结构信息</li> 914 * <li><b>使用场景</b>: 915 * <ul> 916 * <li>环境层(TSQLEnv)处理完整限定名</li> 917 * <li>名称比较和匹配(需要保留层级信息)</li> 918 * <li>快速索引查找(NameKey 构造)</li> 919 * </ul> 920 * </li> 921 * </ul> 922 * 923 * <h3>与相关方法的区别</h3> 924 * <ul> 925 * <li><b>{@link #normalizeIdentifier(EDbVendor, ESQLDataObjectType, String)}</b>: 926 * 单段规范化,不解析限定名,直接处理引号和大小写,返回单段名</li> 927 * <li><b>{@code IdentifierService.keyForMap(String, ESQLDataObjectType)}</b>: 928 * 仅接受单段名,用于生成 Map 的 key,会抛出异常如果输入是多段名</li> 929 * <li><b>{@code IdentifierService.normalizeQualifiedName(String, ESQLDataObjectType)}</b>: 930 * 新架构中的等价方法,提供相同的多段名规范化功能</li> 931 * </ul> 932 * 933 * <h3>厂商特定行为</h3> 934 * <ul> 935 * <li><b>MySQL</b>: 仅支持 catalog(即 database),反引号引用,大小写根据系统变量决定</li> 936 * <li><b>PostgreSQL</b>: 仅支持 schema,双引号引用,未加引号的标识符转小写</li> 937 * <li><b>SQL Server</b>: 支持 catalog+schema,方括号或双引号引用,".." 展开为 ".dbo."</li> 938 * <li><b>Oracle</b>: 仅支持 schema,双引号引用,未加引号的标识符转大写</li> 939 * <li><b>Snowflake</b>: 支持 catalog+schema,双引号引用,大小写保留但匹配不敏感</li> 940 * <li><b>BigQuery</b>: 支持 catalog+schema(项目+数据集),反引号引用,大小写不敏感,可能内部转小写</li> 941 * </ul> 942 * 943 * @param dbVendor 数据库厂商类型(决定层级支持、引号风格、大小写规则) 944 * @param name 原始标识符或多段限定名(可能包含引号/反引号;可能包含 catalog/schema 前缀; 945 * 可能包含厂商特定语法如 MSSQL 的 "..") 946 * @param sqlDataObjectType 期望的对象类型(例如 dotTable, dotColumn, dotSchema, dotCatalog), 947 * 用于指导段类型推断和规范化规则应用 948 * @return 规范化后的完整限定名,用点号连接各段;如果输入为 {@code null},返回 {@code null}; 949 * 如果输入为空字符串或无法解析,返回空字符串 950 * 951 * @see #normalizeIdentifier(EDbVendor, ESQLDataObjectType, String) 单段规范化方法 952 * @see #parseNames(String) 多段名解析方法 953 * @see #mergeSegments(List, int) 段合并工具方法 954 * @see TSQLEnv#normalizeIdentifier(EDbVendor, ESQLDataObjectType, String) 955 * @see IdentifierService#normalizeQualifiedName(String, ESQLDataObjectType) Phase 0 新架构中的等价方法 956 * 957 * @since 3.1.0.8 958 */ 959 public static String getIdentifierNormalName(EDbVendor dbVendor, String name, 960 ESQLDataObjectType sqlDataObjectType) { 961 if (name == null) { 962 return null; 963 } 964 if (dbVendor == EDbVendor.dbvmssql || dbVendor == EDbVendor.dbvazuresql) { 965 if (name.indexOf("..") != -1) { 966 if (ModelBindingManager.getGlobalSchema() != null) { 967 name = name.replace("..", "." + ModelBindingManager.getGlobalSchema() + "."); 968 } else { 969 name = name.replace("..", ".dbo."); 970 } 971 } 972 } 973 List<String> segments = parseNames(name); 974 StringBuilder builder = new StringBuilder(); 975 boolean supportCatalog = TSQLEnv.supportCatalog(dbVendor); 976 boolean supportSchema = TSQLEnv.supportSchema(dbVendor); 977 978 if(supportCatalog && supportSchema) { 979 if (sqlDataObjectType == ESQLDataObjectType.dotColumn) { 980 if (segments.size() > 4) { 981 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 982 .append(".") 983 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(1))) 984 .append(".") 985 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(2))) 986 .append(".") 987 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, mergeSegments(segments, 3))); 988 } else if (segments.size() == 4) { 989 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 990 .append(".") 991 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(1))) 992 .append(".") 993 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(2))) 994 .append(".") 995 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(3))); 996 } else if (segments.size() == 3) { 997 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(0))) 998 .append(".") 999 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(1))) 1000 .append(".") 1001 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(2))); 1002 } else if (segments.size() == 2) { 1003 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(0))) 1004 .append(".") 1005 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(1))); 1006 } else if (segments.size() == 1) { 1007 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(0))); 1008 } 1009 } else if (sqlDataObjectType == ESQLDataObjectType.dotTable 1010 || sqlDataObjectType == ESQLDataObjectType.dotOraclePackage 1011 || sqlDataObjectType == ESQLDataObjectType.dotFunction 1012 || sqlDataObjectType == ESQLDataObjectType.dotProcedure 1013 || sqlDataObjectType == ESQLDataObjectType.dotTrigger) { 1014 if (segments.size() > 3) { 1015 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1016 .append(".") 1017 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(1))) 1018 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments, 2))); 1019 } else if (segments.size() == 3) { 1020 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1021 .append(".") 1022 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(1))) 1023 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(2))); 1024 } else if (segments.size() == 2) { 1025 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(0))) 1026 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(1))); 1027 } else if (segments.size() == 1) { 1028 builder.append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(0))); 1029 } 1030 } else if (sqlDataObjectType == ESQLDataObjectType.dotSchema) { 1031 if (segments.size() > 2) { 1032 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1033 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments, 1))); 1034 } else if (segments.size() == 2) { 1035 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1036 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(1))); 1037 } else if (segments.size() == 1) { 1038 builder.append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(0))); 1039 } 1040 } else if (sqlDataObjectType == ESQLDataObjectType.dotCatalog) { 1041 if (segments.size() > 1) { 1042 builder.append(normalizeIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments, 0))); 1043 } else if (segments.size() == 1) { 1044 builder.append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(0))); 1045 } 1046 } 1047 } 1048 else if(supportCatalog){ 1049 if (sqlDataObjectType == ESQLDataObjectType.dotColumn) { 1050 if (segments.size() > 3) { 1051 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1052 .append(".") 1053 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(1))) 1054 .append(".") 1055 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, mergeSegments(segments, 2))); 1056 } else if (segments.size() == 3) { 1057 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1058 .append(".") 1059 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(1))) 1060 .append(".") 1061 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(2))); 1062 } else if (segments.size() == 2) { 1063 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(0))) 1064 .append(".") 1065 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(1))); 1066 } else if (segments.size() == 1) { 1067 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(0))); 1068 } 1069 } else if (sqlDataObjectType == ESQLDataObjectType.dotTable 1070 || sqlDataObjectType == ESQLDataObjectType.dotOraclePackage 1071 || sqlDataObjectType == ESQLDataObjectType.dotFunction 1072 || sqlDataObjectType == ESQLDataObjectType.dotProcedure 1073 || sqlDataObjectType == ESQLDataObjectType.dotTrigger) { 1074 if (segments.size() > 2) { 1075 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1076 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments, 1))); 1077 } else if (segments.size() == 2) { 1078 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))) 1079 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(1))); 1080 } else if (segments.size() == 1) { 1081 builder.append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(0))); 1082 } 1083 } else if (sqlDataObjectType == ESQLDataObjectType.dotSchema || sqlDataObjectType == ESQLDataObjectType.dotCatalog) { 1084 if (segments.size() > 1) { 1085 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, mergeSegments(segments, 0))); 1086 } else if (segments.size() == 1) { 1087 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotCatalog, segments.get(0))); 1088 } 1089 } 1090 } 1091 else if(supportSchema){ 1092 if (sqlDataObjectType == ESQLDataObjectType.dotColumn) { 1093 if (segments.size() > 3) { 1094 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(0))) 1095 .append(".") 1096 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(1))) 1097 .append(".") 1098 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, mergeSegments(segments, 2))); 1099 } else if (segments.size() == 3) { 1100 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(0))) 1101 .append(".") 1102 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(1))) 1103 .append(".") 1104 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(2))); 1105 } else if (segments.size() == 2) { 1106 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotTable, segments.get(0))) 1107 .append(".") 1108 .append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(1))); 1109 } else if (segments.size() == 1) { 1110 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotColumn, segments.get(0))); 1111 } 1112 } else if (sqlDataObjectType == ESQLDataObjectType.dotTable 1113 || sqlDataObjectType == ESQLDataObjectType.dotOraclePackage 1114 || sqlDataObjectType == ESQLDataObjectType.dotFunction 1115 || sqlDataObjectType == ESQLDataObjectType.dotProcedure 1116 || sqlDataObjectType == ESQLDataObjectType.dotTrigger) { 1117 if (segments.size() > 2) { 1118 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(0))) 1119 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, mergeSegments(segments, 1))); 1120 } else if (segments.size() == 2) { 1121 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(0))) 1122 .append(".").append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(1))); 1123 } else if (segments.size() == 1) { 1124 builder.append(normalizeIdentifier(dbVendor, sqlDataObjectType, segments.get(0))); 1125 } 1126 } else if (sqlDataObjectType == ESQLDataObjectType.dotSchema || sqlDataObjectType == ESQLDataObjectType.dotCatalog) { 1127 if (segments.size() > 1) { 1128 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, mergeSegments(segments, 0))); 1129 } else if (segments.size() == 1) { 1130 builder.append(normalizeIdentifier(dbVendor, ESQLDataObjectType.dotSchema, segments.get(0))); 1131 } 1132 } 1133 } 1134 return builder.toString(); 1135 } 1136 1137 public static String mergeSegments(List<String> segments, int index) { 1138 StringBuilder buffer = new StringBuilder(); 1139 for (int i = index; i < segments.size(); i++) { 1140 buffer.append(segments.get(i)); 1141 if(i<segments.size()-1) { 1142 buffer.append("."); 1143 } 1144 } 1145 return buffer.toString(); 1146 } 1147 1148// public static String getIdentifierNormalName(EDbVendor vendor, String name) { 1149// if (isEmpty(name)) { 1150// return null; 1151// } 1152// name = name.replaceAll("(?i)null\\.", ""); 1153// switch (vendor) { 1154// case dbvbigquery: 1155// return replaceIdentifierNormalName(name, "`.*?`", "`", true).replaceAll("\\.\\s+", "."); 1156// case dbvcouchbase: 1157// case dbvhive: 1158// case dbvimpala: 1159// case dbvmysql: 1160// return replaceIdentifierNormalName(name, "`.*?`", "`", true).replaceAll("\\.\\s+", "."); 1161// case dbvdax: 1162// return replaceIdentifierNormalName(name, "'.*?'", "'", true).replaceAll("\\.\\s+", "."); 1163// case dbvdb2: 1164// case dbvhana: 1165// case dbvinformix: 1166// case dbvnetezza: 1167// case dbvoracle: 1168// case dbvsnowflake: 1169// case dbvsybase: 1170// case dbvteradata: 1171// case dbvvertica: 1172// return replaceIdentifierNormalName(name, "\".*?\"", "\"", true).replaceAll("\\.\\s+", "."); 1173// case dbvpostgresql: 1174// case dbvgreenplum: 1175// case dbvredshift: 1176// return replaceIdentifierNormalName(name, "\".*?\"", "\"", false).replaceAll("\\.\\s+", "."); 1177// case dbvmssql: 1178// return replaceIdentifierNormalName(name, "([\"\\[']).*?([\"\\]'])", "[\"\\[\\]']", true) 1179// .replaceAll("\\.\\s+", "."); 1180// default: 1181// return replaceIdentifierNormalName(name, "\".*?\"", "\"", true).replaceAll("\\.\\s+", "."); 1182// } 1183// } 1184// 1185// private static String replaceIdentifierNormalName(String content, String match, String replace, boolean toUpper) { 1186// Pattern pattern = Pattern.compile(match, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); 1187// Matcher matcher = pattern.matcher(content); 1188// StringBuilder buffer = new StringBuilder(); 1189// int start = 0; 1190// while (matcher.find()) { 1191// int matchStart = matcher.start(); 1192// int macthEnd = matcher.end(); 1193// if (start < matchStart) { 1194// if (toUpper) { 1195// buffer.append(content.substring(start, matchStart).toUpperCase()); 1196// } else { 1197// buffer.append(content.substring(start, matchStart).toLowerCase()); 1198// } 1199// } 1200// buffer.append(matcher.group().replaceAll(replace, "")); 1201// start = macthEnd; 1202// } 1203// if (start < content.length()) { 1204// if (toUpper) { 1205// buffer.append(content.substring(start).toUpperCase()); 1206// } else { 1207// buffer.append(content.substring(start).toLowerCase()); 1208// } 1209// } 1210// return buffer.toString(); 1211// } 1212 1213 public static boolean isTempTable(table table) { 1214 if(SubType.temp_table.name().equals(table.getSubType())) { 1215 return true; 1216 } 1217 String tableName = table.getName(); 1218 List<String> segments = parseNames(tableName); 1219 if (tableName.startsWith("@") || segments.get(segments.size() - 1).startsWith("@")) { 1220 return true; 1221 } 1222 if (tableName.startsWith("#") || segments.get(segments.size() - 1).startsWith("#")) { 1223 return true; 1224 } 1225 return false; 1226 } 1227 1228// public static boolean isTempTable(String tableName) { 1229// List<String> segments = parseNames(tableName); 1230// if (tableName.startsWith("@") || segments.get(segments.size() - 1).startsWith("@")) { 1231// return true; 1232// } 1233// if (tableName.startsWith("#") || segments.get(segments.size() - 1).startsWith("#")) { 1234// return true; 1235// } 1236// return false; 1237// } 1238 1239// public static boolean isTempTable(TTable table, EDbVendor vendor) { 1240// switch (vendor) { 1241// case dbvmssql: 1242// return table.getName().startsWith("#"); 1243// default: 1244// return false; 1245// } 1246// } 1247 1248 public static File[] listFiles(File sqlFiles) { 1249 List<File> children = new ArrayList<File>(); 1250 if (sqlFiles != null) 1251 listFiles(sqlFiles, children); 1252 Collections.sort(children); 1253 return children.toArray(new File[0]); 1254 } 1255 1256 public static File[] listFiles(File sqlFiles, FileFilter filter) { 1257 List<File> children = new ArrayList<File>(); 1258 if (sqlFiles != null) 1259 listFiles(sqlFiles, children, filter); 1260 Collections.sort(children); 1261 return children.toArray(new File[0]); 1262 } 1263 1264 private static Set<String> extensions = new HashSet<String>(Arrays.asList("java", "class", "php", "c", "cpp", "properties", "iml", 1265 "yml", "xml", "md", "jpg", "png", "gif", "bmp", "tiff", "tif", "svg", "pdf", "mp3", "mp4", "bak", "jar", "gz", 1266 "tar", "log", "conf", "dll", "exe", "so", "sh", "bat", "cdr", "docx", "doc", "xps", "xlsx", "xls", "ppt", "pptx", 1267 "rar", "7z", "ttf", "caj", "dwg", "dwf", "dxf", "ico", "epub", "webp", "heic", "html", "htm", "vsd", "vsdx", "rtf", "ico")); 1268 1269 public static void listFiles(File rootFile, List<File> children) { 1270 if (rootFile.isFile()) 1271 children.add(rootFile); 1272 else { 1273 File[] files = rootFile.listFiles(t -> { 1274 int dotIndex = t.getName().lastIndexOf("."); 1275 if (dotIndex == -1) { 1276 return true; 1277 } 1278 String extension = t.getName().toLowerCase().substring(dotIndex + 1); 1279 return !extensions.contains(extension); 1280 }); 1281 if (files != null) { 1282 for (int i = 0; i < files.length; i++) { 1283 listFiles(files[i], children); 1284 } 1285 } 1286 } 1287 } 1288 1289 public static void listFiles(File rootFile, List<File> children, FileFilter filter) { 1290 if (rootFile.isFile() && filter.accept(rootFile)) 1291 children.add(rootFile); 1292 else { 1293 File[] files = rootFile.listFiles(filter); 1294 if (files != null) { 1295 for (int i = 0; i < files.length; i++) { 1296 listFiles(files[i], children, filter); 1297 } 1298 } 1299 } 1300 } 1301 1302 public static String readFile(File file) { 1303 StringBuilder stringBuilder = new StringBuilder(); 1304 BufferedReader reader = null; 1305 try { 1306 reader = new BufferedReader(new FileReader(file)); 1307 1308 String line = null; 1309 String ls = System.getProperty("line.separator"); 1310 while ((line = reader.readLine()) != null) { 1311 stringBuilder.append(line); 1312 stringBuilder.append(ls); 1313 } 1314 stringBuilder.deleteCharAt(stringBuilder.length() - 1); 1315 } catch (IOException e) { 1316 logger.error("read file failed.", e); 1317 } finally { 1318 if (reader != null) { 1319 try { 1320 reader.close(); 1321 } catch (IOException e) { 1322 logger.error("close reader failed.", e); 1323 } 1324 } 1325 } 1326 return stringBuilder.toString(); 1327 } 1328 1329 public static String stringToMD5(String plainText) { 1330 byte[] secretBytes = null; 1331 try { 1332 secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes("UTF-8")); 1333 StringBuffer sb = new StringBuffer(); 1334 for (int i = 0; i < secretBytes.length; ++i) { 1335 sb.append(Integer.toHexString((secretBytes[i] & 0xFF) | 0x100).substring(1, 3)); 1336 } 1337 return sb.toString(); 1338 } catch (Exception e) { 1339 logger.error("get text md5 value failed.", e); 1340 } 1341 return null; 1342 } 1343 1344 public static String trimSingleQuote(String columnAlias) { 1345 if(columnAlias.startsWith("'") && columnAlias.endsWith("'")) { 1346 return columnAlias.substring(1, columnAlias.length() - 1); 1347 } 1348 return columnAlias; 1349 } 1350 1351 public static String endTrim(String input) { 1352 if (input == null) { 1353 return null; 1354 } 1355 1356 int end = input.length(); 1357 while (end > 0 && Character.isWhitespace(input.charAt(end - 1))) { 1358 end--; 1359 } 1360 1361 return input.substring(0, end); 1362 } 1363 1364 public static void endTrim(StringBuilder buffer) { 1365 int length = buffer.length(); 1366 while (length > 0 && Character.isWhitespace(buffer.charAt(length - 1))) { 1367 length--; // 逐步减少长度 1368 } 1369 buffer.setLength(length); // 直接截断尾部空白字符 1370 } 1371 1372 public static String joinNonEmpty(String... parts) { 1373 return Arrays.stream(parts) 1374 .filter(s -> s != null && !s.trim().isEmpty()) 1375 .collect(Collectors.joining("/")); 1376 } 1377}