Thread: pqlib large object error

pqlib large object error

From
Edward Amsden
Date:
I am writing some proof-of-concept code for a project which involves
using PostgreSQL's large object facility to store audio data. Currently,
the goal for this code is to test the performance of reading audio data
from a file and writing it to a large object. I am learning as I go, but
I cannot seem to figure this error message out:

ERROR:  duplicate key value violates unique constraint "pg_largeobject_loid_pn_index"

I am using the following code to create the large object:    lo_1 =  lo_creat(connect1, INV_READ|INV_WRITE);    if
(lo_1> 0) {        ... (open and write)    } else {        fprintf (stderr, "Unable to create large object: %s\n",
PQerrorMessage(connect1));   }
 

where connect1 is the pointer to my connection. Why is there a duplicate key if lo_creat() is supposed to assign an
unusedOID?
 

Thanks,
Edward



Re: pqlib large object error

From
Tom Lane
Date:
Edward Amsden <amsden_linux@embarqmail.com> writes:
> I cannot seem to figure this error message out:

> ERROR:  duplicate key value violates unique constraint "pg_largeobject_loid_pn_index"

Huh, that shouldn't happen.  Is it repeatable?  What PG version
is your server?
        regards, tom lane


Re: pqlib large object error

From
Edward Amsden
Date:
On Tue, 2008-06-10 at 14:29 -0400, Tom Lane wrote:
> Edward Amsden <amsden_linux@embarqmail.com> writes:
> > I cannot seem to figure this error message out:
> 
> > ERROR:  duplicate key value violates unique constraint "pg_largeobject_loid_pn_index"
> 
> Huh, that shouldn't happen.  Is it repeatable?
Yes. It happens every time the program runs, no matter what db or user,
tried unix socket and tcp connect
>   What PG version
> is your server?
8.3.1, running on Ubuntu Linux
> 
>             regards, tom lane



Re: pqlib large object error

From
Tom Lane
Date:
Edward Amsden <amsden_linux@embarqmail.com> writes:
> On Tue, 2008-06-10 at 14:29 -0400, Tom Lane wrote:
>> Edward Amsden <amsden_linux@embarqmail.com> writes:
>>> I cannot seem to figure this error message out:
>>> 
>>> ERROR:  duplicate key value violates unique constraint "pg_largeobject_loid_pn_index"
>> 
>> Huh, that shouldn't happen.  Is it repeatable?

> Yes. It happens every time the program runs, no matter what db or user,
> tried unix socket and tcp connect

>> What PG version
>> is your server?

> 8.3.1, running on Ubuntu Linux

Hmph.  The only thing I can think of is that that index is corrupt,
but it seems unlikely that it would be so in all databases.  What
happens if you REINDEX pg_largeobject?
        regards, tom lane


Re: pqlib large object error

From
Tom Lane
Date:
Edward Amsden <amsden_linux@embarqmail.com> writes:
> I am using the following code to create the large object:
>         lo_1 =  lo_creat(connect1, INV_READ|INV_WRITE);
>         if (lo_1 > 0) {
>             ... (open and write)
>         } else {
>             fprintf (stderr, "Unable to create large object: %s\n", PQerrorMessage(connect1));
>         }

BTW, what type do you have lo_1 declared as?  It strikes me that if it's
signed int32, and your OID counter is past 2 billion, this code would
fail because it would misinterpret a valid OID as negative.  The printf
would then report whatever the last error on the connection had been.
This still wouldn't explain why you're getting the duplicate-key error,
but it might at least point to the proper place to look.
        regards, tom lane


Re: pqlib large object error

From
Edward Amsden
Date:
On Tue, 2008-06-10 at 17:06 -0400, Tom Lane wrote:
> Edward Amsden <amsden_linux@embarqmail.com> writes:
> > I am using the following code to create the large object:
> >         lo_1 =  lo_creat(connect1, INV_READ|INV_WRITE);
> >         if (lo_1 > 0) {
> >             ... (open and write)
> >         } else {
> >             fprintf (stderr, "Unable to create large object: %s\n", PQerrorMessage(connect1));
> >         }
> 
> BTW, what type do you have lo_1 declared as?  It strikes me that if it's
> signed int32, and your OID counter is past 2 billion, this code would
> fail because it would misinterpret a valid OID as negative.  The printf
> would then report whatever the last error on the connection had been.
> This still wouldn't explain why you're getting the duplicate-key error,
> but it might at least point to the proper place to look.
> 
It is defined as the Oid type from pqlib-fs.h
>             regards, tom lane



