Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

column "x" is of type jsonb but expression is of type character varying #31

Open
marcj opened this issue Oct 5, 2023 · 8 comments
Open
Assignees
Labels
question Further information is requested

Comments

@marcj
Copy link

marcj commented Oct 5, 2023

Describe the bug

I have a table

create table model1
(
    id  serial primary key,
    doc  jsonb   default '{"flag": false}'::jsonb not null
);

and I want to insert data

    const con = new Connection({
        host: 'localhost',
        user: 'postgres',
        database: 'postgres',
    });
    await con.connect();
    await con.query('INSERT INTO model1 (doc) VALUES ($1)', {params: [JSON.stringify({ flag: true })]});

I get the following error:

Error: column "doc" is of type jsonb but expression is of type character varying

    at /Users/marc/bude/deepkit-framework/packages/postgres/node_modules/postgresql-client/cjs/protocol/pg-socket.js:229:44
    at Backend.parse (/Users/marc/bude/deepkit-framework/packages/postgres/node_modules/postgresql-client/cjs/protocol/backend.js:51:13)
    at PgSocket._handleData (/Users/marc/bude/deepkit-framework/packages/postgres/node_modules/postgresql-client/cjs/protocol/pg-socket.js:222:23)
    at Socket.<anonymous> (/Users/marc/bude/deepkit-framework/packages/postgres/node_modules/postgresql-client/cjs/protocol/pg-socket.js:201:42)
    at Socket.emit (node:events:513:28)
    at addChunk (node:internal/streams/readable:324:12)
    at readableAddChunk (node:internal/streams/readable:297:9)
    at Socket.Readable.push (node:internal/streams/readable:234:10)
    at TCP.onStreamRead (node:internal/stream_base_commons:190:23)

(btw, the error stack is wrong. My original call con.query is not in the stack trace)

Expected behavior

Goes through without warning like the pg package, which works like that.
I do not expect to pass for each parameter an explicit type, as I have often many parameters and this would destroy UX.

Desktop (please complete the following information):

  • OS: macOS
@erayhanoglu
Copy link
Member

Hi,
Do not stringify the object. Just pass the object in the params.

const doc = { flag: true };
await con.query('INSERT INTO model1 (doc) VALUES ($1)', {params: [doc]});

Or you can define bind parameter explicitly.

const doc = { flag: true };
await con.query('INSERT INTO model1 (doc) VALUES ($1)', {
    params: [new BindParam(DataTypeOIDs.jsonb, doc)]
});

@erayhanoglu erayhanoglu added the question Further information is requested label Oct 6, 2023
@erayhanoglu erayhanoglu self-assigned this Oct 6, 2023
@marcj
Copy link
Author

marcj commented Oct 10, 2023

thanks! I do use literal values for jsonb too, so string, number, etc. This works fine with pg so would be lovely if this library could support it as well without having to specify each param manually

@erayhanoglu
Copy link
Member

pg uses text format for data transfer which is very slow and cumbersome. postgresql-client uses binary format which is fast and performant. This is why we created this library.

In text format everything is converted to the text than sent to the server; dates, numbers, binary data etc. This is why you can use any value to send as literal. text format is easy to implement and easy to use.

If there is no intense data flow in your application, you can use other libraries which uses text format. If your application needs performance you should use a library which uses binary format.

@marcj
Copy link
Author

marcj commented Oct 19, 2023

How is text format slower? Last time I benchmarked, V8 was notoriously slow converting utf-8 text to binary and vice versa. Do you have any benchmarks showing that binary is actually faster for Postgres? From my experience writing very fast binary encoder in JS, it gets slower and slower compared to JSON.parse for example the longer strings are in there. if your message primarily consists of numbers and small strings (<12 characters), binary is faster though.

@erayhanoglu
Copy link
Member

You can find some benchmark result in the internet. Here is some links that i found.

https://www.postgresql.org/message-id/[email protected]

In the text protocol, data is first converted to string on the client side, sent to the server, and parsed by the server again. This workflow couses so much cpu time for both client and server side. And also the data size to be transered over the network gets larger.

Text transfer format:
[Client] raw data -> stringify -> transfer -> [Server] - parse -> execute -> stringify -> transfer -> [Client] parse

Binary transfer format:
[Client] raw data -> transfer -> [Server] - execute -> transfer -> [Client]

@marcj
Copy link
Author

marcj commented Oct 19, 2023

Thank you! I'll play around with your client in binary mode and compare it with our pg implementation in our benchmark suite. Would be awesome if your client is much faster, then we could switch our orm postgres adapter to yours.

@erayhanoglu
Copy link
Member

It will be very nice to have a benchmark result. Don't forget that text columns (chars, varchars, json, jsonb etc.) will not make a difference, thus they are not binary. Binary data columns (number, date, blob etc) and binary column arrays will make sense. And testing memory usage benchmark would be perfect. Please contact me anytime if you need help.

@erayhanoglu
Copy link
Member

Thank you! I'll play around with your client in binary mode and compare it with our pg implementation in our benchmark suite. Would be awesome if your client is much faster, then we could switch our orm postgres adapter to yours.

Hi marcj. I'm curious if you were able to create a bechmark result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants