This file holds what is known about Apache Druid, for the driver druid
(W25, D154 and D162). The headings are the template of
DRIVER.md.
Steps 5a and 6 measured 36.0.0 and 37.0.0 on 2026-10-01 and 2026-10-02, as
admin, the administrator, and as dbmeta_user, an ordinary user who can
read every datasource. A fact marked "recorded" is in testdata/druid/, and
the name in quotes after it is the name of its request in requests.json
there. The two releases gave the same answers, except where a line says
otherwise. A request whose name starts with step 7: ran on 36.0.0 only. A
fact marked "measured" names how it was measured. Each section starts with
the measured facts. The facts after them come from the sources of step 3,
and each one that is not measured says so. The sources, each read on
2026-10-01, are these:
- "The dbmeta entry" is
container/druid.goindbmeta. It starts the imagedocker.io/apache/druidwith ZooKeeper and the five services of the nano quickstart in one container, and the basic security extension. The administrator isadmin. ItsInitmakes the userdbmeta_userwith the roledbmeta_role, which canREADevery datasource and nothing else. - "godruid" is
github.com/IfanTsai/godruidat commit64f1a49of 2026-09-12, a Go client with adatabase/sqldriver indruidsql/. - "kaplanmaxe" is
github.com/kaplanmaxe/go-druidat commit1d99314of 2020-01-05, a Godatabase/sqldriver indsql/. - "pydruid" is
github.com/druid-io/pydruidat commit735ba4aof 2026-05-04, the Python client of the Druid project, and its DB-API modulepydruid/db/api.py. - "Gemini" is
gemini-3.8-flash, and "DeepSeek" isdeepseek-flash, asked on 2026-10-01 and 2026-10-02.
- Apache Druid is a column store for analytics. A table is a datasource,
and each row has the timestamp
__time. Druid stores a datasource in segments, and each segment holds one span of time. - R holds.
dbrunstartsdruid-36.0.0anddruid-37.0.0, in the Staged tier with the cadencetested(the dbmeta entry, dbmeta D113). Each one uses up to 2.7 GB (dbmeta D113).GET /statusgave the version of each (recorded: "the version"). - H and S hold.
POST /druid/v2/sqlon the Router took SQL and answered with HTTP 200 as both principals on each release (recorded: "a statement"). - The SQL API reads only.
INSERTandREPLACErun as tasks of the multi-stage engine throughPOST /druid/v2/sql/task.UPDATEandDELETEfail on both APIs.REPLACEof a span of time replaces the rows of that span, and aREPLACEwith no rows removes them (recorded: "crud: insert", "crud: update", "crud: replace one day", "crud: delete" and "crud: delete one day with replace"). DRIVER.md says to stop and ask Ken when a server refuses one of insert, select, update and delete. See the open questions. - The priority is in TARGETS.md: Druid is number 10 of the
order (D162). D154 gives it a driver of its own, and not a flavor of
Avatica, although Druid also speaks Avatica at
/druid/v2/sql/avatica/. dburlhas no scheme for Druid, andusqlhas no driver for it (measured withgrepindburl/scheme.goandls usql/driverson 2026-10-01).dbmetahas no model for Druid. Its backlog waits for this driver and a scheme indburl(dbmeta/docs/BACKLOG.md).
These facts were recorded on each release:
- A statement is
POST /druid/v2/sqlwithContent-Type: application/jsonand a JSON object.queryholds the text. The other fields are optional:resultFormat,header,typesHeader,sqlTypesHeader,contextandparameters(recorded: "a statement"). - A request with no
Content-Typefails with HTTP 400 andMissing Content-Type header(recorded: "a statement with no content type"). A body oftext/plainis the SQL text itself, and the answer has the default form (recorded: "a statement as plain text").GET /druid/v2/sqlanswers HTTP 405 (recorded: "a GET of the SQL API"). - A field that the server does not know is ignored, in the body and in the
context (recorded: "an unknown field in the body" and "feature: an unknown
context key"). An unknown
resultFormatfails with HTTP 400 (recorded: "an unknown result format"). contextholds the parameters of one query, such assqlQueryId,sqlTimeZone,sqlStringifyArrays,sqlOuterLimitandtimeout(recorded: "feature: a query id", "feature: the time zone in the context", "every type with arrays as arrays", "a result with an outer limit" and "a timeout in the context"). ASETstatement before the query sets the same keys (recorded: "feature: SET before a statement").- The answer names the query in
X-Druid-SQL-Query-IdandX-Druid-Query-Id. WithsqlQueryIdin the context, both hold that id (recorded: "feature: a query id").X-Druid-Response-Contextholds a JSON object, such as{"missingSegments":[]}. - A write is
POST /druid/v2/sql/taskwith the same body. It answers HTTP 202 withtaskIdandstateRUNNING(recorded: "crud: insert").GET /druid/indexer/v1/task/<taskId>/statusgivesstatusCodeSUCCESSwhen the task ends (recorded: "crud: the state of the insert task"). The rows of the task answer a query some seconds after it ends: a select 60 seconds after the task showed them (recorded: "crud: select"). - A statement that the task API refuses before it runs answers HTTP 400
with
taskId,stateFAILEDanderror(recorded: "crud: update through the task API" and "an error of a task"). - The SQL API refuses
INSERTwithINSERT operations are not supported by requested SQL engine [native], consider using MSQ.(recorded: "crud: insert through the SQL API"). - Authentication is HTTP Basic. A wrong password answers HTTP 401 with a page of HTML (recorded: "a wrong password").
- The Router passes
/druid/coordinator/...,/druid/indexer/...and/proxy/coordinator/...to the Coordinator and the Overlord (recorded: "the datasources of the Coordinator", "crud: the state of the insert task" and "the users of the security API").
This fact was measured with curl on 37.0.0 on 2026-10-01:
- Two tasks of the multi-stage engine that started at the same time never
ended, and four more waited behind them. Each task needs a slot for its
controller and one for its worker, and the nano quickstart has two slots.
POST /druid/indexer/v1/task/<id>/shutdownended them. So the setup ofrequests.jsonwaits 40 seconds between two tasks.
- Step 9 decides the URL (D27 and D35). godruid takes the schemes
druid,druids,httpandhttps, and the keysheader,token,jwt,skip_tls_verify,ca_cert,client_cert,client_key,proxy,userandpassword(godruid,druidsql/dsn.go). kaplanmaxe takes the address of the Broker, and a path for its ping (kaplanmaxe,dsn.go). dbrungives each principal ashttp://user:password@127.0.0.1:<port>, the address of the Router, which listens on 8888 in the container (the dbmeta entry).- Druid has no database to choose. Every datasource is in the schema
druid, and the other schemas aresys,INFORMATION_SCHEMAandlookup(recorded: "schema: the datasources" and "feature: lookup table").
These facts were recorded on each release:
- The answer is HTTP 200 with
Content-Type: application/json, for every result format,csvtoo (recorded: "a statement" and "the result format csv"). resultFormatisobjectby default: one JSON array of objects, each with the name of each column (recorded: "a statement with no options").arrayis one JSON array of arrays, in the order of the columns.objectLinesandarrayLineswrite one row on each line, and end with an empty line.csvwrites one row on each line, with quotes where they are needed, and ends with an empty line (recorded: "the result format objectLines", "the result format arrayLines" and "the result format csv").tsvis not a format (recorded: "an unknown result format").- With
header, the first row holds the names of the columns. WithtypesHeaderas well, the next row holds the native type of each column, such asLONGorARRAY<STRING>. WithsqlTypesHeader, the next row holds the SQL type, such asBIGINTorARRAY(recorded: "a statement" and "only the names of the columns"). InobjectandobjectLines, the first object maps each name to{"type": ..., "sqlType": ...}(recorded: "the result format object").X-Druid-SQL-Header-Included: yessays that the header is there. - So the names and the types of the columns arrive before the first row, in the order of the statement. A result with no rows still has its header (recorded: "the columns of an empty result", "the columns of an empty result in lines" and "the columns of a limit of zero").
- Two columns with one name keep both in
array. Inobject, the object holds the name twice, as{"a":1,"a":9223372036854775807}(recorded: "two columns with one name as arrays" and "two columns with one name as objects"). - A result of 400 rows came whole in one answer, in the order of
__time(recorded: "a result of 400 rows" and "a result of 400 rows in lines"). The SQL API does not page.sqlOuterLimitcuts the result at that many rows, with no sign in the answer, andLIMITwithOFFSETworks (recorded: "a result with an outer limit" and "a result with limit and offset"). ORDER BYon a column other than__time, with noGROUP BY, fails withQuery could not be planned(measured with the recorder on 37.0.0 on 2026-10-01, in a run that a later run replaced).- On 37.0.0 the datasource
dbimp_tis in the answers too. A probe withcurlmade it before the recordings (recorded: "schema: the datasources"). - With
Accept-Encoding: gzip, the answer hasContent-Encoding: gzip(recorded: "a gzip answer"). - No answer redirects.
GET /druid/coordinator/v1/leaderthrough the Router gives the address of the Coordinator inside the container,http://localhost:8081(recorded: "a path of the Coordinator through the Router").
These facts were recorded as step 7: requests on 36.0.0:
POST /druid/v2/sql/statementswithexecutionModeASYNCin the context runs a query as a task. It answers HTTP 200 withqueryId,stateACCEPTEDand theschemaof the result (recorded: "step 7: a statement of the statements API").GETof the statement gives its state and its pages, andGET .../results?page=0gives the rows (recorded: "step 7: the state of the statement" and "step 7: the first page of the statement").- Without durable storage, the result is one page whatever
rowsPerPagesays, and the next page fails withPage number [1] is out of the range of results.selectDestinationdurableStoragefails, because the server has no durable storage (recorded: "step 7: the second page of the statement" and "step 7: a statement that asks for durable storage").
These facts come from the sources, and are not measured:
- pydruid reads the answer as it arrives, in chunks, and godruid reads the
rows one at a time (pydruid and godruid). kaplanmaxe reads the whole body
with
ioutil.ReadAll(kaplanmaxe,connection.go). - Without durable storage, the statements API keeps at most 3,000 rows (Gemini).
The column Kind names the kind of each type in TYPES.md, which
maps every kind onto its Go type (D135 and D137). Step 8a wrote this table
for Ken to review. The wire type is the SQL type of sqlTypesHeader, except
for OTHER, which the native type of typesHeader names.
| Wire type | Kind | Go type | Scan type | Database type | Can be NULL |
|---|---|---|---|---|---|
| BIGINT | integer | int64 |
int64 |
BIGINT |
yes |
| INTEGER | integer | int64 |
int64 |
INTEGER |
yes |
| FLOAT | float | float64, from the JSON number of a float32 |
float64 |
FLOAT |
yes |
| REAL | float | float64 |
float64 |
REAL |
yes |
| DOUBLE | float | float64, with the infinities and NaN from their strings |
float64 |
DOUBLE |
yes |
| DECIMAL | decimal | float64, because the server computes it as a double (D164) |
float64 |
DECIMAL |
yes |
| BOOLEAN | boolean | bool |
bool |
BOOLEAN |
yes |
| VARCHAR | string | string. A multi-value string with more than one value is a []any of its strings (D164) |
string |
VARCHAR |
yes |
| CHAR | string | string |
string |
CHAR |
yes |
| TIMESTAMP | timestamp | time.Time, from the ISO 8601 text with the offset of sqlTimeZone |
time.Time |
TIMESTAMP |
yes |
| DATE | date | dbimp.Date, from the date of the ISO 8601 text of its midnight in sqlTimeZone |
dbimp.Date |
DATE |
yes |
| ARRAY | array | []any, of the Go types of the elements that the native type names, from the JSON text or the JSON array |
[]interface {} |
ARRAY |
yes |
| COMPLEX | json | the decoded JSON value: nil, bool, string, int64, float64, *apd.Decimal, []any or map[string]any, from the JSON text in a string |
interface {} |
OTHER |
yes |
| COMPLEX | binary | []byte, from the base64 in the JSON text of a string |
[]uint8 |
OTHER |
yes |
| NULL | null | nil |
interface {} |
NULL |
yes |
These facts were recorded on each release, from the datasource
dbimp_types with three rows: one with values, one with empty or small
values, and one of NULL (recorded: "every type", unless a line says
otherwise):
- A NULL is the JSON
nullin every type and every JSON format. Incsv, a NULL and an empty string are both an empty field (recorded: "every type as csv"). - A
BIGINTis a JSON number, and keeps every digit from -9223372036854775808 to 9223372036854775807. A literal outside that range fails withNumeric literal ... out of range(recorded: "an integer literal out of range"). CAST(... AS INTEGER)givesINTEGERwith the native typeLONG.CAST(... AS SMALLINT)andCAST(... AS TINYINT)fail withCannot coerce field [id] from type [java.lang.Integer] to type [SMALLINT](recorded: "casts to other types", "a smallint" and "a tinyint").- A
FLOATcolumn holds a float32:3.4e38reads back as3.4E38, and as3.3999999521443642E38when cast toDOUBLE(recorded: "a float near its limit").REALis aDOUBLEin the native type. - A
DOUBLEis a JSON number, and an infinity or NaN is the string"Infinity","-Infinity"or"NaN"(recorded: "an infinity and NaN").CAST('NaN' AS DOUBLE)fails (measured withcurlon 37.0.0 on 2026-10-01). - A
DECIMALhas the native typeDOUBLE.CAST(d AS DECIMAL(38, 10))of1.7976931348623157e308reads1.7976931348623157E308, and the literal1234567890.123reads1.234567890123E9(recorded: "casts to other types", and measured withcurlon 37.0.0 on 2026-10-01). - A
BOOLEANof the query, such asid = 1, is a JSON boolean with the native typeLONG. A boolean written to a datasource is stored as aBIGINTof 1 or 0 (recorded: "a boolean column of the query" and "every type"). - A
VARCHARis a JSON string, with every character, and an empty string stays empty (recorded). A literal string isCHAR(recorded: "literals of each type"). - A multi-value string has the SQL type
VARCHARand the native typeSTRING. One value is that string, and two values are the JSON text of an array of strings,"[\"x\",\"y\"]", whateversqlStringifyArrayssays.GROUP BYgives one row for each value (recorded: "feature: multi-value strings" and "feature: a multi-value string grouped").MV_TO_ARRAYgives a JSON array of strings (recorded: "step 7: a multi-value string as an array"). - A
TIMESTAMPis ISO 8601 text with milliseconds, such as"2026-10-01T12:34:56.789Z". WithsqlTimeZoneAsia/Jakarta, it is"2026-10-01T19:34:56.789+07:00"(recorded: "feature: the time zone in the context").0001-01-01T00:00:00.000Zand1900-01-01T00:00:00.000Zread back as written (recorded: "a timestamp before 1970"). - A
DATEis the ISO 8601 text of its midnight, such as"2026-10-01T00:00:00.000Z", or"2026-10-01T00:00:00.000+07:00"withsqlTimeZone(recorded: "casts to other types" and "feature: the time zone in the context"). - An
ARRAYhas the native typeARRAY<STRING>,ARRAY<LONG>orARRAY<DOUBLE>. By default it is the JSON text of the array, such as"[\"a\",null,\"c\"]". WithsqlStringifyArraysfalse, it is a JSON array (recorded: "every type" and "every type with arrays as arrays"). An element can be NULL.ARRAY[]fails withRequire at least 1 argument(measured withcurlon 37.0.0 on 2026-10-01). - A JSON column has the SQL type
OTHERand the native typeCOMPLEX<json>. It is the JSON text in a string, such as"{\"k\":[1,\"two\",null,{\"n\":1.5}]}", withsqlStringifyArraystrue or false (recorded: "every type" and "every type with arrays as arrays"). - An HLL sketch has the SQL type
OTHERand the native typeCOMPLEX<HLLSketch>. It is the JSON text of a string of base64, such as"\"AgEHDAMIAQD2fr0F\""(recorded: "feature: a sketch"). - A NULL literal has the SQL type
NULLand the native typeSTRING(recorded: "literals of each type" and "typed parameters"). TIMEfails withUnsupported DateTime type[TIME], andVARBINARYfails withUnhandled Query Planning Failure(recorded: "a time of day" and "a binary value").
These facts come from the sources, and are not measured:
- godruid gives a
TIMESTAMPand aDATEas astring, and an array or a JSON value as its JSON text in a[]byte(godruid,druidsql/rows.go). - Other sketches, such as a theta sketch, arrive as base64 too (Gemini).
These facts were recorded on each release:
- A statement names each parameter as
?.parametersis a list of{"type": ..., "value": ...}, in the order of the marks. A type is a SQL type, such asVARCHAR,BIGINT,DOUBLE,BOOLEAN,TIMESTAMP,DATE,DECIMALorARRAY(recorded: "typed parameters" and "an array parameter"). - A
TIMESTAMPtakes its text, such as2026-10-01 12:34:56.789, or its milliseconds since 1970-01-01 (recorded: "a timestamp parameter in milliseconds"). ADATEtakes its text (recorded: "a date parameter"). - A
VARCHARofnullbinds NULL (recorded: "typed parameters"). - Too few values fail with
No value bound for parameter (position [2]). Too many are ignored (recorded: "too few parameters" and "too many parameters"). - The
INTEGER"1", a string, fails with HTTP 500 andCannot handle query. A parameter with notypefails with HTTP 400 andNullPointerException(recorded: "a string for an integer" and "a parameter with no type"). - A
DECIMALbinds as the type of its JSON number: the value1.2345678901234568e18came back as theBIGINT1234567890123456768 (recorded: "a decimal parameter"). :idis a syntax error. A?inside a quoted string is text, and not a parameter (recorded: "a named parameter" and "a parameter in a quoted string").- A
?whose type the statement cannot infer fails withIllegal use of dynamic parameter(measured withcurlon 37.0.0 on 2026-10-01).
These facts come from the sources, and are not measured:
- godruid sends each argument as a parameter, with
VARCHARfor nil and for[]byte,BIGINTfor an integer,DOUBLEfor a float andTIMESTAMPin milliseconds for atime.Time. It refuses a named argument (godruid,sqlparam.goanddruidsql/conn.go). - pydruid writes each argument into the text as a literal, with
'doubled in a string (pydruid). kaplanmaxe ignores the arguments (kaplanmaxe).
- Druid has no transactions.
BEGINandCOMMITfail with a syntax error (recorded: "begin a transaction" and "commit a transaction"). - A task replaces whole segments, so a write of one span of time is atomic (Gemini, not measured).
These facts were recorded on each release:
- An error before any rows answers with a JSON object:
error,errorCode,persona,category,errorMessageandcontext. A syntax error and an unknown datasource are HTTP 400 withcategoryINVALID_INPUT(recorded: "a syntax error" and "an unknown datasource"). - An error while the query runs, such as a division of a
BIGINTby zero, is HTTP 500 witherrorClassjava.lang.ArithmeticExceptionandcategoryRUNTIME_FAILURE. ItserrorMessageis/ by zeroon 36.0.0 andnullon 37.0.0 (recorded: "an error before any rows"). A query that the server cannot plan is HTTP 400 or HTTP 501 (recorded: "a binary value"). - A query that passes its
timeoutis HTTP 504 withcategoryTIMEOUT(recorded: "a timeout in the context"). - An error after some rows ends a response of HTTP 200 with no sign of the
error. The query divided by zero in the last row, which is in a second
segment. In
array, the body ends after row 397 with no closing]. InarrayLinesandobjectLines, it ends with no empty line. Rows 398 and 399 never arrived, and the connection ended in the normal way (recorded: "an error after some rows", "an error after some rows in lines" and "an error after some rows as objects"). - A wrong password is HTTP 401 with a page of HTML. A refused privilege is
HTTP 403 with
{"Access-Check-Result": ...}(recorded: "a wrong password" and "a system table that needs a privilege"). - No request answered HTTP 429.
These facts were recorded on each release:
DELETE /druid/v2/sql/<sqlQueryId>cancels a running query, and answers HTTP 202. The query then answers HTTP 500 withSequence canceled. An id that is not running answers HTTP 404 (recorded: "a statement to cancel", "cancel the statement by its id" and "cancel a statement that is not running"). The ordinary user cancelled its own query.timeoutin the context, in milliseconds, stops the query on the server (recorded: "a timeout in the context").- A statement after a client left answered at once (recorded: "a statement after the client left").
These facts were measured with curl and the processor time of the
container in /sys/fs/cgroup/cpu.stat, on 37.0.0 on 2026-10-01:
- A query that the client left after 2 seconds used about 2.3 seconds of
processor time in each 2 seconds until its
timeout, 8 seconds later. So the server does not stop a query when the client leaves. - After
DELETE /druid/v2/sql/<sqlQueryId>, the processor time dropped to the idle level at once. - As
dbmeta_user,DELETEof the query ofadminanswered HTTP 404.
These facts come from the sources, and are not measured:
- The server notices a client that left only when it writes to the socket (Gemini).
- godruid cancels a query of the statements API with
DELETE /druid/v2/sql/statements/<id>(godruid,statement.go).
These facts were recorded on each release:
- Two statements in one request fail:
Only SET statements can appear before the final statement in a statement list.SETstatements before the last one set keys of the context (recorded: "two statements in one request" and "feature: SET before a statement"). - Comments
--and/* */are part of the text, and a statement can end with a semicolon (recorded: "comments" and "a statement that ends with a semicolon"). EXPLAIN PLAN FORgives the native query as JSON text in one row (recorded: "feature: explain").UPSERTfails withUPSERT is not supported.on the task API (recorded: "step 7: upsert through the task API").CREATE TABLE,CREATE INDEX,CREATE VIEW,ALTER TABLEandDROP TABLEfail with a syntax error, which namesINSERT,UPSERT,EXPLAIN,SETandRESETamong the statements that it expects (recorded: "schema: create table", "schema: create index", "schema: create view", "schema: alter table" and "schema: drop table"). A datasource is made by its first write, andDELETE /druid/coordinator/v1/datasources/<name>drops it (recorded: "teardown: drop the datasource for crud").
These facts were recorded on each release:
dbmeta_userreads every datasource,INFORMATION_SCHEMA,sys.segments,sys.tasksand the lookups (recorded asdbmeta_user).dbmeta_useris refusedsys.servers,GET /status, the security API, the leader of the Coordinator, and every task, with HTTP 403 (recorded asdbmeta_user: "a system table that needs a privilege", "the version", "the users of the security API", "a path of the Coordinator through the Router" and "crud: insert").- So
dbmeta_usercannot read the version.adminreads it fromGET /statusand fromSELECT server_type, version FROM sys.servers(recorded: "the version" and "the version of each service"). dbmeta_userreadsGET /druid/coordinator/v1/datasources(recorded: "the datasources of the Coordinator").
- No flavor was measured.
- Imply Enterprise and Imply Polaris serve the same SQL API, and Polaris adds its own authentication (Gemini, not measured).
Step 10 writes this table from the code.
These are faults of the Go drivers that a driver here does not repeat:
- kaplanmaxe reads the whole body with
ioutil.ReadAll, returnsdriver.ErrSkipfromPrepareandBegin, ignores the arguments, and creates anhttp.Transportfor each query (kaplanmaxe,connection.go). - godruid gives an array and a JSON value as the JSON text in a
[]byte, and aTIMESTAMPas astring(godruid,druidsql/rows.go). - godruid answers
ExecwithRowsAffected(0), and sends a write to the SQL API, which refuses it (godruid,druidsql/conn.go). - Neither Go driver notices an error after some rows, because neither one
checks for the closing
]or the empty line (godruid and kaplanmaxe).
Step 7 tested each lead on the server. Gemini was asked on 2026-10-02. DeepSeek timed out on each of the four times that it was asked the questions of step 7, on 2026-10-02.
- Named parameters. Gemini said that Druid has only
?. The server agrees (recorded: "a named parameter"). - Transactions. Gemini said that there are none, and that a task replaces
segments as one change. The server refuses
BEGIN. - Paging. Gemini said that the statements API pages, but that without durable storage the result is one page of at most 3,000 rows. The server gave one page, and refused durable storage.
- Types. Gemini said that a
DATEcan be text with no time. The server sends the text of its midnight. Gemini said thatMV_TO_ARRAYwithsqlStringifyArraysfalse gives a typed array. The server agrees. - Cancel. Gemini said that the server does not stop a query when the client leaves. The server agrees.
UPSERT. Gemini said that it is a word of the grammar of Calcite, and that Druid refuses it. The server agrees.- The end of a result. Gemini said that
arrayandobjectend with], and that the lines formats have no sign of their end. The server ends each lines format with an empty line, and leaves it out after an error.
Step 8a asked both models on 2026-10-02 to review the mapping of the types against TYPES.md and D135. DeepSeek timed out on each of three tries. Gemini answered:
- It agreed with the integers, the floats with their strings, the boolean, the strings, the timestamp, the date, the array, the JSON value and the sketch as bytes.
- It said that a
DECIMALis afloat64, because its native type isDOUBLEand it holds no exact digits. The table follows D135, which gives a decimal an*apd.Decimal. See the open questions. - It said that a multi-value string stays a
string, because the server names itVARCHAR. - It said that the SQL type
NULLneeds a row of the kind null, for aSELECT NULL. The table has one. - It said that a boolean stored in a datasource is a
BIGINT, because the server names it so. The server does (recorded: "every type").
The coordinator asked DeepSeek again on 2026-10-02, through
deepseek-v4-pro, because deepseek-flash timed out once more. It
answered:
- It agreed with the integers, the floats with their strings, the boolean, the timestamp, the date, the array, the JSON value, the sketch as bytes and NULL.
- It said that a
DECIMALis afloat64, because the server computes it as a double, and an*apd.Decimalwould claim a precision that the server does not keep. Gemini said the same. See the open questions. - It said that a multi-value string with more than one value is a
[]any, decoded from the JSON text, and a single value stays astring. Gemini said the opposite. See the open questions.
These wait for Ken:
- Druid refuses
UPDATEandDELETE. A write goes through the task API, andREPLACEof a span of time takes the place of both. DRIVER.md says to stop and ask when a server refuses one of insert, select, update and delete. Can the driver go on, and does it sendINSERTandREPLACEto the task API, which answers before the rows can be read? - An error after some rows ends an answer of HTTP 200 with no error text.
Only the missing
], or the missing empty line of a lines format, shows it. Does that meet D21, or does it make Druid a target of "When it cannot be a driver"? The driver can readarrayorarrayLinesand fail when the end is missing. - A
DECIMALhas the native typeDOUBLE. Is it an*apd.Decimal, as D135 says for a decimal, or afloat64, as Gemini said? - A multi-value string is a
VARCHAR, and two values arrive as the JSON text of an array. Does the driver keep it as astring, as D135 says for a string column? dbmeta_usercannot read the version, becauseGET /statusandsys.serversneed more thanREADon the datasources. Does thedbmetaentry give its role more, or does the version stay out of reach for an ordinary user?- Two tasks of the multi-stage engine at once never ended on the nano
quickstart, which has two slots. Does the
dbmetaentry give the Middle Manager more slots, so that the tests of the driver can write without a wait?