001package gudusoft.gsqlparser.stmt.oceanbase; 002 003import gudusoft.gsqlparser.EDbVendor; 004import gudusoft.gsqlparser.ESqlStatementType; 005import gudusoft.gsqlparser.TCustomSqlStatement; 006import gudusoft.gsqlparser.TSourceToken; 007import gudusoft.gsqlparser.TSourceTokenList; 008import gudusoft.gsqlparser.nodes.TConstant; 009import gudusoft.gsqlparser.nodes.TObjectName; 010import gudusoft.gsqlparser.nodes.TParseTreeVisitor; 011import gudusoft.gsqlparser.nodes.oceanbase.TOceanbaseShowTenantSqlNode; 012import gudusoft.gsqlparser.nodes.oceanbase.TOceanbaseShowTenantSqlNode.EShowType; 013 014/** 015 * OceanBase system-tenant {@code SHOW} statement covering the OB-only 016 * variants that are not understood by the inherited MySQL grammar: 017 * {@code SHOW TENANT [LIKE 'pattern']}, {@code SHOW CREATE TENANT name}, 018 * and {@code SHOW RESOURCE POOL}. 019 * 020 * <p>Tagged {@link ESqlStatementType#sstoceanbase_show_tenant}. Use 021 * {@link #getShowType()} to distinguish between the variants. 022 * 023 * @since 4.0.1.4 024 */ 025public class TShowTenantSqlStatement extends TCustomSqlStatement { 026 027 private EShowType showType; 028 private TObjectName tenantName; 029 private TConstant likePattern; 030 031 public TShowTenantSqlStatement(EDbVendor dbvendor) { 032 super(dbvendor); 033 this.sqlstatementtype = ESqlStatementType.sstoceanbase_show_tenant; 034 } 035 036 public EShowType getShowType() { 037 return showType; 038 } 039 040 public TObjectName getTenantName() { 041 return tenantName; 042 } 043 044 public TConstant getLikePattern() { 045 return likePattern; 046 } 047 048 @Override 049 public int doParseStatement(TCustomSqlStatement psql) { 050 if (rootNode == null) return -1; 051 super.doParseStatement(psql); 052 // Two production paths feed this statement class: 053 // 054 // 1. The OceanBase grammar rule `showOceanBaseTenantStmt` 055 // (SHOW TENANT [LIKE ...] and SHOW RESOURCE POOL) creates a 056 // first-class TOceanbaseShowTenantSqlNode with structured 057 // fields. 058 // 059 // 2. SHOW CREATE TENANT cannot be expressed as a new grammar 060 // alternative without breaking the existing SHOW CREATE 061 // TABLE / VIEW / SCHEMA stub (they share the 062 // `RW_SHOW RW_CREATE` 2-token prefix whose make_stmt magic 063 // eats the remaining tokens). The splitter recognizes it 064 // via addCmd("show", "create", "tenant") and routes the 065 // statement through the inherited mysqlStubStmt rule, 066 // producing a generic TStubStmtSqlNode root. When that 067 // happens we reconstruct the show variant / tenant name 068 // from the raw token stream. 069 if (rootNode instanceof TOceanbaseShowTenantSqlNode) { 070 TOceanbaseShowTenantSqlNode node = (TOceanbaseShowTenantSqlNode) rootNode; 071 this.showType = node.getShowType(); 072 this.tenantName = node.getTenantName(); 073 this.likePattern = node.getLikePattern(); 074 } else { 075 // Stub-path fallback — only SHOW CREATE TENANT lands here. 076 populateFromSourceTokens(); 077 } 078 return 0; 079 } 080 081 /** 082 * Walk the statement's {@code sourcetokenlist} to identify the SHOW 083 * variant and capture the tenant name. Used only when the grammar 084 * path produced a generic stub node (SHOW CREATE TENANT route). 085 */ 086 private void populateFromSourceTokens() { 087 this.showType = EShowType.createTenant; 088 TSourceTokenList tokens = this.sourcetokenlist; 089 if (tokens == null) return; 090 // Find the TENANT keyword (by text — the lexer token code 091 // varies by dialect) and grab the first identifier following 092 // it. The splitter has already validated the prefix, so a 093 // missing tenant name is silently ignored. 094 for (int i = 0; i < tokens.size(); i++) { 095 TSourceToken t = tokens.get(i); 096 if (t == null || t.isnonsolidtoken()) continue; 097 if ("TENANT".equalsIgnoreCase(t.toString())) { 098 // Next solid token is the tenant name identifier. 099 for (int j = i + 1; j < tokens.size(); j++) { 100 TSourceToken n = tokens.get(j); 101 if (n == null || n.isnonsolidtoken()) continue; 102 String text = n.toString(); 103 if (text != null && !";".equals(text)) { 104 this.tenantName = new TObjectName(); 105 this.tenantName.setObjectToken(n); 106 this.tenantName.setStartToken(n); 107 this.tenantName.setEndToken(n); 108 } 109 break; 110 } 111 return; 112 } 113 } 114 } 115 116 @Override 117 public void accept(TParseTreeVisitor v) { 118 v.preVisit(this); 119 v.postVisit(this); 120 } 121 122 @Override 123 public void acceptChildren(TParseTreeVisitor v) { 124 v.preVisit(this); 125 v.postVisit(this); 126 } 127}