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}