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 * SQL update statement. 013 * <br> 014 * <br> {@link #getTargetTable} returns the target table, this table can also be fetched from the first element of {@link #tables}. 015 * <br> If there is a from clause in update statement, {@link #joins} returns all the tables in the from clause. 016 * <br> {@link #getResultColumnList()} returns assignment in set clause. 017 * 018 *<pre> 019 * UPDATE dbo.Table2 020 * SET dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB 021 * FROM dbo.Table2 022 * INNER JOIN dbo.Table1 023 * ON (dbo.Table2.ColA = dbo.Table1.ColA); 024 *</pre> 025 * Table: dbo.Table2 can be fetched from {@link #getTargetTable} or {@link #tables} 026 * <br>set clause: dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB, {@link #getResultColumnList} 027 * <br>from clause: dbo.Table2 inner join , {@link #joins} 028 * 029 * 030 * @see TCustomSqlStatement#cteList 031 * @see TCustomSqlStatement#topClause 032 * @see TCustomSqlStatement#targetTable 033 * @see TCustomSqlStatement#outputClause 034 * @see TCustomSqlStatement#joins 035 * @see TCustomSqlStatement#resultColumnList 036 * @see TCustomSqlStatement#whereClause 037 * @see TCustomSqlStatement#returningClause 038 */ 039 040public class TUpdateSqlStatement extends TCustomSqlStatement { 041 042 043 private TInsertSqlStatement insertSqlStatement = null; 044 045 /** 046 * Teradata, insert statement used after ELSE keyword 047 * @return insert statement used after ELSE keyword 048 */ 049 public TInsertSqlStatement getInsertSqlStatement() { 050 return insertSqlStatement; 051 } 052 053 private TErrorLoggingClause errorLoggingClause; 054 055 /** 056 * Oracle, error logging clause 057 * @return Oracle, error logging clause 058 */ 059 public TErrorLoggingClause getErrorLoggingClause() { 060 return errorLoggingClause; 061 } 062 063 private TOptionClause optionClause; 064 065 /** 066 * sql server option clause 067 * @return option clause 068 * 069 * @see gudusoft.gsqlparser.nodes.mssql.TOptionClause 070 */ 071 public TOptionClause getOptionClause() { 072 return optionClause; 073 } 074 075 private TSourceToken updateToken = null; 076 077 public void setUpdateToken(TSourceToken updateToken) { 078 this.updateToken = updateToken; 079 } 080 081 /** 082 * UPDATE keyword 083 * 084 * @return UPDATE keyword in update statement. 085 */ 086 public TSourceToken getUpdateToken() { 087 088 return updateToken; 089 } 090 091 private TJoinList referenceJoins = null; 092 093 /** 094 * @deprecated As of v1.9.7.2, use {@link #joins} instead. 095 * <br> 096 * <p> getReferenceJoins() represents: table_references 097 * @return table references in from clause 098 */ 099 public TJoinList getReferenceJoins() { 100 if (this.referenceJoins == null){ 101 this.referenceJoins = new TJoinList(); 102 } 103 return referenceJoins; 104 } 105 106 private TOrderBy orderByClause = null; 107 108 /** 109 * Couchbase, MySQL limit clause. 110 * @return Couchbase, MySQL limit clause. 111 */ 112 public TLimitClause getLimitClause() { 113 return limitClause; 114 } 115 116 /** 117 * Order by clause is not used. 118 * @return Order by clause 119 */ 120 public TOrderBy getOrderByClause() { 121 return orderByClause; 122 } 123 124 private TLimitClause limitClause = null; 125 126 public TUpdateSqlStatement(EDbVendor dbvendor) { 127 super(dbvendor); 128 sqlstatementtype = ESqlStatementType.sstupdate; 129 } 130 131 void buildsql() { 132 } 133 134 void clear() { 135 } 136 137 String getasprettytext() { 138 return ""; 139 } 140 141 void iterate(TVisitorAbs pvisitor) { 142 } 143 144 public int doParseStatement(TCustomSqlStatement psql) { 145 if (rootNode == null) return -1; 146 TUpdateSqlNode updateNode = (TUpdateSqlNode)rootNode; 147 148 if (this.sourcetokenlist.size() == 0){ 149 // subquery nested in other statements. 150 this.setStartToken(updateNode.getStartToken()); 151 this.setEndToken(updateNode.getEndToken()); 152 } 153 154 super.doParseStatement(psql); 155 this.updateToken = updateNode.getUpdateToken(); 156 157 if (updateNode.cteList != null){ 158 this.setCteList(updateNode.cteList); 159 this.getCteList().doParse(this, ESqlClause.cte); 160 } 161 162 if (updateNode.getTopClause() != null){ 163 updateNode.getTopClause().doParse(this,ESqlClause.top); 164 this.setTopClause(updateNode.getTopClause()); 165 } 166 167 if (updateNode.getSourceTableList() != null){ // update ... from source table list 168 TFromTable lcFromTable = null; 169 TJoin lcJoin = null; 170 171 for(int i=0; i<updateNode.getSourceTableList().size();i++){ 172 lcFromTable = updateNode.getSourceTableList().getFromTable(i); 173 if (lcFromTable.getFromtableType() != ETableSource.join){ 174 lcJoin = new TJoin(); 175 TTable lcTable = analyzeFromTable(lcFromTable,true); 176 lcTable.setEffectType(ETableEffectType.tetSelect); 177 lcJoin.setTable(lcTable); 178 this.getRelations().add(lcTable); 179 }else{ 180 this.fromSourceJoin = lcFromTable.getJoinExpr(); 181 182 this.fromSourceTable = new TTable(); 183 this.fromSourceTable.setTableType(ETableSource.join); 184 this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause()); 185 this.fromSourceTable.setStartToken(lcFromTable.getStartToken()); 186 this.fromSourceTable.setEndToken(lcFromTable.getEndToken()); 187 this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser()); 188 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 189 this.getRelations().add(this.fromSourceTable); 190 191 lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 192 lcJoin.doParse(this, ESqlClause.join); 193 } 194 joins.addJoin(lcJoin); 195 } 196 } 197 198 if (updateNode.getTargetTable().getFromtableType() != ETableSource.join ){ 199 // search in from clause to see if this is the table alias of table in from clause 200 boolean isTableAlias = false; 201 TTable lcLinkTable = null; 202 String targetName = updateNode.getTargetTable().toString(); 203 if (getJoins().size() > 0){ 204 for(int j=0;j<getJoins().size() && !isTableAlias;j++){ 205 TJoin lcJoinForAlias = getJoins().getJoin(j); 206 TTable lcCandidate = lcJoinForAlias.getTable(); 207 if (lcCandidate != null && lcCandidate.getAliasClause() != null 208 && targetName.equalsIgnoreCase(lcCandidate.getAliasName())){ 209 lcLinkTable = lcCandidate; 210 isTableAlias = true; 211 break; 212 } 213 // Also walk join items - the target alias may be on a joined table 214 // (e.g. UPDATE S ... FROM A JOIN B S ON ...) 215 if (lcJoinForAlias.getJoinItems() != null){ 216 for(int k=0;k<lcJoinForAlias.getJoinItems().size();k++){ 217 TTable lcItemTable = lcJoinForAlias.getJoinItems().getJoinItem(k).getTable(); 218 if (lcItemTable != null && lcItemTable.getAliasClause() != null 219 && targetName.equalsIgnoreCase(lcItemTable.getAliasName())){ 220 lcLinkTable = lcItemTable; 221 isTableAlias = true; 222 break; 223 } 224 } 225 } 226 } 227 } 228 TTable lcTable = analyzeFromTable(updateNode.getTargetTable(),false); 229 lcTable.setEffectType(ETableEffectType.tetUpdate); 230 if (isTableAlias){ 231 lcTable.setLinkTable(lcLinkTable); 232 setTargetTable(lcLinkTable); 233 }else{ 234 tables.insertElementAt(lcTable,0); 235 setTargetTable(lcTable); 236 this.getRelations().add(0,lcTable); // update table 需要放在 from table 前 237 } 238 //setTargetTable(lcTable); 239 }else{ 240 this.fromSourceJoin = updateNode.getTargetTable().getJoinExpr(); 241 242 this.fromSourceTable = new TTable(); 243 this.fromSourceTable.setTableType(ETableSource.join); 244 this.fromSourceTable.setAliasClause(updateNode.getTargetTable().getJoinExpr().getAliasClause()); 245 this.fromSourceTable.setStartToken(updateNode.getTargetTable().getJoinExpr().getStartToken()); 246 this.fromSourceTable.setEndToken(updateNode.getTargetTable().getJoinExpr().getEndToken()); 247 this.fromSourceTable.setGsqlparser(updateNode.getTargetTable().getJoinExpr().getGsqlparser()); 248 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 249 this.getRelations().add(0,this.fromSourceTable); // update table 需要放在 from table 前 250 251 TJoin lcJoin1 = analyzeJoin(updateNode.getTargetTable().getJoinExpr(),null,true); 252 lcJoin1.doParse(this, ESqlClause.join); 253 setTargetTable(lcJoin1.getTable()); 254 joins.addJoin(lcJoin1); 255 } 256 257 if (updateNode.getUseKeyIndex() != null){ 258 setUseKeyIndex(updateNode.getUseKeyIndex()); 259 getUseKeyIndex().doParse(this,ESqlClause.unknown); 260 } 261 262 if (updateNode.getOutputClause() != null){ 263 updateNode.getOutputClause().doParse(this,ESqlClause.output); 264 this.setOutputClause(updateNode.getOutputClause()); 265 } 266 267 setResultColumnList(updateNode.getResultColumnList()); 268 269 if (updateNode.getUnSetTerms() != null){ 270 setUnSetTerms(updateNode.getUnSetTerms()); 271 getUnSetTerms().doParse(this,ESqlClause.unSet); 272 } 273 274 275 if (updateNode.getReferenceTableList() != null){ 276 // Postgresql syntax: 277 // update table_name1 set f=1 278 // from table_references 279 TFromTable lcFromTable = null; 280 TJoin lcJoin = null; 281 282 for(int i=0; i<updateNode.getReferenceTableList().size();i++){ 283 lcFromTable = updateNode.getReferenceTableList().getFromTable(i); 284 if (lcFromTable.getFromtableType() != ETableSource.join){ 285 lcJoin = new TJoin(); 286 TTable lcTable = analyzeFromTable(lcFromTable,true); 287 lcTable.setEffectType(ETableEffectType.tetSelect); 288 lcJoin.setTable( lcTable); 289 this.getRelations().add(lcTable); 290 }else{ 291 this.fromSourceJoin = lcFromTable.getJoinExpr(); 292 293 this.fromSourceTable = new TTable(); 294 this.fromSourceTable.setTableType(ETableSource.join); 295 this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause()); 296 this.fromSourceTable.setStartToken(lcFromTable.getJoinExpr().getStartToken()); 297 this.fromSourceTable.setEndToken(lcFromTable.getJoinExpr().getEndToken()); 298 this.fromSourceTable.setGsqlparser(lcFromTable.getJoinExpr().getGsqlparser()); 299 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 300 this.getRelations().add(this.fromSourceTable); 301 302 lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 303 lcJoin.doParse(this, ESqlClause.join); 304 } 305 // this.getReferenceJoins().addJoin(lcJoin); 306 joins.addJoin(lcJoin); 307 } 308 309 } 310 311 if (getResultColumnList() != null){ 312 getResultColumnList().doParse(this,ESqlClause.set); 313 } 314 315 if (updateNode.getOrderByClause() != null){ 316 setOrderByClause(updateNode.getOrderByClause()); 317 getOrderByClause().doParse(this,ESqlClause.orderby); 318 } 319 320 if (updateNode.getLimitClause() != null){ 321 setLimitClause(updateNode.getLimitClause()); 322 getLimitClause().doParse(this,ESqlClause.limit); 323 } 324 325 if (updateNode.getWhereCondition() != null){ 326 updateNode.getWhereCondition().doParse(this,ESqlClause.where); 327 this.setWhereClause(updateNode.getWhereCondition()); 328 } 329 330 if (updateNode.getReturningClause() != null){ 331 updateNode.getReturningClause().doParse(this,ESqlClause.returning); 332 this.setReturningClause(updateNode.getReturningClause()); 333 } 334 335 this.optionClause = updateNode.getOptionClause(); 336 337 errorLoggingClause = updateNode.getErrorLoggingClause(); 338 339 if (updateNode.getInsertSqlNode() != null){ 340 insertSqlStatement = new TInsertSqlStatement(this.dbvendor); 341 insertSqlStatement.rootNode = updateNode.getInsertSqlNode(); 342 insertSqlStatement.doParseStatement(this); 343 344 } 345 346 // remove table alias A from tables like this SQL: 347 // delete A 348 // from myTable A 349 // join otherTable B on A.Id=B.Id 350 int deletedTables[] = new int[this.tables.size()]; 351 TTable lcTable = null,lcTable2 = null; 352 for(int i=0;i<this.tables.size();i++){ 353 lcTable = this.tables.getTable(i); 354 if ((lcTable.getAliasClause() == null)&&(lcTable.isBaseTable())){ 355 for(int j=0;j<this.tables.size();j++){ 356 if (i == j) {continue;} 357 lcTable2 = this.tables.getTable(j); 358 if (lcTable2.getAliasClause() != null){ 359 if (lcTable2.getAliasClause().toString().compareToIgnoreCase(lcTable.toString()) == 0){ 360 deletedTables[i] = 1; 361 //lcTable.setLinkTable(true); 362 lcTable.setLinkTable(lcTable2); 363// for(int k=0;k<lcTable.getObjectNameReferences().size();k++){ 364// lcTable2.getObjectNameReferences().addObjectName(lcTable.getObjectNameReferences().getObjectName(k)); 365// //lcTable2.getLinkedColumns().addObjectName(lcTable.getObjectNameReferences().getObjectName(k)); 366// //lcTable.getObjectNameReferences().getObjectName(k).setSourceTable(lcTable2); 367// // System.out.println(lcTable.getObjectNameReferences().getAliasName(k).toString()); 368// } 369 } 370 } 371 372 } 373 } 374 } 375// for(int i = this.tables.size()-1;i>=0;i--){ 376// if (deletedTables[i] == 1){ 377// //this.tables.removeElementAt(i); 378// } 379// } 380 381 return 0; 382 } 383 384 public void accept(TParseTreeVisitor v){ 385 v.preVisit(this); 386 v.postVisit(this); 387 } 388 389 public void acceptChildren(TParseTreeVisitor v){ 390 v.preVisit(this); 391 392 if (this.getCteList() != null){ 393 this.getCteList().acceptChildren(v); 394 } 395 396 397 398 if (TBaseType.USE_JOINEXPR_INSTEAD_OF_JOIN){ 399 400 for(TTable table:getRelations()){ 401 table.acceptChildren(v); 402 } 403 404 }else{ 405 this.getTargetTable().acceptChildren(v); 406 if (this.joins.size() > 0){ 407 this.joins.acceptChildren(v); 408 } 409 } 410 411 if (this.getTopClause() != null){ 412 this.getTopClause().acceptChildren(v); 413 } 414 415 if (this.getOutputClause() != null){ 416 this.getOutputClause().acceptChildren(v); 417 } 418 419 if (this.getResultColumnList() != null){ 420 this.getResultColumnList().acceptChildren(v); 421 }else{ 422 TBaseType.log("set clause in update stmt is null",TLog.WARNING); 423 } 424 425 426 if (this.getWhereClause() != null){ 427 this.getWhereClause().acceptChildren(v); 428 } 429 430 if (this.getOrderByClause() != null){ 431 this.getOrderByClause().acceptChildren(v); 432 } 433 434 if (this.getLimitClause() != null){ 435 this.getLimitClause().acceptChildren(v); 436 } 437 438 if (this.getReturningClause() != null){ 439 this.getReturningClause().acceptChildren(v); 440 } 441 442 v.postVisit(this); 443 } 444 445 public void setErrorLoggingClause(TErrorLoggingClause errorLoggingClause) { 446 this.errorLoggingClause = errorLoggingClause; 447 } 448 449 public void setOptionClause(TOptionClause optionClause) { 450 this.optionClause = optionClause; 451 } 452 453 public void setReferenceJoins(TJoinList referenceJoins) { 454 this.referenceJoins = referenceJoins; 455 } 456 457 public void setOrderByClause(TOrderBy orderByClause) { 458 this.orderByClause = orderByClause; 459 } 460 461 public void setLimitClause(TLimitClause limitClause) { 462 this.limitClause = limitClause; 463 } 464 465 private TUseKeyIndex useKeyIndex;//couchbase 466 467 public void setUseKeyIndex(TUseKeyIndex useKeyIndex) { 468 this.useKeyIndex = useKeyIndex; 469 } 470 471 public TUseKeyIndex getUseKeyIndex() { 472 473 return useKeyIndex; 474 } 475 476 private TResultColumnList unSetTerms; //couchbase 477 478 public void setUnSetTerms(TResultColumnList unSetTerms) { 479 this.unSetTerms = unSetTerms; 480 } 481 482 /** 483 * Couchbase unset clause 484 * @return Couchbase unset clause 485 */ 486 public TResultColumnList getUnSetTerms() { 487 488 return unSetTerms; 489 } 490 491}