PeachQ additions and compatibility¶
On-disk databases: what works today
Flat files and splayed tables work: PeachQ reads and writes them in the kdb+ on-disk format, including compressed splayed tables when reading. Partitioned and segmented databases do not load yet, and .Q.dpft, dsave and partitioned writes are not available. For a typical historical database (HDB) this is the largest gap today; see the details.
If your team runs kdb+ in production and partitioned support would let you evaluate PeachQ, we would like to hear about your setup and what you need. Real workloads decide what we build next. Tell us what you need
PeachQ builds on familiar q syntax with richer interactive tools, flexible data readers and connections to other systems. Start with the additions below, then review behaviour changes and unsupported features when bringing an existing application across.
More with PeachQ¶
| Feature | What it adds |
|---|---|
| REPL and table display | Built-in editing, history and a richer table display. |
Reading CSV: .csv.read, .csv.info |
Type inference, quoting dialects, streaming targets, a reject channel. |
Reading JSON: .j.read, .j.info |
A reader beside kdb's .j.k converter: written forms, a table, a schema. |
| The shared loader laws | What a cell means, the freeze, the error classes, the tolerance levers. |
| Resources at a URL | Read supported files and remote resources; available operations depend on the transport and format. |
Regular expressions: .regexp, rlike |
RE2-backed matching, extraction, replacement and splitting. |
| Typed parameters (design preview) | Declared types, optional arguments, defaults and varargs, read statically. |
Foreign functions: .ffi |
Call into a shared library from q. |
Startup evaluation: -eval, -eval-before |
Run q text from argv after / before the startup script; no stdin piping. |
String helpers: .str |
printf/format, strip, prefix and suffix tests, character-class predicates. |
DuckDB-backed storage: .duckdb |
Experimental native integration: query DuckDB from q and use its Parquet and S3 support. |
Parquet: .parquet.read, .parquet.write |
Read and write Parquet through DuckDB; supported q types round-trip using PeachQ schema metadata. |
The bundled library's namespaces load automatically. Typed parameters are a design preview; the feature guide records which stages have not shipped. String helpers and DuckDB functions also have doc comments at the prompt: try .str.printf or .duckdb.exec.
Behaviour changes¶
These choices make some operations behave differently from q. Check them when migrating code.
| Feature | What to expect |
|---|---|
| Reserved words in name positions | Refused wherever a name is bound, not only at name:. |
set to a .csv/.json/.txt/.xml/.xls/.parquet path |
Writes that format, not the q binary form; t must be a table. |
Serializing functions with -8! and IPC |
Primitives use kx's bytes; keywords kx defines in k travel as a q lambda. |
set writes the format the suffix names. `:f.csv set t writes CSV (the lines save writes),
`:f.parquet set t writes parquet, and so on for every .h.tx key, where kx writes the q binary form under any
name. The read side already worked that way (select from `:f.csv); the write side now matches it. A value that
is not a table signals 'type under those endings; a path with no recognised ending is the binary form as in kx.
See Handles and resources § Format inference and Parquet.
get reads the format the suffix names. get `:f.csv (and value) answers the table select from `:f.csv
reads, for every ending select from speaks (.csv .tsv .json .jsonl .ndjson .parquet), where kx signals 'type
for any file that is not a kdb+ data file. An error becomes a value, so no working kx program changes meaning. A path
with no recognised ending is the kdb+ file read as in kx; an ending with a writer and no reader (.xml, .xls,
.txt) is 'type as in kx.
Reserved words in name positions. ([] null), select null from t, {[null] null} and w[1] div:3 all signal
'assign where kx accepts them. Each was silently producing a broken table, or resolving to the keyword's own
function instead of the binding.
Serializing functions. Every function value serializes, through -8!, -9! and IPC, and -9!-8!f answers
a value matching f. What goes on the wire depends on what the function is:
- A primitive, or a composition of primitives, uses the kx wire form:
-8!negis0x010000000a0000006502and-8!ceilingis the composition0x0100000018000000690200000065026902000000650e6502. - A keyword kx defines in k (
ej,mod,xbar,ljand others) travels as a q lambda that calls it, not as kx's k source:-8!ejcarries{ej[x;y;z]}. peachq decodes that exact text back to the keyword itself; a kx process receives an ordinary lambda that calls its ownej. - A PeachQ library function implemented in C (
.regexp.i.*,.duckdb.i.*and others) travels as its2:call, such as{[x;y;z] (`pq 2:(`.regexp.i.test;3))[x;y;z]}. A peachq process decodes it to its own native; a kx process cannot run it.
Two gaps remain. A parse tree holding a composition head, such as -8!parse "sum abs::", signals 'nyi. A
malformed message given to -9! signals 'domain or 'badfunc where kx signals 'badmsg, and a lambda written in
k (k){...}) does not decode, since peachq does not run k.
Storage and memory use¶
Splayed tables map at get and \l, and stay mapped. get `:dir/ is the flip of cols!`:dir/ as in
kx (a table whose fixed-width columns are memory-mapped and whose compressed columns inflate a block on first
touch) and the maps live as long as the value does, so a table bound by \l holds its maps for the session.
-3!t prints +`a`b!`:dir/, flip t is the dictionary, value t is the path, .Q.qp t is 0b, and a table
derived from it (select, 1#, ,, update by value) is plain.
Nested, string and enumerated columns are read into memory at get. kx maps those lazily; peachq decodes them
when the table is opened, so a splayed table with large string, nested or sym columns costs memory at load time,
not at first touch. Fixed-width columns are mapped as in kx. The enumerated column stays an enumeration (20h),
and its domain file binds under its own name at get.
Unsupported features¶
The following capabilities are unavailable or only partly implemented in this snapshot. The linked guides describe alternatives and per-option status.
| Feature | What to expect |
|---|---|
| Partitioned and segmented databases | Do not load. Splayed tables do. |
| Splayed and partitioned writing | Reading kx on-disk format is in scope; writing it is not. |
| Pattern matching (kdb+ 4.1) | List patterns work after 0.91; dictionary, table and filter-function patterns do not. |
| System commands and launch flags | See the reference pages for PeachQ-specific session commands and launch options. |
Partitioned and segmented databases. This is the largest single gap for an existing kdb+ installation: a partitioned or segmented HDB does not load. Splayed tables do, including nested columns, attributes and kx compression.
Splayed and partitioned writing. .Q.dpft, dsave, partitioned set, save's binary arm, rsave and -24!
are unavailable. Flat set, `:dir/ set and .z.zd all work. For large local storage the route is the
.duckdb provider; see Handles and resources.
Pattern matching. Builds after 0.91 support the kdb+ 4.1 list patterns, in assignment and in a function's parameter list: names, nested lists, the null pattern (an empty slot), constants and type checks. Names bound inside a lambda are local to it.
q)(b;c):(2;3)
q)(h;g):(c;b)
q)(a;(d;e)):(1;(2;3))
q)(s:`s;n:`j):(`x;5)
q)(s:`s;n:`j):(`x;5.0)
'type
q)(1 2):1 3
'match
q)r:{[x;(m;n)] x*m+n}
q)r[2;3 4]
14
Dictionary and table patterns, such as (i:`a;j:`c):d, signal 'nyi. Filter functions, such as
{[x:tempCheck]32+1.8*x}, signal 'parse and are not planned; use an ordinary check in the body, or a declared
type where a type suffices (see typed parameters).