github-advanced-security[bot] commented on code in PR #110:
URL: https://github.com/apache/iotdb-extras/pull/110#discussion_r3449699995


##########
iotdb-thingsboard-table/src/provided/java/org/thingsboard/server/dao/timeseries/TimeseriesDao.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+// Compile-only ThingsBoard stub (Strategy F). Verified against ThingsBoard 
v4.3.1.2
+// (commit c37fb509) on 2026-06-12.
+package org.thingsboard.server.dao.timeseries;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQueryResult;
+import org.thingsboard.server.common.data.kv.TsKvEntry;
+
+import java.util.List;
+
+public interface TimeseriesDao {
+  ListenableFuture<List<ReadTsKvQueryResult>> findAllAsync(
+      TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries);
+
+  ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, 
TsKvEntry tsKvEntry, long ttl);
+
+  ListenableFuture<Integer> savePartition(
+      TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key);

Review Comment:
   ## CodeQL / Useless parameter
   
   The parameter 'tenantId' is never used.
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/297)



##########
iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesWriter.java:
##########
@@ -0,0 +1,551 @@
+/*
+ * 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.iotdb.extras.thingsboard.table;
+
+import org.apache.iotdb.isession.ITableSession;
+import org.apache.iotdb.isession.pool.ITableSessionPool;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.StatementExecutionException;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tsfile.enums.ColumnCategory;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.write.record.Tablet;
+import org.springframework.beans.factory.DisposableBean;
+import org.thingsboard.server.common.data.kv.DataType;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.LongSupplier;
+
+@Slf4j
+public class IoTDBTableTimeseriesWriter implements DisposableBean {
+  static final String TABLE_NAME = "telemetry";
+  static final List<String> COLUMN_NAMES =
+      List.of(
+          "entity_type",
+          "tenant_id",
+          "key",
+          "entity_id",
+          "bool_v",
+          "long_v",
+          "double_v",
+          "str_v",
+          "json_v");
+  static final List<TSDataType> DATA_TYPES =
+      List.of(
+          TSDataType.STRING,
+          TSDataType.STRING,
+          TSDataType.STRING,
+          TSDataType.STRING,
+          TSDataType.BOOLEAN,
+          TSDataType.INT64,
+          TSDataType.DOUBLE,
+          TSDataType.STRING,
+          TSDataType.TEXT);
+  static final List<ColumnCategory> COLUMN_CATEGORIES =
+      List.of(
+          ColumnCategory.TAG,
+          ColumnCategory.TAG,
+          ColumnCategory.TAG,
+          ColumnCategory.TAG,
+          ColumnCategory.FIELD,
+          ColumnCategory.FIELD,
+          ColumnCategory.FIELD,
+          ColumnCategory.FIELD,
+          ColumnCategory.FIELD);
+  // Rate-limited because overload or shutdown can reject many points on the 
write hot path.
+  private static final long REJECT_WARN_INTERVAL_NANOS = 
TimeUnit.SECONDS.toNanos(10);
+  private static final long NEVER_WARNED_NANOS = Long.MIN_VALUE;
+  // After the graceful drain window expires, wait briefly for the interrupted 
worker to stop.
+  private static final long FORCE_STOP_JOIN_TIMEOUT_MS = 1000L;
+
+  private final ITableSessionPool tableSessionPool;
+  private final BlockingQueue<IoTDBTablePendingSave> queue;
+  private final LongSupplier nanoTime;
+  private final int batchSize;
+  private final long maxLingerNanos;
+  private final long shutdownDrainTimeoutMs;
+  private final int retryMaxAttempts;
+  private final long retryInitialBackoffMs;
+  private final long retryMaxBackoffMs;
+  private final AtomicBoolean accepting = new AtomicBoolean(true);
+  private final AtomicBoolean destroyed = new AtomicBoolean(false);
+  private final ConcurrentMap<SettableFuture<Integer>, IoTDBTablePendingSave> 
acceptedSaves =
+      new ConcurrentHashMap<>();
+  private final AtomicLong enqueued = new AtomicLong();
+  private final AtomicLong flushed = new AtomicLong();
+  private final AtomicLong flushFailures = new AtomicLong();
+  private final AtomicLong retries = new AtomicLong();
+  private final AtomicLong rejectsFull = new AtomicLong();
+  private final AtomicLong rejectsShutdown = new AtomicLong();
+  private final AtomicLong lastRejectWarnNanos = new 
AtomicLong(NEVER_WARNED_NANOS);
+  private final AtomicLong shutdownFailedPending = new AtomicLong();
+  private final AtomicLong queueDepth = new AtomicLong();
+  private volatile boolean forceStopped;
+  private final Thread worker;
+
+  public IoTDBTableTimeseriesWriter(ITableSessionPool tableSessionPool, 
IoTDBTableConfig config) {
+    this(tableSessionPool, config, true);
+  }
+
+  IoTDBTableTimeseriesWriter(
+      ITableSessionPool tableSessionPool, IoTDBTableConfig config, boolean 
startWorker) {
+    this(
+        tableSessionPool,
+        config,
+        startWorker,
+        new ArrayBlockingQueue<>(config.getTs().getSave().getQueueCapacity()),
+        System::nanoTime);
+  }
+
+  IoTDBTableTimeseriesWriter(
+      ITableSessionPool tableSessionPool,
+      IoTDBTableConfig config,
+      boolean startWorker,
+      BlockingQueue<IoTDBTablePendingSave> queue) {
+    this(tableSessionPool, config, startWorker, queue, System::nanoTime);
+  }
+
+  IoTDBTableTimeseriesWriter(
+      ITableSessionPool tableSessionPool,
+      IoTDBTableConfig config,
+      boolean startWorker,
+      BlockingQueue<IoTDBTablePendingSave> queue,
+      LongSupplier nanoTime) {
+    this.tableSessionPool = Objects.requireNonNull(tableSessionPool, 
"tableSessionPool");
+    Objects.requireNonNull(config, "config");
+    IoTDBTableConfig.Save saveConfig = config.getTs().getSave();
+    this.batchSize = saveConfig.getBatchSize();
+    this.maxLingerNanos = 
TimeUnit.MILLISECONDS.toNanos(saveConfig.getMaxLingerMs());
+    this.shutdownDrainTimeoutMs = saveConfig.getShutdownDrainTimeoutMs();
+    this.retryMaxAttempts = saveConfig.getRetryMaxAttempts();
+    this.retryInitialBackoffMs = saveConfig.getRetryInitialBackoffMs();
+    this.retryMaxBackoffMs = saveConfig.getRetryMaxBackoffMs();
+    this.queue = Objects.requireNonNull(queue, "queue");
+    this.nanoTime = Objects.requireNonNull(nanoTime, "nanoTime");
+    this.worker = new Thread(this::runFlushLoop, 
"iotdb-table-timeseries-flush-worker");
+    this.worker.setDaemon(true);
+    if (startWorker) {
+      this.worker.start();

Review Comment:
   ## CodeQL / Start of thread in constructor
   
   Class [IoTDBTableTimeseriesWriter](1) starts a thread in its constructor.
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/293)



##########
iotdb-thingsboard-table/src/provided/java/org/thingsboard/server/dao/timeseries/TimeseriesDao.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+// Compile-only ThingsBoard stub (Strategy F). Verified against ThingsBoard 
v4.3.1.2
+// (commit c37fb509) on 2026-06-12.
+package org.thingsboard.server.dao.timeseries;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQueryResult;
+import org.thingsboard.server.common.data.kv.TsKvEntry;
+
+import java.util.List;
+
+public interface TimeseriesDao {
+  ListenableFuture<List<ReadTsKvQueryResult>> findAllAsync(
+      TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries);
+
+  ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, 
TsKvEntry tsKvEntry, long ttl);
+
+  ListenableFuture<Integer> savePartition(
+      TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key);
+
+  ListenableFuture<Void> remove(TenantId tenantId, EntityId entityId, 
DeleteTsKvQuery query);
+
+  void cleanup(long systemTtl);

Review Comment:
   ## CodeQL / Useless parameter
   
   The parameter 'systemTtl' is never used.
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/296)



##########
iotdb-thingsboard-table/src/provided/java/org/thingsboard/server/dao/timeseries/TimeseriesDao.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+// Compile-only ThingsBoard stub (Strategy F). Verified against ThingsBoard 
v4.3.1.2
+// (commit c37fb509) on 2026-06-12.
+package org.thingsboard.server.dao.timeseries;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQueryResult;
+import org.thingsboard.server.common.data.kv.TsKvEntry;
+
+import java.util.List;
+
+public interface TimeseriesDao {
+  ListenableFuture<List<ReadTsKvQueryResult>> findAllAsync(
+      TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries);
+
+  ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, 
TsKvEntry tsKvEntry, long ttl);
+
+  ListenableFuture<Integer> savePartition(
+      TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key);

Review Comment:
   ## CodeQL / Useless parameter
   
   The parameter 'tsKvEntryTs' is never used.
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/299)



##########
iotdb-thingsboard-table/src/provided/java/org/thingsboard/server/dao/timeseries/TimeseriesDao.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+// Compile-only ThingsBoard stub (Strategy F). Verified against ThingsBoard 
v4.3.1.2
+// (commit c37fb509) on 2026-06-12.
+package org.thingsboard.server.dao.timeseries;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQueryResult;
+import org.thingsboard.server.common.data.kv.TsKvEntry;
+
+import java.util.List;
+
+public interface TimeseriesDao {
+  ListenableFuture<List<ReadTsKvQueryResult>> findAllAsync(
+      TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries);
+
+  ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, 
TsKvEntry tsKvEntry, long ttl);
+
+  ListenableFuture<Integer> savePartition(
+      TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key);

Review Comment:
   ## CodeQL / Useless parameter
   
   The parameter 'key' is never used.
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/300)



##########
iotdb-thingsboard-table/src/provided/java/org/thingsboard/server/common/data/HasVersion.java:
##########
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+// Compile-only ThingsBoard stub (Strategy F). Verified against ThingsBoard 
v4.3.1.2
+// (commit c37fb509) on 2026-06-12.
+package org.thingsboard.server.common.data;
+
+public interface HasVersion {
+  Long getVersion();
+
+  default void setVersion(Long version) {}

Review Comment:
   ## CodeQL / Useless parameter
   
   The parameter 'version' is never used.
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/295)



##########
iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableConfiguration.java:
##########
@@ -0,0 +1,206 @@
+/*
+ * 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.iotdb.extras.thingsboard.table;
+
+import org.apache.iotdb.isession.pool.ITableSessionPool;
+import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import 
org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.ResolvableType;
+import org.springframework.util.ClassUtils;
+
+import java.util.List;
+
+/**
+ * Spring Boot auto-configuration entry point for the IoTDB Table Mode backend.
+ *
+ * <p>This class is registered via {@code
+ * 
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports}
 (Spring Boot
+ * 3.x mechanism) and, as a belt-and-suspenders fallback, via {@code 
META-INF/spring.factories}, so
+ * the module activates in a real ThingsBoard deployment without the host 
application having to
+ * component-scan {@code org.apache.iotdb.extras}.
+ *
+ * <p>The {@code @Bean} methods below explicitly register the session pool, 
the timeseries writer,
+ * the schema bootstrap, and the {@code @Repository} {@link 
IoTDBTableTimeseriesDao}. Explicit bean
+ * methods are used in preference to {@code @ComponentScan}, which Spring 
deliberately filters out
+ * of auto-configuration classes (it would otherwise re-scan the host 
application's packages). Each
+ * bean stays under the same selected-and-explicitly-enabled activation guard, 
so this foundation is
+ * inert unless {@code database.ts.type=iotdb-table} and {@code 
iotdb.ts.experimental-raw-only=true}
+ * are both set. This initial module delivers only the timeseries backend; the 
latest-telemetry and
+ * label selectors return when those DAOs are implemented.
+ */
+@Slf4j
+@AutoConfiguration
+@ConditionalOnClass(name = IoTDBTableConfiguration.TIMESERIES_DAO_CLASS_NAME)
+public class IoTDBTableConfiguration {
+  static final String IOTDB_TABLE_SESSION_POOL_BEAN_NAME = 
"iotdbThingsboardTableSessionPool";
+  static final String IOTDB_TABLE_TIMESERIES_DAO_BEAN_NAME = 
"ioTDBTableTimeseriesDao";
+  static final String TIMESERIES_DAO_CLASS_NAME =
+      "org.thingsboard.server.dao.timeseries.TimeseriesDao";
+
+  @Configuration(proxyBeanMethods = false)
+  @ConditionalOnClass(name = TIMESERIES_DAO_CLASS_NAME)
+  @Conditional(IoTDBTableRawOnlyEnabledCondition.class)
+  @EnableConfigurationProperties(IoTDBTableConfig.class)
+  static class EnabledRawOnlyConfiguration {
+
+    // This module implements only the timeseries backend. The latest-telemetry
+    // (database.ts_latest.type) and label (iotdb.labels.enabled) selectors 
are intentionally NOT
+    // included here: those DAOs do not exist yet, so they must not spin up a 
session pool or schema
+    // bootstrap for a backend that has not shipped. Those conditions return 
when the corresponding
+    // DAOs are implemented.
+    @Bean(name = IOTDB_TABLE_SESSION_POOL_BEAN_NAME, destroyMethod = "close")
+    @ConditionalOnMissingBean(name = IOTDB_TABLE_SESSION_POOL_BEAN_NAME)
+    ITableSessionPool tableSessionPool(IoTDBTableConfig config) {
+      String nodeUrl = config.getHost() + ":" + config.getPort();
+      ITableSessionPool pool =
+          new TableSessionPoolBuilder()
+              .nodeUrls(List.of(nodeUrl))
+              .user(config.getUsername())
+              .password(config.getPassword())
+              .database(config.getDatabase())
+              .maxSize(config.getSessionPoolSize())
+              .connectionTimeoutInMs(config.getConnectionTimeoutMs())
+              .enableIoTDBRpcCompression(config.isEnableCompression())
+              .build();
+      log.info(
+          "IoTDB Table Mode session pool initialized: nodeUrl={}, database={}, 
poolSize={}, compression={}, storageAccountingDefaultTtlMs={}",
+          nodeUrl,
+          config.getDatabase(),
+          config.getSessionPoolSize(),
+          config.isEnableCompression(),
+          config.getDefaultTtlMs());
+      return pool;
+    }
+
+    @Bean
+    IoTDBTableTimeseriesWriter timeseriesWriter(
+        @Qualifier(IOTDB_TABLE_SESSION_POOL_BEAN_NAME) ITableSessionPool 
tableSessionPool,
+        IoTDBTableConfig config) {
+      return new IoTDBTableTimeseriesWriter(tableSessionPool, config);
+    }
+
+    /**
+     * Fails startup before any IoTDB pool/bootstrap/writer singleton is 
created if the explicit
+     * IoTDB backend selection conflicts with a host-provided TimeseriesDao.
+     */
+    @Bean
+    static BeanFactoryPostProcessor timeseriesDaoConflictGuard() {
+      return new TimeseriesDaoConflictGuard();
+    }
+
+    /**
+     * Registers the historical-telemetry DAO. The bean name {@code 
ioTDBTableTimeseriesDao} matches
+     * the default component-scan name, and the string-based missing-bean 
guard avoids loading
+     * ThingsBoard classes while evaluating auto-configuration metadata.
+     */
+    @Bean
+    @ConditionalOnBean(name = IOTDB_TABLE_SESSION_POOL_BEAN_NAME)
+    @ConditionalOnMissingBean(type = TIMESERIES_DAO_CLASS_NAME)
+    IoTDBTableTimeseriesDao ioTDBTableTimeseriesDao(
+        @Qualifier(IOTDB_TABLE_SESSION_POOL_BEAN_NAME) ITableSessionPool 
tableSessionPool,
+        IoTDBTableTimeseriesWriter timeseriesWriter,
+        IoTDBTableConfig config) {
+      return new IoTDBTableTimeseriesDao(tableSessionPool, timeseriesWriter, 
config);
+    }
+
+    /**
+     * Idempotent startup schema bootstrap. Only registered when the IoTDB 
Table Mode backend is
+     * selected and explicitly enabled (same activation guard as the 
pool/DAO), the session pool
+     * bean is present, and {@code iotdb.schema.bootstrap} is not disabled 
(defaults to {@code
+     * true}).
+     */
+    @Bean
+    @ConditionalOnBean(name = IOTDB_TABLE_SESSION_POOL_BEAN_NAME)
+    @ConditionalOnProperty(
+        name = "iotdb.schema.bootstrap",
+        havingValue = "true",
+        matchIfMissing = true)
+    IoTDBTableSchemaBootstrap schemaBootstrap(
+        @Qualifier(IOTDB_TABLE_SESSION_POOL_BEAN_NAME) ITableSessionPool 
tableSessionPool,
+        IoTDBTableConfig config) {
+      return new IoTDBTableSchemaBootstrap(tableSessionPool, config);
+    }
+  }
+
+  private static final class TimeseriesDaoConflictGuard implements 
BeanFactoryPostProcessor {
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory 
beanFactory)
+        throws BeansException {
+      Class<?> timeseriesDaoType = resolveTimeseriesDaoClass(beanFactory);
+      for (String beanName : 
beanFactory.getBeanNamesForType(timeseriesDaoType, true, false)) {
+        if (!isIoTDBTimeseriesDaoBean(beanFactory, beanName)) {
+          throw new IllegalStateException(
+              "database.ts.type=iotdb-table with 
iotdb.ts.experimental-raw-only=true, but a "
+                  + "non-IoTDB TimeseriesDao bean '"
+                  + beanName
+                  + "' is present; remove it or unset the IoTDB selector");
+        }
+      }
+    }
+
+    private static boolean isIoTDBTimeseriesDaoBean(
+        ConfigurableListableBeanFactory beanFactory, String beanName) {
+      Class<?> beanType = resolveBeanType(beanFactory, beanName);
+      if (beanType == null) {
+        throw new IllegalStateException(
+            "database.ts.type=iotdb-table with 
iotdb.ts.experimental-raw-only=true, but "
+                + "TimeseriesDao bean '"
+                + beanName
+                + "' has no resolvable type; expose a concrete 
IoTDBTableTimeseriesDao type or "
+                + "remove the bean");
+      }
+      return beanType != null && 
IoTDBTableTimeseriesDao.class.isAssignableFrom(beanType);

Review Comment:
   ## CodeQL / Useless null check
   
   This check is useless. [beanType](1) cannot be null at this check, since it 
is guarded by [... == ...](2).
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/294)



##########
iotdb-thingsboard-table/src/provided/java/org/thingsboard/server/dao/timeseries/TimeseriesDao.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+// Compile-only ThingsBoard stub (Strategy F). Verified against ThingsBoard 
v4.3.1.2
+// (commit c37fb509) on 2026-06-12.
+package org.thingsboard.server.dao.timeseries;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
+import org.thingsboard.server.common.data.kv.ReadTsKvQueryResult;
+import org.thingsboard.server.common.data.kv.TsKvEntry;
+
+import java.util.List;
+
+public interface TimeseriesDao {
+  ListenableFuture<List<ReadTsKvQueryResult>> findAllAsync(
+      TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries);
+
+  ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, 
TsKvEntry tsKvEntry, long ttl);
+
+  ListenableFuture<Integer> savePartition(
+      TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key);

Review Comment:
   ## CodeQL / Useless parameter
   
   The parameter 'entityId' is never used.
   
   [Show more 
details](https://github.com/apache/iotdb-extras/security/code-scanning/298)



-- 
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]

Reply via email to