question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Low-level prepared statements API (PQprepare, PQdescribePrepared)

See original GitHub issue

From the docs it looks like prepared statements can only be created and then immediately executed.

I want to create a prepared statement without executing it, and I also need the equivalent of PQdescribePrepared

I am trying to do something similar to the \gdesc command of psql: https://github.com/postgres/postgres/blob/e24a815c1c8550fcba5cc5aeb0d130db46570872/src/bin/psql/common.c#L1569

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
benny-medflytcommented, Aug 13, 2019

Thanks. I’ve had some time to look at all this, and I’ve made some progress.

I will share some code I was able to come up with.

Here is a function to create a prepared statement (without executing it):

/**
 * Submits a request to create a prepared statement
 *
 * See:
 * <https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE>
 *
 * @param {pg.Client} client
 * @param {string} name
 * @param {string} text
 * @param {Function} cb
 */
function pgPrepareQuery(client, name, text, cb) {
    const PrepareQuery = function () {
        pg.Query.call(this, {});
    }

    PrepareQuery.prototype = Object.create(pg.Query.prototype);
    PrepareQuery.prototype.constructor = PrepareQuery;

    PrepareQuery.prototype.submit = function (connection) {
        connection.parse({
            name: name,
            text: text,
            types: []
        }, false);

        connection.sync();
    }

    client.query(new PrepareQuery(), cb);
}

The “describe prepared” is more difficult, because Connection.prototype.parseMessage is missing a case for the ‘t’ (0x74 ParameterDescription).

What I have chosen to do for now is to monkey patch this function, so that it just ignores that message:

/**
 * Patches the connection object so that it won't crash when it receives a
 * `ParameterDescription (B)` message from the backend. (The message will be
 * ignored)
 */
function pgMonkeyPatchConnection(connection) {
    const origParseMessage = connection.parseMessage;
    connection.parseMessage = function (buffer) {
        if (this._reader.header == 0x74) { // 't'
            this.offset = 0
            var length = buffer.length + 4

            return {
                name: 'parameterDescription',
                length: length
            };
        } else {
            return origParseMessage.call(this, buffer);
        }
    }
}

After a connection has been monkey-patched, we can issue a “describe prepared” statement. Here is a function that does it:

/**
 * Submits a request to obtain information about the specified prepared
 * statement
 *
 * See:
 * <https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED>
 *
 * @param {pg.Client} client
 * @param {string} name
 * @param {Function} cb The result may be `null` if the prepared statement
 * returns no results (for example an INSERT statement)
 */
function pgDescribePrepared(client, name, cb) {
    var rowDescription = null;

    const DescribePrepared = function () {
        pg.Query.call(this, {
        }, function (err) {
            if (err) {
                cb(err);
                return;
            }
            cb(null, rowDescription);
        });
    }

    DescribePrepared.prototype = Object.create(pg.Query.prototype);
    DescribePrepared.prototype.constructor = DescribePrepared;

    DescribePrepared.prototype.submit = function (connection) {
        connection.describe({
            type: 'S',
            name: name
        });

        connection.sync();
    }

    DescribePrepared.prototype.handleRowDescription = function (msg) {
        rowDescription = msg;
    };

    client.query(new DescribePrepared());
}

This will successfully provide the information about the result columns of the prepared statement. Unfortunately, because we are ignoring the “ParameterDescription” message from the backend, we don’t get the info about the parameters of the prepared statement. Adding code to parse the “ParameterDescription” message (instead of ignoring it) should not be too difficult.

For now, this code is working for my needs. It would be great if the functionality could be added to this library, but I am still a bit confused as to how best to add it.

0reactions
abenhamdinecommented, Feb 20, 2022

if someone plans to work on this, IMHO it would be relevant to add feature to release prepared statements as well, see https://github.com/brianc/node-postgres/issues/1889

Read more comments on GitHub >

github_iconTop Results From Across the Web

15: 34.3. Command Execution Functions - PostgreSQL
PQprepare creates a prepared statement for later execution with PQexecPrepared . This feature allows commands to be executed repeatedly without being parsed ...
Read more >
6.1 Overview of the C API Prepared Statement Interface
To prepare the statement on the server, call mysql_stmt_prepare() and pass it a string containing the SQL statement. Set the values of any...
Read more >
Why use prepared statements instead of Query / Exec with go ...
Prepared statement already bound to concrete connection to DB, contains low-level driver.Stmt and can be used concurrently by multiple go-routings.
Read more >
Data Retrieval And Manipulation - Doctrine
PHP has a generic abstraction layer for this kind of API called PDO ... Prepared statements separate these two concepts by requiring the ......
Read more >
(The only proper) PDO tutorial - Treating PHP Delusions
Unlike mysql and mysqli, both of which are low level bare APIs not intended ... For all other cases you cannot use PDO...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found