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.getReferenceTableList() != null){ 199 // Postgresql syntax: 200 // update table_name1 set f=1 201 // from table_references 202 // Processed before the target table so that the alias search below can 203 // link a target that is the alias of a table in the FROM clause 204 // (e.g. Snowflake/migration-style: UPDATE a SET ... FROM real_table a JOIN ...) 205 TFromTable lcFromTable = null; 206 TJoin lcJoin = null; 207 208 for(int i=0; i<updateNode.getReferenceTableList().size();i++){ 209 lcFromTable = updateNode.getReferenceTableList().getFromTable(i); 210 if (lcFromTable.getFromtableType() != ETableSource.join){ 211 lcJoin = new TJoin(); 212 TTable lcTable = analyzeFromTable(lcFromTable,true); 213 lcTable.setEffectType(ETableEffectType.tetSelect); 214 lcJoin.setTable( lcTable); 215 this.getRelations().add(lcTable); 216 }else{ 217 this.fromSourceJoin = lcFromTable.getJoinExpr(); 218 219 this.fromSourceTable = new TTable(); 220 this.fromSourceTable.setTableType(ETableSource.join); 221 this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause()); 222 this.fromSourceTable.setStartToken(lcFromTable.getJoinExpr().getStartToken()); 223 this.fromSourceTable.setEndToken(lcFromTable.getJoinExpr().getEndToken()); 224 this.fromSourceTable.setGsqlparser(lcFromTable.getJoinExpr().getGsqlparser()); 225 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 226 this.getRelations().add(this.fromSourceTable); 227 228 lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 229 lcJoin.doParse(this, ESqlClause.join); 230 } 231 // this.getReferenceJoins().addJoin(lcJoin); 232 joins.addJoin(lcJoin); 233 } 234 235 } 236 237 if (updateNode.getTargetTable().getFromtableType() != ETableSource.join ){ 238 // search in from clause to see if this is the table alias of table in from clause 239 boolean isTableAlias = false; 240 TTable lcLinkTable = null; 241 String targetName = updateNode.getTargetTable().toString(); 242 if (getJoins().size() > 0){ 243 for(int j=0;j<getJoins().size() && !isTableAlias;j++){ 244 TJoin lcJoinForAlias = getJoins().getJoin(j); 245 TTable lcCandidate = lcJoinForAlias.getTable(); 246 if (lcCandidate != null && lcCandidate.getAliasClause() != null 247 && targetName.equalsIgnoreCase(lcCandidate.getAliasName())){ 248 lcLinkTable = lcCandidate; 249 isTableAlias = true; 250 break; 251 } 252 // Also walk join items - the target alias may be on a joined table 253 // (e.g. UPDATE S ... FROM A JOIN B S ON ...) 254 if (lcJoinForAlias.getJoinItems() != null){ 255 for(int k=0;k<lcJoinForAlias.getJoinItems().size();k++){ 256 TTable lcItemTable = lcJoinForAlias.getJoinItems().getJoinItem(k).getTable(); 257 if (lcItemTable != null && lcItemTable.getAliasClause() != null 258 && targetName.equalsIgnoreCase(lcItemTable.getAliasName())){ 259 lcLinkTable = lcItemTable; 260 isTableAlias = true; 261 break; 262 } 263 } 264 } 265 } 266 } 267 TTable lcTable = analyzeFromTable(updateNode.getTargetTable(),false); 268 lcTable.setEffectType(ETableEffectType.tetUpdate); 269 if (isTableAlias){ 270 lcTable.setLinkTable(lcLinkTable); 271 // the linked FROM table is the real update target, so it must 272 // report the update effect, same as a directly named target 273 lcLinkTable.setEffectType(ETableEffectType.tetUpdate); 274 setTargetTable(lcLinkTable); 275 }else{ 276 tables.insertElementAt(lcTable,0); 277 setTargetTable(lcTable); 278 this.getRelations().add(0,lcTable); // update table 需要放在 from table 前 279 } 280 //setTargetTable(lcTable); 281 }else{ 282 this.fromSourceJoin = updateNode.getTargetTable().getJoinExpr(); 283 284 this.fromSourceTable = new TTable(); 285 this.fromSourceTable.setTableType(ETableSource.join); 286 this.fromSourceTable.setAliasClause(updateNode.getTargetTable().getJoinExpr().getAliasClause()); 287 this.fromSourceTable.setStartToken(updateNode.getTargetTable().getJoinExpr().getStartToken()); 288 this.fromSourceTable.setEndToken(updateNode.getTargetTable().getJoinExpr().getEndToken()); 289 this.fromSourceTable.setGsqlparser(updateNode.getTargetTable().getJoinExpr().getGsqlparser()); 290 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 291 this.getRelations().add(0,this.fromSourceTable); // update table 需要放在 from table 前 292 293 TJoin lcJoin1 = analyzeJoin(updateNode.getTargetTable().getJoinExpr(),null,true); 294 lcJoin1.doParse(this, ESqlClause.join); 295 setTargetTable(lcJoin1.getTable()); 296 joins.addJoin(lcJoin1); 297 } 298 299 if (updateNode.getUseKeyIndex() != null){ 300 setUseKeyIndex(updateNode.getUseKeyIndex()); 301 getUseKeyIndex().doParse(this,ESqlClause.unknown); 302 } 303 304 if (updateNode.getOutputClause() != null){ 305 updateNode.getOutputClause().doParse(this,ESqlClause.output); 306 this.setOutputClause(updateNode.getOutputClause()); 307 } 308 309 setResultColumnList(updateNode.getResultColumnList()); 310 311 if (updateNode.getUnSetTerms() != null){ 312 setUnSetTerms(updateNode.getUnSetTerms()); 313 getUnSetTerms().doParse(this,ESqlClause.unSet); 314 } 315 316 317 if (getResultColumnList() != null){ 318 getResultColumnList().doParse(this,ESqlClause.set); 319 } 320 321 if (updateNode.getOrderByClause() != null){ 322 setOrderByClause(updateNode.getOrderByClause()); 323 getOrderByClause().doParse(this,ESqlClause.orderby); 324 } 325 326 if (updateNode.getLimitClause() != null){ 327 setLimitClause(updateNode.getLimitClause()); 328 getLimitClause().doParse(this,ESqlClause.limit); 329 } 330 331 if (updateNode.getWhereCondition() != null){ 332 updateNode.getWhereCondition().doParse(this,ESqlClause.where); 333 this.setWhereClause(updateNode.getWhereCondition()); 334 } 335 336 if (updateNode.getReturningClause() != null){ 337 updateNode.getReturningClause().doParse(this,ESqlClause.returning); 338 this.setReturningClause(updateNode.getReturningClause()); 339 } 340 341 this.optionClause = updateNode.getOptionClause(); 342 343 errorLoggingClause = updateNode.getErrorLoggingClause(); 344 345 if (updateNode.getInsertSqlNode() != null){ 346 insertSqlStatement = new TInsertSqlStatement(this.dbvendor); 347 insertSqlStatement.rootNode = updateNode.getInsertSqlNode(); 348 insertSqlStatement.doParseStatement(this); 349 350 } 351 352 // remove table alias A from tables like this SQL: 353 // delete A 354 // from myTable A 355 // join otherTable B on A.Id=B.Id 356 int deletedTables[] = new int[this.tables.size()]; 357 TTable lcTable = null,lcTable2 = null; 358 for(int i=0;i<this.tables.size();i++){ 359 lcTable = this.tables.getTable(i); 360 if ((lcTable.getAliasClause() == null)&&(lcTable.isBaseTable())){ 361 for(int j=0;j<this.tables.size();j++){ 362 if (i == j) {continue;} 363 lcTable2 = this.tables.getTable(j); 364 if (lcTable2.getAliasClause() != null){ 365 if (lcTable2.getAliasClause().toString().compareToIgnoreCase(lcTable.toString()) == 0){ 366 deletedTables[i] = 1; 367 //lcTable.setLinkTable(true); 368 lcTable.setLinkTable(lcTable2); 369// for(int k=0;k<lcTable.getObjectNameReferences().size();k++){ 370// lcTable2.getObjectNameReferences().addObjectName(lcTable.getObjectNameReferences().getObjectName(k)); 371// //lcTable2.getLinkedColumns().addObjectName(lcTable.getObjectNameReferences().getObjectName(k)); 372// //lcTable.getObjectNameReferences().getObjectName(k).setSourceTable(lcTable2); 373// // System.out.println(lcTable.getObjectNameReferences().getAliasName(k).toString()); 374// } 375 } 376 } 377 378 } 379 } 380 } 381// for(int i = this.tables.size()-1;i>=0;i--){ 382// if (deletedTables[i] == 1){ 383// //this.tables.removeElementAt(i); 384// } 385// } 386 387 return 0; 388 } 389 390 public void accept(TParseTreeVisitor v){ 391 v.preVisit(this); 392 v.postVisit(this); 393 } 394 395 public void acceptChildren(TParseTreeVisitor v){ 396 v.preVisit(this); 397 398 if (this.getCteList() != null){ 399 this.getCteList().acceptChildren(v); 400 } 401 402 403 404 if (TBaseType.USE_JOINEXPR_INSTEAD_OF_JOIN){ 405 406 for(TTable table:getRelations()){ 407 table.acceptChildren(v); 408 } 409 410 }else{ 411 this.getTargetTable().acceptChildren(v); 412 if (this.joins.size() > 0){ 413 this.joins.acceptChildren(v); 414 } 415 } 416 417 if (this.getTopClause() != null){ 418 this.getTopClause().acceptChildren(v); 419 } 420 421 if (this.getOutputClause() != null){ 422 this.getOutputClause().acceptChildren(v); 423 } 424 425 if (this.getResultColumnList() != null){ 426 this.getResultColumnList().acceptChildren(v); 427 }else{ 428 TBaseType.log("set clause in update stmt is null",TLog.WARNING); 429 } 430 431 432 if (this.getWhereClause() != null){ 433 this.getWhereClause().acceptChildren(v); 434 } 435 436 if (this.getOrderByClause() != null){ 437 this.getOrderByClause().acceptChildren(v); 438 } 439 440 if (this.getLimitClause() != null){ 441 this.getLimitClause().acceptChildren(v); 442 } 443 444 if (this.getReturningClause() != null){ 445 this.getReturningClause().acceptChildren(v); 446 } 447 448 v.postVisit(this); 449 } 450 451 public void setErrorLoggingClause(TErrorLoggingClause errorLoggingClause) { 452 this.errorLoggingClause = errorLoggingClause; 453 } 454 455 public void setOptionClause(TOptionClause optionClause) { 456 this.optionClause = optionClause; 457 } 458 459 public void setReferenceJoins(TJoinList referenceJoins) { 460 this.referenceJoins = referenceJoins; 461 } 462 463 public void setOrderByClause(TOrderBy orderByClause) { 464 this.orderByClause = orderByClause; 465 } 466 467 public void setLimitClause(TLimitClause limitClause) { 468 this.limitClause = limitClause; 469 } 470 471 private TUseKeyIndex useKeyIndex;//couchbase 472 473 public void setUseKeyIndex(TUseKeyIndex useKeyIndex) { 474 this.useKeyIndex = useKeyIndex; 475 } 476 477 public TUseKeyIndex getUseKeyIndex() { 478 479 return useKeyIndex; 480 } 481 482 private TResultColumnList unSetTerms; //couchbase 483 484 public void setUnSetTerms(TResultColumnList unSetTerms) { 485 this.unSetTerms = unSetTerms; 486 } 487 488 /** 489 * Couchbase unset clause 490 * @return Couchbase unset clause 491 */ 492 public TResultColumnList getUnSetTerms() { 493 494 return unSetTerms; 495 } 496 497}