github-actions[bot] commented on code in PR #64878:
URL: https://github.com/apache/doris/pull/64878#discussion_r3600200426


##########
fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java:
##########
@@ -2040,7 +2140,57 @@ public void gsonPostProcess() throws IOException {
         }
     }
 
-    public abstract void modifyProperties(AlterRoutineLoadCommand command) 
throws UserException;
+    public void modifyProperties(AlterRoutineLoadCommand command) throws 
UserException {
+        writeLock();
+        try {
+            if (getState() != JobState.PAUSED) {
+                throw new DdlException("Only supports modification of PAUSED 
jobs");
+            }
+            if (!command.hasTargetTable()) {
+                unprotectApplyAlter(command);
+                return;
+            }
+
+            Database db = Env.getCurrentInternalCatalog().getDbNullable(dbId);
+            if (db == null) {
+                throw new DdlException("Database not found: " + dbId);
+            }
+            db.readLock();
+            try {
+                Table table = db.getTableNullable(command.getTargetTableId());
+                if (table == null) {
+                    throw new DdlException("Table not found: " + 
command.getTargetTableId());
+                }
+                if (!(table instanceof OlapTable)) {
+                    throw new DdlException("Routine load target table must be 
an OLAP table");
+                }
+                table.readLock();
+                try {
+                    unprotectApplyAlter(command);
+                } finally {
+                    table.readUnlock();
+                }
+            } finally {
+                db.readUnlock();
+            }
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    private void unprotectApplyAlter(AlterRoutineLoadCommand command) throws 
UserException {
+        validateAlterJobPropertiesForMutation(command);
+        unprotectModifyProperties(command);
+        if (command.hasTargetTable()) {
+            this.tableId = command.getTargetTableId();

Review Comment:
   [P1] Revalidate every pre-lock tableId decision. tableId is now mutable, but 
RESUME/STOP/ALTER and SHOW/SHOW CREATE authorize the old target before 
acquiring the job lock, while update() checks the old table's existence before 
its write lock. A concurrent switch here can therefore let an old-target user 
act on or render the new-target job, or let a stale missing-old lookup 
permanently cancel a job already switched to a live table. Bind each 
privilege/existence check and its consumer to the same job read/write lock and 
current tableId.



##########
fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java:
##########
@@ -2040,7 +2140,57 @@ public void gsonPostProcess() throws IOException {
         }
     }
 
-    public abstract void modifyProperties(AlterRoutineLoadCommand command) 
throws UserException;
+    public void modifyProperties(AlterRoutineLoadCommand command) throws 
UserException {
+        writeLock();
+        try {
+            if (getState() != JobState.PAUSED) {
+                throw new DdlException("Only supports modification of PAUSED 
jobs");
+            }
+            if (!command.hasTargetTable()) {
+                unprotectApplyAlter(command);
+                return;
+            }
+
+            Database db = Env.getCurrentInternalCatalog().getDbNullable(dbId);
+            if (db == null) {
+                throw new DdlException("Database not found: " + dbId);
+            }
+            db.readLock();
+            try {
+                Table table = db.getTableNullable(command.getTargetTableId());

Review Comment:
   [P1] Recheck LOAD after resolving the target ID. The command checks LOAD 
against targetTableName during analysis, but this later critical section 
follows only the saved table ID. A concurrent RENAME preserves the ID while 
changing the name, so a user authorized for the old name can journal the 
renamed table without LOAD on its current name. Recheck LOAD for 
table.getName() while these database/table locks are held, before validation or 
mutation.



##########
fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java:
##########
@@ -470,6 +471,97 @@ protected void setRoutineLoadDesc(RoutineLoadDesc 
routineLoadDesc) {
         }
     }
 
+    public void validateTargetTable(Database db, OlapTable targetTable) throws 
UserException {
+        validateTargetTable(db, targetTable, Maps.newHashMap(), 
uniqueKeyUpdateMode);
+    }
+
+    public void validateTargetTable(Database db, OlapTable targetTable,
+            Map<String, String> alteredJobProperties, TUniqueKeyUpdateMode 
effectiveUniqueKeyUpdateMode)
+            throws UserException {
+        if (isMultiTable) {
+            throw new AnalysisException("ALTER ROUTINE LOAD target table 
change only supports single-table job");
+        }
+        List<ImportColumnDesc> columnsInfo = null;
+        if (columnDescs != null && !columnDescs.descs.isEmpty()) {
+            columnsInfo = new ArrayList<>(columnDescs.descs);
+        }
+        checkMeta(targetTable, new RoutineLoadDesc(columnSeparator, 
lineDelimiter, columnsInfo, precedingFilter,
+                whereExpr, partitionNamesInfo, deleteCondition, mergeType, 
sequenceCol));
+        validateAlterJobProperties(targetTable, alteredJobProperties, 
effectiveUniqueKeyUpdateMode);
+
+        targetTable.readLock();
+        try {
+            NereidsRoutineLoadTaskInfo taskInfo = 
toNereidsRoutineLoadTaskInfo();
+            taskInfo.applyAlterPropertiesForValidation(alteredJobProperties, 
effectiveUniqueKeyUpdateMode);
+            NereidsStreamLoadPlanner planner = new 
NereidsStreamLoadPlanner(db, targetTable, taskInfo);
+            planner.plan(new TUniqueId(0, 0));

Review Comment:
   [P1] Validate with the job's execution context. This direct planner call 
runs as the ALTER session, while the real task path first installs 
getUserIdentity() and the job's cloud cluster/compute group. 
Privilege-sensitive rewrites such as EncryptKeyRef therefore can pass here 
under the caller and fail immediately on resume under the stored job user (or 
be rejected in the reverse grant split). Share the runtime context setup for 
validation and restore the caller context afterward.



##########
fe/fe-core/src/main/java/org/apache/doris/load/routineload/RoutineLoadJob.java:
##########
@@ -2079,17 +2229,16 @@ protected void modifyCommonJobProperties(Map<String, 
String> jobProperties) thro
                     
jobProperties.remove(CreateRoutineLoadInfo.MAX_BATCH_SIZE_PROPERTY));
         }
 
-        if 
(jobProperties.containsKey(CreateRoutineLoadInfo.UNIQUE_KEY_UPDATE_MODE)) {
+        boolean hasExplicitUniqueKeyUpdateMode = jobProperties.containsKey(
+                CreateRoutineLoadInfo.UNIQUE_KEY_UPDATE_MODE);
+        if (hasExplicitUniqueKeyUpdateMode) {
             String modeStr = 
jobProperties.remove(CreateRoutineLoadInfo.UNIQUE_KEY_UPDATE_MODE);
             TUniqueKeyUpdateMode newMode = 
CreateRoutineLoadInfo.parseAndValidateUniqueKeyUpdateMode(modeStr);
-            // Validate flexible partial update constraints when changing to 
UPDATE_FLEXIBLE_COLUMNS
-            if (newMode == TUniqueKeyUpdateMode.UPDATE_FLEXIBLE_COLUMNS) {
-                validateFlexiblePartialUpdateForAlter();
-            }
             this.uniqueKeyUpdateMode = newMode;
             this.isPartialUpdate = (uniqueKeyUpdateMode == 
TUniqueKeyUpdateMode.UPDATE_FIXED_COLUMNS);
             
this.jobProperties.put(CreateRoutineLoadInfo.UNIQUE_KEY_UPDATE_MODE, 
uniqueKeyUpdateMode.name());
             this.jobProperties.put(CreateRoutineLoadInfo.PARTIAL_COLUMNS, 
String.valueOf(isPartialUpdate));
+            jobProperties.remove(CreateRoutineLoadInfo.PARTIAL_COLUMNS);

Review Comment:
   [P1] Apply the same precedence fix to Kinesis. This removal makes an 
explicit unique_key_update_mode win in the common/Kafka path, but 
KinesisRoutineLoadJob.modifyPropertiesInternal() still rereads the original 
partial_columns value and overwrites isPartialUpdate. UPSERT plus 
partial_columns=true therefore leaves live application and edit-log replay with 
UPSERT/isPartialUpdate=true, while a checkpoint image reload reconstructs false 
from jobProperties. Remove the Kinesis override and add the parallel precedence 
test.



##########
fe/fe-core/src/main/java/org/apache/doris/load/routineload/kafka/KafkaRoutineLoadJob.java:
##########
@@ -885,6 +886,51 @@ private void modifyPropertiesInternal(Map<String, String> 
jobProperties,
                 this.id, jobProperties, dataSourceProperties);
     }
 
+    private KafkaDataSourceSnapshot 
stageDataSourceProperties(KafkaDataSourceProperties dataSourceProperties)
+            throws DdlException {
+        Map<String, String> stagedCustomProperties = 
Maps.newHashMap(customProperties);
+        Map<String, String> stagedConvertedCustomProperties = 
Maps.newHashMap(convertedCustomProperties);
+        String stagedKafkaDefaultOffset = kafkaDefaultOffSet;
+        Map<String, String> alteredCustomProperties = 
dataSourceProperties.getCustomKafkaProperties();
+        boolean customPropertiesChanged = 
MapUtils.isNotEmpty(alteredCustomProperties);
+        if (customPropertiesChanged) {
+            stagedCustomProperties.putAll(alteredCustomProperties);

Review Comment:
   [P1] Replace the datetime origin together with the default. If the job 
currently has a datetime default, customProperties contains both 
kafka_default_offsets and kafka_origin_default_offsets. A later ALTER using the 
newly supported direct kafka_default_offsets=OFFSET_BEGINNING/END spelling adds 
only the new default here, leaving the old origin; 
buildConvertedCustomProperties() then prefers that stale origin, so the ALTER 
is ineffective for future partitions. Remove the staged origin whenever a new 
default is supplied without one, and cover datetime-to-symbolic ALTER.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to