Repository: tikv/tikv
File: components/tidb_query_executors/src/index_scan_executor.rs (Rust)

Code before:
    }

    /// Decode int handle from index key.
    ///
    /// # Key Format
    ///
    /// ## Normal format (local index or old global index):
    /// ```text
    /// [handle_flag][handle_data]
    /// ```
    ///
    /// ## V1 Global Index (non-unique, non-clustered):
    /// ```text
    /// [INDEX_VALUE_PARTITION_ID_FLAG][partition_id (8 bytes)][handle_flag][handle_data]
    /// ```
    ///
    /// Where `handle_flag` is `datum::INT_FLAG` or `datum::UINT_FLAG`.
    ///
    /// # Note for V1
    /// In V1, partition ID appears in both KEY and VALUE:
    /// - KEY: Contains partition ID prefix (this function skips it)
    /// - VALUE: Still contains partition ID (extracted by `split_partition_id`)
    ///
    /// Future V2 will remove partition ID from VALUE.
    #[inline]
    fn decode_int_handle_from_key(&self, key: &[u8]) -> Result<i64> {
        let mut val = key;
        let first_flag = val[0];
        val = &val[1..];

        // Support partition handle prefix: PARTITION_ID_FLAG + partition_id(8 bytes) +
        // inner_handle
        let handle_flag = if first_flag == table::INDEX_VALUE_PARTITION_ID_FLAG {
            // Ensure there are at least 8 bytes for partition id + 1 byte for handle flag
            if val.len() < table::ID_LEN + 1 {
                return Err(other_err!(
                    "Remaining len {} is too short to decode partition ID and handle",
                    val.len()
                ));
            }
            // Skip the partition id (8 bytes)
            val = &val[table::ID_LEN..];
            // Read the actual handle flag
            let flag = val[0];
            val = &val[1..];
            flag
        } else {
            // first_flag is already the handle flag
            first_flag
        };


Review comment (suggestion):
The function accesses `val[0]` without first checking if the `key` parameter is empty. This could cause a panic if an empty key is passed to this function. Add a check to ensure `key` has at least one byte before accessing `val[0]`.
```suggestion
    fn decode_int_handle_from_key(&self, key: &[u8]) -> Result<i64> {
        if key.is_empty() {
            return Err(other_err!("Key is empty, cannot decode handle"));
        }
```

Code after:
    }

    /// Decode int handle from index key.
    ///
    /// # Key Format
    ///
    /// ## Normal format (local index or old global index):
    /// ```text
    /// [handle_flag][handle_data]
    /// ```
    ///
    /// ## V1 Global Index (non-unique, non-clustered):
    /// ```text
    /// [INDEX_VALUE_PARTITION_ID_FLAG][partition_id (8 bytes)][handle_flag][handle_data]
    /// ```
    ///
    /// Where `handle_flag` is `datum::INT_FLAG` or `datum::UINT_FLAG`.
    ///
    /// # Note for V1
    /// In V1, partition ID appears in both KEY and VALUE:
    /// - KEY: Contains partition ID prefix (this function skips it)
    /// - VALUE: Still contains partition ID (extracted by `split_partition_id`)
    ///
    /// Future V2 will remove partition ID from VALUE.
    #[inline]
    fn decode_int_handle_from_key(&self, key: &[u8]) -> Result<i64> {
        let mut val = key;
        if val.is_empty() {
            return Err(other_err!("Key is empty, cannot decode handle"));
        }
        let first_flag = val[0];
        val = &val[1..];

        // Support partition handle prefix: PARTITION_ID_FLAG + partition_id(8 bytes) +
        // inner_handle
        let handle_flag = if first_flag == table::INDEX_VALUE_PARTITION_ID_FLAG {
            // Ensure there are at least 8 bytes for partition id + 1 byte for handle flag
            if val.len() < table::ID_LEN + 1 {
                return Err(other_err!(
                    "Insufficient data to decode partition ID and handle flag: \
expected at least {} bytes after first flag, got {}",
                    table::ID_LEN + 1,
                    val.len()
                ));
            }
            // Skip the partition id (8 bytes)
            val = &val[table::ID_LEN..];
            // Read the actual handle flag
            let flag = val[0];
            val = &val[1..];
            flag