Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@
zig-out/
# SQLite amalgamation — generated during build setup, not committed
lib/
# Vendored C source (linenoise, yaml, carquet, compression libs)
# Vendored C source (linenoise, yaml)
!lib/linenoise/
!lib/yaml/
!lib/carquet/
!lib/zstd/
!lib/lz4/
!lib/zlib/
!lib/parquet/
sqlite.zip
# Nix build output symlink
result
Expand Down
79 changes: 22 additions & 57 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ pub fn build(b: *std.Build) void {
});
exe.root_module.addImport("yaml", translate_yaml.createModule());

// Parquet reader: pure Zig library with pure-Zig compression codecs (zstd, gzip, snappy, lz4, brotli).
// Replaces bundled carquet C library + zstd/lz4/zlib C sources.
// codecs=zig-only: no C compression sources are compiled (all codecs are pure Zig).
const zig_parquet = b.dependency("zig_parquet", .{
.target = target,
.optimize = optimize,
.codecs = "zig-only",
});
exe.root_module.addImport("zig_parquet", zig_parquet.module("parquet"));

if (bundle_sqlite) {
exe.root_module.addIncludePath(b.path("lib"));
exe.root_module.addCSourceFile(.{
Expand Down Expand Up @@ -81,63 +91,6 @@ pub fn build(b: *std.Build) void {
exe.root_module.addCSourceFile(.{ .file = b.path("lib/yaml/writer.c"), .flags = &.{} });
exe.root_module.addCSourceFile(.{ .file = b.path("lib/yaml/loader.c"), .flags = &.{} });

// Parquet support via carquet C library (MIT, by Johan Natter).
// Compression libs (zstd, lz4, zlib) bundled as C source alongside carquet.
// All statically linked — zero runtime deps.
// NetBSD: Zig's bundled libc stdio.h uses GCC extensions @cImport can't
// parse. Shadow it with a minimal shim that only declares what carquet needs.
if (target.result.os.tag == .netbsd) {
exe.root_module.addIncludePath(b.path("lib/carquet/netbsd-shim"));
}

exe.root_module.addIncludePath(b.path("lib/carquet/include"));
exe.root_module.addIncludePath(b.path("lib/carquet/src"));
exe.root_module.addIncludePath(b.path("lib/zstd"));
exe.root_module.addIncludePath(b.path("lib/lz4"));
exe.root_module.addIncludePath(b.path("lib/zlib"));

const carquet_src_root = "lib/carquet/src";
const carquet_flags = &.{ "-std=gnu11", "-D_GNU_SOURCE" };
inline for (.{
"core/arena.c", "core/allocator.c", "core/buffer.c",
"core/bitpack.c", "core/endian.c", "core/error.c", "core/geo_wkb.c",
"thrift/thrift_decode.c", "thrift/thrift_encode.c", "thrift/parquet_types.c",
"encoding/plain.c", "encoding/rle.c", "encoding/delta.c",
"encoding/delta_length.c", "encoding/delta_strings.c",
"encoding/dictionary.c", "encoding/byte_stream_split.c",
"compression/lz4.c", "compression/snappy.c", "compression/zstd.c",
"compression/gzip.c", "compression/custom.c",
"simd/detect.c", "simd/dispatch.c",
"reader/file_reader.c", "reader/batch_reader.c", "reader/column_reader.c",
"reader/page_reader.c", "reader/row_group_reader.c",
"reader/mmap_reader.c", "reader/statistics.c", "reader/page_filter.c",
"reader/worker_pool.c", "reader/arrow_c_export.c",
"reader/arrow_c_read.c", "reader/arrow_schema_read.c",
"writer/file_writer.c", "writer/row_group_writer.c", "writer/column_writer.c",
"writer/page_writer.c", "writer/arrow_schema.c", "writer/arrow_c_import.c",
"metadata/schema.c", "metadata/bloom_filter.c", "metadata/page_index.c",
"util/crc32.c", "util/xxhash.c",
}) |src_file| {
exe.root_module.addCSourceFile(.{
.file = b.path(carquet_src_root ++ "/" ++ src_file),
.flags = carquet_flags,
});
}

// Bundled compression libraries (C source, cross-compiles everywhere)
exe.root_module.addCSourceFile(.{ .file = b.path("lib/zstd/zstd.c"), .flags = &.{"-std=gnu11"} });
exe.root_module.addCSourceFile(.{ .file = b.path("lib/lz4/lz4.c"), .flags = &.{"-std=gnu11"} });
inline for (.{
"adler32.c", "compress.c", "crc32.c", "deflate.c",
"infback.c", "inffast.c",
"inflate.c", "inftrees.c", "trees.c", "uncompr.c", "zutil.c",
}) |zf| {
exe.root_module.addCSourceFile(.{ .file = b.path("lib/zlib/" ++ zf), .flags = &.{"-std=gnu11"} });
}

exe.root_module.linkSystemLibrary("pthread", .{});
exe.root_module.linkSystemLibrary("m", .{});

b.installArtifact(exe);

// Generate man page from scdoc source if scdoc (and gzip) are available (optional dependencies)
Expand Down Expand Up @@ -3708,6 +3661,18 @@ pub fn build(b: *std.Build) void {
test_parquet_columns.step.dependOn(b.getInstallStep());
test_step.dependOn(&test_parquet_columns.step);

// Integration test 206g: Parquet INT96 legacy timestamps → TEXT column with ISO values
const test_parquet_int96 = b.addSystemCommand(&.{
"bash", "-c",
\\result=$(./zig-out/bin/sql-pipe tests/fixtures/int96.parquet 'SELECT ts FROM int96 ORDER BY ts')
\\expected=$(printf '2023-06-01 00:00:00\n2024-01-15 10:30:00')
\\[ "$result" = "$expected" ]
\\schema=$(./zig-out/bin/sql-pipe tests/fixtures/int96.parquet --schema)
\\echo "$schema" | grep -q '"ts" TEXT'
});
test_parquet_int96.step.dependOn(b.getInstallStep());
test_step.dependOn(&test_parquet_int96.step);

// Fuzzing tests: malformed Parquet files must not crash
const test_parquet_fuzz_truncated = b.addSystemCommand(&.{
"bash", "-c",
Expand Down
8 changes: 6 additions & 2 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
.fingerprint = 0xf649b9ac95d768ab,
.minimum_zig_version = "0.16.0",
.paths = .{"."},
.dependencies = .{},
}
.dependencies = .{
.zig_parquet = .{
.path = "lib/parquet",
},
},
}
12 changes: 6 additions & 6 deletions codemap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

## Project Responsibility

CLI tool that pipes structured data (CSV, TSV, JSON, NDJSON, XML, YAML, Parquet) into an in-memory SQLite engine, runs a user-supplied SQL query, and emits results in eight formats (CSV, TSV, JSON, NDJSON, XML, Markdown, HTML table, SQL INSERT, pretty-printed table). Also provides ancillary modes for column listing, validation, sampling, statistics, schema DDL generation, and fused `--inspect` — plus a native interactive `--repl` — and shell completion for bash/zsh/fish. Single binary, zero external dependencies, bundles SQLite amalgamation, libyaml subset, and carquet (Parquet) C library.
CLI tool that pipes structured data (CSV, TSV, JSON, NDJSON, XML, YAML, Parquet) into an in-memory SQLite engine, runs a user-supplied SQL query, and emits results in eight formats (CSV, TSV, JSON, NDJSON, XML, Markdown, HTML table, SQL INSERT, pretty-printed table). Also provides ancillary modes for column listing, validation, sampling, statistics, schema DDL generation, and fused `--inspect` — plus a native interactive `--repl` — and shell completion for bash/zsh/fish. Single binary, zero external dependencies, bundles SQLite amalgamation, libyaml subset, and zig-parquet (Parquet) pure Zig library.

## System Entry Points

- `src/main.zig` — CLI entry point, argument parsing, mode dispatch, pipeline orchestration
- `build.zig` — Zig build system with 120+ integration tests, bundles C deps (sqlite3, libyaml, carquet)
- `build.zig` — Zig build system with 120+ integration tests, bundles C deps (sqlite3, libyaml)
- `build.zig.zon` — Package manifest (name=`sql_pipe`, version=`0.0.0-dev`, min Zig `0.16.0`)

## Directory Map
Expand All @@ -16,7 +16,7 @@ CLI tool that pipes structured data (CSV, TSV, JSON, NDJSON, XML, YAML, Parquet)
|-----------|---------------|--------------|
| `src/` | Core pipeline: argument parsing, multi-format I/O loaders (incl. Parquet), SQLite wrappers, output formatters (15 modules) | [View Map](src/codemap.md) |
| `src/modes/` | CLI sub-command modes: `--inspect` (fused columns/validate/sample/stats/schema), `--repl`, legacy flags (8 modules) | [View Map](src/modes/codemap.md) |
| `lib/` | Vendored C deps: SQLite amalgamation (`sqlite3.c/h`), libyaml subset, carquet (Parquet) | (vendored) |
| `lib/` | Vendored C deps: SQLite amalgamation (`sqlite3.c/h`), libyaml subset, zig-parquet (Parquet) | (vendored) |
| `tests/` | Test fixtures (CSV, JSON, NDJSON, XML sample data) + HTTP test server | (fixtures) |
| `docs/` | Man page source (`sql-pipe.1.scd`) | — |
| `packaging/` | nfpm, winget packaging configs | — |
Expand Down Expand Up @@ -65,7 +65,7 @@ CLI args → parseArgs() → dispatch
| NDJSON | `.ndjson` | `json.zig` | Newline-delimited, one object per line |
| XML | `.xml` | `xml.zig` | Custom streaming parser, configurable container/row elements |
| YAML | `.yaml` | `yaml.zig` | Sequence of mappings via libyaml FFI |
| Parquet | `.parquet` | `parquet.zig` | Columnar via carquet FFI, batch inserts, logical-type conversion |
| Parquet | `.parquet` | `parquet.zig` | Columnar via zig-parquet DynamicReader, batch inserts, logical-type conversion |

## Output Formats

Expand All @@ -82,9 +82,9 @@ CSV, TSV, JSON (array), NDJSON, XML, Markdown table, HTML table, SQL INSERT, pre

## Integration Points

- **FFI**: SQLite3 C API (`sqlite3_open`, `sqlite3_prepare_v2`, `sqlite3_step`, etc.), libyaml C API (`yaml_parser_parse`, etc.), carquet C API (Parquet reading, logical-type conversion)
- **FFI**: SQLite3 C API (`sqlite3_open`, `sqlite3_prepare_v2`, `sqlite3_step`, etc.), libyaml C API (`yaml_parser_parse`, etc.)
- **HTTP**: `std.http.Client` for HTTPS URL input sources (`http.zig`)
- **Build**: `c` module (SQLite + libyaml + carquet C bindings), `yaml` module (libyaml Zig bindings), `build_options.VERSION`
- **Build**: `c` module (SQLite + libyaml C bindings), `yaml` module (libyaml Zig bindings), `zig_parquet` module (zig-parquet pure Zig), `build_options.VERSION`

## Build & Test

Expand Down
Loading
Loading