001package gudusoft.gsqlparser.sqlenv; 002 003 004import gudusoft.gsqlparser.TBaseType; 005import gudusoft.gsqlparser.util.SQLUtil; 006 007import java.util.*; 008 009/** 010 * In the most sql-implementation, Catalog is the anonymous of the Database. 011 * So, use this class represents a database. 012 */ 013public class TSQLCatalog extends TSQLObject { 014 015 // IdentifierService for consistent key generation (lazy initialization). 016 // volatile: concurrent lazy init may build duplicate (equivalent) instances, 017 // but must never publish a partially constructed one to another thread. 018 private volatile IdentifierService identifierService; 019 020 // ===== Phase 6: Catalog seal mechanism for thread-safety hardening ===== 021 /** 022 * Seal state flag (volatile for thread visibility). 023 */ 024 private volatile boolean sealed = false; 025 026 /** 027 * Seal this catalog to prevent further modifications (Phase 6). 028 * 029 * <p>See {@link TSQLEnv#seal()} for detailed documentation. 030 */ 031 public void seal() { 032 this.sealed = true; 033 } 034 035 /** 036 * Check if this catalog is sealed (Phase 6). 037 * 038 * @return true if sealed, false otherwise 039 */ 040 public boolean isSealed() { 041 return sealed; 042 } 043 044 /** 045 * Check if catalog is not sealed, throw exception if sealed and enforcement is enabled. 046 * 047 * @throws IllegalStateException if sealed and TBaseType.ENFORCE_CATALOG_SEAL is true 048 */ 049 private void checkNotSealed() { 050 if (sealed && TBaseType.ENFORCE_CATALOG_SEAL) { 051 throw new IllegalStateException("Cannot modify sealed catalog. Call seal() marks catalog as read-only."); 052 } 053 } 054 055 /** 056 * The identifier service of the environment this object belongs to (lazy initialization). 057 * 058 * <p>Inherited, never rebuilt from the vendor: this object's local indexes are part of the 059 * same catalog the environment's {@link CatalogStore} indexes, so keying them under the 060 * vendor default while the environment ran a per-category configuration would let one half 061 * of a lookup answer a question the other half never asked. 062 */ 063 private IdentifierService getIdentifierService() { 064 if (identifierService == null) { 065 if (this.sqlEnv == null) { 066 // Every catalog object is created against an environment; with none there is no 067 // vendor and no configuration to inherit, so say so instead of guessing one. 068 throw new IllegalStateException(getClass().getSimpleName() 069 + " has no TSQLEnv, so it has no identifier configuration to compare with"); 070 } 071 identifierService = this.sqlEnv.getIdentifierService(); 072 } 073 return identifierService; 074 } 075 076 /** 077 * create a catalog and add to the SQL environment. 078 * 079 * @param sqlEnv SQL environment 080 * @param catalogName catalog name 081 */ 082 public TSQLCatalog(TSQLEnv sqlEnv, String catalogName){ 083 super(sqlEnv,catalogName,ESQLDataObjectType.dotCatalog); 084 this.sqlEnv.doAddCatalog(this); 085 } 086 087 /** 088 * schema list in this catalog 089 * 090 * @return schema list 091 */ 092 public List<TSQLSchema> getSchemaList() { 093 List<TSQLSchema> schemaList = new LinkedList<>(); 094 synchronized (schemaMap) { 095 for(CanonKey schema: schemaMap.keySet()){ 096 schemaList.add(schemaMap.get(schema)); 097 } 098 } 099 return schemaList; 100 } 101 102 private Map<CanonKey, TSQLSchema> schemaMap = Collections.synchronizedMap(new LinkedHashMap<CanonKey, TSQLSchema>()); 103 104 protected TSQLSchema searchSchema(String schemaName){ 105 return schemaMap.get(sqlEnv.getIdentifierService().canonKey(schemaName, ESQLDataObjectType.dotSchema)); 106 } 107 108 protected void addSchema(TSQLSchema schema) { 109 synchronized (schemaMap) { 110 checkNotSealed(); 111 CanonKey key = sqlEnv.getIdentifierService().canonKeyOf(schema.getName(), ESQLDataObjectType.dotSchema, 112 IdentifierInputForm.CATALOG_STORED); 113 if (!schemaMap.containsKey(key)) schemaMap.put(key, schema); 114 } 115 } 116 117 /** 118 * get a schema instance from the catalog, create a new schema if this schema is not exist and the createIfNotExist parameter is true. 119 * 120 * @param schemaName schema name 121 * @param createIfNotExist create a new schema if this schema is not exist and the createIfNotExist parameter is true. 122 * @return the schema instance 123 */ 124 public TSQLSchema getSchema(String schemaName, boolean createIfNotExist){ 125 TSQLSchema result = searchSchema(schemaName); 126 if ((result == null)&&(createIfNotExist)){ 127 // synchronized so concurrent get-or-create of the same schema can't 128 // produce duplicate twins; the TSQLSchema constructor re-enters this 129 // monitor via addSchema (reentrant) 130 synchronized (schemaMap) { 131 result = searchSchema(schemaName); 132 if (result == null){ 133 result = new TSQLSchema(this,schemaName); 134 } 135 } 136 } 137 138 return result; 139 } 140 141 /** 142 * create a schema under this catalog 143 * 144 * @param schemaName schema name 145 * @return schema instance 146 */ 147 public TSQLSchema createSchema(String schemaName){ 148 return getSchema(schemaName,true); 149 } 150 151}