001package gudusoft.gsqlparser.stmt; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.nodes.*; 005import gudusoft.gsqlparser.nodes.couchbase.TUseKeyIndex; 006import gudusoft.gsqlparser.nodes.mssql.TOptionClause; 007import gudusoft.gsqlparser.nodes.oracle.TErrorLoggingClause; 008 009import java.util.ArrayList; 010 011/** 012 * 013 * SQL delete statement. 014 * <br> 015 * <br>{@link #getTargetTable} returns the target table of delete statement, this table also stored in the first element of {@link #tables}. 016 * <br>MySQL may contains multiple target tables, please fetch those tables from {@link #joins}. 017 * <br>If there is a FROM clause in the delete statement, all those tables in the from clause can be fetched from {@link #getReferenceJoins}. 018 * <br> 019 * <pre> 020 * DELETE FROM Production.ProductCostHistory 021 * WHERE StandardCost > 1000.00; 022 * </pre> 023 * <p> Production.ProductCostHistory can be fetched from {@link #getTargetTable} or {@link #tables} 024 * <pre> 025 * DELETE FROM Sales.SalesPersonQuotaHistory 026 * FROM Sales.SalesPersonQuotaHistory AS spqh 027 * INNER JOIN Sales.SalesPerson AS sp 028 * ON spqh.BusinessEntityID = sp.BusinessEntityID 029 * WHERE sp.SalesYTD > 2500000.00; 030 * </pre> 031 * 032 * Sales.SalesPersonQuotaHistory AS spqh should be fetched froom {@link #getReferenceJoins} 033 * 034 * @see TCustomSqlStatement#cteList 035 * @see TCustomSqlStatement#topClause 036 * @see TCustomSqlStatement#targetTable 037 * @see TCustomSqlStatement#joins 038 * @see TCustomSqlStatement#whereClause 039 * @see TCustomSqlStatement#returningClause 040 * @see TCustomSqlStatement#outputClause 041 */ 042public class TDeleteSqlStatement extends TCustomSqlStatement { 043 044// public ArrayList<TObjectName> getReferenceAttributes(){ 045// return null; 046// } 047 048// @Override 049// public ArrayList<TAttributeNode> getAttributes(){ 050// if (relationAttributes.size() != 0) return relationAttributes; 051// 052// for(TTable table:getTables()){ 053// relationAttributes.addAll(table.getAttributes()); 054// } 055// 056// return relationAttributes; 057// } 058 059 060 private boolean fromKeyword = false; 061 062 public void setFromKeyword(boolean fromKeyword) { 063 this.fromKeyword = fromKeyword; 064 } 065 066 /** 067 * Whether FROM keyword is used. 068 * 069 * @return true if FROM keyword is used after delete. 070 */ 071 public boolean isFromKeyword() { 072 073 return fromKeyword; 074 } 075 076 private TErrorLoggingClause errorLoggingClause; 077 078 /** 079 * Oracle error logging clause 080 * @return Oracle error logging clause 081 */ 082 public TErrorLoggingClause getErrorLoggingClause() { 083 return errorLoggingClause; 084 } 085 086 private TOptionClause optionClause; 087 088 /** 089 * sql server option clause 090 * @return {@link TOptionClause option clause} 091 * 092 * @see gudusoft.gsqlparser.nodes.mssql.TOptionClause 093 */ 094 public TOptionClause getOptionClause() { 095 return optionClause; 096 } 097 098 private TSourceToken deleteToken = null; 099 100 public void setDeleteToken(TSourceToken deleteToken) { 101 this.deleteToken = deleteToken; 102 } 103 104 /** 105 * DELETE keyword of the delete statement. 106 * @return DELETE token in delete statement. 107 */ 108 public TSourceToken getDeleteToken() { 109 110 return deleteToken; 111 } 112 113 private TOrderBy orderByClause = null; 114 115 /** 116 * MySQL order by clause. 117 * @return MySQL order by clause. 118 */ 119 public TOrderBy getOrderByClause() { 120 121 return orderByClause; 122 } 123 124 private TLimitClause limitClause = null; 125 126 127 /** 128 * MySQL limit clause. 129 * @return MySQL limit clause. 130 */ 131 public TLimitClause getLimitClause() { 132 133 return limitClause; 134 } 135 136 private TJoinList referenceJoins = null; 137 138 /** 139 * If there is a FROM clause in delete statement, this method returns the list of join table in the from clause. 140 * @return list of {@link gudusoft.gsqlparser.nodes.TJoin} 141 */ 142 public TJoinList getReferenceJoins() { 143 if (this.referenceJoins == null){ 144 this.referenceJoins = new TJoinList(); 145 } 146 return referenceJoins; 147 } 148 149 public TDeleteSqlStatement(EDbVendor dbvendor) { 150 super(dbvendor); 151 sqlstatementtype = ESqlStatementType.sstdelete; 152 } 153 154 void buildsql() { 155 } 156 157 void clear() { 158 } 159 160 String getasprettytext() { 161 return ""; 162 } 163 164 void iterate(TVisitorAbs pvisitor) { 165 } 166 167 /** 168 * Used internal. 169 * 170 * @param psql input sql. 171 * @return zero if no syntax error detected. 172 */ 173 public int doParseStatement(TCustomSqlStatement psql) { 174 if (rootNode == null) return -1; 175 TDeleteSqlNode deleteNode = (TDeleteSqlNode)rootNode; 176 177 this.fromKeyword = deleteNode.isFromKeyword(); 178 179 if (this.sourcetokenlist.size() == 0){ 180 // subquery nested in other statements. 181 this.setStartToken(deleteNode.getStartToken()); 182 this.setEndToken(deleteNode.getEndToken()); 183 } 184 185 super.doParseStatement(psql); 186 this.deleteToken = deleteNode.getDeleteToken(); 187 188 if (deleteNode.cteList != null){ 189 this.setCteList( deleteNode.cteList); 190 this.getCteList().doParse(this, ESqlClause.cte); 191 } 192 193 if (deleteNode.getTopClause() != null){ 194 deleteNode.getTopClause().doParse(this,ESqlClause.top); 195 this.setTopClause(deleteNode.getTopClause()); 196 } 197 198 TTable lcTable1 = analyzeFromTable(deleteNode.getTargetTable(),true); 199 lcTable1.setEffectType(ETableEffectType.tetDelete); 200 setTargetTable(lcTable1); 201 this.getRelations().add(lcTable1); 202 203 if (deleteNode.getSourceTableList() != null){ 204 TFromTable lcFromTable = null; 205 TJoin lcJoin = null; 206 207 for(int i=0; i<deleteNode.getSourceTableList().size();i++){ 208 lcFromTable = deleteNode.getSourceTableList().getFromTable(i); 209 if (lcFromTable.getFromtableType() != ETableSource.join){ 210 lcJoin = new TJoin(); 211 lcTable1 = analyzeFromTable(lcFromTable,true); 212 lcTable1.setEffectType(ETableEffectType.tetSelect); 213 lcJoin.setTable(lcTable1); 214 this.getRelations().add(lcTable1); 215 }else{ 216 this.fromSourceJoin = lcFromTable.getJoinExpr(); 217 218 this.fromSourceTable = new TTable(); 219 this.fromSourceTable.setTableType(ETableSource.join); 220 this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause()); 221 this.fromSourceTable.setStartToken(lcFromTable.getStartToken()); 222 this.fromSourceTable.setEndToken(lcFromTable.getEndToken()); 223 this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser()); 224 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 225 this.getRelations().add(this.fromSourceTable); 226 227 lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 228 lcJoin.doParse(this, ESqlClause.join); 229 } 230 joins.addJoin(lcJoin); 231 } 232 } 233 234 if (deleteNode.getReferenceTableList() != null){ 235 // MySQL syntax: 236 // delete table_name1.[*],table_name2.[*] ... 237 // from table_references 238 TFromTable lcFromTable = null; 239 TJoin lcJoin = null; 240 241 for(int i=0; i<deleteNode.getReferenceTableList().size();i++){ 242 lcFromTable = deleteNode.getReferenceTableList().getFromTable(i); 243 if (lcFromTable.getFromtableType() != ETableSource.join){ 244 lcJoin = new TJoin(); 245 lcTable1 = analyzeFromTable(lcFromTable,true); 246 lcJoin.setTable( lcTable1); 247 this.getRelations().add(lcTable1); 248 }else{ 249 this.fromSourceJoin = lcFromTable.getJoinExpr(); 250 251 this.fromSourceTable = new TTable(); 252 this.fromSourceTable.setTableType(ETableSource.join); 253 this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause()); 254 this.fromSourceTable.setStartToken(lcFromTable.getStartToken()); 255 this.fromSourceTable.setEndToken(lcFromTable.getEndToken()); 256 this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser()); 257 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 258 this.getRelations().add(this.fromSourceTable); 259 260 lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 261 lcJoin.doParse(this, ESqlClause.join); 262 } 263 this.getReferenceJoins().addJoin(lcJoin); 264 } 265 266 } 267 268 if (deleteNode.getOutputClause() != null){ 269 deleteNode.getOutputClause().doParse(this,ESqlClause.output); 270 this.setOutputClause(deleteNode.getOutputClause()); 271 } 272 273 if (deleteNode.getWhereCondition() != null){ 274 deleteNode.getWhereCondition().doParse(this,ESqlClause.where); 275 this.setWhereClause(deleteNode.getWhereCondition()); 276 } 277 278 if (deleteNode.getReturningClause() != null){ 279 deleteNode.getReturningClause().doParse(this,ESqlClause.returning); 280 this.setReturningClause(deleteNode.getReturningClause()); 281 } 282 283 this.orderByClause = deleteNode.getOrderByClause(); 284 if (this.orderByClause != null){ 285 this.orderByClause.doParse(this,ESqlClause.orderby); 286 } 287 288 this.limitClause = deleteNode.getLimitClause(); 289 if (this.limitClause != null){ 290 this.limitClause.doParse(this,ESqlClause.limit); 291 } 292 293 this.optionClause = deleteNode.getOptionClause(); 294 295 errorLoggingClause = deleteNode.getErrorLoggingClause(); 296 297 // remove table alias A from tables like this SQL: 298 // delete A 299 // from myTable A 300 // join otherTable B on A.Id=B.Id 301 int deletedTables[] = new int[this.tables.size()]; 302 TTable lcTable = null,lcTable2 = null; 303 for(int i=0;i<this.tables.size();i++){ 304 lcTable = this.tables.getTable(i); 305 if ((lcTable.getAliasClause() == null)&&(lcTable.isBaseTable())){ 306 for(int j=0;j<this.tables.size();j++){ 307 if (i == j) {continue;} 308 lcTable2 = this.tables.getTable(j); 309 if (lcTable2.getAliasClause() != null){ 310 if (lcTable2.getAliasClause().toString().compareToIgnoreCase(lcTable.toString()) == 0){ 311 deletedTables[i] = 1; 312 for(int k=0;k<lcTable.getObjectNameReferences().size();k++){ 313 lcTable2.getObjectNameReferences().addObjectName(lcTable.getObjectNameReferences().getObjectName(k)); 314 lcTable2.getLinkedColumns().addObjectName(lcTable.getObjectNameReferences().getObjectName(k)); 315 lcTable.getObjectNameReferences().getObjectName(k).setSourceTable(lcTable2); 316 // System.out.println(lcTable.getObjectNameReferences().getAliasName(k).toString()); 317 } 318 if (lcTable == getTargetTable()){ 319 setTargetTable(lcTable2); 320 } 321 } 322 } 323 324 } 325 } 326 } 327 for(int i = this.tables.size()-1;i>=0;i--){ 328 if (deletedTables[i] == 1){ 329 this.tables.removeElementWithoutSyncTokens(i); 330 } 331 } 332 333 //couchbase 334 useKeyIndex = deleteNode.getUseKeyIndex(); 335 336 337 return 0; 338 } 339 340 public void accept(TParseTreeVisitor v){ 341 v.preVisit(this); 342 v.postVisit(this); 343 } 344 345 public void acceptChildren(TParseTreeVisitor v){ 346 v.preVisit(this); 347 348 if (this.getCteList() != null){ 349 this.getCteList().acceptChildren(v); 350 } 351 352 if (this.getTopClause() != null){ 353 this.getTopClause().acceptChildren(v); 354 } 355 356 this.getTargetTable().acceptChildren(v); 357 if (this.joins.size() > 0){ 358 this.joins.acceptChildren(v); 359 } 360 361 if (this.getOutputClause() != null){ 362 this.getOutputClause().acceptChildren(v); 363 } 364 365 if (this.getWhereClause() != null){ 366 this.getWhereClause().acceptChildren(v); 367 } 368 369 if (this.getReturningClause() != null){ 370 this.getReturningClause().acceptChildren(v); 371 } 372 373 v.postVisit(this); 374 } 375 376 public void setErrorLoggingClause(TErrorLoggingClause errorLoggingClause) { 377 this.errorLoggingClause = errorLoggingClause; 378 } 379 380 public void setOptionClause(TOptionClause optionClause) { 381 this.optionClause = optionClause; 382 } 383 384 public void setOrderByClause(TOrderBy orderByClause) { 385 this.orderByClause = orderByClause; 386 } 387 388 public void setLimitClause(TLimitClause limitClause) { 389 this.limitClause = limitClause; 390 } 391 392 public void setReferenceJoins(TJoinList referenceJoins) { 393 this.referenceJoins = referenceJoins; 394 } 395 396 //couchbase 397 private TUseKeyIndex useKeyIndex; 398 399 public void setUseKeyIndex(TUseKeyIndex useKeyIndex) { 400 this.useKeyIndex = useKeyIndex; 401 } 402 403 /** 404 * Couchbase use key index 405 * @return use key index 406 */ 407 public TUseKeyIndex getUseKeyIndex() { 408 409 return useKeyIndex; 410 } 411 412 413}