Repository navigation
Bind JSON values as their JSON text - #39
Merged
Merged
Conversation
json and jsonb columns decode to JSON.LazyValue, but binding one back as a
parameter sent Julia's display of it ("LazyObject{String} with 1 entry:
..."). json and jsonb targets rejected that text; text targets stored it
silently. LazyValue and JSONText parameters now send their JSON text, in
scalars and array elements alike.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
quinnj-bot Bot
pushed a commit
that referenced
this pull request
Oct 30, 2026
JSON values read from json/jsonb columns, and JSON.JSONText, now get a jsonb column instead of text when load! creates the table. Their COPY text is the JSON itself (#39). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
quinnj-bot Bot
added a commit
that referenced
this pull request
Oct 30, 2026
* Add Postgres.load! to load a Tables.jl source into a table MySQL.jl, SQLite.jl, ODBC.jl and LibPQ.jl can load a Tables.jl source; Postgres.jl needed a hand-written CREATE TABLE plus executemany, or hand-formatted COPY text. `Postgres.load!(table, conn, name; append, coltypes, quoteidentifiers)` creates the table from the source schema when it is missing and sends the rows with COPY FROM STDIN in text format, in 4 MiB batches, each value as its bind-parameter text with COPY escapes. The load is one transaction, so a failure adds no rows and removes a table it created. 1M rows x 4 columns: 2.6 s, against 20.9 s for pipelined executemany. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Create JSON columns as jsonb in load! JSON values read from json/jsonb columns, and JSON.JSONText, now get a jsonb column instead of text when load! creates the table. Their COPY text is the JSON itself (#39). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Jacob Quinn <quinn.jacobd@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Merged
quinnj
referenced
this pull request
Oct 30, 2026
Co-authored-by: Jacob Quinn <quinn.jacobd@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
jsonandjsonbcolumns decode toJSON.LazyValue. Binding one back as a parameter sent Julia's display of it (LazyObject{String} with 1 entry: ...).jsonandjsonbtargets rejected that text (Token "LazyObject" is invalid), andtexttargets stored it silently.JSON.JSONTexthad the same problem.Both now bind as their JSON text, as scalars and as array elements. The text comes from JSON.jl's public
JSON.parse(x, JSONText), which returns the value's exact source text, so large numbers keep every digit.This also matters for
Postgres.load!in #37. On that branch, copying a query result that has ajsonbcolumn creates atextcolumn filled with"LazyObject{String}()". With this change applied on top of #37, the column holds the JSON text. The column type still comes from #37's type mapping.Found by a differential check of Postgres.jl against psycopg 3 on PostgreSQL 16 (bound parameters of every type, read back through the binary protocol).
Verification
JSONText, bound intojson,jsonbandjsonb[], through unnamed execute, prepared execute,executemanyand explicit casts. All are stored byte-for-byte as expected.WHERE v = $1onjsonbmatches the stored row.Pkg.test()(Julia 1.12.6, Docker PostgreSQL 16): 9244/9244 passed.🤖 Generated with Claude Code