Re: pqlib large object error

From
Tom Lane
Date:
Edward Amsden <amsden_linux@embarqmail.com> writes:
> On Tue, 2008-06-10 at 17:06 -0400, Tom Lane wrote:
>> BTW, what type do you have lo_1 declared as?

> It is defined as the Oid type from pqlib-fs.h

OK, scratch that theory then.  Did you have any success with reindexing?
        regards, tom lane


Re: pqlib large object error

From
Edward Amsden
Date:
On Tue, 2008-06-10 at 16:49 -0400, Tom Lane wrote:
> Edward Amsden <amsden_linux@embarqmail.com> writes:
> > On Tue, 2008-06-10 at 14:29 -0400, Tom Lane wrote:
> >> Edward Amsden <amsden_linux@embarqmail.com> writes:
> >>> I cannot seem to figure this error message out:
> >>> 
> >>> ERROR:  duplicate key value violates unique constraint "pg_largeobject_loid_pn_index"
> >> 
> >> Huh, that shouldn't happen.  Is it repeatable?
> 
> > Yes. It happens every time the program runs, no matter what db or user,
> > tried unix socket and tcp connect
> 
> >> What PG version
> >> is your server?
> 
> > 8.3.1, running on Ubuntu Linux
> 
> Hmph.  The only thing I can think of is that that index is corrupt,
> but it seems unlikely that it would be so in all databases.  What
> happens if you REINDEX pg_largeobject?
The error has disappeared. Now it can't write to the object. lo_open
seems to be successful, but lo_write is failing with:
> ERROR:  invalid large-object descriptor: 0
0 is a valid value (I checked) but it appears it cannot write to the object. lo_open should return a negative value if
itcannot create the handle
 

Here is my code:


if (PQstatus(connect1) == CONNECTION_OK) {    lo_1 =  lo_creat(connect1, INV_READ|INV_WRITE);    if (lo_1 > 0) {
lo_1_fd= lo_open(connect1, lo_1, INV_READ|INV_WRITE);        written = lo_write(connect1, lo_1_fd, filedata, (size_t)
filelen);       if (written == filelen) {            printf ("Write successful, %d bytes written.\n", written);
}else if (written < 0) {            printf ("Write unsuccessful: %s\n", PQerrorMessage(connect1));        } else {
     printf ("Write partially successful. %d of %d bytes written.\n",
 
written, filelen);        }    } else {        fprintf (stderr, "Unable to create large object: %s\n",
PQerrorMessage(connect1));    }} else {    fprintf (stderr, "Unable to open connection: %s\n",
PQerrorMessage(connect1));}

Let me know if it's unreadable, my mail client can do funny things with
indents.

>             regards, tom lane



Re: pqlib large object error

From
Tom Lane
Date:
Edward Amsden <amsden_linux@embarqmail.com> writes:
> On Tue, 2008-06-10 at 16:49 -0400, Tom Lane wrote:
>> Hmph.  The only thing I can think of is that that index is corrupt,
>> but it seems unlikely that it would be so in all databases.  What
>> happens if you REINDEX pg_largeobject?

> The error has disappeared.

Hmm, so something did happen to your index.

> Now it can't write to the object. lo_open
> seems to be successful, but lo_write is failing with:
>> ERROR:  invalid large-object descriptor: 0

You forgot to put the open-and-use-descriptor sequence inside a 
BEGIN block.
        regards, tom lane


Re: pqlib large object error

From
Edward Amsden
Date:
Thanks for all your help. I'm somewhat amateur with C and even less
experienced with PostgreSQL (I'm a recent MySQL convert). Even after
some googling, I have no idea what this BEGIN block is. Is it C or is it
SQL? That probably makes me a n00b. :-| If you could explain I'd
appreciate it :-)

