001package gudusoft.gsqlparser.stmt.mssql; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.nodes.TBlockSqlNode; 005import gudusoft.gsqlparser.nodes.TParseTreeVisitor; 006import gudusoft.gsqlparser.nodes.TStatementSqlNode; 007import gudusoft.gsqlparser.nodes.mssql.TTryCatchSqlNode; 008 009/** 010 * Represents SQL Server TRY...CATCH statement. 011 * <p> 012 * Syntax: 013 * <pre> 014 * BEGIN TRY 015 * { sql_statement | statement_block } 016 * END TRY 017 * BEGIN CATCH 018 * [ { sql_statement | statement_block } ] 019 * END CATCH 020 * </pre> 021 * <p> 022 * Example: 023 * <pre> 024 * BEGIN TRY 025 * SELECT 1/0; 026 * END TRY 027 * BEGIN CATCH 028 * SELECT ERROR_MESSAGE(); 029 * END CATCH 030 * </pre> 031 */ 032public class TMssqlTryCatch extends TCustomSqlStatement { 033 034 private TStatementList tryStatements = null; 035 private TStatementList catchStatements = null; 036 037 public TMssqlTryCatch(EDbVendor dbvendor) { 038 super(dbvendor); 039 sqlstatementtype = ESqlStatementType.sstmssqlTryCatch; 040 } 041 042 void buildsql() { 043 } 044 045 void clear() { 046 } 047 048 String getasprettytext() { 049 return ""; 050 } 051 052 void iterate(TVisitorAbs pvisitor) { 053 } 054 055 /** 056 * Get the statements inside the BEGIN TRY ... END TRY block. 057 */ 058 public TStatementList getTryStatements() { 059 if (tryStatements == null) { 060 tryStatements = new TStatementList(); 061 } 062 return tryStatements; 063 } 064 065 /** 066 * Get the statements inside the BEGIN CATCH ... END CATCH block. 067 * May be empty if the CATCH block has no statements. 068 */ 069 public TStatementList getCatchStatements() { 070 if (catchStatements == null) { 071 catchStatements = new TStatementList(); 072 } 073 return catchStatements; 074 } 075 076 public int doParseStatement(TCustomSqlStatement psql) { 077 if (rootNode == null) return -1; 078 super.doParseStatement(psql); 079 080 // Handle TTryCatchSqlNode (from grammar with separate TRY/CATCH lists) 081 if (rootNode instanceof TTryCatchSqlNode) { 082 TTryCatchSqlNode tryCatchNode = (TTryCatchSqlNode) rootNode; 083 084 // Parse TRY block statements 085 if (tryCatchNode.getTryStmts() != null) { 086 tryCatchNode.getTryStmts().doParse(this, ESqlClause.unknown); 087 for (int i = 0; i < tryCatchNode.getTryStmts().size(); i++) { 088 this.getTryStatements().add(tryCatchNode.getTryStmts().getStatementSqlNode(i).getStmt()); 089 } 090 } 091 092 // Parse CATCH block statements 093 if (tryCatchNode.getCatchStmts() != null) { 094 tryCatchNode.getCatchStmts().doParse(this, ESqlClause.unknown); 095 for (int i = 0; i < tryCatchNode.getCatchStmts().size(); i++) { 096 this.getCatchStatements().add(tryCatchNode.getCatchStmts().getStatementSqlNode(i).getStmt()); 097 } 098 } 099 } 100 // Handle TBlockSqlNode (from token-based detection where grammar merges TRY+CATCH) 101 else if (rootNode instanceof TBlockSqlNode) { 102 TBlockSqlNode blockNode = (TBlockSqlNode) rootNode; 103 104 if (blockNode.getStmts() != null) { 105 blockNode.getStmts().doParse(this, ESqlClause.unknown); 106 107 // Find the position where TRY block ends and CATCH block begins 108 // by looking for END TRY tokens 109 int endTryPosition = findEndTryPosition(); 110 int catchStartPosition = findCatchStartPosition(); 111 112 for (int i = 0; i < blockNode.getStmts().size(); i++) { 113 TStatementSqlNode stmtNode = blockNode.getStmts().getStatementSqlNode(i); 114 TCustomSqlStatement stmt = stmtNode.getStmt(); 115 116 if (stmt != null) { 117 // Determine if statement is in TRY or CATCH block based on token position 118 int stmtStartPos = (stmt.getStartToken() != null) ? stmt.getStartToken().posinlist : -1; 119 120 if (catchStartPosition > 0 && stmtStartPos >= catchStartPosition) { 121 // Statement is after BEGIN CATCH, belongs to CATCH block 122 this.getCatchStatements().add(stmt); 123 } else if (endTryPosition > 0 && stmtStartPos < endTryPosition) { 124 // Statement is before END TRY, belongs to TRY block 125 this.getTryStatements().add(stmt); 126 } else if (catchStartPosition <= 0) { 127 // No CATCH block, all statements are in TRY 128 this.getTryStatements().add(stmt); 129 } 130 } 131 } 132 } 133 } 134 135 return 0; 136 } 137 138 /** 139 * Find the token position of END TRY in the source. 140 */ 141 private int findEndTryPosition() { 142 if (getStartToken() == null) return -1; 143 TSourceTokenList tokenList = getStartToken().container; 144 if (tokenList == null) return -1; 145 146 int startPos = getStartToken().posinlist; 147 int endPos = (getEndToken() != null) ? getEndToken().posinlist : tokenList.size(); 148 149 for (int i = startPos; i < endPos; i++) { 150 TSourceToken token = tokenList.get(i); 151 if (token.astext != null && token.astext.equalsIgnoreCase("END")) { 152 // Check if next solid token is TRY 153 for (int j = i + 1; j < endPos; j++) { 154 TSourceToken nextToken = tokenList.get(j); 155 if (nextToken.tokentype != ETokenType.ttwhitespace && 156 nextToken.tokentype != ETokenType.ttreturn) { 157 if (nextToken.astext != null && nextToken.astext.equalsIgnoreCase("TRY")) { 158 return j; // Return position after END TRY 159 } 160 break; 161 } 162 } 163 } 164 } 165 return -1; 166 } 167 168 /** 169 * Find the token position where BEGIN CATCH starts. 170 */ 171 private int findCatchStartPosition() { 172 if (getStartToken() == null) return -1; 173 TSourceTokenList tokenList = getStartToken().container; 174 if (tokenList == null) return -1; 175 176 int startPos = getStartToken().posinlist; 177 int endPos = (getEndToken() != null) ? getEndToken().posinlist : tokenList.size(); 178 179 for (int i = startPos; i < endPos; i++) { 180 TSourceToken token = tokenList.get(i); 181 if (token.astext != null && token.astext.equalsIgnoreCase("BEGIN")) { 182 // Check if next solid token is CATCH 183 for (int j = i + 1; j < endPos; j++) { 184 TSourceToken nextToken = tokenList.get(j); 185 if (nextToken.tokentype != ETokenType.ttwhitespace && 186 nextToken.tokentype != ETokenType.ttreturn) { 187 if (nextToken.astext != null && nextToken.astext.equalsIgnoreCase("CATCH")) { 188 return j; // Return position of BEGIN CATCH 189 } 190 break; 191 } 192 } 193 } 194 } 195 return -1; 196 } 197 198 public void accept(TParseTreeVisitor v) { 199 v.preVisit(this); 200 v.postVisit(this); 201 } 202 203 public void acceptChildren(TParseTreeVisitor v) { 204 v.preVisit(this); 205 if (tryStatements != null && tryStatements.size() > 0) { 206 tryStatements.acceptChildren(v); 207 } 208 if (catchStatements != null && catchStatements.size() > 0) { 209 catchStatements.acceptChildren(v); 210 } 211 v.postVisit(this); 212 } 213 214 public void setTryStatements(TStatementList tryStatements) { 215 this.tryStatements = tryStatements; 216 } 217 218 public void setCatchStatements(TStatementList catchStatements) { 219 this.catchStatements = catchStatements; 220 } 221}