- Mailing list pgsql-bugs

From Ian Grant
Subject
Date
Msg-id E1329ve-0000DW-00@wisbech.cl.cam.ac.uk
Whole thread Raw
Responses Re: large object seek/write bug
List pgsql-bugs
Hi,

I sent this message to pgsql-bugs@postresql.org a couple of weeks ago and I
got an automated response from pgsql-bugs-owner@hub.org indicating that I'd
been subscribed to this list, but I've not seen any traffic from it all since
then.  Either there are really very few bugs in PostgreSQL (congratulations!)
or something is wrong with my subscription.  Any (non-automatic) feedback
would be welcomed.

Here's the message again:

I'm using V 7.0 on a Linux machine and I believe I have found a bug in the
large object interface provided by libpq.  The code below will reproduce it, I
hope.  Basically it creates a large object, writes six 'a' characters to it,
then closes it.  Then, in another transaction, it opens the object, seeks to
position 1 from the start, writes a 'b', then seeks to position 3 from the
start and writes another 'b'. Then it closes the object and COMMITs the
transaction.  Finally, in a further separate transaction, it calls lo_export
to write out the resulting object to a file testloseek.c.lobj  I find this
file, instead of containing the string 'ababaa' as expected, contains
'^@b^@baa' where ^@ is ASCII NUL.

Compile with something like

       gcc -o testloseek testloseek.c -lpq

The program sets the PQtrace to STDOUT and writes messages to STDERR, so run
it with STDOUT redirected to a log file.

This is a C version of a basic regression test of guile-pg, my Guile language
bindings for libpq.  You may recall I reported a similar bug a year or so ago,
and I believed it was then fixed by Tatsuo, after a couple of iterations.  I'm
sorry to be the bearer of bad news ...

Please reply to me directly since I'm not on the list.

Thanks
Ian

#include <stdio.h>
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"

void exec_cmd(PGconn *conn, char *str);

main (int argc, char *argv[])
{
   PGconn *conn;
   int lobj_fd;
   char buf[256];
   int ret, i;
   Oid lobj_id;

   conn = PQconnectdb("dbname=test");
   if (PQstatus(conn) != CONNECTION_OK) {
      fprintf(stderr, "Can't connect to backend.\n");
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   exec_cmd(conn, "BEGIN TRANSACTION");
   PQtrace (conn, stdout);
   if ((lobj_id = lo_creat(conn, INV_READ | INV_WRITE)) < 0) {
      fprintf(stderr, "Can't create lobj.\n");
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   fprintf(stderr, "lo_creat() returned OID %ld.\n", lobj_id);
   if ((lobj_fd = lo_open(conn, lobj_id, INV_READ | INV_WRITE)) < 0) {
      fprintf(stderr, "Can't open lobj.\n");
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   fprintf(stderr, "lo_open returned fd = %d.\n", lobj_fd);
   if ((ret = lo_write(conn, lobj_fd, "aaaaaa", 6)) != 6) {
      fprintf(stderr, "Can't write lobj.\n");
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   ret = lo_close(conn, lobj_fd);
   printf("lo_close returned %d.\n", ret);
   exec_cmd(conn, "END TRANSACTION");

   exec_cmd(conn, "BEGIN TRANSACTION");
   if ((lobj_fd = lo_open(conn, lobj_id, INV_READ | INV_WRITE)) < 0) {
      fprintf(stderr, "Can't open lobj.\n");
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   fprintf(stderr, "lo_open returned fd = %d.\n", lobj_fd);
   if (ret)
      fprintf(stderr, "Error message: %s\n", PQerrorMessage(conn));
   if ((ret = lo_lseek(conn, lobj_fd, 1, 0)) != 1) {
      fprintf(stderr, "error (%d) lseeking in large object.\n", ret);
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   if ((ret = lo_write(conn, lobj_fd, "b", 1)) != 1) {
      fprintf(stderr, "Can't write lobj.\n");
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   if ((ret = lo_lseek(conn, lobj_fd, 3, 0)) != 3) {
      fprintf(stderr, "error (%d) lseeking in large object.\n", ret);
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   if ((ret = lo_write(conn, lobj_fd, "b", 1)) != 1) {
      fprintf(stderr, "Can't write lobj.\n");
      fprintf(stderr, "ERROR: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   ret = lo_close(conn, lobj_fd);
   printf("lo_close returned %d.\n", ret);
   if (ret)
      fprintf(stderr, "Error message: %s\n", PQerrorMessage(conn));
   PQuntrace(conn);
   exec_cmd(conn, "END TRANSACTION");

   exec_cmd(conn, "BEGIN TRANSACTION");
   ret = lo_export(conn, lobj_id, "testloseek.c.lobj");
   printf("lo_export returned %d.\n", ret);
   if (ret != 1)
      fprintf(stderr, "Error message: %s\n", PQerrorMessage(conn));
   exec_cmd(conn, "END TRANSACTION");
   exit(0);
}

void exec_cmd(PGconn *conn, char *str)
{
   PGresult *res;

   if ((res = PQexec(conn, str)) == NULL) {
      fprintf(stderr, "Error executing %s.\n", str);
      fprintf(stderr, "Error message: %s\n", PQerrorMessage(conn));
      exit(1);
   }
   if (PQresultStatus(res) != PGRES_COMMAND_OK) {
      fprintf(stderr, "Error executing %s.\n", str);
      fprintf(stderr, "Error message: %s\n", PQerrorMessage(conn));
      PQclear(res);
      exit(1);
   }
   PQclear(res);
}

--
Ian Grant, Computer Lab., New Museums Site, Pembroke Street, Cambridge
Phone: +44 1223 334420          Personal e-mail: iang at pobox dot com

pgsql-bugs by date:

Previous
From: Tom Lane
Date:
Subject: Re: Problem with ecpg
Next
From: Travis Bauer
Date:
Subject: Re: foregein key