001package gudusoft.gsqlparser.sqlcmds; 002 003import gudusoft.gsqlparser.EDbVendor; 004import java.util.concurrent.ConcurrentHashMap; 005 006/** 007 * Factory for creating vendor-specific SQL command resolvers. 008 * This factory ensures only the necessary vendor implementations are loaded, 009 * reducing memory footprint and class loading overhead. 010 * 011 * Thread-safe implementation that creates new instances on each request 012 * to avoid shared mutable state between concurrent parser instances. 013 * 014 * @since 3.1.0.9 015 */ 016public class SqlCmdsFactory { 017 018 // Kept for backward compatibility with clearCache() and getCacheSize() methods 019 private static final ConcurrentHashMap<EDbVendor, ISqlCmds> providers = new ConcurrentHashMap<>(); 020 021 /** 022 * Feature flag for gradual migration. When true, uses new modular providers. 023 * When false, falls back to monolithic TSqlCmds (for safety during migration). 024 */ 025 private static boolean useModularProviders = true; 026 027 // Private constructor to prevent instantiation 028 private SqlCmdsFactory() {} 029 030 /** 031 * Gets or creates a vendor-specific SQL command resolver. 032 * Always creates a new instance to ensure thread safety (no shared mutable state). 033 * 034 * @param vendor Database vendor 035 * @return SQL command resolver for the vendor 036 * @throws IllegalArgumentException if vendor is null or unsupported 037 */ 038 public static ISqlCmds get(EDbVendor vendor) { 039 if (vendor == null) { 040 throw new IllegalArgumentException("Database vendor cannot be null"); 041 } 042 043 // Always create new instance - no caching to avoid shared mutable state 044 return createProvider(vendor); 045 } 046 047 /** 048 * Creates a new provider instance for the given vendor. 049 * Called for every get() request to ensure thread safety. 050 */ 051 private static ISqlCmds createProvider(EDbVendor vendor) { 052 if (!useModularProviders) { 053 // Migration safety: use monolithic adapter during transition 054 return new TSqlCmdsAdapter(vendor); 055 } 056 057 // Create vendor-specific provider 058 switch (vendor) { 059 case dbvoracle: 060 return new TSqlCmdsOracle(); 061 case dbvaccess: 062 case dbvmssql: 063 return new TSqlCmdsMssql(); 064 case dbvpostgresql: 065 return new TSqlCmdsPostgresql(); 066 case dbvmysql: 067 return new TSqlCmdsMysql(); 068 case dbvredshift: 069 return new TSqlCmdsRedshift(); 070 case dbvgreenplum: 071 return new TSqlCmdsGreenplum(); 072 case dbvsnowflake: 073 return new TSqlCmdsSnowflake(); 074 case dbvbigquery: 075 return new TSqlCmdsBigquery(); 076 case dbvteradata: 077 return new TSqlCmdsTeradata(); 078 case dbvhive: 079 case dbvimpala: // Impala uses Hive commands 080 return new TSqlCmdsHive(); 081 case dbvansi: 082 case dbvdb2: 083 return new TSqlCmdsDb2(); 084 case dbvsybase: 085 return new TSqlCmdsSybase(); 086 case dbvinformix: 087 return new TSqlCmdsInformix(); 088 case dbvhana: 089 return new TSqlCmdsHana(); 090 case dbvvertica: 091 return new TSqlCmdsVertica(); 092 case dbvcouchbase: 093 return new TSqlCmdsCouchbase(); 094 case dbvflink: 095 return new TSqlCmdsFlink(); 096 case dbvsparksql: 097 return new TSqlCmdsSparksql(); 098 case dbvtrino: 099 case dbvpresto: 100 return new TSqlCmdsPresto(); 101 case dbvathena: 102 return new TSqlCmdsAthena(); 103 case dbvdatabricks: 104 return new TSqlCmdsDatabricks(); 105 case dbvdoris: 106 return new TSqlCmdsDoris(); 107 case dbvstarrocks: 108 return new TSqlCmdsStarrocks(); 109 case dbvnetezza: 110 return new TSqlCmdsNetezza(); 111 case dbvmdx: 112 return new TSqlCmdsMdx(); 113 case dbvgaussdb: 114 return new TSqlCmdsGaussdb(); 115 case dbvopenedge: 116 return new TSqlCmdsOpenedge(); 117 case dbvsqlite: 118 return new TSqlCmdsSqlite(); 119 case dbvclickhouse: 120 return new TSqlCmdsClickhouse(); 121 case dbvsoql: 122 case dbvodbc: // odbc use mssql commands 123 TSqlCmdsMssql mssqlCmds = new TSqlCmdsMssql(); 124 mssqlCmds.setVendor(vendor); 125 return mssqlCmds; // TSqlCmdsOdbc(); 126 default: 127 // For generic or unknown vendors, use a default implementation 128 return new TSqlCmdsMssql(); 129 } 130 } 131 132 /** 133 * Clears the provider cache. Useful for testing and memory management. 134 */ 135 public static void clearCache() { 136 providers.clear(); 137 } 138 139 /** 140 * Sets whether to use modular providers or fall back to monolithic TSqlCmds. 141 * @param useModular true to use new modular system, false for monolithic 142 */ 143 public static void setUseModularProviders(boolean useModular) { 144 useModularProviders = useModular; 145 if (useModular != useModularProviders) { 146 clearCache(); // Clear cache when switching modes 147 } 148 } 149 150 /** 151 * Gets the number of cached providers (for monitoring/debugging). 152 * @return Number of providers currently in cache 153 */ 154 public static int getCacheSize() { 155 return providers.size(); 156 } 157}