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