Skip site navigation (1) Skip section navigation (2)

Bug in libpq large-object interface

From: Ian Grant <Ian(dot)Grant(at)cl(dot)cam(dot)ac(dot)uk>
To: pgsql-bugs(at)postgresql(dot)org
Cc: t-ishii(at)sra(dot)co(dot)jp, Ian(dot)Grant(at)cl(dot)cam(dot)ac(dot)uk
Subject: Bug in libpq large-object interface
Date: 2000-05-29 16:01:53
Message-ID: E12wRzG-00011A-00@wisbech.cl.cam.ac.uk (view raw or flat)
Thread:
Lists: pgsql-bugs
Uh ... I forgot to send the code I referred to.  Here it is again:

Hi PostgreSQL people in general and Tatsuo in particular,

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 
'^(at)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

Next:From: Olivier JeannetDate: 2000-05-29 19:46:40
Subject: pg_dumpall's output not totally usable
Previous:From: Ian GrantDate: 2000-05-29 15:48:40
Subject: Bug in libpq large-object interface

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group