diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 7fcb43db48944a..a3f5142fc1ecb4 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -155,12 +155,28 @@ supportedCreateStatement properties=propertyClause? (BROKER extProperties=propertyClause)? (AS query)? #createTable + | CREATE (TEMPORARY)? TABLE (IF NOT EXISTS)? name=multipartIdentifier + ((ctasCols=identifierList)? | (LEFT_PAREN columnDefs (COMMA indexDefs)? COMMA? RIGHT_PAREN)) + (ENGINE EQ engine=identifier)? + ((AGGREGATE | UNIQUE | DUPLICATE) KEY keys=identifierList + (CLUSTER BY clusterKeys=identifierList)?)? + (COMMENT STRING_LITERAL)? + (partition=partitionTable)? + (DISTRIBUTED BY (HASH hashKeys=identifierList | RANDOM) + (BUCKETS (INTEGER_VALUE | autoBucket=AUTO))?)? + (ROLLUP LEFT_PAREN rollupDefs RIGHT_PAREN)? + properties=propertyClause? + (BROKER extProperties=propertyClause)? + (AS query)? #createTable | CREATE (OR REPLACE)? VIEW (IF NOT EXISTS)? name=multipartIdentifier (LEFT_PAREN cols=simpleColumnDefs RIGHT_PAREN)? (COMMENT STRING_LITERAL)? AS query #createView | CREATE (EXTERNAL)? TABLE (IF NOT EXISTS)? name=multipartIdentifier LIKE existedTable=multipartIdentifier (WITH ROLLUP (rollupNames=identifierList)?)? #createTableLike + | CREATE (TEMPORARY)? TABLE (IF NOT EXISTS)? name=multipartIdentifier + LIKE existedTable=multipartIdentifier + (WITH ROLLUP (rollupNames=identifierList)?)? #createTableLike | CREATE ROW POLICY (IF NOT EXISTS)? name=identifier ON table=multipartIdentifier AS type=(RESTRICTIVE | PERMISSIVE) diff --git a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java index d028f3aeae1437..3e95cf381f4af7 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java @@ -187,6 +187,8 @@ public static void start(String dorisHomeDir, String pidDir, String[] args, Star Env.getCurrentEnv().initialize(args); Env.getCurrentEnv().waitForReady(); + Env.getCurrentEnv().cleanPhantomTempTable(); + // init and start: // 1. HttpServer for HTTP Server // 2. FeServer for Thrift Server diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java index e6a2fe0229f0a8..714d314e78c429 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java @@ -125,7 +125,7 @@ public void processCreateMaterializedView(CreateMaterializedViewStmt stmt) Database db = Env.getCurrentInternalCatalog().getDbOrDdlException(dbName); Env.getCurrentInternalCatalog().checkAvailableCapacity(db); - OlapTable olapTable = (OlapTable) db.getTableOrMetaException(tableName, TableType.OLAP); + OlapTable olapTable = (OlapTable) db.getNonTempTableOrMetaException(tableName, TableType.OLAP); ((MaterializedViewHandler) materializedViewHandler).processCreateMaterializedView(stmt, db, olapTable); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMTMVStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMTMVStmt.java index d586535572bfc4..55e63aec08c202 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMTMVStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMTMVStmt.java @@ -38,8 +38,8 @@ public CreateMTMVStmt(boolean ifNotExists, TableName mvName, List column MTMVRefreshInfo refreshInfo, KeysDesc keyDesc, DistributionDesc distributionDesc, Map properties, Map mvProperties, String querySql, String comment, PartitionDesc partitionDesc, MTMVPartitionInfo mvPartitionInfo, MTMVRelation relation) { - super(ifNotExists, false, mvName, columns, new ArrayList(), DEFAULT_ENGINE_NAME, keyDesc, partitionDesc, - distributionDesc, properties, null, comment, null, null); + super(ifNotExists, false, false, mvName, columns, new ArrayList(), DEFAULT_ENGINE_NAME, keyDesc, + partitionDesc, distributionDesc, properties, null, comment, null, null); this.refreshInfo = refreshInfo; this.querySql = querySql; this.mvProperties = mvProperties; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableLikeStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableLikeStmt.java index aab0f362afe93f..1fbf3253d3e301 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableLikeStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableLikeStmt.java @@ -44,6 +44,7 @@ public class CreateTableLikeStmt extends DdlStmt implements NotFallbackInParser private static final Logger LOG = LogManager.getLogger(CreateTableLikeStmt.class); private final boolean ifNotExists; + private final boolean isTemp; private final TableName tableName; private final TableName existedTableName; private final ArrayList rollupNames; @@ -51,7 +52,13 @@ public class CreateTableLikeStmt extends DdlStmt implements NotFallbackInParser public CreateTableLikeStmt(boolean ifNotExists, TableName tableName, TableName existedTableName, ArrayList rollupNames, boolean withAllRollup) throws DdlException { + this(ifNotExists, false, tableName, existedTableName, rollupNames, withAllRollup); + } + + public CreateTableLikeStmt(boolean ifNotExists, boolean isTemp, TableName tableName, TableName existedTableName, + ArrayList rollupNames, boolean withAllRollup) throws DdlException { this.ifNotExists = ifNotExists; + this.isTemp = isTemp; this.tableName = tableName; this.existedTableName = existedTableName; if (!CollectionUtils.isEmpty(rollupNames) && withAllRollup) { @@ -65,6 +72,10 @@ public boolean isIfNotExists() { return ifNotExists; } + public boolean isTemp() { + return isTemp; + } + public String getDbName() { return tableName.getDb(); } @@ -115,7 +126,11 @@ public void analyze(Analyzer analyzer) throws UserException { @Override public String toSql() { StringBuilder sb = new StringBuilder(); - sb.append("CREATE TABLE ").append(tableName.toSql()).append(" LIKE ").append(existedTableName.toSql()); + sb.append("CREATE "); + if (isTemp) { + sb.append("TEMPORARY "); + } + sb.append("TABLE ").append(tableName.toSql()).append(" LIKE ").append(existedTableName.toSql()); if (withAllRollup && CollectionUtils.isEmpty(rollupNames)) { sb.append(" WITH ROLLUP"); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableStmt.java index d3f37b632ca0a5..de8758bd415051 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateTableStmt.java @@ -80,6 +80,7 @@ public class CreateTableStmt extends DdlStmt implements NotFallbackInParser { protected boolean ifNotExists; private boolean isExternal; + private boolean isTemp; protected TableName tableName; protected List columnDefs; private List indexDefs; @@ -187,12 +188,14 @@ public CreateTableStmt(boolean ifNotExists, boolean isExternal, TableName tableN } // for Nereids - public CreateTableStmt(boolean ifNotExists, boolean isExternal, TableName tableName, List columns, - List indexes, String engineName, KeysDesc keysDesc, PartitionDesc partitionDesc, - DistributionDesc distributionDesc, Map properties, Map extProperties, - String comment, List rollupAlterClauseList, Void unused) { + public CreateTableStmt(boolean ifNotExists, boolean isExternal, boolean isTemp, TableName tableName, + List columns, List indexes, String engineName, KeysDesc keysDesc, + PartitionDesc partitionDesc, DistributionDesc distributionDesc, Map properties, + Map extProperties, String comment, + List rollupAlterClauseList, Void unused) { this.ifNotExists = ifNotExists; this.isExternal = isExternal; + this.isTemp = isTemp; this.tableName = tableName; this.columns = columns; this.indexes = indexes; @@ -224,6 +227,14 @@ public boolean isExternal() { return isExternal; } + public boolean isTemp() { + return isTemp; + } + + public void setTemp(boolean temp) { + isTemp = temp; + } + public TableName getDbTbl() { return tableName; } @@ -652,6 +663,9 @@ public String toSql() { StringBuilder sb = new StringBuilder(); sb.append("CREATE "); + if (isTemp) { + sb.append("TEMPORARY "); + } if (isExternal) { sb.append("EXTERNAL "); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDataStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDataStmt.java index 26b77e0b3d5d26..20cd37a0d8fa3d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDataStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDataStmt.java @@ -178,6 +178,10 @@ public int compare(Table t1, Table t2) { PrivPredicate.SHOW)) { continue; } + if (table.getType() == TableType.TEMP && Util.getTempTableConnectionId(table.getName()) + != ConnectContext.get().getConnectionId()) { + continue; + } sortedTables.add(table); } @@ -196,7 +200,13 @@ public int compare(Table t1, Table t2) { remoteSize = olapTable.getRemoteDataSize(); //|TableName|Size|ReplicaCount|RemoteSize - List row = Arrays.asList(table.getName(), tableSize, replicaCount, remoteSize); + List row; + if (table.getType() == TableType.TEMP) { + row = Arrays.asList(Util.getTempTableOuterName(table.getName()), tableSize, + replicaCount, remoteSize); + } else { + row = Arrays.asList(table.getName(), tableSize, replicaCount, remoteSize); + } totalRowsObject.add(row); totalSize += tableSize; @@ -299,7 +309,9 @@ public int compare(Table t1, Table t2) { String indexName = olapTable.getIndexNameById(indexId); // .add("TableName").add("IndexName").add("Size").add("ReplicaCount").add("RowCount") // .add("RemoteSize") - List row = Arrays.asList(tableName, indexName, indexSize, indexReplicaCount, + String tableShowName = olapTable.getType() == TableType.TEMP + ? Util.getTempTableOuterName(tableName.getTbl()) : tableName.getTbl(); + List row = Arrays.asList(tableShowName, indexName, indexSize, indexReplicaCount, indexRowCount, indexRemoteSize); totalRowsObject.add(row); diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowQueryStatsStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowQueryStatsStmt.java index 723a0ef8629a6c..a4bd934eab0694 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowQueryStatsStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowQueryStatsStmt.java @@ -25,6 +25,7 @@ import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; import org.apache.doris.common.UserException; +import org.apache.doris.common.util.Util; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.ShowResultSetMetaData; @@ -137,7 +138,14 @@ public void analyze(Analyzer analyzer) throws UserException { stats.forEach((tableName, queryHit) -> { if (Env.getCurrentEnv().getAccessManager() .checkTblPriv(ConnectContext.get(), ctlName, dbName, tableName, PrivPredicate.SHOW)) { - totalRows.add(Arrays.asList(tableName, String.valueOf(queryHit))); + if (Util.isTempTable(tableName)) { + if (Util.isTempTableInCurrentSession(tableName)) { + totalRows.add(Arrays.asList(Util.getTempTableOuterName(tableName), + String.valueOf(queryHit))); + } + } else { + totalRows.add(Arrays.asList(tableName, String.valueOf(queryHit))); + } } }); } else { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/UpdateStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/UpdateStmt.java index 786ad16237ec6e..57d87e8dd756a7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/UpdateStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/UpdateStmt.java @@ -23,6 +23,7 @@ import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.Table; import org.apache.doris.catalog.TableIf; +import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; @@ -146,7 +147,7 @@ private void analyzeTargetTable(Analyzer analyzer) throws UserException { // step2: resolve table name with catalog, only unique olap table could be updated targetTable = targetTableRef.getTable(); - if (targetTable.getType() != Table.TableType.OLAP + if ((targetTable.getType() != Table.TableType.OLAP && targetTable.getType() != TableType.TEMP) || ((OlapTable) targetTable).getKeysType() != KeysType.UNIQUE_KEYS) { throw new AnalysisException("Only unique table could be updated."); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java index 6862c3b61c02a3..e28a06bef78a7c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java @@ -37,6 +37,7 @@ import org.apache.doris.persist.CreateTableInfo; import org.apache.doris.persist.gson.GsonPostProcessable; import org.apache.doris.persist.gson.GsonUtils; +import org.apache.doris.qe.ConnectContext; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -378,6 +379,19 @@ public void checkQuota() throws DdlException { checkReplicaQuota(); } + public boolean isTableExist(String tableName, TableType tableType) { + if (Env.isTableNamesCaseInsensitive()) { + tableName = tableName.toLowerCase(); + } + + if (tableType == TableType.TEMP) { + Set tableSet = ConnectContext.get().getDbToTempTableNamesMap().get(fullQualifiedName); + return tableSet != null && tableSet.contains(tableName); + } else { + return nameToTable.containsKey(tableName); + } + } + public boolean isTableExist(String tableName) { if (Env.isTableNamesCaseInsensitive()) { tableName = lowerCaseToTableName.get(tableName.toLowerCase()); @@ -407,8 +421,16 @@ public Pair createTableWithLock( isTableExist = true; } else { idToTable.put(table.getId(), table); - nameToTable.put(table.getName(), table); lowerCaseToTableName.put(tableName.toLowerCase(), tableName); + nameToTable.put(table.getName(), table); + if (table.getType() == TableType.TEMP) { + if (isReplay) { + // add to to-deleted list, and delete it after catalog is ready + Env.getCurrentEnv().addPhantomTempTable(table); + } else { + ConnectContext.get().addTempTableToDB(table.getQualifiedDbName(), table.getName()); + } + } if (!isReplay) { // Write edit log @@ -454,8 +476,8 @@ public void unregisterTable(String tableName) { Table table = getTableNullable(tableName); if (table != null) { this.nameToTable.remove(tableName); - this.idToTable.remove(table.getId()); this.lowerCaseToTableName.remove(tableName.toLowerCase()); + this.idToTable.remove(table.getId()); table.markDropped(); } } @@ -549,7 +571,33 @@ public Table getTableNullable(String tableName) { return null; } } - return nameToTable.get(tableName); + + // return temp table first + Table table = nameToTable.get(Util.generateTempTableInnerName(tableName)); + if (table == null) { + table = nameToTable.get(tableName); + } + + return table; + } + + /** + * This is a thread-safe method when nameToTable is a concurrent hash map + */ + @Override + public Table getNonTempTableNullable(String tableName) { + if (Env.isStoredTableNamesLowerCase()) { + tableName = tableName.toLowerCase(); + } + if (Env.isTableNamesCaseInsensitive()) { + tableName = lowerCaseToTableName.get(tableName.toLowerCase()); + if (tableName == null) { + return null; + } + } + + Table table = nameToTable.get(tableName); + return table; } /** diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/DatabaseIf.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/DatabaseIf.java index b1d40770cae342..5502e94e2025bd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/DatabaseIf.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/DatabaseIf.java @@ -111,6 +111,8 @@ default Set getTableNamesOrEmptyWithLock() { T getTableNullable(String tableName); + T getNonTempTableNullable(String tableName); + default T getTableNullableIfException(String tableName) { try { return getTableNullable(tableName); @@ -139,6 +141,15 @@ default T getTableOrException(String tableName, java.util. return table; } + default T getNonTempTableOrException(String tableName, + java.util.function.Function e) throws E { + T table = getNonTempTableNullable(tableName); + if (table == null) { + throw e.apply(tableName); + } + return table; + } + default T getTableOrException(long tableId, Function e) throws E { T table = getTableNullable(tableId); if (table == null) { @@ -152,6 +163,11 @@ default T getTableOrMetaException(String tableName) throws MetaNotFoundException ErrorCode.ERR_BAD_TABLE_ERROR)); } + default T getNonTempTableOrMetaException(String tableName) throws MetaNotFoundException { + return getNonTempTableOrException(tableName, t -> new MetaNotFoundException("table not found, tableName=" + t, + ErrorCode.ERR_BAD_TABLE_ERROR)); + } + default T getTableOrMetaException(long tableId) throws MetaNotFoundException { return getTableOrException(tableId, t -> new MetaNotFoundException("table not found, tableId=" + t, ErrorCode.ERR_BAD_TABLE_ERROR)); @@ -167,6 +183,17 @@ default T getTableOrMetaException(String tableName, TableIf.TableType tableType) return table; } + default T getNonTempTableOrMetaException(String tableName, TableIf.TableType tableType) + throws MetaNotFoundException { + T table = getNonTempTableOrMetaException(tableName); + TableType type = Objects.requireNonNull(table.getType()); + if (type != tableType && type.getParentType() != tableType) { + throw new MetaNotFoundException( + "table type is not " + tableType + ", tableName=" + tableName + ", type=" + type); + } + return table; + } + default T getTableOrMetaException(String tableName, List tableTypes) throws MetaNotFoundException { T table = getTableOrMetaException(tableName); @@ -256,7 +283,7 @@ default OlapTable getOlapTableOrDdlException(String tableName) throws DdlExcepti default OlapTable getOlapTableOrAnalysisException(String tableName) throws AnalysisException { T table = getTableOrAnalysisException(tableName); - if (!(table instanceof OlapTable)) { + if (!(table instanceof OlapTable) && !(table.getType() == TableType.TEMP)) { throw new AnalysisException(ErrorCode.ERR_NOT_OLAP_TABLE.formatErrorMsg(tableName)); } return (OlapTable) table; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java index 8787fd97607b16..c1b7dd8aabd1e5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java @@ -573,6 +573,8 @@ public class Env { private final List forceSkipJournalIds = Arrays.asList(Config.force_skip_journal_ids); + private List phantomTempTableList; + // if a config is relative to a daemon thread. record the relation here. we will proactively change interval of it. private final Map> configtoThreads = ImmutableMap .of("dynamic_partition_check_interval_seconds", this::getDynamicPartitionScheduler); @@ -820,6 +822,27 @@ public Env(boolean isCheckpointCatalog) { this.sqlCacheManager = new NereidsSqlCacheManager(); this.splitSourceManager = new SplitSourceManager(); this.globalExternalTransactionInfoMgr = new GlobalExternalTransactionInfoMgr(); + this.phantomTempTableList = new ArrayList<>(); + } + + public void addPhantomTempTable(Table table) { + phantomTempTableList.add(table); + } + + public void removePhantomTempTable(Table table) { + phantomTempTableList.remove(table); + } + + public void cleanPhantomTempTable() { + for (Table table : phantomTempTableList) { + try { + getInternalCatalog().dropTableWithoutCheck(getInternalCatalog().getDb(table.getDBName()).get(), + table, true); + } catch (DdlException e) { + LOG.error("drop temporary table error: db: {}, table: {}", table.getDBName(), table.getName(), e); + } + } + phantomTempTableList.clear(); } public static void destroyCheckpoint() { @@ -3741,12 +3764,19 @@ public static void getDdlStmt(DdlStmt ddlStmt, String dbName, TableIf table, Lis || table.getType() == TableType.HIVE || table.getType() == TableType.JDBC) { sb.append("EXTERNAL "); } + if (table.getType() == TableType.TEMP) { + sb.append("TEMPORARY "); + } sb.append(table.getType() != TableType.MATERIALIZED_VIEW ? "TABLE " : "MATERIALIZED VIEW "); if (!Strings.isNullOrEmpty(dbName)) { sb.append("`").append(dbName).append("`."); } - sb.append("`").append(table.getName()).append("`"); + if (table.getType() == TableType.TEMP) { + sb.append("`").append(Util.getTempTableOuterName(table.getName())).append("`"); + } else { + sb.append("`").append(table.getName()).append("`"); + } sb.append(" (\n"); @@ -3775,7 +3805,11 @@ public static void getDdlStmt(DdlStmt ddlStmt, String dbName, TableIf table, Lis } } sb.append("\n) ENGINE="); - sb.append(table.getType().name()); + if (table.getType() == TableType.TEMP) { + sb.append("OLAP"); + } else { + sb.append(table.getType().name()); + } if (table instanceof OlapTable) { OlapTable olapTable = (OlapTable) table; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java index faaba5dcc3871d..51ca8151236e5d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java @@ -219,12 +219,12 @@ public OlapTable() { public OlapTable(long id, String tableName, List baseSchema, KeysType keysType, PartitionInfo partitionInfo, DistributionInfo defaultDistributionInfo) { - this(id, tableName, baseSchema, keysType, partitionInfo, defaultDistributionInfo, null); + this(id, tableName, TableType.OLAP, baseSchema, keysType, partitionInfo, defaultDistributionInfo, null); } - public OlapTable(long id, String tableName, List baseSchema, KeysType keysType, + public OlapTable(long id, String tableName, TableType tableType, List baseSchema, KeysType keysType, PartitionInfo partitionInfo, DistributionInfo defaultDistributionInfo, TableIndexes indexes) { - super(id, tableName, TableType.OLAP, baseSchema); + super(id, tableName, tableType, baseSchema); this.state = OlapTableState.NORMAL; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTableFactory.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTableFactory.java index cc86535c8b1345..393d19a9d94ef3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTableFactory.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTableFactory.java @@ -35,6 +35,7 @@ public class OlapTableFactory { public static class BuildParams { public long tableId; public String tableName; + public TableType tableType; public List schema; public KeysType keysType; public PartitionInfo partitionInfo; @@ -43,6 +44,10 @@ public static class BuildParams { public static class OlapTableParams extends BuildParams { public TableIndexes indexes; + + public OlapTableParams(TableType tableType) { + this.tableType = tableType; + } } public static class MTMVParams extends BuildParams { @@ -59,14 +64,18 @@ public static TableType getTableType(DdlStmt stmt) { if (stmt instanceof CreateMTMVStmt) { return TableType.MATERIALIZED_VIEW; } else if (stmt instanceof CreateTableStmt) { - return TableType.OLAP; + return ((CreateTableStmt) stmt).isTemp() ? TableType.TEMP : TableType.OLAP; } else { throw new IllegalArgumentException("Invalid DDL statement: " + stmt.toSql()); } } public OlapTableFactory init(TableType type) { - params = (type == TableType.OLAP) ? new OlapTableParams() : new MTMVParams(); + if (type == TableType.OLAP || type == TableType.TEMP) { + params = new OlapTableParams(type); + } else { + params = new MTMVParams(); + } return this; } @@ -78,6 +87,7 @@ public Table build() { return new OlapTable( olapTableParams.tableId, olapTableParams.tableName, + olapTableParams.tableType, olapTableParams.schema, olapTableParams.keysType, olapTableParams.partitionInfo, diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java index ed40840239a3ed..76d05ba0d5df54 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java @@ -427,7 +427,7 @@ default boolean needReadLockWhenPlan() { */ enum TableType { MYSQL, ODBC, OLAP, SCHEMA, INLINE_VIEW, VIEW, BROKER, ELASTICSEARCH, HIVE, - @Deprecated ICEBERG, @Deprecated HUDI, JDBC, + @Deprecated ICEBERG, @Deprecated HUDI, JDBC, TEMP, TABLE_VALUED_FUNCTION, HMS_EXTERNAL_TABLE, ES_EXTERNAL_TABLE, MATERIALIZED_VIEW, JDBC_EXTERNAL_TABLE, ICEBERG_EXTERNAL_TABLE, TEST_EXTERNAL_TABLE, PAIMON_EXTERNAL_TABLE, MAX_COMPUTE_EXTERNAL_TABLE, HUDI_EXTERNAL_TABLE, TRINO_CONNECTOR_EXTERNAL_TABLE, LAKESOUl_EXTERNAL_TABLE; @@ -475,6 +475,7 @@ public String toEngineName() { public TableType getParentType() { switch (this) { case MATERIALIZED_VIEW: + case TEMP: return OLAP; default: return this; @@ -536,7 +537,7 @@ default String getNameWithFullQualifiers() { } default boolean isManagedTable() { - return getType() == TableType.OLAP || getType() == TableType.MATERIALIZED_VIEW; + return getType() == TableType.OLAP || getType() == TableType.MATERIALIZED_VIEW || getType() == TableType.TEMP; } default long getDataSize(boolean singleReplica) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java index 326f77f178cc2f..e7ffc0c8e65c77 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/Util.java @@ -690,4 +690,27 @@ public static long sha256long(String str) { public static long genIdByName(String... names) { return Math.abs(sha256long(String.join(".", names))); } + + + public static String generateTempTableInnerName(String tableName) { + ConnectContext ctx = ConnectContext.get(); + // when replay edit log, no need to generate temp table name + return ctx == null ? tableName : ctx.getConnectionId() + "_#TEMP#_" + tableName; + } + + public static String getTempTableOuterName(String tableName) { + return tableName.indexOf("_#TEMP#_") != -1 ? tableName.split("_#TEMP#_")[1] : tableName; + } + + public static int getTempTableConnectionId(String tableName) { + return tableName.indexOf("_#TEMP#_") != -1 ? new Integer(tableName.split("_#TEMP#_")[0]) : -1; + } + + public static boolean isTempTable(String tableName) { + return tableName.indexOf("_#TEMP#_") != -1; + } + + public static boolean isTempTableInCurrentSession(String tableName) { + return getTempTableConnectionId(tableName) == ConnectContext.get().getConnectionId(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java index d653a5a178e484..01eb6767561198 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalDatabase.java @@ -387,6 +387,11 @@ public T getTableNullable(String tableName) { } } + @Override + public T getNonTempTableNullable(String tableName) { + throw new NotImplementedException("getNonTempTableNullable() is not implemented"); + } + @Override public T getTableNullable(long tableId) { makeSureInitialized(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java index 9f7d27669d8d74..e902a564e6a23a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java @@ -941,7 +941,11 @@ public void dropTable(DropTableStmt stmt) throws DdlException { } } - dropTableInternal(db, table, stmt.isForceDrop(), watch, costTimes); + if (table.getType() == TableType.TEMP) { + dropTableInternal(db, table, true, watch, costTimes); + } else { + dropTableInternal(db, table, stmt.isForceDrop(), watch, costTimes); + } } catch (UserException e) { throw new DdlException(e.getMessage(), e.getMysqlErrorCode()); } finally { @@ -1004,6 +1008,9 @@ private void dropTableInternal(Database db, Table table, boolean forceDrop, DropInfo info = new DropInfo(db.getId(), table.getId(), tableName, -1L, forceDrop, recycleTime); Env.getCurrentEnv().getEditLog().logDropTable(info); Env.getCurrentEnv().getMtmvService().dropTable(table); + if (table.getType() == TableType.TEMP && ConnectContext.get() != null) { + ConnectContext.get().removeTempTableFromDB(db.getFullName(), tableName); + } } private static String genDropHint(String dbName, TableIf table) { @@ -1030,6 +1037,10 @@ public boolean unprotectDropTable(Database db, Table table, boolean isForceDrop, if (table.getType() == TableType.MATERIALIZED_VIEW) { Env.getCurrentEnv().getMtmvService().deregisterMTMV((MTMV) table); } + + if (isReplay && table.getType() == TableType.TEMP) { + Env.getCurrentEnv().removePhantomTempTable(table); + } Env.getCurrentEnv().getAnalysisManager().removeTableStats(table.getId()); db.unregisterTable(table.getName()); StopWatch watch = StopWatch.createStarted(); @@ -1210,12 +1221,16 @@ public boolean createTable(CreateTableStmt stmt) throws UserException { String engineName = stmt.getEngineName(); String dbName = stmt.getDbName(); String tableName = stmt.getTableName(); + String tableShowName = tableName; + if (stmt.isTemp()) { + tableName = Util.generateTempTableInnerName(tableName); + } // check if db exists Database db = getDbOrDdlException(dbName); // InfoSchemaDb and MysqlDb can not create table manually if (db instanceof MysqlCompatibleDatabase) { - ErrorReport.reportDdlException(ErrorCode.ERR_CANT_CREATE_TABLE, tableName, + ErrorReport.reportDdlException(ErrorCode.ERR_CANT_CREATE_TABLE, tableShowName, ErrorCode.ERR_CANT_CREATE_TABLE.getCode(), "not supported create table in this database"); } @@ -1225,12 +1240,13 @@ public boolean createTable(CreateTableStmt stmt) throws UserException { } // check if table exists in db - if (db.getTable(tableName).isPresent()) { + boolean isTableExist = stmt.isTemp() ? db.isTableExist(tableName, TableType.TEMP) : db.isTableExist(tableName); + if (isTableExist) { if (stmt.isSetIfNotExists()) { - LOG.info("create table[{}] which already exists", tableName); + LOG.info("create table[{}] which already exists", tableShowName); return true; } else { - ErrorReport.reportDdlException(ErrorCode.ERR_TABLE_EXISTS_ERROR, tableName); + ErrorReport.reportDdlException(ErrorCode.ERR_TABLE_EXISTS_ERROR, tableShowName); } } if (db.getTable(RestoreJob.tableAliasWithAtomicRestore(tableName)).isPresent()) { @@ -1315,6 +1331,7 @@ public void createTableLike(CreateTableLikeStmt stmt) throws DdlException { createTableStmt.get(0), ctx); parsedCreateTableStmt.setTableName(stmt.getTableName()); parsedCreateTableStmt.setIfNotExists(stmt.isIfNotExists()); + parsedCreateTableStmt.setTemp(stmt.isTemp()); createTable(parsedCreateTableStmt); } finally { ctx.setSkipAuth(false); @@ -2389,6 +2406,10 @@ private boolean createOlapTable(Database db, CreateTableStmt stmt) throws UserEx if (LOG.isDebugEnabled()) { LOG.debug("begin create olap table: {}", tableName); } + String tableShowName = tableName; + if (stmt.isTemp()) { + tableName = Util.generateTempTableInnerName(tableName); + } boolean tableHasExist = false; BinlogConfig dbBinlogConfig; db.readLock(); @@ -3056,8 +3077,9 @@ private boolean createOlapTable(Database db, CreateTableStmt stmt) throws UserEx long totalReplicaNum = indexNum * bucketNum * replicaNum; if (Config.isNotCloudMode() && totalReplicaNum >= db.getReplicaQuotaLeftWithLock()) { throw new DdlException( - "Database " + db.getFullName() + " create unpartitioned table " + tableName + " increasing " - + totalReplicaNum + " of replica exceeds quota[" + db.getReplicaQuota() + "]"); + "Database " + db.getFullName() + " create unpartitioned table " + tableShowName + + " increasing " + totalReplicaNum + " of replica exceeds quota[" + + db.getReplicaQuota() + "]"); } beforeCreatePartitions(db.getId(), olapTable.getId(), null, olapTable.getIndexIdList(), true); Partition partition = createPartitionWithIndices(db.getId(), olapTable, @@ -3120,7 +3142,7 @@ private boolean createOlapTable(Database db, CreateTableStmt stmt) throws UserEx } if (Config.isNotCloudMode() && totalReplicaNum >= db.getReplicaQuotaLeftWithLock()) { throw new DdlException( - "Database " + db.getFullName() + " create table " + tableName + " increasing " + "Database " + db.getFullName() + " create table " + tableShowName + " increasing " + totalReplicaNum + " of replica exceeds quota[" + db.getReplicaQuota() + "]"); } @@ -3166,7 +3188,7 @@ private boolean createOlapTable(Database db, CreateTableStmt stmt) throws UserEx Pair result = db.createTableWithLock(olapTable, false, stmt.isSetIfNotExists()); if (!result.first) { - ErrorReport.reportDdlException(ErrorCode.ERR_TABLE_EXISTS_ERROR, tableName); + ErrorReport.reportDdlException(ErrorCode.ERR_TABLE_EXISTS_ERROR, tableShowName); } if (result.second) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/load/DeleteHandler.java b/fe/fe-core/src/main/java/org/apache/doris/load/DeleteHandler.java index 299dac295dc909..61c8ec3be771f0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/load/DeleteHandler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/load/DeleteHandler.java @@ -29,6 +29,7 @@ import org.apache.doris.common.io.Writable; import org.apache.doris.common.util.ListComparator; import org.apache.doris.common.util.TimeUtils; +import org.apache.doris.common.util.Util; import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.persist.gson.GsonUtils; @@ -264,15 +265,23 @@ public List> getDeleteInfosByDb(long dbId) { } for (DeleteInfo deleteInfo : deleteInfoList) { + String tableName = deleteInfo.getTableName(); if (!Env.getCurrentEnv().getAccessManager() .checkTblPriv(ConnectContext.get(), InternalCatalog.INTERNAL_CATALOG_NAME, dbName, - deleteInfo.getTableName(), - PrivPredicate.LOAD)) { + tableName, PrivPredicate.LOAD)) { continue; } List info = Lists.newArrayList(); - info.add(deleteInfo.getTableName()); + if (Util.isTempTable(tableName)) { + info.add(Util.getTempTableOuterName(tableName)); + if (!Util.isTempTableInCurrentSession(tableName)) { + continue; + } + } else { + info.add(deleteInfo.getTableName()); + } + if (deleteInfo.isNoPartitionSpecified()) { info.add("*"); } else { diff --git a/fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java b/fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java index b9985e95d08fdb..0390fdae24eddd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java @@ -31,6 +31,7 @@ import org.apache.doris.catalog.Env; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.Table; +import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.cloud.qe.ComputeGroupException; import org.apache.doris.cloud.system.CloudSystemInfoService; import org.apache.doris.common.AnalysisException; @@ -48,6 +49,7 @@ import org.apache.doris.common.util.LogKey; import org.apache.doris.common.util.SqlParserUtils; import org.apache.doris.common.util.TimeUtils; +import org.apache.doris.common.util.Util; import org.apache.doris.load.RoutineLoadDesc; import org.apache.doris.load.loadv2.LoadTask; import org.apache.doris.load.routineload.kafka.KafkaConfiguration; @@ -1351,6 +1353,10 @@ protected static void checkMeta(OlapTable olapTable, RoutineLoadDesc routineLoad return; } + if (olapTable.getType() == TableType.TEMP) { + throw new DdlException("Cannot create routine load for temporary table " + + Util.getTempTableOuterName(olapTable.getName())); + } // check partitions olapTable.readLock(); try { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index d5a48f8e1129c6..203fb79fa7a34d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -2705,6 +2705,7 @@ public LogicalPlan visitCreateTable(CreateTableContext ctx) { return new CreateTableCommand(Optional.empty(), new CreateTableInfo( ctx.EXISTS() != null, ctx.EXTERNAL() != null, + ctx.TEMPORARY() != null, ctlName, dbName, tableName, @@ -2724,6 +2725,7 @@ public LogicalPlan visitCreateTable(CreateTableContext ctx) { return new CreateTableCommand(Optional.of(visitQuery(ctx.query())), new CreateTableInfo( ctx.EXISTS() != null, ctx.EXTERNAL() != null, + ctx.TEMPORARY() != null, ctlName, dbName, tableName, @@ -3755,6 +3757,7 @@ public LogicalPlan visitCreateTableLike(CreateTableLikeContext ctx) { withAllRollUp = true; } CreateTableLikeInfo info = new CreateTableLikeInfo(ctx.EXISTS() != null, + ctx.TEMPORARY() != null, new TableNameInfo(nameParts), new TableNameInfo(existedTableNameParts), rollupNames, withAllRollUp); return new CreateTableLikeCommand(info); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java index b0bf689d1e1612..33de97c05072e1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java @@ -406,6 +406,7 @@ private LogicalPlan getLogicalPlan(TableIf table, UnboundRelation unboundRelatio try { switch (table.getType()) { case OLAP: + case TEMP: case MATERIALIZED_VIEW: return makeOlapScan(table, unboundRelation, qualifierWithoutTableName); case VIEW: diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExportCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExportCommand.java index dbf6cf7067e52e..67402a7d1dac1a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExportCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExportCommand.java @@ -30,6 +30,7 @@ import org.apache.doris.catalog.Partition; import org.apache.doris.catalog.Table; import org.apache.doris.catalog.TableIf; +import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.common.Config; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; @@ -197,8 +198,9 @@ private void checkPartitions(ConnectContext ctx, TableName tblName) throws Analy case OLAP: break; case VIEW: // We support export view, so we do not need to check partition here. + case TEMP: if (this.partitionsNames.size() > 0) { - throw new AnalysisException("Table[" + tblName.getTbl() + "] is VIEW type, " + throw new AnalysisException("Table[" + tblName.getTbl() + "] is " + tblType + " type, " + "do not support export PARTITION."); } return; @@ -247,6 +249,10 @@ private ExportJob generateExportJob(ConnectContext ctx, Map file CatalogIf catalog = ctx.getEnv().getCatalogMgr().getCatalogOrAnalysisException(tblName.getCtl()); DatabaseIf db = catalog.getDbOrAnalysisException(tblName.getDb()); TableIf table = db.getTableOrAnalysisException(tblName.getTbl()); + if (table.getType() == TableType.TEMP) { + throw new AnalysisException("Table[" + tblName.getTbl() + "] is " + + table.getType() + " type, do not support export."); + } exportJob.setDbId(db.getId()); exportJob.setTableName(tblName); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/UpdateCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/UpdateCommand.java index 51cfbf0b27271f..05f12c4697c93f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/UpdateCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/UpdateCommand.java @@ -232,7 +232,7 @@ private void checkTable(ConnectContext ctx) { throw new AnalysisException("target table in update command should be an olapTable"); } targetTable = ((OlapTable) table); - if (targetTable.getType() != Table.TableType.OLAP + if ((targetTable.getType() != Table.TableType.OLAP && targetTable.getType() != Table.TableType.TEMP) || targetTable.getKeysType() != KeysType.UNIQUE_KEYS) { throw new AnalysisException("Only unique table could be updated."); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java index c2daeaa6ec474e..2418c931d8086b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java @@ -128,6 +128,7 @@ public class CreateTableInfo { private boolean isEnableMergeOnWrite = false; private boolean isExternal = false; + private boolean isTemp = false; private String clusterName = null; private List clusterKeysColumnNames = null; private PartitionTableInfo partitionTableInfo; // get when validate @@ -135,7 +136,7 @@ public class CreateTableInfo { /** * constructor for create table */ - public CreateTableInfo(boolean ifNotExists, boolean isExternal, String ctlName, String dbName, + public CreateTableInfo(boolean ifNotExists, boolean isExternal, boolean isTemp, String ctlName, String dbName, String tableName, List columns, List indexes, String engineName, KeysType keysType, List keys, String comment, PartitionTableInfo partitionTableInfo, @@ -144,6 +145,7 @@ public CreateTableInfo(boolean ifNotExists, boolean isExternal, String ctlName, List clusterKeyColumnNames) { this.ifNotExists = ifNotExists; this.isExternal = isExternal; + this.isTemp = isTemp; this.ctlName = ctlName; this.dbName = dbName; this.tableName = tableName; @@ -166,7 +168,7 @@ public CreateTableInfo(boolean ifNotExists, boolean isExternal, String ctlName, /** * constructor for create table as select */ - public CreateTableInfo(boolean ifNotExists, boolean isExternal, String ctlName, String dbName, + public CreateTableInfo(boolean ifNotExists, boolean isExternal, boolean isTemp, String ctlName, String dbName, String tableName, List cols, String engineName, KeysType keysType, List keys, String comment, PartitionTableInfo partitionTableInfo, @@ -175,6 +177,7 @@ public CreateTableInfo(boolean ifNotExists, boolean isExternal, String ctlName, List clusterKeyColumnNames) { this.ifNotExists = ifNotExists; this.isExternal = isExternal; + this.isTemp = isTemp; this.ctlName = ctlName; this.dbName = dbName; this.tableName = tableName; @@ -847,7 +850,7 @@ public CreateTableStmt translateToLegacyStmt() { } } - return new CreateTableStmt(ifNotExists, isExternal, + return new CreateTableStmt(ifNotExists, isExternal, isTemp, new TableName(ctlName, dbName, tableName), catalogColumns, catalogIndexes, engineName, new KeysDesc(keysType, keys, clusterKeysColumnNames), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java index 5428898d40327a..f24d30ea0856fa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableLikeInfo.java @@ -33,14 +33,19 @@ /** CreateTableLikeInfo */ public class CreateTableLikeInfo { private final boolean ifNotExists; + private final boolean isTemp; private final TableNameInfo tableName; private final TableNameInfo existedTableName; private final ArrayList rollupNames; private final boolean withAllRollup; - public CreateTableLikeInfo(boolean ifNotExists, TableNameInfo tableName, TableNameInfo existedTableName, - ArrayList rollupNames, boolean withAllRollup) { + /** + * constructor for create table like + */ + public CreateTableLikeInfo(boolean ifNotExists, boolean isTemp, TableNameInfo tableName, + TableNameInfo existedTableName, ArrayList rollupNames, boolean withAllRollup) { this.ifNotExists = ifNotExists; + this.isTemp = isTemp; this.tableName = tableName; this.existedTableName = existedTableName; this.rollupNames = rollupNames; @@ -48,7 +53,7 @@ public CreateTableLikeInfo(boolean ifNotExists, TableNameInfo tableName, TableNa } public CreateTableLikeStmt translateToLegacyStmt() throws DdlException { - return new CreateTableLikeStmt(ifNotExists, tableName.transferToTableName(), + return new CreateTableLikeStmt(ifNotExists, isTemp, tableName.transferToTableName(), existedTableName.transferToTableName(), rollupNames, withAllRollup); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java b/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java index 152bb7cc8813e2..92e6cf6cdd3110 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java @@ -1921,6 +1921,7 @@ private PlanNode createScanNode(Analyzer analyzer, TableRef tblRef, SelectStmt s switch (tblRef.getTable().getType()) { case OLAP: + case TEMP: case MATERIALIZED_VIEW: OlapScanNode olapNode = new OlapScanNode(ctx.getNextNodeId(), tblRef.getDesc(), "OlapScanNode"); diff --git a/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java b/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java index 6e8bd4f08cb2f7..8c05c12f3582c1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java @@ -29,12 +29,14 @@ import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.PartitionInfo; import org.apache.doris.catalog.Table; +import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.DdlException; import org.apache.doris.common.UserException; import org.apache.doris.common.io.Text; import org.apache.doris.common.io.Writable; +import org.apache.doris.common.util.Util; import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.persist.gson.GsonUtils; import org.apache.doris.qe.ShowResultSet; @@ -183,12 +185,16 @@ public void dropPolicy(DropPolicyStmt stmt) throws DdlException, AnalysisExcepti for (Table table : tables) { if (table instanceof OlapTable) { OlapTable olapTable = (OlapTable) table; + String tableName = table.getName(); + if (table.getType() == TableType.TEMP) { + tableName = Util.getTempTableOuterName(tableName); + } PartitionInfo partitionInfo = olapTable.getPartitionInfo(); for (Long partitionId : olapTable.getPartitionIds()) { String policyName = partitionInfo.getDataProperty(partitionId).getStoragePolicy(); if (policyName.equals(dropPolicyLog.getPolicyName())) { throw new DdlException("the policy " + policyName + " is used by table: " - + table.getName()); + + tableName); } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java index 579fdeff8e7b18..df51701b3049e8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java @@ -29,6 +29,7 @@ import org.apache.doris.analysis.StringLiteral; import org.apache.doris.analysis.UserIdentity; import org.apache.doris.analysis.VariableExpr; +import org.apache.doris.catalog.Database; import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.FunctionRegistry; @@ -38,11 +39,13 @@ import org.apache.doris.cloud.system.CloudSystemInfoService; import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.Config; +import org.apache.doris.common.DdlException; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.Status; import org.apache.doris.common.UserException; import org.apache.doris.common.util.DebugUtil; import org.apache.doris.common.util.TimeUtils; +import org.apache.doris.common.util.Util; import org.apache.doris.datasource.CatalogIf; import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.datasource.SessionContext; @@ -88,6 +91,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -241,6 +245,8 @@ public enum ConnectType { private TResultSinkType resultSinkType = TResultSinkType.MYSQL_PROTOCAL; + private Map> dbToTempTableNamesMap = new HashMap<>(); + // internal call like `insert overwrite` need skipAuth // For example, `insert overwrite` only requires load permission, // but the internal implementation will call the logic of `AlterTable`. @@ -311,7 +317,8 @@ public void setOrUpdateInsertResult(long txnId, String label, String db, String if (isTxnModel() && insertResult != null) { insertResult.updateResult(txnStatus, loadedRows, filteredRows); } else { - insertResult = new InsertResult(txnId, label, db, tbl, txnStatus, loadedRows, filteredRows); + insertResult = new InsertResult(txnId, label, db, Util.getTempTableOuterName(tbl), + txnStatus, loadedRows, filteredRows); } } @@ -876,6 +883,21 @@ public void cleanup() { closeChannel(); threadLocalInfo.remove(); returnRows = 0; + deleteTempTable(); + } + + protected void deleteTempTable() { + for (String dbName : dbToTempTableNamesMap.keySet()) { + Database db = Env.getCurrentEnv().getInternalCatalog().getDb(dbName).get(); + for (String tableName : dbToTempTableNamesMap.get(dbName)) { + try { + Env.getCurrentEnv().getInternalCatalog() + .dropTableWithoutCheck(db, db.getTable(tableName).get(), true); + } catch (DdlException e) { + LOG.error("drop temporary table error: db: {}, table: {}", dbName, tableName, e); + } + } + } } public boolean isKilled() { @@ -1395,4 +1417,25 @@ public void setMysqlHandshakePacket(MysqlHandshakePacket mysqlHandshakePacket) { public byte[] getAuthPluginData() { return mysqlHandshakePacket == null ? null : mysqlHandshakePacket.getAuthPluginData(); } + + public Map> getDbToTempTableNamesMap() { + return dbToTempTableNamesMap; + } + + public void addTempTableToDB(String database, String tableName) { + Set tableNameSet = dbToTempTableNamesMap.get(database); + if (tableNameSet == null) { + tableNameSet = new HashSet<>(); + } + + tableNameSet.add(tableName); + dbToTempTableNamesMap.put(database, tableNameSet); + } + + public void removeTempTableFromDB(String database, String tableName) { + Set tableNameSet = dbToTempTableNamesMap.get(database); + if (tableNameSet != null) { + tableNameSet.remove(tableName); + } + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java index 8204f00676dab0..52ea8b0890a093 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java @@ -872,7 +872,14 @@ private void handleShowTableId() throws AnalysisException { if (table != null) { List row = new ArrayList<>(); row.add(database.getFullName()); - row.add(table.getName()); + if (table.getType() == TableType.TEMP) { + if (!Util.isTempTableInCurrentSession(table.getName())) { + continue; + } + row.add(Util.getTempTableOuterName(table.getName())); + } else { + row.add(table.getName()); + } row.add(String.valueOf(database.getId())); rows.add(row); break; @@ -902,7 +909,14 @@ private void handleShowPartitionId() throws AnalysisException { if (partition != null) { List row = new ArrayList<>(); row.add(database.getFullName()); - row.add(tbl.getName()); + if (tbl.getType() == TableType.TEMP) { + if (!Util.isTempTableInCurrentSession(tbl.getName())) { + continue; + } + row.add(Util.getTempTableOuterName(tbl.getName())); + } else { + row.add(tbl.getName()); + } row.add(partition.getName()); row.add(String.valueOf(database.getId())); row.add(String.valueOf(tbl.getId())); @@ -975,6 +989,9 @@ private void handleShowTable() throws AnalysisException { if (showTableStmt.getType() != null && tbl.getType() != showTableStmt.getType()) { continue; } + if (tbl.getType() == TableType.TEMP) { + continue; + } if (matcher != null && !matcher.match(tbl.getName())) { continue; } @@ -1031,7 +1048,14 @@ private void handleShowTableStatus() throws AnalysisException { } List row = Lists.newArrayList(); // Name - row.add(table.getName()); + if (table.getType() == TableType.TEMP) { + if (!Util.isTempTableInCurrentSession(table.getName())) { + continue; + } + row.add(Util.getTempTableOuterName(table.getName())); + } else { + row.add(table.getName()); + } // Engine row.add(table.getEngine()); // version @@ -1168,7 +1192,7 @@ private void handleShowCreateTable() throws AnalysisException { ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_OBJECT, showStmt.getDb(), showStmt.getTable(), "VIEW", "Use 'SHOW CREATE TABLE '" + table.getName()); } - rows.add(Lists.newArrayList(table.getName(), createTableStmt.get(0))); + rows.add(Lists.newArrayList(Util.getTempTableOuterName(table.getName()), createTableStmt.get(0))); resultSet = table.getType() != TableType.MATERIALIZED_VIEW ? new ShowResultSet(showStmt.getMetaData(), rows) : new ShowResultSet(ShowCreateTableStmt.getMaterializedViewMetaData(), rows); @@ -2021,6 +2045,12 @@ private void handleShowTablet() throws AnalysisException { table.readLock(); try { tableName = table.getName(); + if (table.getType() == TableType.TEMP) { + if (!Util.isTempTableInCurrentSession(table.getName())) { + throw new AnalysisException("Unknown tablet: " + tabletId); + } + tableName = Util.getTempTableOuterName(tableName); + } OlapTable olapTable = (OlapTable) table; Partition partition = olapTable.getPartition(partitionId); if (partition == null) { @@ -2523,6 +2553,12 @@ private void handleShowDynamicPartition() throws AnalysisException { DynamicPartitionProperty dynamicPartitionProperty = olapTable.getTableProperty().getDynamicPartitionProperty(); String tableName = olapTable.getName(); + if (olapTable.getType() == TableType.TEMP) { + if (!Util.isTempTableInCurrentSession(tableName)) { + continue; + } + tableName = Util.getTempTableOuterName(tableName); + } ReplicaAllocation replicaAlloc = dynamicPartitionProperty.getReplicaAllocation(); if (replicaAlloc.isNotSet()) { replicaAlloc = olapTable.getDefaultReplicaAllocation(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index 4a7b540d120b4d..224b8dc0f5677c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -3128,7 +3128,7 @@ private void handleOverwriteTable(InsertOverwriteTableStmt iotStmt) { TableName targetTableName = new TableName(null, iotStmt.getDb(), iotStmt.getTbl()); try { // create a tmp table with uuid - parsedStmt = new CreateTableLikeStmt(false, tmpTableName, targetTableName, null, false); + parsedStmt = new CreateTableLikeStmt(false, false, tmpTableName, targetTableName, null, false); parsedStmt.setUserInfo(context.getCurrentUserIdentity()); execute(); // if create tmp table err, return diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java index c2b20707f133e8..a62fe99b2d57ec 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java @@ -39,6 +39,7 @@ import org.apache.doris.catalog.ScalarType; import org.apache.doris.catalog.Table; import org.apache.doris.catalog.TableIf; +import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.catalog.Tablet; import org.apache.doris.catalog.View; import org.apache.doris.common.AnalysisException; @@ -205,6 +206,9 @@ public List buildAnalysisInfosForDB(DatabaseIf db, Analyz if (table instanceof View) { continue; } + if (table.getType() == TableType.TEMP) { + continue; + } TableName tableName = new TableName(db.getCatalog().getName(), db.getFullName(), table.getName()); // columnNames null means to add all visible columns. // Will get all the visible columns in analyzeTblStmt.check() diff --git a/fe/fe-core/src/test/java/org/apache/doris/common/proc/IndexesProcNodeTest.java b/fe/fe-core/src/test/java/org/apache/doris/common/proc/IndexesProcNodeTest.java index aeb5bc471fee42..9a3e89abc3d716 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/common/proc/IndexesProcNodeTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/common/proc/IndexesProcNodeTest.java @@ -24,6 +24,7 @@ import org.apache.doris.catalog.KeysType; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.PartitionInfo; +import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.catalog.TableIndexes; import org.apache.doris.common.AnalysisException; @@ -59,8 +60,8 @@ public void testFetchResult() throws AnalysisException { indexes.add(indexBf); indexes.add(indexNgramBf); - OlapTable table = new OlapTable(1, "tbl_test_indexes_proc", Lists.newArrayList(new Column()), KeysType.DUP_KEYS, new PartitionInfo(), - new HashDistributionInfo(), new TableIndexes(indexes)); + OlapTable table = new OlapTable(1, "tbl_test_indexes_proc", TableType.OLAP, Lists.newArrayList(new Column()), + KeysType.DUP_KEYS, new PartitionInfo(), new HashDistributionInfo(), new TableIndexes(indexes)); IndexesProcNode indexesProcNode = new IndexesProcNode(table); ProcResult procResult = indexesProcNode.fetchResult(); diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveMetadataOpsTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveMetadataOpsTest.java index 46d3e1b897d111..1d40e914cc0b1a 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveMetadataOpsTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveMetadataOpsTest.java @@ -121,7 +121,7 @@ private void createTable(TableName tableName, distributionDesc = new HashDistributionDesc(10, buckets); } List colsName = cols.stream().map(Column::getName).collect(Collectors.toList()); - CreateTableStmt stmt = new CreateTableStmt(true, false, + CreateTableStmt stmt = new CreateTableStmt(true, false, false, tableName, cols, null, "hive", diff --git a/regression-test/data/table_p0/temp_table_data.csv b/regression-test/data/table_p0/temp_table_data.csv new file mode 100644 index 00000000000000..1c1a86d658ff48 --- /dev/null +++ b/regression-test/data/table_p0/temp_table_data.csv @@ -0,0 +1,3 @@ +1,'2024-01-01','Alice' +2,'2024-01-02','Bob' +3,'2024-02-01','Carl' \ No newline at end of file diff --git a/regression-test/suites/cold_heat_separation/empty_table_use_policy/create_table_use_policy.groovy b/regression-test/suites/cold_heat_separation/empty_table_use_policy/create_table_use_policy.groovy index 4e2ef09c99dae2..e47e35c7e13ed6 100644 --- a/regression-test/suites/cold_heat_separation/empty_table_use_policy/create_table_use_policy.groovy +++ b/regression-test/suites/cold_heat_separation/empty_table_use_policy/create_table_use_policy.groovy @@ -92,6 +92,28 @@ suite("create_table_use_policy") { // storage policy is disabled on mow table assertEquals(create_table_use_created_policy.size(), 1); + // success + def create_temp_table_use_created_policy = try_sql """ + CREATE TEMPORARY TABLE IF NOT EXISTS create_temp_table_use_created_policy + ( + k1 BIGINT, + k2 LARGEINT, + v1 VARCHAR(2048) + ) + UNIQUE KEY(k1) + DISTRIBUTED BY HASH (k1) BUCKETS 3 + PROPERTIES( + "storage_policy" = "test_create_table_use_policy", + "replication_num" = "1", + "enable_unique_key_merge_on_write" = "false" + ); + """ + // storage policy is disabled on mow table + assertEquals(create_temp_table_use_created_policy.size(), 1); + + sql """ + DROP TABLE IF EXISTS create_temp_table_use_created_policy + """ sql """ DROP TABLE IF EXISTS create_table_use_created_policy """ diff --git a/regression-test/suites/table_p0/test_temp_table.groovy b/regression-test/suites/table_p0/test_temp_table.groovy new file mode 100644 index 00000000000000..0eaff937e08abb --- /dev/null +++ b/regression-test/suites/table_p0/test_temp_table.groovy @@ -0,0 +1,360 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import org.junit.Assert; + +suite("test_temp_table") { + sql """ + DROP TABLE IF EXISTS `t_test_table_with_data` + """ + sql """ + CREATE TABLE `t_test_table_with_data` ( + `id` int, + `add_date` date, + `name` varchar(32), + ) ENGINE=OLAP + UNIQUE KEY(`id`,`add_date`) + COMMENT 'OLAP' + PARTITION BY RANGE(`add_date`) + ( + PARTITION p201701_1000 VALUES [('0000-01-01'), ('2017-02-01')), + PARTITION p201702_2000 VALUES [('2017-02-01'), ('2017-03-01')), + PARTITION p201703_3000 VALUES [('2017-03-01'), ('2017-04-01')) + ) + DISTRIBUTED BY HASH(`id`) BUCKETS 1 + PROPERTIES ('replication_num' = '1'); + """ + + sql """ + insert into t_test_table_with_data values (1,"2017-01-15","Alice"),(2,"2017-02-12","Bob"),(3,"2017-03-20","Carl"); + """ + + sql """ + CREATE TABLE IF NOT EXISTS `t_test_temp_table1` ( + `id` int, + `add_date` date, + `name` varchar(32), + ) ENGINE=OLAP + UNIQUE KEY(`id`,`add_date`) + COMMENT 'OLAP' + PARTITION BY RANGE(`add_date`) + ( + PARTITION p201701_1000 VALUES [('0000-01-01'), ('2017-02-01')), + PARTITION p201702_2000 VALUES [('2017-02-01'), ('2017-03-01')), + PARTITION p201703_3000 VALUES [('2017-03-01'), ('2017-04-01')) + ) + DISTRIBUTED BY HASH(`id`) BUCKETS 1 + PROPERTIES ('replication_num' = '1'); + """ + + // temporary table have same name with common olap table + sql """ + CREATE TEMPORARY TABLE `t_test_temp_table1` ( + `id` int, + `add_date` date, + `name` varchar(32), + ) ENGINE=OLAP + UNIQUE KEY(`id`,`add_date`) + COMMENT 'OLAP' + PARTITION BY RANGE(`add_date`) + ( + PARTITION p201701_1000 VALUES [('0000-01-01'), ('2017-02-01')), + PARTITION p201702_2000 VALUES [('2017-02-01'), ('2017-03-01')), + PARTITION p201703_3000 VALUES [('2017-03-01'), ('2017-04-01')) + ) + DISTRIBUTED BY HASH(`id`) BUCKETS 1 + PROPERTIES ( + 'replication_num' = '1', + 'storage_medium' = 'hdd', + 'storage_cooldown_time' = '2040-11-20 00:00:00', + 'bloom_filter_columns' = 'add_date', + 'enable_unique_key_merge_on_write' = 'true', + 'function_column.sequence_col' = 'add_date' + ); + """ + + // create table as + sql """ + create temporary table t_test_temp_table2 PROPERTIES ( + 'replication_num' = '1', 'light_schema_change' = 'true', 'bloom_filter_columns' = 'add_date' + ) + as select * from t_test_temp_table1; + """ + + def show_tables = sql "show tables" + def hasTempTable = false + for(int i = 0; i < show_tables.size(); i++) { + if (show_tables[i][0].equals("t_test_temp_table2")) { + hasTempTable = true; + } + } + assertFalse(hasTempTable) + + def show_data = sql "show data" + def containTempTable = false + for(int i = 0; i < show_data.size(); i++) { + if (show_data[i][0].equals("t_test_temp_table2")) { + containTempTable = true; + } + } + assertTrue(containTempTable) + + def desc_result = sql "desc t_test_temp_table2" + assertEquals(desc_result.size(), 3) + + def show_partition_result = sql "show partitions from t_test_temp_table2" + assertEquals(show_partition_result.size(), 1) + + def show_column_result = sql "show full columns from t_test_temp_table2" + assertEquals(show_column_result.size(), 3) + + def show_tablets_result = sql "show tablets from t_test_temp_table1" + assertEquals(show_tablets_result.size(), 3) + + sql "show column stats t_test_temp_table2;" + + sql "show data skew from t_test_temp_table2" + + def show_result = sql "show create table t_test_temp_table1" + assertEquals(show_result[0][0], "t_test_temp_table1") + assertTrue(show_result[0][1].contains("CREATE TEMPORARY TABLE")) + + sql """ + insert into t_test_temp_table1 select * from t_test_table_with_data; + """ + sql """ + insert into t_test_temp_table2 select * from t_test_table_with_data; + """ + + // must be in front of update, update is a kind of insert + def show_insert = sql "show last insert" + containTempTable = false + for(int i = 0; i < show_insert.size(); i++) { + if (show_insert[i][3].equals("t_test_temp_table2")) { + containTempTable = true; + } + } + assertTrue(containTempTable) + + sql """ + update t_test_temp_table1 set name='Blair' where id=2; + """ + + sql """ + delete from t_test_temp_table2 where id=3; + """ + + def select_result1 = sql "select * from t_test_temp_table2" + assertEquals(select_result1.size(), 2) + + def select_result2 = sql "select t1.* from t_test_temp_table1 t1 join t_test_temp_table2 t2 on t1.id = t2.id and t1.name = t2.name" + assertEquals(select_result2.size(), 1) + assertEquals(select_result2[0][2], "Alice") + + def show_delete = sql "show delete" + containTempTable = false + for(int i = 0; i < show_delete.size(); i++) { + if (show_delete[i][0].equals("t_test_temp_table2")) { + containTempTable = true; + } + } + assertTrue(containTempTable) + + def show_table_status = sql "show table status" + containTempTable = false + for(int i = 0; i < show_table_status.size(); i++) { + if (show_table_status[i][0].equals("t_test_temp_table2")) { + containTempTable = true; + } + } + assertTrue(containTempTable) + + //export + def uuid = UUID.randomUUID().toString() + def outFilePath = """/tmp/test_export_${uuid}""" + + try { + sql """ + EXPORT TABLE t_test_temp_table2 TO "file://${outFilePath}" + PROPERTIES ( + "columns" = "id,name,add_date", + "format" = "parquet" + ) + """ + throw new IllegalStateException("Should throw error") + } catch (Exception ex) { + assertTrue(ex.getMessage().contains("do not support export"), ex.getMessage()) + } + + //outfile + sql """ + select * from t_test_temp_table2 + into outfile "file://${outFilePath}" + """ + + + // temporary table with dynamic partitions and colocate group + sql """ + CREATE TEMPORARY TABLE temp_table_with_dyncmic_partition + ( + k1 DATE + ) + PARTITION BY RANGE(k1) () + DISTRIBUTED BY HASH(k1) + PROPERTIES + ( + "replication_allocation" = "tag.location.default: 1", + "dynamic_partition.enable" = "true", + "dynamic_partition.time_unit" = "DAY", + "dynamic_partition.start" = "-7", + "dynamic_partition.end" = "3", + "dynamic_partition.prefix" = "p", + "dynamic_partition.buckets" = "10", + "colocate_with" = "colocate_group1" + ); + """ + def select_partitions1 = sql "show partitions from temp_table_with_dyncmic_partition" + assertEquals(select_partitions1.size(), 4) + + try { + sql "CREATE MATERIALIZED VIEW mv_mtmv1 as select k1 from temp_table_with_dyncmic_partition" + throw new IllegalStateException("Should throw error") + } catch (Exception ex) { + assertTrue(ex.getMessage().contains("table not found"), ex.getMessage()) + } + def show_create_mv1 = sql "show create materialized view mv_mtmv1 on temp_table_with_dyncmic_partition" + assertEquals(show_create_mv1.size(), 0) + + // create another session and check temp table related function in it + def result2 = connect('root') { + sql "use regression_test_table_p0" + // cannot use temp table created by another session + def show_result3 = sql "show create table t_test_temp_table1" + assertEquals(show_result3.size(), 1) + assertFalse(show_result3[0][1].contains("CREATE TEMPORARY TABLE")) + + def select_result3 = sql "select * from t_test_temp_table1" + assertEquals(select_result3.size(), 0) + + // can create a temp table with anther temp table which is created by another session in the same db + sql """ + create temporary table t_test_temp_table1 PROPERTIES ('replication_num' = '1') as + select * + from t_test_table_with_data; + """ + + // temp table with same name in another db is legal + sql """create database if not exists regression_test_temp_table_db2""" + sql """ + create temporary table regression_test_temp_table_db2.t_test_temp_table1 PROPERTIES ('replication_num' = '1', 'compression' = 'ZSTD') as + select * + from t_test_table_with_data; + """ + + // only show delete info in current session + def show_delete2 = sql "show delete" + containTempTable = false + for(int i = 0; i < show_delete2.size(); i++) { + if (show_delete2[i][0].equals("t_test_temp_table2")) { + containTempTable = true; + } + } + assertFalse(containTempTable) + + // only show table status info in current session + def show_status = sql "show table status" + containTempTable = false + for(int i = 0; i < show_status.size(); i++) { + if (show_status[i][0].equals("t_test_temp_table2")) { + containTempTable = true; + } + } + assertFalse(containTempTable) + } + + // temp tables created by a session will be deleted when the session exit + try { + sql """show create table regression_test_temp_table_db2.t_test_temp_table1""" + throw new IllegalStateException("Should throw error") + } catch (Exception ex) { + assertTrue(ex.getMessage().contains("detailMessage = Unknown table"), ex.getMessage()) + } + + sql """ + drop table t_test_temp_table1; + """ + def show_result2 = sql "show create table t_test_temp_table1" + assertEquals(show_result2.size(), 1) + assertFalse(show_result2[0][1].contains("CREATE TEMPORARY TABLE")) + + // analyze + sql """analyze table t_test_temp_table2 with sample percent 10""" + sleep(6000) + def show_analyze_result1 = sql "show column stats t_test_temp_table2" + assertEquals(show_analyze_result1.size(), 3) + + def show_dynamic_partitions = sql "show dynamic partition tables" + containTempTable = false + for(int i = 0; i < show_dynamic_partitions.size(); i++) { + if (show_dynamic_partitions[i][0].equals("temp_table_with_dyncmic_partition")) { + containTempTable = true; + } + } + assertTrue(containTempTable) + + // truncate + sql "truncate table t_test_temp_table2" + select_result3 = sql "select * from t_test_temp_table2" + assertEquals(select_result3.size(), 0) + + // alter + try { + sql "alter table t_test_temp_table2 rename t_test_temp_table2_new" + throw new IllegalStateException("Should throw error") + } catch (Exception ex) { + assertTrue(ex.getMessage().contains("detailMessage = Do not support alter"), ex.getMessage()) + } + try { + sql "alter table t_test_temp_table2 add column new_col int" + throw new IllegalStateException("Should throw error") + } catch (Exception ex) { + assertTrue(ex.getMessage().contains("detailMessage = Do not support alter"), ex.getMessage()) + } + try { + sql "CREATE INDEX bitmap_index_1 ON t_test_temp_table2 (name) USING BITMAP COMMENT 'bitmap_name';" + throw new IllegalStateException("Should throw error") + } catch (Exception ex) { + assertTrue(ex.getMessage().contains("detailMessage = Do not support alter"), ex.getMessage()) + } + def show_index_2 = sql "show index from t_test_temp_table2" + assertEquals(show_index_2.size(), 0) + + sql """drop table temp_table_with_dyncmic_partition""" + def show_recycle_result1 = sql "show catalog recycle bin" + containTempTable = false + for(int i = 0; i < show_recycle_result1.size(); i++) { + if (show_recycle_result1[i][1].equals("temp_table_with_dyncmic_partition")) { + containTempTable = true; + } + } + assertFalse(containTempTable) + + // clean + sql """drop table t_test_temp_table1""" + sql """drop table if exists t_test_table_with_data""" + sql """drop database regression_test_temp_table_db2""" +}