001package gudusoft.gsqlparser.nodes; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.compiler.TSymbolTableManager; 005import gudusoft.gsqlparser.compiler.TVariable; 006import gudusoft.gsqlparser.sqlenv.TSQLTable; 007import gudusoft.gsqlparser.stmt.TSelectSqlStatement; 008 009import java.util.ArrayList; 010 011 012public class TIntoClause extends TParseTreeNode { 013 014 public void setBulkCollect(boolean bulkCollect) { 015 this.bulkCollect = bulkCollect; 016 } 017 018 public boolean isBulkCollect() { 019 020 return bulkCollect; 021 } 022 023 024 public TObjectName getTableName() { 025 return tableName; 026 } 027 028 private TObjectName tableName; 029 030 private boolean bulkCollect = false; 031 private TSourceToken filename; 032 private TExpressionList exprList = null; 033 private TObjectName intoName = null; 034 private TObjectNameList variableList = null; 035 private ETableKind tableKind = ETableKind.etkBase; 036 private boolean tableKindDetected = false; 037 038 /** 039 * Returns the table kind for SELECT INTO targets (TEMPORARY, TEMP, LOCAL TEMPORARY, etc.). 040 * <p> 041 * This is consistent with {@link gudusoft.gsqlparser.stmt.TCreateTableSqlStatement#getTableKinds()} 042 * but returns a single ETableKind value since SELECT INTO can only specify one kind. 043 * <p> 044 * For SQL Server, table kind is detected from the # or ## prefix on the table name. 045 * For PostgreSQL, Redshift, Greenplum, and Netezza, table kind is detected from 046 * TEMPORARY/TEMP/LOCAL/GLOBAL/UNLOGGED keywords in the INTO clause. 047 * 048 * @return the table kind, or {@link ETableKind#etkBase} if no special kind is specified 049 */ 050 public ETableKind getTableKind() { 051 if (!tableKindDetected) { 052 detectTableKindFromTokens(); 053 } 054 return tableKind; 055 } 056 057 public void setTableKind(ETableKind tableKind) { 058 this.tableKind = tableKind; 059 this.tableKindDetected = true; 060 } 061 062 public TObjectNameList getVariableList() { 063 return variableList; 064 } 065 066 public void setIntoName(TObjectName intoName) { 067 this.intoName = intoName; 068 } 069 070 public TObjectName getIntoName() { 071 if (intoName != null){ 072 return intoName; 073 }else{ 074 return exprList.getExpression(0).getObjectOperand(); 075 } 076 } 077 078 public TExpressionList getExprList() { 079 return exprList; 080 } 081 082 public TSourceToken getFilename() { 083 return filename; 084 } 085 086 public void init(Object arg1) 087 { 088 if (arg1 instanceof TExpressionList){ 089 exprList = (TExpressionList)arg1; 090 }else if (arg1 instanceof TSourceToken){ 091 filename = (TSourceToken)arg1; 092 }else if (arg1 instanceof TObjectNameList){ 093 variableList = (TObjectNameList)arg1; 094 for(int i=0;i<variableList.size();i++){ 095 if (variableList.getObjectName(i).toString().startsWith("#")){ 096 // #temp_table, not a variable 097 variableList.getObjectName(i).setDbObjectType(EDbObjectType.TEMP_TABLE); 098 }else{ 099 variableList.getObjectName(i).setDbObjectType(EDbObjectType.variable); 100 } 101 102 } 103 intoName = variableList.getObjectName(0); 104 }else if (arg1 instanceof TObjectName){ 105 tableName = (TObjectName)arg1; 106 } 107 } 108 109 /** 110 * Detects the table kind (TEMPORARY, TEMP, LOCAL, GLOBAL, UNLOGGED, VOLATILE) 111 * by scanning the tokens between the INTO keyword (startToken) and the table name. 112 * This handles SELECT INTO TEMPORARY TABLE, SELECT INTO LOCAL TEMP TABLE, etc. 113 */ 114 private void detectTableKindFromTokens() { 115 tableKindDetected = true; 116 TSourceToken st = getStartToken(); 117 if (st == null) return; 118 119 boolean hasLocal = false; 120 boolean hasGlobal = false; 121 122 // Scan tokens after startToken (INTO) looking for table-kind keywords 123 st = st.getNextTokenInChain(); 124 TSourceToken endSt = getEndToken(); 125 while (st != null && st != endSt) { 126 if (st.tokencode == TBaseType.lexspace || st.tokencode == TBaseType.lexnewline 127 || st.tokencode == TBaseType.cmtslashstar || st.tokencode == TBaseType.cmtdoublehyphen) { 128 st = st.getNextTokenInChain(); 129 continue; 130 } 131 String text = st.toString().toUpperCase(); 132 if (text.equals("LOCAL")) { 133 hasLocal = true; 134 } else if (text.equals("GLOBAL")) { 135 hasGlobal = true; 136 } else if (text.equals("TEMPORARY")) { 137 if (hasLocal) tableKind = ETableKind.etkLocalTemporary; 138 else if (hasGlobal) tableKind = ETableKind.etkGlobalTemporary; 139 else tableKind = ETableKind.etkTemporary; 140 return; 141 } else if (text.equals("TEMP")) { 142 if (hasLocal) tableKind = ETableKind.etkLocalTemp; 143 else if (hasGlobal) tableKind = ETableKind.etkGlobalTemp; 144 else tableKind = ETableKind.etkTemp; 145 return; 146 } else if (text.equals("UNLOGGED")) { 147 tableKind = ETableKind.etkUnlogged; 148 return; 149 } else if (text.equals("VOLATILE")) { 150 if (hasLocal) tableKind = ETableKind.etkLocalVolatile; 151 else if (hasGlobal) tableKind = ETableKind.etkGlobalVolatile; 152 else tableKind = ETableKind.etkVolatile; 153 return; 154 } else if (text.equals("STRICT") || text.equals("TABLE")) { 155 // Skip known non-kind keywords in INTO clause 156 } else { 157 // Reached the table name or unknown token, stop scanning 158 break; 159 } 160 st = st.getNextTokenInChain(); 161 } 162 } 163 164 public void doParse(TCustomSqlStatement psql, ESqlClause plocation){ 165 // Detect table kind from tokens (TEMPORARY, TEMP, LOCAL, GLOBAL, etc.) 166 if (!tableKindDetected) { 167 detectTableKindFromTokens(); 168 } 169 170 if (exprList != null){ 171 for(int i=0;i<exprList.size();i++){ 172 TExpression expr = exprList.getExpression(i); 173 if (expr.getExpressionType() == EExpressionType.simple_object_name_t){ 174 TObjectName dbObject = expr.getObjectOperand(); 175 if ((psql.dbvendor == EDbVendor.dbvmssql) 176 ||(psql.dbvendor == EDbVendor.dbvgreenplum) 177 ||(psql.dbvendor == EDbVendor.dbvpostgresql) 178 ||(psql.dbvendor == EDbVendor.dbvsybase) 179 ||(psql.dbvendor == EDbVendor.dbvodbc) 180 ||(psql.dbvendor == EDbVendor.dbvredshift) 181 ||(psql.dbvendor == EDbVendor.dbvnetezza) 182 ){ // database support: select .. into table 183 if (dbObject.toString().startsWith("@")){ 184 // table variable 185 dbObject.setObjectType(TObjectName.ttobjVariable); 186 }else { 187 TVariable symbolVariable = TSymbolTableManager.searchSymbolVariable(psql.getFrameStack(),dbObject.toString()); //psql.searchSymbolVariable(dbObject.toString()); 188 if (symbolVariable != null){ 189 dbObject.setDbObjectType(EDbObjectType.variable); 190 }else{ 191 TTable table = new TTable(); 192 dbObject.setObjectType(TObjectName.ttobjTable); 193 if (tableKind != ETableKind.etkBase) { 194 // Table kind detected from TEMPORARY/TEMP/etc. keywords 195 dbObject.setTableKind(tableKind); 196 } else if (dbObject.toString().startsWith("##")){ 197 // SQL Server global temporary table (##tablename) 198 dbObject.setTableKind(ETableKind.etkGlobalTemporary); 199 } else if (dbObject.toString().startsWith("#")){ 200 // SQL Server local temporary table (#tablename) 201 dbObject.setTableKind(ETableKind.etkTemporary); 202 } 203 table.setTableName(dbObject); 204 table.setTableType(ETableSource.objectname); 205 table.setEffectType(ETableEffectType.tetSelectInto); 206 psql.addToTables(table); 207 if (psql instanceof TSelectSqlStatement){ 208 TSelectSqlStatement subQuery = ((TSelectSqlStatement)psql); 209 table.setColumnListInTempTable(subQuery.getResultColumnList()); 210 211 TSQLTable sqlTmpTable = null; 212 if (psql.getSqlEnv() != null) { 213 sqlTmpTable = psql.getSqlEnv().addTable(dbObject.toString(),true); 214 215 if (subQuery.getResultColumnList().getResultColumn(0).toString().endsWith("*")){ 216 // select * into #tmp, we need to find real columns in from clause 217 // if (subQuery.getTables().getTable()) 218 ArrayList<String> columns = subQuery.getColumnsInFromClause(); 219 if (columns.size() > 0){ 220 for(String c:columns){ 221 sqlTmpTable.addColumn(c); 222 } 223 } 224 }else{ 225 subQuery.addColumnInSelectListToSQLEnv(sqlTmpTable); 226 } 227 } 228 } 229 } 230 } 231 }else { // database support: select .. into variable 232 if (dbObject.toString().startsWith(":")){ 233 // oracle, INTO :NEW.DI_RESID 234 expr.doParse(psql, ESqlClause.selectInto); 235 }else{ 236 if (dbObject.toString().startsWith("#")){ 237 // #temp_table, not a variable 238 dbObject.setDbObjectType(EDbObjectType.TEMP_TABLE); 239 }else{ 240 dbObject.setObjectType(TObjectName.ttobjVariable); 241 dbObject.setDbObjectType(EDbObjectType.variable); 242 } 243 } 244 } 245 }else{ 246 expr.doParse(psql, ESqlClause.selectInto); 247 } 248 } 249 } 250 } 251 252 //public void addTableToList() 253 254 public void accept(TParseTreeVisitor v){ 255 v.preVisit(this); 256 v.postVisit(this); 257 258 } 259 260 public void acceptChildren(TParseTreeVisitor v){ 261 v.preVisit(this); 262 v.postVisit(this); 263 } 264 265 public void setExprList(TExpressionList exprList) { 266 this.exprList = exprList; 267 } 268}