On Sat, 26 Jun 2021, Tom Lane wrote:
You probably would have better results from specifying the composite
type explicitly in the query:
PQexecParams("insert into sometable values($1::composite, ...);",
I gather from the complaint that you're currently doing something that
causes the Param to be typed as a generic "record", which is problematic
since the record's details are not available from anyplace. But if you
cast it directly to a named composite type, that should work.
If it still doesn't work, please provide a more concrete example.
Thanks, unfortunately adding the explicit cast doesn't help. I've
attached a minimal runnable example.
I am serializing as a generic record, so it occurs to me that another
solution would be to use the actual type of the composite in question.
(Though it also seems to me that my code should work as-is.) Is there a
way to discover the OID of a composite type? And is the wire format the
same as for a generic record?
-E
#include <libpq-fe.h>
#include <server/catalog/pg_type_d.h>
#include <assert.h>
#include <unistd.h>
#define check(r) do { \
PGresult *res = r; \
if (PQresultStatus(res) == PGRES_NONFATAL_ERROR \
|| PQresultStatus(res) == PGRES_FATAL_ERROR) { \
puts(PQresultErrorMessage(res)); \
} \
} while (0)
int main() {
PGconn *c = PQconnectStart("postgresql://test:test@localhost/test");
assert(c);
for (int tries = 0; PQconnectPoll(c) != CONNECTION_MADE && tries < 10;
tries++)
usleep(100000);
assert(PQconnectPoll(c) == CONNECTION_MADE);
check(PQexec(c, "CREATE TYPE some_record AS (x int);"));
check(PQexec(c, "CREATE TABLE tab (rec some_record, bar int);"));
// ok:
check(PQexec(c, "INSERT INTO tab VALUES(ROW(7), 8);"));
char recbuf[4096], *rec = recbuf;
*(int*)rec = __builtin_bswap32(1), rec += 4; //# elements
*(int*)rec = __builtin_bswap32(INT4OID), rec += 4;
*(int*)rec = __builtin_bswap32(4), rec += 4; //n bytes in entry
*(int*)rec = __builtin_bswap32(7), rec += 4;
// error:
check(PQexecParams(c, "INSERT INTO tab VALUES($1, 8);",
1, &(Oid){RECORDOID}, &(const char*){recbuf},
&(int){rec - recbuf}, &(int){1/*binary*/},
1/*binary result*/));
// error as well:
check(PQexecParams(c, "INSERT INTO tab VALUES($1::some_record, 8);",
1, &(Oid){RECORDOID}, &(const char*){recbuf},
&(int){rec - recbuf}, &(int){1},
1));
PQfinish(c);
}