001package gudusoft.gsqlparser.nodes; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.stmt.TDeleteSqlStatement; 005import gudusoft.gsqlparser.stmt.TInsertSqlStatement; 006import gudusoft.gsqlparser.stmt.TSelectSqlStatement; 007import gudusoft.gsqlparser.stmt.TUpdateSqlStatement; 008 009import java.util.ArrayList; 010 011/** 012 * A common table expression permits defining a result table with a table-name that can be specified as a table name in any FROM clause of the fullselect that follows. 013 *<p> Multiple common table expressions can be specified following the single WITH keyword. 014 *<p> Each common table expression specified can also be referenced by name in the FROM clause of subsequent common table expressions. 015 *<p> Syntax: 016 * <blockquote><pre> 017 * table-name [column-name [,...n]] AS (fullselect)</pre> 018 * </blockquote> 019*/ 020public class TCTE extends TTable{ 021 022 private boolean recursive = false; 023 024 public void setRecursive(boolean recursive) { 025 this.recursive = recursive; 026 } 027 028 public boolean isRecursive() { 029 return recursive; 030 } 031 032 public void initAttributesFromColumnList(){ 033 if (this.getColumnList() != null){ 034 int i = 0; 035 if ((this.getSubquery() != null)&&(this.getSubquery().getResultColumnList() != null)){ 036 if (this.getSubquery().getResultColumnList().size() != this.getColumnList().size()){ 037 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 038 TBaseType.log(String.format("CTE: <%s> columns list size is not the same as select list in subQuery, maybe due to list -> * ", this.getTableName().toString()) 039 ,TLog.ERROR,this.getTableName()); 040 } 041 } 042 } 043 for(TObjectName column: this.getColumnList()){ 044 if ((this.getSubquery() != null)&&(this.getSubquery().getResultColumnList(true) != null)){ 045 TResultColumnList resultColumnListFromSubquery = this.getSubquery().getResultColumnList(true); 046 // 关联 subQuery 中 select list 047 // relationAttributes.add(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this,this.getSubquery().getResultColumnList().getResultColumn(i) )); 048 // Fix: When subquery has SELECT *, all CTE columns should reference the single star column 049 TResultColumn resultColumn = null; 050 if (resultColumnListFromSubquery.size() == 1 && 051 resultColumnListFromSubquery.getResultColumn(0).toString().endsWith("*")) { 052 // All CTE columns map to the single star column 053 resultColumn = resultColumnListFromSubquery.getResultColumn(0); 054 } else if (i < resultColumnListFromSubquery.size()) { 055 // Normal mapping by position 056 resultColumn = resultColumnListFromSubquery.getResultColumn(i); 057 } 058 TAttributeNode.addNodeToList(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this,resultColumn ),getAttributes()); 059 060 }else{ 061 //relationAttributes.add(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this)); 062 TAttributeNode.addNodeToList(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this),getAttributes()); 063 } 064 i++; 065 } 066 // 067 if ((this.getSubquery() != null)&&(this.getSubquery().isCombinedQuery())&&(this.getSubquery().getLeftStmt().getResultColumnList() != null)){ 068 TSelectSqlStatement left = subquery.getLeftStmt(); 069 070 String prefix = this.getTableName().toString()+"."; 071 addNewAttributeFromSubQuery(left.getResultColumnList(),getAttributes(),prefix,this.getColumnList()); 072 while (left.isCombinedQuery()){ 073 left = left.getLeftStmt(); 074 addNewAttributeFromSubQuery(left.getResultColumnList(),getAttributes(),prefix,this.getColumnList()); 075 } 076 } 077 } 078 079 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 080 TBaseType.log(String.format("Prepare attributes for CTE: <%s> via column list",this.getTableName().toString()),TLog.DEBUG,this.getTableName()); 081 for(TAttributeNode node:getAttributes()){ 082 TBaseType.log(String.format("\tAttribute: <%s>, Select list column: <%s>",node.getName(),node.getSubLevelResultColumn()!=null?node.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG); 083 } 084 } 085 086 } 087 public void initAttributesFromSubQuery(){ 088 if (this.getSubquery() == null) return; 089 super.initAttributesFromSubquery(this.getSubquery(),this.getTableName().toString()+"."); 090 091 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 092 TBaseType.log(String.format("Prepare attributes (num = %d) for CTE: <%s> via subQuery",getAttributes().size() ,this.getTableName().toString()),TLog.DEBUG,this.getTableName()); 093 } 094 int c = 0; 095 for(TAttributeNode node:getAttributes()){ 096 if (node.getSqlColumn() != null){ 097 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 098 TBaseType.log(String.format("\tAttribute: <%s>, SQL column: <%s>",node.getName(), node.getSqlColumn()!=null?node.getSqlColumn().toString():"N/A" ),TLog.DEBUG); 099 } 100 }else{ 101 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 102 TBaseType.log(String.format("\tAttribute: <%s>, Select list column: <%s>",node.getName(), node.getSubLevelResultColumn()!=null?node.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG); 103 } 104 } 105 if (node.getAccompaniedAttributeNodes().size() >0 ){ 106 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 107 TBaseType.log(String.format("\t\tAccompanied nodes: %d",node.getAccompaniedAttributeNodes().size()),TLog.DEBUG); 108 } 109 for(TAttributeNode n:node.getAccompaniedAttributeNodes()){ 110 if (n.getSqlColumn() != null){ 111 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 112 TBaseType.log(String.format("\t\tAttribute: <%s>, SQL column: <%s>",n.getName(), n.getSqlColumn()!=null?n.getSqlColumn().toString():"N/A" ),TLog.DEBUG); 113 } 114 }else{ 115 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 116 TBaseType.log(String.format("\t\tAttribute: <%s>, Select list column: <%s>",n.getName(), n.getSubLevelResultColumn()!=null?n.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG); 117 } 118 } 119 } 120 } 121 122 c++; 123 if (c > TLog.OUTPUT_ATTRIBUTES_MAX){ 124 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 125 TBaseType.log(String.format("\t...skipped after output %d attributes",c-1),TLog.DEBUG,this.getTableName().getStartToken()); 126 } 127 128 break; 129 } 130 } 131 } 132 133 public String getRelationName(){ 134 return this.getTableName().toString(); 135 } 136 137// public ArrayList<TAttributeNode> getAttributes(){ 138// return relationAttributes; 139// } 140 141 private TSelectSqlNode selectNode; 142 private TSelectSqlStatement subquery; 143 144 private TInsertSqlNode insertSqlNode; 145 private TInsertSqlStatement insertStmt; 146 147 private TUpdateSqlNode updateSqlNode; 148 private TUpdateSqlStatement updateStmt; 149 150 private TDeleteSqlNode deleteSqlNode; 151 private TDeleteSqlStatement deleteStmt; 152 153 private TCustomSqlStatement preparableStmt; 154 155 public boolean searchColumnInResultSet(TCustomSqlStatement pSql,TTable pTable,TObjectName pColumn,boolean pMustIn){ 156 boolean lcResult = false; 157 if (getColumnList() != null){ 158 for (int i=0;i<getColumnList().size();i++){ 159 lcResult = getColumnList().getObjectName(i).toString().equalsIgnoreCase(pColumn.getColumnNameOnly()); 160 //pColumn.setSourceColumn(getColumnList().getObjectName(i)); 161 if (lcResult) break; 162 } 163 return lcResult; 164 } 165 166 TCustomSqlStatement lcStmt = pSql; 167 while (lcStmt != null){ 168 if (lcStmt == getSubquery()){ 169 pTable.getLinkedColumns().addObjectName(pColumn); 170 pColumn.setSourceTable(pTable); 171 lcResult = true; 172 break; 173 } 174 lcStmt = lcStmt.getParentStmt(); 175 } 176 177 if (lcResult) return true; 178 179 if (getSubquery() == null) return false; 180 lcResult = getSubquery().searchColumnInResultSet(pColumn,pMustIn); 181 182 return lcResult; 183 } 184 185 /** 186 * preparable statement can be: 187 * <p> {@link #getSubquery()} 188 * <p> or{@link #getUpdateStmt()} 189 * <p> or{@link #getInsertStmt()} 190 * <p> or{@link #getDeleteStmt()} 191 * @return 192 */ 193 public TCustomSqlStatement getPreparableStmt() { 194 preparableStmt = null; 195 if (subquery!=null){ 196 preparableStmt = subquery; 197 }else if (updateStmt != null){ 198 preparableStmt = updateStmt; 199 }else if (deleteStmt != null){ 200 preparableStmt = deleteStmt; 201 }else if (insertStmt != null){ 202 preparableStmt = insertStmt; 203 } 204 205 return preparableStmt; 206 } 207 208 public TUpdateSqlStatement getUpdateStmt() { 209 return updateStmt; 210 } 211 212 public TInsertSqlStatement getInsertStmt() { 213 214 return insertStmt; 215 } 216 217 public TDeleteSqlStatement getDeleteStmt() { 218 219 return deleteStmt; 220 } 221 222 /** 223 * @return table name of this common table expression. 224 */ 225 public TObjectName getTableName() { 226 return tableName; 227 } 228 229 private TObjectName tableName; 230 231 public void setColumnList(TObjectNameList columnList) { 232 this.columnList = columnList; 233 } 234 235 /** 236 * fullselect of this common table expression. 237 * @return 238 */ 239 public TSelectSqlStatement getSubquery() { 240 return subquery; 241 } 242 243 /** 244 * @return List of column name of this common table expression. 245 246 */ 247 public TObjectNameList getColumnList() { 248 return columnList; 249 } 250 251 private TObjectNameList columnList = null; 252 253 public void init(Object arg1,Object arg2) 254 { 255 tableName = (TObjectName)arg1; 256 //tableName.parseTablename(); 257 //tableName.setObjectType(TObjectName.ttobjTableCTE); 258 tableName.setDbObjectType(EDbObjectType.cte); 259 260 if (arg2 instanceof TSelectSqlNode){ 261 selectNode = (TSelectSqlNode)arg2; 262 }else if (arg2 instanceof TInsertSqlNode){ 263 insertSqlNode = (TInsertSqlNode)arg2; 264 }else if (arg2 instanceof TUpdateSqlNode){ 265 updateSqlNode = (TUpdateSqlNode)arg2; 266 }else if (arg2 instanceof TDeleteSqlNode){ 267 deleteSqlNode = (TDeleteSqlNode)arg2; 268 } 269 } 270 271 public void incParenthesisCount() { 272 if (selectNode != null){ 273 selectNode.incParenthesisCount(); 274 } 275 } 276 277 public void doParse(TCustomSqlStatement psql, ESqlClause plocation){ 278 279 if (selectNode != null){ 280 //long t = System.currentTimeMillis(); 281 subquery = new TSelectSqlStatement(psql.dbvendor); 282 subquery.rootNode = selectNode; 283 subquery.setQueryOfCTE(true); 284 subquery.setCteIncludeThisStmt(this); 285 subquery.doParseStatement(psql); 286 for(TTable t:subquery.getRelations()){ 287 if (t.isCTEName() && t.getCTE() == this){ 288 // System.out.println("found cte name in the same level:"+ t.getCTE().toString()); 289 t.setCTEName(false); 290 t.setCTE(null); 291 } 292 } 293// if (columnList == null){ 294// columnList = new TObjectNameList(); 295// for(TResultColumn resultColumn:subquery.getResultColumnList()){ 296// columnList.addObjectName(new TObjectName()); 297// 298// } 299// } 300 //System.out.println("Time Escaped: " + (System.currentTimeMillis() - t)+", sql size:"+ this.toString().length() ); 301 }else if (insertSqlNode != null){ 302 insertStmt = new TInsertSqlStatement(psql.dbvendor); 303 insertStmt.rootNode = insertSqlNode; 304 insertStmt.setCteIncludeThisStmt(this); 305 insertStmt.doParseStatement(psql); 306 }else if (deleteSqlNode != null){ 307 deleteStmt = new TDeleteSqlStatement(psql.dbvendor); 308 deleteStmt.rootNode = deleteSqlNode; 309 deleteStmt.setCteIncludeThisStmt(this); 310 deleteStmt.doParseStatement(psql); 311 }else if (updateSqlNode != null){ 312 updateStmt = new TUpdateSqlStatement(psql.dbvendor); 313 updateStmt.rootNode = updateSqlNode; 314 updateStmt.setCteIncludeThisStmt(this); 315 updateStmt.doParseStatement(psql); 316 } 317 } 318 319 public void accept(TParseTreeVisitor v){ 320 v.preVisit(this); 321 v.postVisit(this); 322 } 323 324 public void acceptChildren(TParseTreeVisitor v){ 325 v.preVisit(this); 326 if (subquery != null){ 327 subquery.acceptChildren(v); 328 } 329 v.postVisit(this); 330 } 331 332 public void setSubquery(TSelectSqlStatement subquery) { 333 this.subquery = subquery; 334 } 335 336 public void setInsertStmt(TInsertSqlStatement insertStmt) { 337 this.insertStmt = insertStmt; 338 } 339 340 public void setUpdateStmt(TUpdateSqlStatement updateStmt) { 341 this.updateStmt = updateStmt; 342 } 343 344 public void setDeleteStmt(TDeleteSqlStatement deleteStmt) { 345 this.deleteStmt = deleteStmt; 346 } 347 348 public void setPreparableStmt(TCustomSqlStatement preparableStmt) { 349 this.preparableStmt = preparableStmt; 350 } 351 352 public void setTableName(TObjectName tableName) { 353 this.tableName = tableName; 354 } 355}