001package gudusoft.gsqlparser.util; 002 003import gudusoft.gsqlparser.EDbVendor; 004 005import java.io.InputStream; 006import java.util.*; 007 008/** 009 * Utility class for checking niladic functions (built-in functions without parentheses). 010 * 011 * Niladic functions are functions that can be called without parentheses and look like 012 * column references but are actually function calls returning values. 013 * 014 * Examples: 015 * - SQL Server: CURRENT_USER, SYSTEM_USER, CURRENT_TIMESTAMP 016 * - BigQuery: CURRENT_DATE, CURRENT_DATETIME, CURRENT_TIME 017 * - PostgreSQL: CURRENT_DATE, CURRENT_USER, LOCALTIME 018 * 019 * The function list is loaded from: 020 * /gudusoft/gsqlparser/builtinFunctions/niladicFunctions.properties 021 */ 022public class TNiladicFunctionUtil { 023 024 private static final Logger logger = LoggerFactory.getLogger(TNiladicFunctionUtil.class); 025 026 /** 027 * Map of vendor to set of niladic function names (uppercase). 028 */ 029 private static Map<EDbVendor, Set<String>> vendorNiladicFunctions = new HashMap<>(); 030 031 private static boolean initialized = false; 032 033 /** 034 * Check if a name is a niladic function for the given database vendor. 035 * 036 * @param vendor The database vendor 037 * @param functionName The function name to check (case-insensitive) 038 * @return true if it's a known niladic function for this vendor 039 */ 040 public static boolean isNiladicFunction(EDbVendor vendor, String functionName) { 041 if (vendor == null || functionName == null || functionName.isEmpty()) { 042 return false; 043 } 044 045 if (!initialized) { 046 loadNiladicFunctions(); 047 } 048 049 Set<String> functions = vendorNiladicFunctions.get(vendor); 050 if (functions == null) { 051 return false; 052 } 053 054 return functions.contains(functionName.toUpperCase(Locale.ROOT)); 055 } 056 057 /** 058 * Get all niladic functions for a vendor. 059 * 060 * @param vendor The database vendor 061 * @return Set of niladic function names (uppercase), or empty set if none 062 */ 063 public static Set<String> getNiladicFunctions(EDbVendor vendor) { 064 if (vendor == null) { 065 return Collections.emptySet(); 066 } 067 068 if (!initialized) { 069 loadNiladicFunctions(); 070 } 071 072 Set<String> functions = vendorNiladicFunctions.get(vendor); 073 return functions != null ? Collections.unmodifiableSet(functions) : Collections.emptySet(); 074 } 075 076 private static void loadNiladicFunctions() { 077 try { 078 String resourcePath = "/gudusoft/gsqlparser/builtinFunctions/niladicFunctions.properties"; 079 InputStream is = TNiladicFunctionUtil.class.getResourceAsStream(resourcePath); 080 081 if (is != null) { 082 String content = SQLUtil.getInputStreamContent(is, false); 083 String[] lines = content.split("\n"); 084 085 for (String line : lines) { 086 line = line.trim(); 087 // Skip comments and empty lines 088 if (line.isEmpty() || line.startsWith("#")) { 089 continue; 090 } 091 092 // Parse key=value format 093 int eqIndex = line.indexOf('='); 094 if (eqIndex <= 0) { 095 continue; 096 } 097 098 String key = line.substring(0, eqIndex).trim(); 099 String value = line.substring(eqIndex + 1).trim(); 100 101 EDbVendor vendor = getVendorFromKey(key); 102 if (vendor != null && !value.isEmpty()) { 103 Set<String> functions = new HashSet<>(); 104 for (String func : value.split(",")) { 105 String trimmed = func.trim().toUpperCase(Locale.ROOT); 106 if (!trimmed.isEmpty()) { 107 functions.add(trimmed); 108 } 109 } 110 if (!functions.isEmpty()) { 111 vendorNiladicFunctions.put(vendor, functions); 112 } 113 } 114 } 115 } 116 } catch (Exception e) { 117 logger.error("Error loading niladic functions", e); 118 } 119 initialized = true; 120 } 121 122 /** 123 * Map property key to EDbVendor. 124 */ 125 private static EDbVendor getVendorFromKey(String key) { 126 if (key == null) return null; 127 128 String lowerKey = key.toLowerCase(Locale.ROOT).trim(); 129 130 switch (lowerKey) { 131 case "mssql": 132 case "sqlserver": 133 return EDbVendor.dbvmssql; 134 case "azuresql": 135 case "azure": 136 return EDbVendor.dbvazuresql; 137 case "bigquery": 138 return EDbVendor.dbvbigquery; 139 case "snowflake": 140 return EDbVendor.dbvsnowflake; 141 case "postgresql": 142 case "postgres": 143 return EDbVendor.dbvpostgresql; 144 case "mysql": 145 return EDbVendor.dbvmysql; 146 case "oracle": 147 return EDbVendor.dbvoracle; 148 case "teradata": 149 return EDbVendor.dbvteradata; 150 case "db2": 151 return EDbVendor.dbvdb2; 152 case "hive": 153 return EDbVendor.dbvhive; 154 case "sparksql": 155 case "spark": 156 return EDbVendor.dbvsparksql; 157 case "redshift": 158 return EDbVendor.dbvredshift; 159 case "athena": 160 return EDbVendor.dbvathena; 161 case "presto": 162 return EDbVendor.dbvpresto; 163 case "vertica": 164 return EDbVendor.dbvvertica; 165 case "gaussdb": 166 return EDbVendor.dbvgaussdb; 167 case "greenplum": 168 return EDbVendor.dbvgreenplum; 169 case "netezza": 170 return EDbVendor.dbvnetezza; 171 case "informix": 172 return EDbVendor.dbvinformix; 173 case "hana": 174 return EDbVendor.dbvhana; 175 case "databricks": 176 return EDbVendor.dbvdatabricks; 177 case "impala": 178 return EDbVendor.dbvimpala; 179 case "couchbase": 180 return EDbVendor.dbvcouchbase; 181 case "sybase": 182 return EDbVendor.dbvsybase; 183 default: 184 return null; 185 } 186 } 187}