Skip to main content

TQL and JDBC Driver

There are two ways to send queries from the outside to the Time Series Engine (TSE) — the query language is TQL, and the access method is the JDBC driver.

One-line summary
드라이버 plantpulse.timeseries.tql.TQLDriver
URL jdbc:ts://<호스트>:7800
계정 tse / (설치가 정한 비밀번호)

TQL is one of four​

The Data Gateway (:5500) selects a backend based on the query language. It is structured so that you don't need to know which engine you are connecting to, and TQL is responsible for the Time Series Engine.

LanguageBackendWhat it is used for
PQLPostgreSQLMaster data · configuration(mm_*)
CQLAster TSDBRaw time series · aggregation(tm_*)
SQLSparkLakehouse · large-scale analytics
TQLTime Series Engine (TSE)Time-window aggregation · gap filling

When sending to the Gateway, specify the language in the header.

curl -sk -X POST https://<호스트>:5501/api/v1/query \
-H 'X-Lang: TQL' \
-H 'X-API-Key: <data.gateway.api.key>' \
-H 'Content-Type: text/plain' \
--data "SELECT LAST('1 DAYS', 'END') FROM CHANNEL1.PUMP1.TEMP_0001 \
WHERE timestamp BETWEEN '2022-01-01 00:00:00.000' AND '2030-12-31 23:59:59.999'"

The response is in the form {"result":"SUCCESS","data":[...]}.

If you send via 5500, you get a 302 redirect to 5501

5500 is plaintext, 5501 is TLS. Even if you send over plaintext, you will be redirected, so it is more efficient to send via 5501 from the start — it saves one round trip.

Table names are "paths"​

The FROM clause of TQL is not a relational table name, but a tag path.

FROM <채널>.<설비>.<태그>
예: CHANNEL1.PUMP1.TEMP_0001

Time ranges are specified with WHERE timestamp BETWEEN … AND …, and string literals use 'YYYY-MM-DD HH:mm:ss.SSS'.

Connecting via JDBC​

BI tools, batch processes, and custom programs use JDBC.

Class.forName("plantpulse.timeseries.tql.TQLDriver");

try (Connection c = DriverManager.getConnection(
"jdbc:ts://192.168.0.41:7800", "tse", "<password>");
Statement st = c.createStatement();
ResultSet rs = st.executeQuery(
"SELECT LAST('1 DAYS','END') FROM CHANNEL1.PUMP1.TEMP_0001 "
+ "WHERE timestamp BETWEEN '2026-09-01 00:00:00.000' "
+ "AND '2026-09-02 00:00:00.000'")) {
while (rs.next()) System.out.println(rs.getString(1));
}

If you want to provide it via configuration, use jdbc.tse.* in plantpulse-jdbc.properties.

KeyValue
jdbc.tse.driverplantpulse.timeseries.tql.TQLDriver
jdbc.tse.urljdbc:ts://<호스트>:${PP_TSE_PORT}
jdbc.tse.usernametse
jdbc.tse.passwordValue set by the installation

Optional keys include jdbc.tse.pool.initial|min|max and jdbc.tse.query.timeout|fetch-size.

Do not change jdbc.tse.url to tss (7801)

The TQL JDBC driver uses the plaintext TSE listener (7800). The default for TSE clients is globally plaintext ts/7800 (as of 2026-08).

If you set it to tss/7801, the failure propagates: JDBC connection failure → Data Gateway boot failure → /api/v1/* returns 404 for everything → analytics catalog 404. That is why ts and PP_TSE_PORT are pinned → Property Reference

TSE Client (Java)​

If JDBC is read-oriented, the TSE Client is a native library that supports writes as well. It is the same library that the platform itself uses to push metrics.

plantpulse-platform:plantpulse-timeseries-engine-client

Two variants​

ClassWhat it doesWhen to use
TSEClientBuffered store-and-forward for writesDefault. Writes are not lost even if the engine briefly disconnects
DirectTSEClientUnbuffered raw HTTPWhen buffering is a hindrance (testing, one-off tools)

The constructor for TSEClient is identical to that of DirectTSEClient, so you can swap them in directly. The buffer worker thread starts lazily upon the first buffered write, so clients that only query do not consume additional threads.

Connecting​

import plantpulse.timeseries.engine.client.TSEClient;

// protocol · host · port · user · password
TSEClient client = new TSEClient("https", "192.168.0.41", 7801, "tse", "<password>");

// URL 한 줄로도 됩니다
TSEClient client2 = new TSEClient("https://192.168.0.41:7801");

Defaults are https, 7801, and timeout 60초.

Client default is 7801 (TLS), JDBC is 7800 (plaintext)

They differ. The TSE Client uses DEFAULT_PROTOCOL=https and DEFAULT_PORT=7801, while the JDBC driver uses plaintext 7800 (see the danger above). They are two listeners on the same engine.

Writing values​

import plantpulse.timeseries.engine.client.builder.MetricBuilder;

MetricBuilder builder = MetricBuilder.getInstance();
builder.addMetric("PLANTPULSE.LINE1.PUMP1.TEMP")
.addDataPoint(System.currentTimeMillis(), 42.7)
.addTag("site", "SITE_00001");

client.pushMetrics(builder);

Reading values​

import plantpulse.timeseries.engine.client.builder.QueryBuilder;

QueryBuilder q = QueryBuilder.getInstance();
// 범위와 메트릭을 지정한 뒤
QueryResponse res = client.query(q);

If you have built the JSON yourself, you can send it directly with client.query(String jsonText).

Other operations​

OperationMethod
List metric namesgetMetricNames()
Engine statusgetStatus() · getStatusCheck()
Manage rollup (pre-aggregation) jobscreateRollupTask() · getRollupTasks() · deleteRollupTask()
Delete metricsdeleteMetric(name) · delete(QueryBuilder)
MetadatagetMetricMetadata() · setMetricMetadata() · deleteMetricMetadata()
Tag queriesqueryTags(QueryTagBuilder)

Which path to choose​

ScenarioWhat to use
App with a single entry point for all four backendsGateway POST /api/v1/query + X-Lang
Java program accessing only TSEJDBC (jdbc:ts://)
PlantPulse Dashboard · BI toolsJDBC → Build a dashboard
Convenient client librarytql() of Data Gateway Client
Java with write access to TSETSE Client — see the section above

See also​