001package gudusoft.gsqlparser.stmt.oceanbase;
002
003import gudusoft.gsqlparser.EDbVendor;
004import gudusoft.gsqlparser.ESqlStatementType;
005import gudusoft.gsqlparser.TCustomSqlStatement;
006import gudusoft.gsqlparser.nodes.TObjectName;
007import gudusoft.gsqlparser.nodes.TParseTreeVisitor;
008import gudusoft.gsqlparser.nodes.oceanbase.TOceanbaseCreateTenantSqlNode;
009import gudusoft.gsqlparser.nodes.oceanbase.TOceanbaseTenantOption;
010
011import java.util.ArrayList;
012
013/**
014 * OceanBase {@code CREATE TENANT} statement (Phase 4 Batch 1).
015 *
016 * <p>Exposes the parsed tenant name, {@code IF NOT EXISTS} flag, and the
017 * full tenant option list. Typed convenience accessors
018 * ({@link #getPrimaryZone()}, {@link #getLocality()},
019 * {@link #getCharset()}, {@link #getCompatibilityMode()},
020 * {@link #getResourcePoolList()}) scan the option list on demand so the
021 * core is not coupled to the exhaustive OceanBase option vocabulary and
022 * future option additions need no code change here.
023 *
024 * <p>Statements of this shape are tagged
025 * {@link ESqlStatementType#sstoceanbase_create_tenant} per ADR-8.
026 *
027 * @see TAlterTenantSqlStatement
028 * @see TDropTenantSqlStatement
029 * @since 4.0.1.4
030 */
031public class TCreateTenantSqlStatement extends TCustomSqlStatement {
032
033    private TObjectName tenantName;
034    private boolean ifNotExists;
035    private ArrayList<TOceanbaseTenantOption> tenantOptions
036            = new ArrayList<TOceanbaseTenantOption>();
037
038    public TCreateTenantSqlStatement(EDbVendor dbvendor) {
039        super(dbvendor);
040        this.sqlstatementtype = ESqlStatementType.sstoceanbase_create_tenant;
041    }
042
043    public TObjectName getTenantName() {
044        return tenantName;
045    }
046
047    public boolean isIfNotExists() {
048        return ifNotExists;
049    }
050
051    public ArrayList<TOceanbaseTenantOption> getTenantOptions() {
052        return tenantOptions;
053    }
054
055    // -----------------------------------------------------------------
056    // Typed convenience accessors — scan the option list on demand.
057    // -----------------------------------------------------------------
058
059    /**
060     * @return the first value of the {@code PRIMARY_ZONE} option, or
061     *         {@code null} when not specified.
062     */
063    public TObjectName getPrimaryZone() {
064        return firstValueOfOption("PRIMARY_ZONE");
065    }
066
067    /**
068     * @return the first value of the {@code LOCALITY} option, or
069     *         {@code null} when not specified.
070     */
071    public TObjectName getLocality() {
072        return firstValueOfOption("LOCALITY");
073    }
074
075    /**
076     * @return the first value of the {@code CHARSET} option, or
077     *         {@code null} when not specified.
078     */
079    public TObjectName getCharset() {
080        return firstValueOfOption("CHARSET");
081    }
082
083    /**
084     * @return the value of {@code SET ob_compatibility_mode = '...'} when
085     *         present among the tenant options, or {@code null} when not
086     *         specified. This is how callers distinguish a MySQL-mode
087     *         tenant from an Oracle-mode tenant at the DDL level.
088     */
089    public TObjectName getCompatibilityMode() {
090        for (TOceanbaseTenantOption opt : tenantOptions) {
091            if (opt == null || opt.getName() == null) continue;
092            if (opt.isSetVariable()
093                    && "OB_COMPATIBILITY_MODE".equals(opt.getName())) {
094                return opt.getFirstValue();
095            }
096        }
097        return null;
098    }
099
100    /**
101     * @return the list of pool names listed in the
102     *         {@code RESOURCE_POOL_LIST = ('p1', 'p2', ...)} option, or an
103     *         empty list when not specified.
104     */
105    public ArrayList<TObjectName> getResourcePoolList() {
106        for (TOceanbaseTenantOption opt : tenantOptions) {
107            if (opt == null || opt.getName() == null) continue;
108            if (!opt.isSetVariable()
109                    && "RESOURCE_POOL_LIST".equals(opt.getName())) {
110                return opt.getValues();
111            }
112        }
113        return new ArrayList<TObjectName>();
114    }
115
116    private TObjectName firstValueOfOption(String canonicalName) {
117        for (TOceanbaseTenantOption opt : tenantOptions) {
118            if (opt == null || opt.getName() == null) continue;
119            if (!opt.isSetVariable() && canonicalName.equals(opt.getName())) {
120                return opt.getFirstValue();
121            }
122        }
123        return null;
124    }
125
126    // -----------------------------------------------------------------
127    // Framework overrides
128    // -----------------------------------------------------------------
129
130    @Override
131    public int doParseStatement(TCustomSqlStatement psql) {
132        if (rootNode == null) return -1;
133        super.doParseStatement(psql);
134        TOceanbaseCreateTenantSqlNode node = (TOceanbaseCreateTenantSqlNode) rootNode;
135        this.tenantName = node.getTenantName();
136        this.ifNotExists = node.isIfNotExists();
137        this.tenantOptions = node.getTenantOptions();
138        return 0;
139    }
140
141    @Override
142    public void accept(TParseTreeVisitor v) {
143        v.preVisit(this);
144        v.postVisit(this);
145    }
146
147    @Override
148    public void acceptChildren(TParseTreeVisitor v) {
149        v.preVisit(this);
150        v.postVisit(this);
151    }
152}