001package gudusoft.gsqlparser.sqlenv;
002
003/**
004 * SQL synonyms object.
005 *
006 * <p>A synonym is an alias for another schema object (its <em>base target</em>).
007 * Besides the synonym name, this class records the base object it points at as a
008 * tri-state (database/catalog, schema, object) triple. Any of the three may be
009 * {@code null} when "unknown": a {@code null} {@link #getSourceDatabase()} /
010 * {@link #getSourceSchema()} means "same database/schema as the synonym itself",
011 * resolved lazily by {@link #resolveBaseTable()}. Cross-database base targets are
012 * allowed (a synonym can point at an object in another database).
013 */
014public class TSQLSynonyms extends TSQLSchemaObject {
015
016    private String sourceDatabase;
017    private String sourceSchema;
018    private String sourceName;
019
020    public TSQLSynonyms(TSQLSchema sqlSchema, String synonymsName){
021        super(sqlSchema,synonymsName,ESQLDataObjectType.dotSynonyms);
022    }
023
024    /**
025     * database/catalog of the base object this synonym points at.
026     * {@code null} means "the same database as this synonym".
027     *
028     * @return base database name, or {@code null} when unknown
029     */
030    public String getSourceDatabase() {
031        return sourceDatabase;
032    }
033
034    public void setSourceDatabase(String sourceDatabase) {
035        this.sourceDatabase = sourceDatabase;
036    }
037
038    /**
039     * schema of the base object this synonym points at.
040     * {@code null} means "the same schema as this synonym".
041     *
042     * @return base schema name, or {@code null} when unknown
043     */
044    public String getSourceSchema() {
045        return sourceSchema;
046    }
047
048    public void setSourceSchema(String sourceSchema) {
049        this.sourceSchema = sourceSchema;
050    }
051
052    /**
053     * name of the base object this synonym points at.
054     *
055     * @return base object name, or {@code null} when unknown
056     */
057    public String getSourceName() {
058        return sourceName;
059    }
060
061    public void setSourceName(String sourceName) {
062        this.sourceName = sourceName;
063    }
064
065    /**
066     * Record the base target this synonym points at in one call.
067     *
068     * @param sourceDatabase base database/catalog, or {@code null} for the synonym's own database
069     * @param sourceSchema   base schema, or {@code null} for the synonym's own schema
070     * @param sourceName     base object name
071     */
072    public void setBaseTarget(String sourceDatabase, String sourceSchema, String sourceName) {
073        this.sourceDatabase = sourceDatabase;
074        this.sourceSchema = sourceSchema;
075        this.sourceName = sourceName;
076    }
077
078    /**
079     * whether this synonym carries a base target (a non-empty source object name).
080     *
081     * @return true if the base object name is known
082     */
083    public boolean hasBaseTarget() {
084        return sourceName != null && !sourceName.trim().isEmpty();
085    }
086
087    /**
088     * the fully qualified name of the base object this synonym points at, in
089     * {@code database.schema.object} form, defaulting the database/schema to the
090     * synonym's own catalog/schema when the source parts are unknown.
091     *
092     * @return qualified base name, or {@code null} when there is no base target
093     */
094    public String getQualifiedBaseName() {
095        if (!hasBaseTarget()) {
096            return null;
097        }
098        String db = (sourceDatabase != null && !sourceDatabase.trim().isEmpty())
099                ? sourceDatabase
100                : (schema != null && schema.getCatalog() != null ? schema.getCatalog().getName() : null);
101        String sch = (sourceSchema != null && !sourceSchema.trim().isEmpty())
102                ? sourceSchema
103                : (schema != null ? schema.getName() : null);
104        StringBuilder builder = new StringBuilder();
105        builder.append(db == null ? "" : db).append('.')
106               .append(sch == null ? "" : sch).append('.')
107               .append(sourceName);
108        return builder.toString();
109    }
110
111    /**
112     * Dereference this synonym to its base table/view by resolving the recorded
113     * base target against the owning SQL environment.
114     *
115     * @return the base {@link TSQLTable} (which may itself be a view), or
116     *         {@code null} when there is no base target or it cannot be resolved
117     */
118    public TSQLTable resolveBaseTable() {
119        if (sqlEnv == null || !hasBaseTarget()) {
120            return null;
121        }
122        String qualifiedBaseName = getQualifiedBaseName();
123        if (qualifiedBaseName == null) {
124            return null;
125        }
126        // Resolve to a table/view only (never re-enter synonym resolution) so a
127        // self/mutually referencing synonym cannot recurse indefinitely.
128        TSQLSchemaObject baseObject =
129                sqlEnv.searchSchemaObject(qualifiedBaseName, ESQLDataObjectType.dotTable);
130        if (baseObject instanceof TSQLTable) {
131            return (TSQLTable) baseObject;
132        }
133        return null;
134    }
135
136    public String getBaseTableQualifiedName() {
137        return getQualifiedBaseName();
138    }
139    
140}