Thread: libpq-fe: how to determine unique collision ?
Hi, I am using libpq (with postgreSQL Version: 6.5.3-23 (Debian 2.2r2)). I have the following questions which, I am afraid, are not answered in the documentation: - how do you detect the error `Can't insert tuple because duplicate' ? - how do you get the OID of an insertion (the goal being to get the value for the SERIAL type, in order to do something with it) ? Thank you. Example: CREATE TABLE file (id SERIAL, creation_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, last_access_time TIMESTAMP, /* read some data */ file_name VARCHAR(100) NOT NULL, /* see servers_defs.h */ client_name VARCHAR(30) NOT NULL, /* from auth */ server_name VARCHAR(30) NOT NULL, /* from auth */ UNIQUE(client_name, server_name, file_name), UNIQUE(id), PRIMARY KEY(id)); #include "libpq-fe.h" #define BUFFER_LENGTH 1024 /* Is boundary-checked */ BOOL db_create_file_tuple(db_context_t context, const char *file_name, const char *client_name, const char *server_name, db_error_t *error) { char buffer[BUFFER_LENGTH]; BOOL result = FALSE; PGconn *conn = (PGconn *) context; *error = DB_ERROR_INTERNAL; if (snprintf(buffer, sizeof(buffer), "INSERT INTO file (file_name, client_name, server_name)" " VALUES('%s', '%s', '%s')", file_name, client_name, server_name) == -1) { *error = DB_ERROR_WOULD_OVERFLOW; } else { PGresult *res; /* BUGS * - Should protect or bind like in Perl. */ res = PQexec(conn, buffer); if (res && (PQresultStatus(res) == PGRES_COMMAND_OK)) { result = TRUE; *error = DB_ERROR_NONE; /* not really useful, shouldn't be read */ } else { debug_log(DEBUG_LEVEL_ERROR, "INSERT query failed: %s", PQerrorMessage(conn)); /* BUGS * - We are not sure this is it, but we can only guess * for now. */ *error = DB_ERROR_FILE_OBJECT_EXISTS; } PQclear(res); /* avoid memory leaks */ } return result; }
Marc SCHAEFER writes: > - how do you detect the error `Can't insert tuple because duplicate' ? if (strcmp(PQerrorMessage(conn), "ERROR: Can't insert tuple because duplicate") == 0) { panic(); } I know it's not ideal, but it's about the best you can do. > > - how do you get the OID of an insertion PQoidValue() > (the goal being to get > the value for the SERIAL type, in order to do something with it) ? Serial values and oids are not related. -- Peter Eisentraut peter_e@gmx.net http://yi.org/peter-e/
On Thu, 4 Jan 2001, Peter Eisentraut wrote: > > - how do you get the OID of an insertion > > PQoidValue() Thanks. > > (the goal being to get > > the value for the SERIAL type, in order to do something with it) ? > > Serial values and oids are not related. No, that right, but do you have a better way of doing the following ? :) INSERT INTO some_table(name, surname) VALUES('marc', 'moua'); -> creates OID 37492374 SELECT id FROM some_table WHERE oid = 37492374; assuming CREATE TABLE some_table(id SERIAL, name VARCHAR(8), surname VARCHAR(8), UNIQUE(id), PRIMARY KEY(id)); What the above does is basically retrieving the id that was created. Of course you could do: BEGIN TRANSACTION SELECT next_val('some_table_id_sequence'); INSERT INTO some_table(id, name, surname) VALUES(current_val('some_table_id_sequence'), 'marc', 'moua'); END TRANSACTION Which one do you recommend, are they really equivalent, and do you have a better way ? (hint: name and surname are not unique). thank you (and, PostgreSQL is great!).
Marc SCHAEFER <schaefer@alphanet.ch> writes: > No, that right, but do you have a better way of doing the following ? :) > INSERT INTO some_table(name, surname) VALUES('marc', 'moua'); > -> creates OID 37492374 > SELECT id FROM some_table WHERE oid = 37492374; This select will get pretty slow as the table gets large, unless you make an index on its OID. Which you could do, but why pay the price of maintaining an index just for this? > Of course you could do: > BEGIN TRANSACTION > SELECT next_val('some_table_id_sequence'); > INSERT INTO some_table(id, name, surname) > VALUES(current_val('some_table_id_sequence'), 'marc', 'moua'); > END TRANSACTION This is the Right Way To Do It. You do not need the transaction (because currval() is backend-private anyway). I'd not bother with currval() at all, but just do SELECT nextval('some_table_id_sequence'); -- this returns 4242, say INSERT INTO some_table(id, name, surname) VALUES(4242, 'marc', 'moua'); Simple, reliable, fast. regards, tom lane