Skip to content

Commit f448a22

Browse files
committed
docs: prepare the v1.0.0-rc5 release
Dates the rc5 entry, which the Unreleased section had been collecting since rc4 was tagged, and orders it the way a release entry reads: what breaks first. Two of the entries move up into Breaking Changes, because both change what a program downstream receives — an Excel export that used to hand back a file now hands back exit 4, and the --inspect source of a credentialed URL is redacted. The migration guide gains the three things an rc4 command line, wrapper, or pair of hands has to absorb: the Excel refusal and what to do instead, the redacted source and why it is not a handle to re-fetch with, and what Ctrl-C does now. Two tests hold the guide and the release notes to each other, as the rc3 and rc4 pairs already do. The README and site banners name rc5 and the contract it adds, and the sample --inspect reports carry the version that writes them.
1 parent 0054399 commit f448a22

6 files changed

Lines changed: 130 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Release candidates and what v1.0.0 freezes
44

5-
`v1.0.0-rc4` is the current release candidate, and it is not the final contract
5+
`v1.0.0-rc5` is the current release candidate, and it is not the final contract
66
either. Breaking changes are still being made, and they are being made now
77
rather than after v1.0.0.
88

@@ -14,16 +14,33 @@ rather than after v1.0.0.
1414
Changes below.
1515

1616
The final RC is announced as the final one in its release notes. That is the
17-
point to pin a version against; none of rc1 through rc4 is it.
17+
point to pin a version against; none of rc1 through rc5 is it.
1818

1919
Upgrading between candidates: [doc/migration.md](doc/migration.md).
2020

21-
## [Unreleased]
21+
## [v1.0.0-rc5](https://github.com/nao1215/sqly/compare/v1.0.0-rc4...v1.0.0-rc5) (2026-08-06)
22+
23+
A release candidate for v1.0.0, not the final one. Everything below is a change
24+
from rc4.
25+
26+
Upgrading from rc4: [doc/migration.md](doc/migration.md).
27+
28+
The theme of this one is the interactive shell, and what an export does with a
29+
value it cannot write. Ctrl-C could not reach a running statement and ended the
30+
session instead of the line; a ";" was a terminator wherever it appeared, so a
31+
trigger could not be typed and a trailing comment was never submitted; a line
32+
holding several statements printed one of their results. Two exports answered an
33+
unwritable value by failing with a parser error nobody could act on, or by
34+
changing the value and saying nothing. And a URL's password was printed back on
35+
both streams.
36+
37+
### Breaking Changes
38+
39+
* Exporting to Excel refuses a value XLSX cannot carry, where it used to change it. XLSX is XML, and XML 1.0 has no way to write a control character other than tab, newline, and carriage return, nor the noncharacters `U+FFFE` and `U+FFFF`; the writer substituted `U+FFFD` for the rest, so the export succeeded, the file appeared, and the byte was gone. It now exits `4`, names the character, and leaves the destination exactly as it was — the contract every other format already followed, and the one the exit-code table already documented. A pipeline that exported such data and got a file now gets a failure; csv, tsv, and json carry the same values unchanged.
40+
* A password carried in a remote URL is redacted in everything sqly prints. `--inspect` wrote it into the `source` field on stdout — the document people commit, attach, and paste — and every message about a download repeated the URL as given on stderr, alongside Go's own error, which redacts it. All of them now show `user:xxxxx@`. A program that read `source` and re-fetched from it has to keep the URL it passed in; the redaction is a display of the source, not a handle to it. Command history still records the line as typed, so the up-arrow returns something runnable.
2241

2342
### Bug Fixes
2443

25-
* A password carried in a remote URL is no longer printed back. Every message about a download repeated the URL as given, so a failed import wrote the secret to stderr — undoing the redaction Go's own transport error performs — and the `--inspect` report wrote it to stdout, the document people attach and paste. Messages, the `--allow-remote` refusal, and the report now show `user:xxxxx@`. Command history still records the line as typed, which the shell page now says.
26-
* Exporting to Excel refuses a value XLSX cannot carry instead of changing it. XLSX is XML, and XML 1.0 has no way to write most control characters, so the writer substituted `U+FFFD`: the export succeeded, the file appeared, and the byte was gone. It now fails with exit code 4, names the character, and leaves the destination exactly as it was — the contract every other format already followed, and the one the reference documents. Tab, newline, and carriage return are the three XML keeps, so a value holding them still exports.
2744
* Exporting to Parquet no longer fails on a value SQLite cannot parse as a literal. The export stages the result in a temporary database, and it built that INSERT as SQL text with every value quoted into it, so a NUL byte — which ends a statement as far as SQLite's tokenizer is concerned — left the literal unclosed: a CSV carrying one exported to every other format and failed Parquet with `unrecognized token`, naming a token nobody typed. Values are bound now, which also parses the statement once for the export instead of once per row.
2845
* A result printed for a statement typed across a continuation line keeps its last line. The prompt that followed it erased one row per row the entry had occupied, so a two-line statement ate the last line of its own result — a table lost its bottom border, while the same query typed on one line kept it. Fixed in prompt v0.0.17.
2946
* Ctrl-C now stops a statement that is already running. The prompt holds the terminal in raw mode, where Ctrl-C is a byte rather than a signal, and between prompts nothing was reading it: the key could not reach a running statement at all. It waited in the input buffer while the query ran to completion, however long that took, and was then read as the next line. A canceled statement rolls back and the session carries on, so canceling is not a failure and the session still exits 0. Needs prompt v0.0.16.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ sqly runs SQL against CSV, TSV, LTSV, JSON, JSONL, Parquet, Excel, ACH, and Fedw
1515

