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