This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new dc848b3fc32 [fix](temp-table) Fix CTAS/DROP for temporary tables and 
unmute 5 P0 cases (#67529)
dc848b3fc32 is described below

commit dc848b3fc32899ffe0a213da489ba6ef032cd1ae
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Fri Sep 4 23:28:52 2026 +0800

    [fix](temp-table) Fix CTAS/DROP for temporary tables and unmute 5 P0 cases 
(#67529)
    
    ### What problem does this PR solve?
    
    Five P0 regression cases are muted on TeamCity. Three of them fail on
    **every** master build — they only look green on `branch-4.1` because
    the suite is skipped there (`if (true) { return }` at the top of
    `test_temp_table.groovy`), so the mute is hiding persistent master
    failures rather than flakiness. The other two are genuinely flaky.
    
    | muted case | failures / last 300 P0 runs |
    |---|---|
    | `nereids_rules_p0/pkfk/eliminate_inner` | 251 |
    | `compaction/test_vertical_compaction_agg_state` | 254 |
    | `temp_table_p0/test_temp_table` | 250 |
    | `load_p0/routine_load/test_routine_load` | 32 |
    | `query_p0/cache/sql_cache_object_type` | 10 / 103 |
    
    Two of them turned out to be real FE bugs.
    
    #### 1. `CREATE TEMPORARY TABLE ... AS SELECT` wrongly rejected
    
    A temporary table is created under `<sessionId>#TEMP#<name>`, but the
    CTAS existence probe added in #66112
    (`CreateTableCommand.targetTableExists`) looked up the **bare** name:
    
    ```java
    return database != null && database.isTableExist(qualifiedName.get(2));
    ```
    
    So any normal table sharing that name makes the statement fail with
    `Table 'x' already exists`, even though the table it would create does
    not exist. This is user-visible, not just a test problem:
    
    ```sql
    CREATE TABLE t (id INT) DISTRIBUTED BY HASH(id) BUCKETS 1 
PROPERTIES('replication_num'='1');
    CREATE TEMPORARY TABLE t PROPERTIES('replication_num'='1') AS SELECT * FROM 
src;
    -- ERROR 1105: errCode = 2, detailMessage = Table 't' already exists
    ```
    
    The probe now mangles the name exactly the way
    `InternalCatalog.createTable` does. Plain `CREATE TEMPORARY TABLE t
    (...)` was never affected, because that path goes straight to
    `Env.createTable`, which mangles internally. This is the failure
    `temp_table_p0/test_temp_table` hits at line 456.
    
    #### 2. `DROP TEMPORARY TABLE IF EXISTS` ignored `IF EXISTS`
    
    `Database.getTableNullable` resolves the temporary table first and falls
    back to the normal table, so when a session owns no temporary table of
    that name, `table != null` and the earlier `ifExists` branch is skipped.
    The `mustTemporary` guard then raised `Unknown table` unconditionally:
    
    ```sql
    DROP TEMPORARY TABLE IF EXISTS never_existed;  -- OK, no-op
    DROP TEMPORARY TABLE IF EXISTS t;              -- ERROR 1105: Unknown table 
't'   (t is a normal table)
    ```
    
    `IF EXISTS` is now honored there. Without `IF EXISTS` the statement
    still reports `Unknown table`, and a `DROP TEMPORARY TABLE` still never
    drops the normal table.
    
    ### Case and baseline fixes
    
    - **`eliminate_inner`** — baseline went stale on 2026-07-16 when #65264
    added `shapeInfo()` overrides to `Cast`, `IsNull` and `Not`, which now
    preserve the table qualifier (`cast(f as ...)` → `cast(fkt_not_null.f as
    ...)`). `branch-4.1` has no such override, which is why it stayed green
    there. Regenerated the 8 affected shape lines.
    - **`test_vertical_compaction_agg_state`** — the first assertion
    compared a literal `collect_set_merge` ordering, but `collect_set` is
    backed by `flat_hash_set`, whose iteration order is unspecified. Wrapped
    it in `array_sort`, matching the two sibling assertions already in the
    same suite. The set contents were never wrong, only their order.
    - **`test_routine_load`** — the `load_to_single_tablet` section waited
    only for the job to leave `NEED_SCHEDULE` (i.e. to be *scheduled*), not
    for a batch to be committed, and its baseline recorded the empty table
    that race produced. It now uses the same data-visibility wait as the
    other nine sections, and the baseline holds the rows that actually load.
    9 of the 14 most recent failures of this suite were exactly this tag.
    - **`sql_cache_object_type`** — asserted that a cache entry survived.
    The FE map holds soft values under a bounded size
    (`Config.sql_cache_manage_num`) and the rows live in the BE result
    cache, so neither is guaranteed to persist. It re-primes the cache
    instead; the assertion that each `return_object_data_as_binary` setting
    is served its own result is unchanged.
---
 .../apache/doris/datasource/InternalCatalog.java   |   8 ++
 .../insert/streaming/StreamingInsertJob.java       |  24 +++++
 .../streaming/StreamingJobSchedulerTask.java       |   7 +-
 .../trees/plans/commands/CreateTableCommand.java   |  13 ++-
 .../StreamingInsertJobStatusTransitionTest.java    |  66 +++++++++++++
 .../test_vertical_compaction_agg_state.out         |   2 +-
 .../load_p0/routine_load/test_routine_load.out     |  20 ++++
 .../data/nereids_rules_p0/pkfk/eliminate_inner.out |  16 ++--
 .../test_mow_compact_multi_segments.groovy         |  16 +++-
 .../test_vertical_compaction_agg_state.groovy      |   2 +-
 .../load_p0/routine_load/test_routine_load.groovy  |  22 +++++
 .../query_p0/cache/sql_cache_object_type.groovy    |   7 +-
 .../runtime_filter/rf_bucket_pruning.groovy        |   5 +
 .../temp_table_p0/test_drop_temporary_table.groovy |  92 ++++++++++++++++++
 .../test_temp_table_ctas_name_conflict.groovy      | 106 +++++++++++++++++++++
 15 files changed, 391 insertions(+), 15 deletions(-)

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 69463ca6dd0..1f3a52c24d7 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
@@ -956,6 +956,14 @@ public class InternalCatalog implements 
CatalogIf<Database> {
                 dropTableInternal(db, table, false, true, watch, costTimes);
             } else {
                 if (mustTemporary) {
+                    // Name resolution falls back to the normal table when 
this session owns no
+                    // temporary one, but DROP TEMPORARY TABLE must never drop 
that table. So the
+                    // temporary table the statement asked for does not exist, 
and IF EXISTS asks
+                    // for a no-op in exactly that case.
+                    if (ifExists) {
+                        LOG.info("drop temporary table[{}] which does not 
exist", tableName);
+                        return;
+                    }
                     
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_TABLE, tableName, dbName);
                 }
                 dropTableInternal(db, table, isView, force, watch, costTimes);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJob.java
index 185aa720c4a..a8cbcab6ac6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJob.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJob.java
@@ -568,6 +568,30 @@ public class StreamingInsertJob extends 
AbstractJob<StreamingJobSchedulerTask, M
         }
     }
 
+    /**
+     * Move the job to {@code newStatus} only if it is still in {@code 
expectedStatus}.
+     *
+     * <p>{@link #createStreamingTask()} hands the task to {@code 
StreamingTaskScheduler} before the
+     * caller has marked the job RUNNING, so that scheduler thread may already 
have failed the task
+     * and paused the job. Writing RUNNING unconditionally would drop that 
PAUSED, and the job would
+     * then sit in RUNNING with a canceled task forever: handleRunningState() 
never creates a task
+     * for a TVF source, and the auto resume handler only runs while PAUSED.
+     *
+     * @return true when the status was updated, false when another thread 
already moved the job
+     */
+    public boolean updateJobStatusIfCurrent(JobStatus expectedStatus, 
JobStatus newStatus) throws JobException {
+        lock.writeLock().lock();
+        try {
+            if (!expectedStatus.equals(getJobStatus())) {
+                return false;
+            }
+            updateJobStatus(newStatus);
+            return true;
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+
     public void resetFailureInfo(FailureReason reason) {
         this.setFailureReason(reason);
         // Currently, only delayMsg is present here, which needs to be cleared 
when the status changes.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingJobSchedulerTask.java
 
b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingJobSchedulerTask.java
index 030c3bb2b8b..c5dfacaadfa 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingJobSchedulerTask.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingJobSchedulerTask.java
@@ -81,7 +81,12 @@ public class StreamingJobSchedulerTask extends AbstractTask {
         }
         streamingInsertJob.createStreamingTask();
         streamingInsertJob.setSampleStartTime(System.currentTimeMillis());
-        streamingInsertJob.updateJobStatus(JobStatus.RUNNING);
+        // The task is already visible to StreamingTaskScheduler, which pauses 
the job when it fails
+        // to schedule it. Only claim RUNNING while the job is still PENDING, 
so that PAUSED survives.
+        if (!streamingInsertJob.updateJobStatusIfCurrent(JobStatus.PENDING, 
JobStatus.RUNNING)) {
+            log.info("streaming job {} left PENDING while its task was 
dispatched, keep status {}",
+                    streamingInsertJob.getJobId(), 
streamingInsertJob.getJobStatus());
+        }
     }
 
     private void handleRunningState() throws JobException {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
index 3031e67be7d..b819ab532fb 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
@@ -23,6 +23,7 @@ import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.FeConstants;
+import org.apache.doris.common.util.Util;
 import org.apache.doris.datasource.CatalogIf;
 import org.apache.doris.nereids.NereidsPlanner;
 import org.apache.doris.nereids.analyzer.UnboundResultSink;
@@ -253,7 +254,17 @@ public class CreateTableCommand extends Command implements 
NeedAuditEncryption,
             return false;
         }
         DatabaseIf<?> database = catalog.getDbNullable(qualifiedName.get(1));
-        return database != null && database.isTableExist(qualifiedName.get(2));
+        if (database == null) {
+            return false;
+        }
+        // A temporary table lives in a per-session namespace and is stored 
under
+        // <sessionId>#TEMP#<name>, which is also the name InternalCatalog 
will create it with.
+        // Probing the bare name would instead match a normal table (or 
another session's temp
+        // table) of the same name, none of which is the table this statement 
would create.
+        String tableName = createTableInfo.isTemp()
+                ? Util.generateTempTableInnerName(qualifiedName.get(2))
+                : qualifiedName.get(2);
+        return database.isTableExist(tableName);
     }
 
     private String getAutoRangePartitionNameOrNull() {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJobStatusTransitionTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJobStatusTransitionTest.java
new file mode 100644
index 00000000000..08d5bcd3fd9
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJobStatusTransitionTest.java
@@ -0,0 +1,66 @@
+// 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.
+
+package org.apache.doris.job.extensions.insert.streaming;
+
+import org.apache.doris.common.jmockit.Deencapsulation;
+import org.apache.doris.job.common.JobStatus;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class StreamingInsertJobStatusTransitionTest {
+
+    private static StreamingInsertJob newJob(JobStatus status) {
+        StreamingInsertJob job = 
Deencapsulation.newInstance(StreamingInsertJob.class);
+        Deencapsulation.setField(job, "lock", new 
ReentrantReadWriteLock(true));
+        Deencapsulation.setField(job, "jobId", 8001L);
+        Deencapsulation.setField(job, "jobName", "test_job");
+        Deencapsulation.setField(job, "jobStatus", status);
+        return job;
+    }
+
+    @Test
+    public void testPendingIsPromotedToRunning() throws Exception {
+        StreamingInsertJob job = newJob(JobStatus.PENDING);
+
+        Assert.assertTrue(job.updateJobStatusIfCurrent(JobStatus.PENDING, 
JobStatus.RUNNING));
+        Assert.assertEquals(JobStatus.RUNNING, job.getJobStatus());
+    }
+
+    @Test
+    public void testPausedSurvivesTheRunningWrite() throws Exception {
+        // StreamingTaskScheduler failed the freshly registered task and 
paused the job before the
+        // dispatching thread reached its RUNNING write. Overwriting PAUSED 
here would strand the
+        // job: it holds a canceled task, and only the PAUSED branch can auto 
resume it.
+        StreamingInsertJob job = newJob(JobStatus.PAUSED);
+
+        Assert.assertFalse(job.updateJobStatusIfCurrent(JobStatus.PENDING, 
JobStatus.RUNNING));
+        Assert.assertEquals(JobStatus.PAUSED, job.getJobStatus());
+    }
+
+    @Test
+    public void testStoppedSurvivesTheRunningWrite() throws Exception {
+        // A concurrent DROP/STOP JOB leaves a terminal status that must not 
be revived either.
+        StreamingInsertJob job = newJob(JobStatus.STOPPED);
+
+        Assert.assertFalse(job.updateJobStatusIfCurrent(JobStatus.PENDING, 
JobStatus.RUNNING));
+        Assert.assertEquals(JobStatus.STOPPED, job.getJobStatus());
+    }
+}
diff --git 
a/regression-test/data/compaction/test_vertical_compaction_agg_state.out 
b/regression-test/data/compaction/test_vertical_compaction_agg_state.out
index 668e00d9179..a3a848a37ca 100644
--- a/regression-test/data/compaction/test_vertical_compaction_agg_state.out
+++ b/regression-test/data/compaction/test_vertical_compaction_agg_state.out
@@ -1,6 +1,6 @@
 -- This file is automatically generated. You should know what you did if you 
want to edit this
 -- !select_default --
-a      ["aa", "a"]
+a      ["a", "aa"]
 
 -- !select_default --
 a      ["a", "aa", "aaa"]
diff --git a/regression-test/data/load_p0/routine_load/test_routine_load.out 
b/regression-test/data/load_p0/routine_load/test_routine_load.out
index 2506366be11..743bd320edc 100644
--- a/regression-test/data/load_p0/routine_load/test_routine_load.out
+++ b/regression-test/data/load_p0/routine_load/test_routine_load.out
@@ -162,6 +162,26 @@
 91     2023-08-27      true    \N      2465    702240964       
6373830997821598984     305860046137409400      15991.356       
1.599972327386147E9     -165530947.0    \N      2023-04-26T19:31:10     
2023-07-21      \N      2               
B7YKYBYT8w0YC926bZ8Yz1VzyiWw2NWDAiTlEoPVyz9AXGti2Npg1FxWqWk4hEaALw0ZBSuiAIPj41lq36g5QRpPmAjNPK
  {"fruit":"apple","color":"red","qty":5,"price":2.5}     true    1       2     
  3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
 
 -- !sql_load_to_single_tablet --
+8      2023-08-14      true    109     -31573  -1362465190     
3990845741226497177     2732763251146840270     -25698.553      
1.312831962567818E9     771983879.0     173937916.0     2023-03-07T14:13:19     
2022-10-18      2023-07-16T05:03:13     D               
PBn1wa6X8WneZYLMac11zzyhGl7tPXB5XgjmOV8L6uav9ja5oY433ktb2yhyQQIqBveZPkme        
{"animal":"lion","weight":200,"habitat":["savannah","grassland"]}       true    
1       2       3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+20     2023-08-17      false   -5      18158   784479801       
1485484354598941738     -6632681928222776815    9708.431        
-3.30432620706069E8     -816424174.0    571112646.0     2022-09-15T21:40:55     
2023-02-23      2023-08-13T21:31:54     O       X       
2pYmX2vAhfEEHZZYPsgAmda1G7otnwx5TmUC879FPhDeIjvWI79ksBZpfFG2gp7jhCSbpZiecKGklB5SvG8tm31i5SUqe1xrWgLt4HSq7lMJWp75tx2kxD7pRIOpn
   {"name":"Sarah","age":30,"city":"London","isMarried":false}     true    1    
   2       3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:0 [...]
+21     2023-08-18      false   63      -27847  -35409596       
8638201997392767650     4919963231735304178     -23382.541      
-1.803403621426313E9    -22009767.0     661750756.0     2023-03-31T10:56:14     
2023-01-20      2023-02-18T13:37:52     N       T       
PSiFwUEx3eVFNtjlnQ70YkgZNvKrGmQ2DN5K9yYHiSdFWeEDB1UpL3Frt8z1kEAIWRDWqXZuyi      
{"city":"Sydney","population":5312000,"area":2058.7}    true    1       2       
3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+31     2023-08-27      false   17      -18849  1728109133      
3266501886640700374     527195452623418935      -24062.328      
-1.514348021262435E9    -322205854.0    -278237157.0    2022-10-07T03:24:23     
2022-09-25      \N      0       8       
yKMiAntORoRa8svnMfcxlOPwwND1m5s2fdS26Xu6cfs6HK5SAibqIp9h8sZcpjHy4       
{"team":"Manchester United","players":["Ronaldo","Rooney","Giggs"],"coach":"Ole 
Gunnar Solskjaer"}      true    1       2       3       4       5       6.0     
7.0     888888888.000000000     999999999.000000000     2023-08-24      
2023-08-24T12:00        2023-08-24      2023-08-24T12:00        我能吞下玻璃而不伤身体     
我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+41     2023-08-27      true    -104    22750   \N      8527773271030840740     
5554497317268279215     -5296.828       -1.71564688801304E9     -306075962.0    
897769189.0     2022-12-02T17:56:44     2022-10-12      2023-02-19T07:02:54     
V       \N      
E9GzQdTwX1ITUQz27IVznAs6Ca4WwprKk6Odjs6SH75D2F1089QiY3HQ52LXRD1V6xAWjhLE2hWgW3EdHuAOnUDVrb5V
    {"food":"Sushi","price":10,"restaurant":"Sushi King"}   true    1       2   
    3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+49     2023-08-08      false   \N      16275   -2144851675     
-2303421957908954634    -46526938720058765      -13141.143      
-6.866322332302E8       229942298.0     -152553823.0    2022-09-01T00:16:01     
2023-03-25      2022-09-07T14:59:03     s               yvuILR2iNxfe8RRml       
{"student":true,"name":"Alice","grade":9,"subjects":["math","science","history"]}
       true    1       2       3       4       5       6.0     7.0     
888888888.000000000     999999999.000000000     2023-08-24      
2023-08-24T12:00        2023-08-24      2023-08-24T12:00        我能吞下玻璃而不伤身体     
我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+50     2023-08-06      true    109     -6330   1479023892      
-8630800697573159428    -1645095773540208759    17880.96        
-1.453844792013949E9    -158871820.0    -862940384.0    2022-09-22T02:03:21     
2023-05-14      2023-03-25T02:18:34     m               
JKnIgXvGVidGiWl9YRSi3mFI7wHKt1sBpWSadKF8VX3LAuElm4sdc9gtxREaUr57oikSYlU8We8h1MWqQlYNiJObl
       {"city":"Tokyo","temperature":20.5,"humidity":75}       true    1       
2       3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+50     2023-08-24      true    15      14403   \N      -6418906115745394180    
9205303779366462513     -4331.549       -6.15112179557648E8     367305015.0     
-551652958.0    2022-12-29T02:27:20     2023-06-01      2023-08-12T04:50:04     
a               
eCl38sztIvBQvGvGKyYZmyMXy9vIJx197iu3JwP9doJGcrYUl9Uova0rz4iCCgrjlAiZU18Fs9YtCq830nhM
    {"band":"The Beatles","members":["John Lennon","Paul McCartney","George 
Harrison","Ringo Starr"]}       true    1       2       3       4       5       
6.0     7.0     888888888.000000000     999999999.000000000     2023-08-24      
2023-08-24T12:00        2023-08-24      2023-08-24T12:00        我能吞下玻璃而不伤 [...]
+57     2023-08-19      true    2       -25462  -74112029       
6458082754318544493     -7910671781690629051    -15205.859      
-3.06870797484914E8     759730669.0     -628556336.0    2023-07-10T18:39:10     
2023-02-12      2023-01-27T07:26:06     y               
Xi9nDVrLv8m6AwEpUxmtzFAuK48sQ   {"name":"John","age":25,"city":"New York"}      
true    1       2       3       4       5       6.0     7.0     
888888888.000000000     999999999.000000000     2023-08-24      
2023-08-24T12:00        2023-08-24      2023-08-24T12:00        我能吞下玻璃而不伤身体     
我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+58     2023-08-22      \N      0       -18231  1832867360      
6997858407575297145     2480714305422728023     -5450.489       
1.475901032138386E9     -893480655.0    -607891858.0    2023-02-02T05:13:24     
2022-09-18      2023-04-23T10:51:15     k               
LdFXF7Kmfzgmnn2R6zLsXdmi3A2cLBLq4G4WDVNDhxvH7dYH8Kga2WA47uSIxp6NSrwPSdw0ssB1TS8RFJTDJAB0Uba3e05NL2Aiw0ja
        {"restaurant":"Pizza Hut","menu":["pizza","pasta","salad"]}     true    
1       2       3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤 [...]
+60     2023-08-27      false   -52     -2338   -757056972      
1047567408607120856     6541476642780646552     6614.0894       
-1.204448798517855E9    236657733.0     731515433.0     2022-12-29T14:47:30     
2022-09-24      2023-08-01T12:41:59     O       F       
RM4F1Ke7lkcnuxF2nK0j9VBW3MDcgyHR4pseBjtFnqS6GUkVFuzF6u3Cp9Nv7ab0O6UYrpP4DhU     
{"game":"Chess","players":2,"time":"1 hour"}    true    1       2       3       
4       5       6.0     7.0     888888888.000000000     999999999.000000000     
2023-08-24      2023-08-24T12:00        2023-08-24      2023-08-24T12:00        
我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+62     2023-08-21      false   81      20302   -200761532      
6365479976421007608     \N      -29916.533      1.709141750828478E9     
549873536.0     -119205359.0    2023-05-04T01:14:51     2022-09-17      
2022-12-04T19:30:09     d       v       
BKWy9dTNg1aZW7ancEJAmEDOPK5TwFsNSHbI78emu9gymeIlx5NoLmyii0QAqdzRvSQPZKiqKkwInGCTIBnK1yYkK7zD
    {"username":"user123","password":"pass123","email":"[email protected]"}   
    true    1       2       3       4       5       6.0     7.0     
888888888.000000000     999999999.000000000     2023-08-24      
2023-08-24T12:00        2023-08-24      2023-08-24T12:00        我能吞下玻璃而不伤身体     
我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+65     2023-08-09      false   94      31514   814994517       
-297697460695940343     734910652450318597      -13061.892      
6.2750847041706E7       -9808654.0      \N      2023-08-14T22:01:27     
2023-05-19      2022-11-13T13:44:28     V               
aGeMsI24O12chGlP5ak0AHghAz7bu5MargJBStHnt0yMnChH0JnfYhsfH1u59XIHkJKMsHYktBqORkGlovu8V47E74KeFpaqxn5yLyXfDbhhzUKf
        {"language":"Python","version":3.9,"frameworks":["Django","Flask"]}     
true    1       2       3       4       5       6.0     7.0     
888888888.000000000     999999999.000000000     2023-08-24      
2023-08-24T12:00        2023-08-24      2023-08-24T12:00        我能吞下玻璃而不伤身体     
我能吞下玻 [...]
+66     2023-08-15      true    -91     28378   609923317       
4872185586197131212     1207709464099378591     \N      -1.863683325985123E9    
-783792012.0    -708986976.0    2022-09-24T10:39:23     2022-09-24      
2022-10-16T18:36:43     Y       z       
AI1BSPQdKiHJiQH1kguyLSWsDXkC7zwy7PwgWnyGSaa9tBKRex8vHBdxg2QSKZKL2mV2lHz7iI1PnsTd4MXDcIKhqiHyPuQPt2tEtgt0UgF6
    {"book":{"title":"The Great Gatsby","author":"F. Scott 
Fitzgerald"},"year":1925}        true    1       2       3       4       5      
 6.0     7.0     888888888.000000000     999999999.000000000     2023-08-24     
 2023-08-24T12:00        2023-08-24      2023-08-24T12:00 [...]
+68     2023-08-23      true    -73     20117   1737338128      
795638676048937749      -5551546237562433901    -30627.04       
6.8589475684545E7       585022347.0     513722420.0     2022-12-28T20:26:51     
2022-10-04      2023-07-30T00:20:06     y               
keZ3JlWWpdnPBejf0cuiCQCVBBTd5gjvO08NVdcAFewqL7nRT4N9lnvSU6pWmletA5VbPQCeQapJdcnQCHfZUDCf4ulCnczyqr7SGrbGRT0XYcd7iktKM
   {"country":"Brazil","continent":"South America","population":211049527} true 
   1       2       3       4       5       6.0     7.0     888888888.000000000  
   999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24   
   2023-08-24T12: [...]
+80     2023-08-18      false   -18     -8971   679027874       
6535956962935330265     3960889045799757165     -13219.76       
1.187161924505394E9     -526615878.0    -947410627.0    2023-03-11T07:40        
2022-11-29      2023-01-14T07:24:07     \N      D       
3Nhx6xX1qdwaq7lxwLRSKMtJFbC03swWv12mpySSVysH3igGZTiGPuKMsYW7HAkf6CWc7c0nzqDsjuH3FYVMNCWRmfxMrmY8rykQCC4Ve
       {"car":"BMW","model":"X5","year":2020,"color":"black"}  true    1       
2       3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体 [...]
+81     2023-08-23      false   106     11492   -667795397      
4480250461471356146     -5346660566234294101    9082.75 3.85167225902608E8      
-717553011.0    649146853.0     2023-03-20T03:33:16     2022-11-24      
2023-02-16T18:29:41     G       9       
Lk3eNVQNjucbekD1rZmUlGPiXS5JvcWr2LQzRU8GSGIbSag 
{"flower":"rose","color":"red","fragrance":true}        true    1       2       
3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+85     2023-08-11      true    -7      24304   -2043877415     
-2024144417867729183    \N      5363.0244       -5.78615669042831E8     
-378574346.0    -810302932.0    2023-07-15T01:07:41     2023-08-13      
2023-01-20T11:57:48     i               WQ9dh9ajPu0y    
{"country":"France","capital":"Paris","population":67081000}    true    1       
2       3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
+90     2023-08-27      true    22      16456   -1476824962     
-3279894870153540825    8990195191470116763     26651.906       
2.06860148942546E8      -580959198.0    -210329147.0    2022-10-07T03:11:03     
2023-03-18      2023-04-15T00:38:33     T       L       
QW0GQ3GoMtHgxPQOWGfVaveynahNpsNs09siMFA1OtO6QEDBQTdivmGyq7bFzejAqwbbVQQpREAmeLjcFSXLnQuou2KbwYD
 
{"company":"Apple","products":[{"name":"iPhone","price":1000},{"name":"MacBook","price":1500}]}
 true    1       2       3       4       5       6.0     7.0     
888888888.000000000     999999999.000000000     2023-08-24      
2023-08-24T12:00        2023-08-24      2023-08 [...]
+91     2023-08-27      true    90      2465    702240964       
6373830997821598984     305860046137409400      15991.356       
1.599972327386147E9     -165530947.0    \N      2023-04-26T19:31:10     
2023-07-21      \N      2               
B7YKYBYT8w0YC926bZ8Yz1VzyiWw2NWDAiTlEoPVyz9AXGti2Npg1FxWqWk4hEaALw0ZBSuiAIPj41lq36g5QRpPmAjNPK
  {"fruit":"apple","color":"red","qty":5,"price":2.5}     true    1       2     
  3       4       5       6.0     7.0     888888888.000000000     
999999999.000000000     2023-08-24      2023-08-24T12:00        2023-08-24      
2023-08-24T12:00        我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     我能吞下玻璃而不伤身体     \N
 
 -- !sql_column_separator --
 
diff --git a/regression-test/data/nereids_rules_p0/pkfk/eliminate_inner.out 
b/regression-test/data/nereids_rules_p0/pkfk/eliminate_inner.out
index 1a2c37fe9df..5441e21cdf8 100644
--- a/regression-test/data/nereids_rules_p0/pkfk/eliminate_inner.out
+++ b/regression-test/data/nereids_rules_p0/pkfk/eliminate_inner.out
@@ -144,7 +144,7 @@ PhysicalResultSink
 --NestedLoopJoin[INNER_JOIN]
 ----filter((pkt.pk = 1))
 ------PhysicalOlapScan[pkt]
-----filter((cast(f as DECIMALV3(38, 6)) = 1.000000) and (fkt_not_null.fk = 1))
+----filter((cast(fkt_not_null.f as DECIMALV3(38, 6)) = 1.000000) and 
(fkt_not_null.fk = 1))
 ------PhysicalOlapScan[fkt_not_null]
 
 -- !res --
@@ -155,9 +155,9 @@ pk with filter that not same as fk
 -- !shape --
 PhysicalResultSink
 --NestedLoopJoin[INNER_JOIN]
-----filter((cast(p as DECIMALV3(38, 6)) = 1.000000) and (pkt.pk = 1))
+----filter((cast(pkt.p as DECIMALV3(38, 6)) = 1.000000) and (pkt.pk = 1))
 ------PhysicalOlapScan[pkt]
-----filter((cast(f as DECIMALV3(38, 6)) = 1.000000) and (fkt_not_null.fk = 1))
+----filter((cast(fkt_not_null.f as DECIMALV3(38, 6)) = 1.000000) and 
(fkt_not_null.fk = 1))
 ------PhysicalOlapScan[fkt_not_null]
 
 -- !res --
@@ -167,7 +167,7 @@ simple_case
 
 -- !shape --
 PhysicalResultSink
---filter(( not fk IS NULL))
+--filter(( not fkt.fk IS NULL))
 ----PhysicalOlapScan[fkt]
 
 -- !res --
@@ -300,7 +300,7 @@ PhysicalResultSink
 --NestedLoopJoin[INNER_JOIN]
 ----filter((pkt.pk = 1))
 ------PhysicalOlapScan[pkt]
-----filter((cast(f as DECIMALV3(38, 6)) = 1.000000) and (fkt.fk = 1))
+----filter((cast(fkt.f as DECIMALV3(38, 6)) = 1.000000) and (fkt.fk = 1))
 ------PhysicalOlapScan[fkt]
 
 -- !res --
@@ -311,9 +311,9 @@ pk with filter that not same as fk
 -- !shape --
 PhysicalResultSink
 --NestedLoopJoin[INNER_JOIN]
-----filter((cast(p as DECIMALV3(38, 6)) = 1.000000) and (pkt.pk = 1))
+----filter((cast(pkt.p as DECIMALV3(38, 6)) = 1.000000) and (pkt.pk = 1))
 ------PhysicalOlapScan[pkt]
-----filter((cast(f as DECIMALV3(38, 6)) = 1.000000) and (fkt.fk = 1))
+----filter((cast(fkt.f as DECIMALV3(38, 6)) = 1.000000) and (fkt.fk = 1))
 ------PhysicalOlapScan[fkt]
 
 -- !res --
@@ -325,7 +325,7 @@ multi_table_join_with_pk_predicate
 PhysicalResultSink
 --hashJoin[INNER_JOIN] hashCondition=((fkt_not_null.fk = fkt_not_null2.fk)) 
otherCondition=()
 ----hashJoin[INNER_JOIN] hashCondition=((pkt.pk = fkt_not_null.fk)) 
otherCondition=()
-------filter((cast(p as DECIMALV3(38, 6)) = 1.000000))
+------filter((cast(pkt.p as DECIMALV3(38, 6)) = 1.000000))
 --------PhysicalOlapScan[pkt]
 ------PhysicalOlapScan[fkt_not_null]
 ----PhysicalOlapScan[fkt_not_null(fkt_not_null2)]
diff --git 
a/regression-test/suites/compaction/test_mow_compact_multi_segments.groovy 
b/regression-test/suites/compaction/test_mow_compact_multi_segments.groovy
index 09bb3c18a93..2fa2f993357 100644
--- a/regression-test/suites/compaction/test_mow_compact_multi_segments.groovy
+++ b/regression-test/suites/compaction/test_mow_compact_multi_segments.groovy
@@ -190,8 +190,14 @@ suite("test_mow_compact_multi_segments", "nonConcurrent") {
     getTabletStatus(tablet, 2, 3)
 
     // trigger compaction
+    // The cloud and the local cumulative policies are different classes with 
their own debug point,
+    // and this suite runs in both deployments, so pin the input rowsets on 
both. Without the local
+    // one, the storage-compute-coupled BE picks the input rowsets by 
size/score: [2-2] alone is
+    // below both thresholds and is skipped, and the next round merges [2-2] 
with [3-3].
     
GetDebugPoint().enableDebugPointForAllBEs("CloudSizeBasedCumulativeCompactionPolicy::pick_input_rowsets.set_input_rowsets",
             [tablet_id: "${tablet.TabletId}", start_version: 2, end_version: 
2])
+    
GetDebugPoint().enableDebugPointForAllBEs("SizeBasedCumulativeCompactionPolicy::pick_input_rowsets.set_input_rowsets",
+            [tablet_id: "${tablet.TabletId}", start_version: 2, end_version: 
2])
     def (code, out, err) = 
be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), 
backendId_to_backendHttpPort.get(backend_id), tablet_id)
     logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + 
err)
     assertEquals(code, 0)
@@ -204,7 +210,9 @@ suite("test_mow_compact_multi_segments", "nonConcurrent") {
         }
         sleep(100)
     }
-    getTabletStatus(tablet, 2, 1)
+    // enableAssert: the loop above exits on timeout as well, so assert the 
segment count here
+    // instead of letting a compaction that never ran slip through to the next 
step.
+    getTabletStatus(tablet, 2, 1, true)
     sql """ select * from ${tableName} limit 1; """
 
     // load 2
@@ -236,6 +244,8 @@ suite("test_mow_compact_multi_segments", "nonConcurrent") {
     // trigger compaction for load 2
     
GetDebugPoint().enableDebugPointForAllBEs("CloudSizeBasedCumulativeCompactionPolicy::pick_input_rowsets.set_input_rowsets",
             [tablet_id: "${tablet.TabletId}", start_version: 3, end_version: 
3])
+    
GetDebugPoint().enableDebugPointForAllBEs("SizeBasedCumulativeCompactionPolicy::pick_input_rowsets.set_input_rowsets",
+            [tablet_id: "${tablet.TabletId}", start_version: 3, end_version: 
3])
     (code, out, err) = 
be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), 
backendId_to_backendHttpPort.get(backend_id), tablet_id)
     logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + 
err)
     assertEquals(code, 0)
@@ -249,7 +259,9 @@ suite("test_mow_compact_multi_segments", "nonConcurrent") {
         }
         sleep(100)
     }
-    getTabletStatus(tablet, 3, 1)
+    // enableAssert: the loop above exits on timeout as well, so assert the 
segment count here
+    // instead of letting a compaction that never ran slip through to the next 
step.
+    getTabletStatus(tablet, 3, 1, true)
 
     
GetDebugPoint().enableDebugPointForAllBEs("DeleteBitmapAction._handle_show_local_delete_bitmap_count.vacuum_stale_rowsets")
 // cloud
     
GetDebugPoint().enableDebugPointForAllBEs("DeleteBitmapAction._handle_show_local_delete_bitmap_count.start_delete_unused_rowset")
 // local
diff --git 
a/regression-test/suites/compaction/test_vertical_compaction_agg_state.groovy 
b/regression-test/suites/compaction/test_vertical_compaction_agg_state.groovy
index b9c56d2d5dd..f66c2bf8956 100644
--- 
a/regression-test/suites/compaction/test_vertical_compaction_agg_state.groovy
+++ 
b/regression-test/suites/compaction/test_vertical_compaction_agg_state.groovy
@@ -62,7 +62,7 @@ suite("test_vertical_compaction_agg_state") {
             ('a',collect_set_state('aa'))
             """
 
-        qt_select_default """ SELECT user_id,collect_set_merge(agg_user_id) 
FROM ${tableName} t group by user_id ORDER BY user_id;"""
+        qt_select_default """ SELECT 
user_id,array_sort(collect_set_merge(agg_user_id)) FROM ${tableName} t group by 
user_id ORDER BY user_id;"""
 
         sql """ INSERT INTO ${tableName} VALUES
              ('b',collect_set_state('b'))
diff --git 
a/regression-test/suites/load_p0/routine_load/test_routine_load.groovy 
b/regression-test/suites/load_p0/routine_load/test_routine_load.groovy
index bbc058b861e..c4e4b01343b 100644
--- a/regression-test/suites/load_p0/routine_load/test_routine_load.groovy
+++ b/regression-test/suites/load_p0/routine_load/test_routine_load.groovy
@@ -1143,7 +1143,29 @@ suite("test_routine_load","p0") {
                     }
                 }
 
+                def count = 0
                 def tableName1 =  "routine_load_" + tableName
+                // Leaving NEED_SCHEDULE only means the job has been 
scheduled, not that any batch
+                // has been committed. Without waiting for the rows to become 
visible the query
+                // below races the load and returns whatever happens to have 
landed so far.
+                while (true) {
+                    def res = sql "select count(*) from ${tableName1}"
+                    def state = sql "show routine load for ${jobs[i]}"
+                    log.info("routine load state: 
${state[0][8].toString()}".toString())
+                    log.info("routine load statistic: 
${state[0][14].toString()}".toString())
+                    log.info("reason of state changed: 
${state[0][17].toString()}".toString())
+                    if (res[0][0] > 0) {
+                        break
+                    }
+                    if (count >= 120) {
+                        log.error("routine load can not visible for long time")
+                        assertEquals(20, res[0][0])
+                        break
+                    }
+                    sleep(5000)
+                    count++
+                }
+
                 if (i <= 3) {
                     qt_sql_load_to_single_tablet "select * from ${tableName1} 
order by k00,k01"
                 } else {
diff --git a/regression-test/suites/query_p0/cache/sql_cache_object_type.groovy 
b/regression-test/suites/query_p0/cache/sql_cache_object_type.groovy
index 6300840d20f..4e2520e70c5 100644
--- a/regression-test/suites/query_p0/cache/sql_cache_object_type.groovy
+++ b/regression-test/suites/query_p0/cache/sql_cache_object_type.groovy
@@ -98,8 +98,13 @@ suite("sql_cache_object_type") {
         assertTrue(isNonEmpty(asBinaryCached[0][0]))
         assertTrue(isNonEmpty(asBinaryCached[0][1]))
 
+        // The sql cache is best-effort: the FE map holds soft values under a 
bounded size
+        // (Config.sql_cache_manage_num) and the rows themselves live in the 
BE result cache, so the
+        // entry created above may legitimately be gone by now. Re-prime it 
instead of asserting it
+        // survived; what must hold is that this setting is served its own 
NULLs and never the
+        // binary rows cached under the other one.
         run "set return_object_data_as_binary=false"
-        assertTrue(hasSqlCache(objectSql))
+        primeSqlCache(objectSql)
         def asNullAgain = run(objectSql)
         assertNull(asNullAgain[0][0])
         assertNull(asNullAgain[0][1])
diff --git 
a/regression-test/suites/query_p0/runtime_filter/rf_bucket_pruning.groovy 
b/regression-test/suites/query_p0/runtime_filter/rf_bucket_pruning.groovy
index 9419c00dffb..084b389ff7b 100644
--- a/regression-test/suites/query_p0/runtime_filter/rf_bucket_pruning.groovy
+++ b/regression-test/suites/query_p0/runtime_filter/rf_bucket_pruning.groovy
@@ -23,6 +23,11 @@ suite("rf_bucket_pruning", "nonConcurrent") {
     sql "set enable_runtime_filter_bucket_prune=true"
     sql "set runtime_filter_wait_infinitely=true"
     sql "set runtime_filter_type='IN'"
+    // Shared regression environments fuzz runtime_filter_max_in_num, and one 
of the four fuzz
+    // branches sets it to 0. Bucket pruning inverts the IN set, so it bails 
out as soon as the set
+    // is larger than this bound -- with 0 even a single-value filter prunes 
nothing. Pin it, the
+    // same way rf_partition_pruning does.
+    sql "set runtime_filter_max_in_num=1024"
     sql "set disable_join_reorder=true"
     sql "set enable_profile=true"
     sql "set profile_level=2"
diff --git 
a/regression-test/suites/temp_table_p0/test_drop_temporary_table.groovy 
b/regression-test/suites/temp_table_p0/test_drop_temporary_table.groovy
new file mode 100644
index 00000000000..25a37803e33
--- /dev/null
+++ b/regression-test/suites/temp_table_p0/test_drop_temporary_table.groovy
@@ -0,0 +1,92 @@
+// 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.
+
+// DROP TEMPORARY TABLE only ever targets the temporary table of the current 
session. Name
+// resolution falls back to the normal table when this session owns no 
temporary one, so the drop
+// path has to tell "found the temporary table" from "found something else 
with that name":
+// it must never drop the normal table, and IF EXISTS must turn the miss into 
a no-op instead of
+// raising "Unknown table".
+suite('test_drop_temporary_table', 'p0') {
+    def srcTable = "t_drop_temp_src"
+    def sharedName = "t_drop_temp_shared"
+
+    // The two tables carry different row counts so a query can tell which one 
it resolved to:
+    // the normal table holds 1 row, the temporary table built from srcTable 
holds 3.
+    sql """DROP TABLE IF EXISTS ${srcTable}"""
+    sql """
+        CREATE TABLE ${srcTable} (id INT, name VARCHAR(32))
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES ('replication_num' = '1')
+    """
+    sql """INSERT INTO ${srcTable} VALUES (1, 'Alice'), (2, 'Bob'), (3, 
'Carl')"""
+
+    sql """DROP TABLE IF EXISTS ${sharedName}"""
+    sql """
+        CREATE TABLE ${sharedName} (id INT, name VARCHAR(32))
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES ('replication_num' = '1')
+    """
+    sql """INSERT INTO ${sharedName} VALUES (99, 'normal')"""
+
+    try {
+        // Nothing at all goes by this name: plainly a no-op.
+        sql """DROP TEMPORARY TABLE IF EXISTS t_drop_temp_never_existed"""
+
+        // Only a normal table goes by this name. The temporary table asked 
for does not exist,
+        // so IF EXISTS makes this a no-op -- and the normal table must 
survive untouched.
+        sql """DROP TEMPORARY TABLE IF EXISTS ${sharedName}"""
+        assertEquals(1, sql("select * from ${sharedName}").size())
+
+        // Without IF EXISTS the same statement reports the missing temporary 
table, and still
+        // must not drop the normal one.
+        try {
+            sql """DROP TEMPORARY TABLE ${sharedName}"""
+            throw new IllegalStateException("Should throw error")
+        } catch (Exception ex) {
+            assertTrue(ex.getMessage().contains("Unknown table"), 
ex.getMessage())
+        }
+        assertEquals(1, sql("select * from ${sharedName}").size())
+
+        // With a temporary table shadowing the normal one, the drop takes the 
temporary table
+        // and leaves the normal table in place.
+        sql """
+            CREATE TEMPORARY TABLE ${sharedName} PROPERTIES ('replication_num' 
= '1') AS
+            SELECT * FROM ${srcTable}
+        """
+        assertEquals(3, sql("select * from ${sharedName}").size())
+        sql """DROP TEMPORARY TABLE ${sharedName}"""
+        assertEquals(1, sql("select * from ${sharedName}").size())
+
+        // A temporary table belongs to the session that created it: another 
session neither sees
+        // it nor can drop it, and its IF EXISTS no-op must leave both tables 
alone.
+        sql """
+            CREATE TEMPORARY TABLE ${sharedName} PROPERTIES ('replication_num' 
= '1') AS
+            SELECT * FROM ${srcTable}
+        """
+        connect('root') {
+            sql "use ${context.dbName}"
+            assertEquals(1, sql("select * from ${sharedName}").size())
+            sql """DROP TEMPORARY TABLE IF EXISTS ${sharedName}"""
+            assertEquals(1, sql("select * from ${sharedName}").size())
+        }
+        assertEquals(3, sql("select * from ${sharedName}").size())
+    } finally {
+        sql """DROP TEMPORARY TABLE IF EXISTS ${sharedName}"""
+        sql """DROP TABLE IF EXISTS ${sharedName}"""
+        sql """DROP TABLE IF EXISTS ${srcTable}"""
+    }
+}
diff --git 
a/regression-test/suites/temp_table_p0/test_temp_table_ctas_name_conflict.groovy
 
b/regression-test/suites/temp_table_p0/test_temp_table_ctas_name_conflict.groovy
new file mode 100644
index 00000000000..7e8e1ba9bc0
--- /dev/null
+++ 
b/regression-test/suites/temp_table_p0/test_temp_table_ctas_name_conflict.groovy
@@ -0,0 +1,106 @@
+// 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.
+
+// A temporary table is stored under <sessionId>#TEMP#<name>, so its name only 
has to be unique
+// inside the creating session. CTAS probes the catalog for an existing table 
before it creates
+// anything (CreateTableCommand.targetTableExists); that probe has to use the 
same namespace the
+// table will be created in, otherwise an unrelated normal table of the same 
name makes
+// CREATE TEMPORARY TABLE ... AS SELECT fail with "Table 'x' already exists".
+suite('test_temp_table_ctas_name_conflict', 'p0') {
+    def srcTable = "t_ctas_src"
+    def sharedName = "t_ctas_shadowed"
+
+    sql """DROP TABLE IF EXISTS ${srcTable}"""
+    sql """
+        CREATE TABLE ${srcTable} (
+            id INT,
+            name VARCHAR(32)
+        )
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES ('replication_num' = '1')
+    """
+    sql """INSERT INTO ${srcTable} VALUES (1, 'Alice'), (2, 'Bob'), (3, 
'Carl')"""
+
+    // A normal table occupies the name in this database, and stays empty on 
purpose so that a
+    // query can tell the two tables apart.
+    sql """DROP TABLE IF EXISTS ${sharedName}"""
+    sql """
+        CREATE TABLE ${sharedName} (
+            id INT,
+            name VARCHAR(32)
+        )
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES ('replication_num' = '1')
+    """
+
+    try {
+        // The regression: this must not be rejected because of the normal 
table above.
+        sql """
+            CREATE TEMPORARY TABLE ${sharedName} PROPERTIES ('replication_num' 
= '1') AS
+            SELECT * FROM ${srcTable}
+        """
+
+        // Inside this session the temporary table shadows the normal one.
+        def showCreate = sql "show create table ${sharedName}"
+        assertEquals(1, showCreate.size())
+        assertEquals(sharedName, showCreate[0][0])
+        assertTrue(showCreate[0][1].contains("CREATE TEMPORARY TABLE"), 
showCreate[0][1])
+        assertEquals(3, sql("select * from ${sharedName}").size())
+
+        // Creating it a second time in the same session does collide, because 
now the probe and
+        // the create target the very same <sessionId>#TEMP#<name>.
+        try {
+            sql """
+                CREATE TEMPORARY TABLE ${sharedName} PROPERTIES 
('replication_num' = '1') AS
+                SELECT * FROM ${srcTable}
+            """
+            throw new IllegalStateException("Should throw error")
+        } catch (Exception ex) {
+            assertTrue(ex.getMessage().contains("already exists"), 
ex.getMessage())
+        }
+
+        // A normal table of an already taken name must still be rejected: the 
probe is only
+        // relaxed for the temporary namespace, not disabled.
+        try {
+            sql """CREATE TABLE ${sharedName} PROPERTIES ('replication_num' = 
'1') AS SELECT * FROM ${srcTable}"""
+            throw new IllegalStateException("Should throw error")
+        } catch (Exception ex) {
+            assertTrue(ex.getMessage().contains("already exists"), 
ex.getMessage())
+        }
+
+        // Another session has its own temporary namespace, so it may create 
the same name again,
+        // and it keeps seeing the normal (empty) table until it does.
+        connect('root') {
+            sql "use ${context.dbName}"
+
+            def otherShowCreate = sql "show create table ${sharedName}"
+            assertEquals(1, otherShowCreate.size())
+            assertFalse(otherShowCreate[0][1].contains("CREATE TEMPORARY 
TABLE"), otherShowCreate[0][1])
+            assertEquals(0, sql("select * from ${sharedName}").size())
+
+            sql """
+                CREATE TEMPORARY TABLE ${sharedName} PROPERTIES 
('replication_num' = '1') AS
+                SELECT * FROM ${srcTable}
+            """
+            assertEquals(3, sql("select * from ${sharedName}").size())
+        }
+    } finally {
+        sql """DROP TEMPORARY TABLE IF EXISTS ${sharedName}"""
+        sql """DROP TABLE IF EXISTS ${sharedName}"""
+        sql """DROP TABLE IF EXISTS ${srcTable}"""
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to