1616
Documentation: **https://nao1215.github.io/sqly/**
1717

18-
This documentation describes `v1.0.0-rc4`, a release candidate. It carries substantial breaking changes over v0.x — classified exit codes, visible-only Excel sheets, SIGTERM `143`, multiple inputs as one atomic import, a schema-only `--inspect`, default-deny remote input, and now stdout carrying nothing but data in every machine-readable format — and more can land before v1.0.0, so read the [CHANGELOG](./CHANGELOG.md) and the [migration guide](./doc/migration.md) before upgrading.
18+
This documentation describes `v1.0.0-rc5`, a release candidate. It carries substantial breaking changes over v0.x — classified exit codes, visible-only Excel sheets, SIGTERM `143`, multiple inputs as one atomic import, a schema-only `--inspect`, default-deny remote input, stdout carrying nothing but data in every machine-readable format, and now an export that refuses a value it cannot write rather than changing it — and more can land before v1.0.0, so read the [CHANGELOG](./CHANGELOG.md) and the [migration guide](./doc/migration.md) before upgrading.
1919

2020
![demo](./doc/img/demo.gif)
2121

@@ -91,7 +91,7 @@ sqly --inspect user.csv
9191
```json
9292
{
9393
"schema_version": 1,
94-
"sqly_version": "v1.0.0-rc4",
94+
"sqly_version": "v1.0.0-rc5",
9595
"tables": [
9696
{
9797
"name": "user",

doc/migration.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,58 @@ The [CHANGELOG](../CHANGELOG.md) records every change. This file records the one
77
that require an edit to a command line, a script, or a program that reads sqly's
88
output.
99

10+
## v1.0.0-rc4 → v1.0.0-rc5
11+
12+
### An Excel export refuses a value XLSX cannot carry
13+
14+
XLSX is XML, and XML 1.0 has no way to write a control character other than tab,
15+
newline, and carriage return, nor the noncharacters `U+FFFE` and `U+FFFF`. The
16+
writer used to substitute `U+FFFD` for them, so the export succeeded and the byte
17+
was gone.
18+
19+
```text
20+
Before rc5:
21+
printf 'id,v\n1,A\x01B\n' > ctl.csv
22+
sqly --output-format excel --output out.xlsx --sql "SELECT * FROM ctl" ctl.csv
23+
# exit 0, and out.xlsx holds "A\uFFFDB"
24+
25+
From rc5:
26+
# excel: value for column "v" contains the character U+0001,
27+
# which XLSX cannot represent; remove it or export to csv/tsv/json
28+
# exit 4, and out.xlsx is untouched
29+
```
30+
31+
**What to change:** a pipeline that exported such data and got a file now has to
32+
handle a failure. Strip the character in SQL — `replace(v, char(1), '')` — or
33+
export to csv, tsv, or json, which carry it unchanged. Tab, newline, and carriage
34+
return still export.
35+
36+
### A password in a remote URL is redacted in what sqly prints
37+
38+
`--inspect` wrote the URL as given into `tables[].source`, and every message about
39+
a download repeated it. Both now show what `url.Redacted` gives.
40+
41+
```text
42+
Before rc5:
43+
sqly --allow-remote --inspect "https://user:secret@host/data.csv"
44+
# "source": "https://user:secret@host/data.csv"
45+
46+
From rc5:
47+
# "source": "https://user:xxxxx@host/data.csv"
48+
```
49+
50+
**What to change:** a program that read `source` and fetched from it keeps the URL
51+
it passed in instead. The field is a display of where a table came from, not a
52+
handle to re-open it. A local path is unaffected — only `http` and `https` are
53+
rewritten, so a Windows path keeps its drive letter.
54+
55+
### Ctrl-C in the interactive shell
56+
57+
Not a change to a command line, but to what the key does. It used to end the
58+
session with exit code `1`; it now discards the line being typed, and stops a
59+
statement that is already running. A canceled statement rolls back and the
60+
session carries on, so a session that ends normally afterward still exits `0`.
61+
1062
## v1.0.0-rc3 → v1.0.0-rc4
1163

1264
### `excel_sheets[].source` is an absolute path

docs_drift_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,57 @@ func TestMigrationGuide_ExplainsRc2ToRc3(t *testing.T) {
18801880
}
18811881
}
18821882

1883+
// TestMigrationGuide_ExplainsRc4ToRc5 holds the guide to the changes an rc4
1884+
// command line or wrapper has to absorb. A breaking change recorded only in the
1885+
// CHANGELOG leaves the person upgrading to work out the edit themselves.
1886+
func TestMigrationGuide_ExplainsRc4ToRc5(t *testing.T) {
1887+
t.Parallel()
1888+
1889+
guide := readDoc(t, migrationGuideFile)
1890+
if !strings.Contains(guide, "## v1.0.0-rc4 → v1.0.0-rc5") {
1891+
t.Fatalf("%s has no rc4 to rc5 section", migrationGuideFile)
1892+
}
1893+
flat := flatten(section(guide, "## v1.0.0-rc4 → v1.0.0-rc5"))
1894+
1895+
for _, claim := range []string{
1896+
"XLSX cannot represent",
1897+
"exit 4",
1898+
"csv, tsv, or json",
1899+
"tables[].source",
1900+
"user:xxxxx@",
1901+
"Ctrl-C",
1902+
} {
1903+
if !strings.Contains(flat, claim) {
1904+
t.Errorf("%s does not state: %s", migrationGuideFile, claim)
1905+
}
1906+
}
1907+
}
1908+
1909+
// TestCHANGELOG_ListsTheRc5BreakingChanges is the rc4 check for the release
1910+
// after it: what the guide tells someone to change, the release notes have to
1911+
// record.
1912+
func TestCHANGELOG_ListsTheRc5BreakingChanges(t *testing.T) {
1913+
t.Parallel()
1914+
1915+
body := readDoc(t, "CHANGELOG.md")
1916+
rc5 := section(body, "## [v1.0.0-rc5]")
1917+
if rc5 == "" {
1918+
t.Fatal("CHANGELOG.md has no v1.0.0-rc5 section")
1919+
}
1920+
breaking := flatten(section(rc5, "### Breaking Changes"))
1921+
if breaking == "" {
1922+
t.Fatal("the v1.0.0-rc5 CHANGELOG entry has no Breaking Changes section")
1923+
}
1924+
for _, claim := range []string{"Excel", "U+FFFE", "source", "user:xxxxx@"} {
1925+
if !strings.Contains(breaking, claim) {
1926+
t.Errorf("the rc5 Breaking Changes section does not mention %s", claim)
1927+
}
1928+
}
1929+
if !strings.Contains(flatten(rc5), migrationGuideLink) {
1930+
t.Errorf("the rc5 CHANGELOG entry does not link the migration guide (%s)", migrationGuideLink)
1931+
}
1932+
}
1933+
18831934
// TestMigrationGuide_ExplainsRc3ToRc4 holds the guide to the changes an rc3
18841935
// command line or wrapper has to absorb. A breaking change recorded only in the
18851936
// CHANGELOG leaves the person upgrading to work out the edit themselves.

website/content/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: sqly
44

55
sqly runs SQL against CSV, TSV, LTSV, JSON, JSONL, Parquet, Excel, ACH, and Fedwire files. It loads them into an in-memory SQLite database, so joins, CTEs, window functions, and aggregates all work — across formats, in one query.
66

7-
This site describes `v1.0.0-rc4`, a release candidate. It carries substantial breaking changes over v0.x — classified exit codes, visible-only Excel sheets, SIGTERM `143`, multiple inputs as one atomic import, a schema-only `--inspect`, default-deny remote input, and now stdout carrying nothing but data in every machine-readable format — and more can land before v1.0.0, so read the [CHANGELOG](https://github.com/nao1215/sqly/blob/main/CHANGELOG.md) and the [migration guide](https://github.com/nao1215/sqly/blob/main/doc/migration.md) before upgrading.
7+
This site describes `v1.0.0-rc5`, a release candidate. It carries substantial breaking changes over v0.x — classified exit codes, visible-only Excel sheets, SIGTERM `143`, multiple inputs as one atomic import, a schema-only `--inspect`, default-deny remote input, stdout carrying nothing but data in every machine-readable format, and now an export that refuses a value it cannot write rather than changing it — and more can land before v1.0.0, so read the [CHANGELOG](https://github.com/nao1215/sqly/blob/main/CHANGELOG.md) and the [migration guide](https://github.com/nao1215/sqly/blob/main/doc/migration.md) before upgrading.
88

99
![sqly running a query against a CSV file](/img/demo.gif)
1010

website/content/reference.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ Every report opens with two fields that answer different questions:
479479
```json
480480
{
481481
"schema_version": 1,
482-
"sqly_version": "v1.0.0-rc4",
482+
"sqly_version": "v1.0.0-rc5",
483483
"tables": []
484484
}
485485
```
@@ -529,7 +529,7 @@ it has sheets, and nothing in `tables` says what is missing.
529529
```json
530530
{
531531
"schema_version": 1,
532-
"sqly_version": "v1.0.0-rc4",
532+
"sqly_version": "v1.0.0-rc5",
533533
"tables": [],
534534
"excel_sheets": [
535535
{

0 commit comments

Comments
 (0)