BTW once I get this working I'm going to write a PostgreSQL Large Object
tutorial on my blog, so others don't have to struggle with the code like
I am :-)
On Tue, 2008-06-10 at 19:05 -0400, Tom Lane wrote:
> Edward Amsden <amsden_linux@embarqmail.com> writes:
> > On Tue, 2008-06-10 at 16:49 -0400, Tom Lane wrote:
> >> Hmph.  The only thing I can think of is that that index is corrupt,
> >> but it seems unlikely that it would be so in all databases.  What
> >> happens if you REINDEX pg_largeobject?
> 
> > The error has disappeared.
> 
> Hmm, so something did happen to your index.
> 
> > Now it can't write to the object. lo_open
> > seems to be successful, but lo_write is failing with:
> >> ERROR:  invalid large-object descriptor: 0
> 
> You forgot to put the open-and-use-descriptor sequence inside a 
> BEGIN block.
> 
>             regards, tom lane



Re: pqlib large object error

From
Tom Lane
Date:
Edward Amsden <amsden_linux@embarqmail.com> writes:
> Thanks for all your help. I'm somewhat amateur with C and even less
> experienced with PostgreSQL (I'm a recent MySQL convert). Even after
> some googling, I have no idea what this BEGIN block is. Is it C or is it
> SQL? That probably makes me a n00b. :-|

You need a SQL "BEGIN" (or "START TRANSACTION") command and a SQL
"COMMIT" (or "END") command around anything that involves having a
large object descriptor open.  It might help to look at the sample
program here:

http://www.postgresql.org/docs/8.3/static/lo-examplesect.html

It's not amazingly well commented :-(, but the lines
res = PQexec(conn, "begin");res = PQexec(conn, "end");

are *not* optional.

Meanwhile, I'm still wondering what happened to your pg_largeobject
index.  You said you saw the problem in multiple databases, which
suggests that the index was broken in template1 and then the damage
was propagated to other databases by CREATE DATABASE.  Can you still
see a problem if you make your program connect to some other database?
        regards, tom lane


Re: pqlib large object error

From
Edward Amsden
Date:
On Tue, 2008-06-10 at 21:24 -0400, Tom Lane wrote:
> Edward Amsden <amsden_linux@embarqmail.com> writes:
> > Thanks for all your help. I'm somewhat amateur with C and even less
> > experienced with PostgreSQL (I'm a recent MySQL convert). Even after
> > some googling, I have no idea what this BEGIN block is. Is it C or is it
> > SQL? That probably makes me a n00b. :-|
> 
> You need a SQL "BEGIN" (or "START TRANSACTION") command and a SQL
> "COMMIT" (or "END") command around anything that involves having a
> large object descriptor open.  It might help to look at the sample
> program here:
> 
> http://www.postgresql.org/docs/8.3/static/lo-examplesect.html
> 
> It's not amazingly well commented :-(, but the lines
> 
>     res = PQexec(conn, "begin");
>     res = PQexec(conn, "end");
> 
> are *not* optional.
Thanks for your help with this.    I successfully wrote about 7MB in and
read it back out :-)
> 
> Meanwhile, I'm still wondering what happened to your pg_largeobject
> index.  You said you saw the problem in multiple databases, which
> suggests that the index was broken in template1 and then the damage
> was propagated to other databases by CREATE DATABASE.  Can you still
> see a problem if you make your program connect to some other database?
There is no issue with other databases. I created another database, and
had no issues.

It is my understanding that it shouldn't be database-dependent, since
the only part of large objects that is stored outside of the postgres
database is references to the large object OIDs.

Again, thanks for your help. Let me know if I should check on anything
else regarding the index corruption.

Also, I will post a link to the tutorial in my blog as a reply to this
thread as soon as the blog post is up.

Edward



Re: pqlib large object error

From
Alvaro Herrera
Date:
Edward Amsden wrote:
> Thanks for all your help. I'm somewhat amateur with C and even less
> experienced with PostgreSQL (I'm a recent MySQL convert). Even after
> some googling, I have no idea what this BEGIN block is. Is it C or is it
> SQL? That probably makes me a n00b. :-| If you could explain I'd
> appreciate it :-)

PQexec("BEGIN");
... do some fooling with large objects ...
PQexec("COMMIT");



-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support