Обсуждение: Error in PQsetvalue

Поиск
Список
Период
Сортировка

Error in PQsetvalue

От
Pavel Golub
Дата:
Hello.

Reproduced under Windows XP SP3 using Visual C++ 2008 and Delphi. If
PQsetvalue is called with second parameter equals to PQntuples then
memory corruption appears. But it should grow internal tuples array
and populate the last item with provided data. Please see the code:


#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"
#pragma comment(lib,"libpq.lib")

static void
exit_nicely(PGconn *conn)
{   PQfinish(conn);   exit(1);
}

int
main(int argc, char **argv)
{   const char *conninfo;   PGconn     *conn;   PGresult   *res;   if (argc > 1)       conninfo = argv[1];   else
conninfo= "dbname = postgres user = postgres password = password";
 
   conn = PQconnectdb(conninfo);
   if (PQstatus(conn) != CONNECTION_OK)   {fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
    exit_nicely(conn);   }
 
  res = PQexec(conn, "SELECT generate_series(1, 10)");
  if (!PQsetvalue(res, PQntuples(res), 0, "1", 1))   /* <----- here
we have memory corruption */{    fprintf(stderr, "Shit happens: %s", PQerrorMessage(conn));    exit_nicely(conn);}
   PQclear(res);   PQfinish(conn);   return 0;
}

BUT! If we change direct call to:

...       res = PQexec(conn, "SELECT generate_series(1, 10)");
res2 = PQcopyResult(res, PG_COPYRES_TUPLES);
if (!PQsetvalue(res2, PQntuples(res), 0, "1", 1)){    fprintf(stderr, "Shit happens: %s", PQerrorMessage(conn));
exit_nicely(conn);}
...
then all is OK!

As you can see, I copied result first. No error occurs.
Can anybody check this on other platforms?
-- 
Nullus est in vitae sensus ipsa vera est sensus.


Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
On 6/3/2011 3:03 PM, Pavel Golub wrote:
> Hello.
>
> Reproduced under Windows XP SP3 using Visual C++ 2008 and Delphi. If
> PQsetvalue is called with second parameter equals to PQntuples then
> memory corruption appears. But it should grow internal tuples array
> and populate the last item with provided data. Please see the code:
>
>

At first glance (have not tested this theory), looks like pqAddTuple() 
doesn't zero the newly allocated tuples slots like PQsetvalue() does. 
PQsetvalue is depending on the unassigned tuple table slots to be NULL 
to detect when a tuple must be allocated.  Around line 446 on fe-exec.c.  I never tested this case since libpqtypes
nevertried to call 
 
PQsetvalue on a PGresult created by the standard libpq library.

The solution I see would be to zero the new table slots within 
pqAddTuple.  Any other ideas?

-- 
Andrew Chernow
eSilo, LLC
global backup
http://www.esilo.com/


Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Fri, Jun 3, 2011 at 2:03 PM, Pavel Golub <pavel@microolap.com> wrote:
> Hello.
>
> Reproduced under Windows XP SP3 using Visual C++ 2008 and Delphi. If
> PQsetvalue is called with second parameter equals to PQntuples then
> memory corruption appears. But it should grow internal tuples array
> and populate the last item with provided data. Please see the code:
>
>
> #include <stdio.h>
> #include <stdlib.h>
> #include "libpq-fe.h"
> #pragma comment(lib,"libpq.lib")
>
> static void
> exit_nicely(PGconn *conn)
> {
>    PQfinish(conn);
>    exit(1);
> }
>
> int
> main(int argc, char **argv)
> {
>    const char *conninfo;
>    PGconn     *conn;
>    PGresult   *res;
>    if (argc > 1)
>        conninfo = argv[1];
>    else
>        conninfo = "dbname = postgres user = postgres password = password";
>
>    conn = PQconnectdb(conninfo);
>
>    if (PQstatus(conn) != CONNECTION_OK)
>    {
>        fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
>        exit_nicely(conn);
>    }
>
>   res = PQexec(conn, "SELECT generate_series(1, 10)");
>
>   if (!PQsetvalue(res, PQntuples(res), 0, "1", 1))   /* <----- here
> we have memory corruption */

hm, what are the exact symptoms you see that is causing you to think
you are having memory corruption? (your example is working for me).

merlin


Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Fri, Jun 3, 2011 at 3:06 PM, Andrew Chernow <ac@esilo.com> wrote:
> On 6/3/2011 3:03 PM, Pavel Golub wrote:
>>
>> Hello.
>>
>> Reproduced under Windows XP SP3 using Visual C++ 2008 and Delphi. If
>> PQsetvalue is called with second parameter equals to PQntuples then
>> memory corruption appears. But it should grow internal tuples array
>> and populate the last item with provided data. Please see the code:
>>
>>
>
> At first glance (have not tested this theory), looks like pqAddTuple()
> doesn't zero the newly allocated tuples slots like PQsetvalue() does.
> PQsetvalue is depending on the unassigned tuple table slots to be NULL to
> detect when a tuple must be allocated.  Around line 446 on fe-exec.c.  I
> never tested this case since libpqtypes never tried to call PQsetvalue on a
> PGresult created by the standard libpq library.
>
> The solution I see would be to zero the new table slots within pqAddTuple.
>  Any other ideas?

It might not be necessary to do that.  AIUI the tuple table slot guard
is there essentially to let setval know if it needs to allocate tuple
attributes, which always has to be done after a new tuple is created
after a set.  It should be enough to keep track of the 'allocation
tuple' as an int (which is incremented after attributes are allocated
for the new tuple).  so if tup# is same is allocation tuple, allocate
the atts and increment the number, otherwise just do a straight 'set'.Basically we are taking advantage of the fact
onlyone tuple can be 
allocated at a time, and it always has to be the next one after the
current set.

merlin


Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
On 6/3/2011 4:06 PM, Andrew Chernow wrote:
> On 6/3/2011 3:03 PM, Pavel Golub wrote:
>> Hello.
>>
>> Reproduced under Windows XP SP3 using Visual C++ 2008 and Delphi. If
>> PQsetvalue is called with second parameter equals to PQntuples then
>> memory corruption appears. But it should grow internal tuples array
>> and populate the last item with provided data. Please see the code:
>>
>>
>
> At first glance (have not tested this theory), looks like pqAddTuple()
> doesn't zero the newly allocated tuples slots like PQsetvalue() does.
> PQsetvalue is depending on the unassigned tuple table slots to be NULL
> to detect when a tuple must be allocated. Around line 446 on fe-exec.c.
> I never tested this case since libpqtypes never tried to call PQsetvalue
> on a PGresult created by the standard libpq library.
>
> The solution I see would be to zero the new table slots within
> pqAddTuple. Any other ideas?
>

Eeekks.  Found an additional bug.  PQsetvalue only allocates the actual 
tuple if the provided tup_num equals the number of tuples (append) and 
that slot is NULL.  This is wrong.  The original idea behind PQsetvalue 
was you can add tuples in any order and overwrite existing ones.

Also, doing res->ntups++ whenever a tuple is allocated is incorrect as 
well; since we may first add tuple 3.  In that case, if ntups is 
currently <= 3 we need to set it to 3+1, otherwise do nothing.  In other 
words, while adding tuples via PQsetvalue the ntups should always be 
equal to (max_supplied_tup_num + 1) with all unset slots being NULL.

PQsetvalue(res, 3, 0, "x", 1); // currently sets res->ntups to 1
PQsetvalue(res, 2, 0, "x", 1); // as code is now, this returns FALSE due 
to bounds checking

-- 
Andrew Chernow
eSilo, LLC
global backup
http://www.esilo.com/


Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
>>
>> At first glance (have not tested this theory), looks like pqAddTuple()
>> doesn't zero the newly allocated tuples slots like PQsetvalue() does.
>> PQsetvalue is depending on the unassigned tuple table slots to be NULL to
>> detect when a tuple must be allocated.  Around line 446 on fe-exec.c.  I
>> never tested this case since libpqtypes never tried to call PQsetvalue on a
>> PGresult created by the standard libpq library.
>>
>> The solution I see would be to zero the new table slots within pqAddTuple.
>>   Any other ideas?
>
> It might not be necessary to do that.  AIUI the tuple table slot guard
> is there essentially to let setval know if it needs to allocate tuple
> attributes, which always has to be done after a new tuple is created
> after a set.

Trying to append a tuple to a libpq generated PGresult will core dump 
due to the pqAddTuple issue, unless the append operation forces 
PQsetvalue to grow the tuple table; in which case new elements are 
zero'd.  OP attempted to append.

res = PQexec("returns 2 tuples");
PQsetvalue(res, PQntuples(res), ...);

-- 
Andrew Chernow
eSilo, LLC
global backup
http://www.esilo.com/


Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Fri, Jun 3, 2011 at 3:38 PM, Andrew Chernow <ac@esilo.com> wrote:

> Eeekks.  Found an additional bug.  PQsetvalue only allocates the actual
> tuple if the provided tup_num equals the number of tuples (append) and that
> slot is NULL.  This is wrong.  The original idea behind PQsetvalue was you
> can add tuples in any order and overwrite existing ones.

That was by design -- you are only supposed to be able to add a tuple
if you pass in exactly the insertion position (which is the same as
PQntuples()).  If you pass less than that, you will overwrite the
value at that position.  If you pass greater, you should get an error.This is also how the function is documented.
That'swhy you don't 
have to zero out the tuple slots at all -- the insertion position is
always known and you just need to make sure the tuple atts are not
allocated more than one time per inserted tuple.  Meaning, PQsetvalue
needs to work more like pqAddTuple (and the insertion code should
probably be abstracted).

merlin


Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
On 6/3/2011 5:54 PM, Merlin Moncure wrote:
> On Fri, Jun 3, 2011 at 3:38 PM, Andrew Chernow<ac@esilo.com>  wrote:
>
>> Eeekks.  Found an additional bug.  PQsetvalue only allocates the actual
>> tuple if the provided tup_num equals the number of tuples (append) and that
>> slot is NULL.  This is wrong.  The original idea behind PQsetvalue was you
>> can add tuples in any order and overwrite existing ones.
>
> That was by design -- you are only supposed to be able to add a tuple
> if you pass in exactly the insertion position (which is the same as
> PQntuples()).  If you pass less than that, you will overwrite the
> value at that position.  If you pass greater, you should get an error.

Actually, the original idea, as I stated UT, was to allow adding tuples 
in any order as well as overwriting them.  Obviously lost that while 
trying to get libpqtypes working, which only appends.

>   This is also how the function is documented.  That's why you don't
> have to zero out the tuple slots at all -- the insertion position is
> always known and you just need to make sure the tuple atts are not
> allocated more than one time per inserted tuple.  Meaning, PQsetvalue
> needs to work more like pqAddTuple (and the insertion code should
> probably be abstracted).
>

You need to have insertion point zero'd in either case.  Look at the 
code.  It only allocates when appending *AND* the tuple at that index is 
NULL.  If pqAddTuple allocated the table, the tuple slots are 
uninitialized memory, thus it is very unlikely that the next tuple slot 
is NULL.

It is trivial to make this work the way it was initially intended (which 
mimics PQgetvalue in that you can fetch values in any order, that was 
the goal).  Are there any preferences?  I plan to supply a patch that 
allows setting values in any order as well as overwriting unless someone 
speaks up.  I fix the docs as well.

-- 
Andrew Chernow
eSilo, LLC
global backup
http://www.esilo.com/


Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Fri, Jun 3, 2011 at 6:22 PM, Andrew Chernow <ac@esilo.com> wrote:
> Actually, the original idea, as I stated UT, was to allow adding tuples in
> any order as well as overwriting them.  Obviously lost that while trying to
> get libpqtypes working, which only appends.

Well, that may or not be the case, but that's irrelevant.  This has to
be backpatched to 9.0 and we can't use a bug to sneak in a behavior
change...regardless of what's done, it has to work as documented --
the current behavior isn't broken.  If we want PQsetvalue to support
creating tuples past the insertion point, that should be proposed for
9.2.

> You need to have insertion point zero'd in either case.  Look at the code.
>  It only allocates when appending *AND* the tuple at that index is NULL.  If
> pqAddTuple allocated the table, the tuple slots are uninitialized memory,
> thus it is very unlikely that the next tuple slot is NULL.

I disagree -- I think the fix is a one-liner.  line 446:
if (tup_num == res->ntups && !res->tuples[tup_num])

should just become
if (tup_num == res->ntups)

also the memset of the tuple slots when the slot array is expanded can
be removed. (in addition, the array tuple array expansion should
really be abstracted, but that isn't strictly necessary here).

merlin


Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
On 6/3/2011 7:14 PM, Merlin Moncure wrote:
> On Fri, Jun 3, 2011 at 6:22 PM, Andrew Chernow<ac@esilo.com>  wrote:
>> Actually, the original idea, as I stated UT, was to allow adding tuples in
>> any order as well as overwriting them.  Obviously lost that while trying to
>> get libpqtypes working, which only appends.
>
> Well, that may or not be the case, but that's irrelevant.  This has to
> be backpatched to 9.0 and we can't use a bug to sneak in a behavior
> change...regardless of what's done, it has to work as documented --
> the current behavior isn't broken.  If we want PQsetvalue to support
> creating tuples past the insertion point, that should be proposed for
> 9.2.
>

Well, not really irrelevant since understanding the rationale behind changes is 
important.  I actually reversed my opinion on this and was preparing a patch 
that simply did a memset in pqAddTuple.  See below for why....

>> You need to have insertion point zero'd in either case.  Look at the code.
>>   It only allocates when appending *AND* the tuple at that index is NULL.  If
>> pqAddTuple allocated the table, the tuple slots are uninitialized memory,
>> thus it is very unlikely that the next tuple slot is NULL.
>
> I disagree -- I think the fix is a one-liner.  line 446:
> if (tup_num == res->ntups&&  !res->tuples[tup_num])
>
> should just become
> if (tup_num == res->ntups)
>
> also the memset of the tuple slots when the slot array is expanded can
> be removed. (in addition, the array tuple array expansion should
> really be abstracted, but that isn't strictly necessary here).
>

All true.  This is a cleaner fix to something that was in fact broken ;)  You 
want to apply it?

The fact that the tuples were being zero'd plus the NULL check is evidence of 
the original intent; which is what confused me.  I found internal libpqtypes 
notes related to this change, it actually had to do with producing a result with 
dead tuples that would cause PQgetvalue and others to crash.  Thus, it seemed 
better to only allow creating a result that is always *valid*.

-- 
Andrew Chernow
eSilo, LLC
every bit counts
http://www.esilo.com/


Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
>> I disagree -- I think the fix is a one-liner. line 446:
>> if (tup_num == res->ntups&& !res->tuples[tup_num])
>>
>> should just become
>> if (tup_num == res->ntups)
>>
>> also the memset of the tuple slots when the slot array is expanded can
>> be removed. (in addition, the array tuple array expansion should
>> really be abstracted, but that isn't strictly necessary here).
>>
>
> All true. This is a cleaner fix to something that was in fact broken ;) You want

Attached a patch that fixes the OP's issue.  PQsetvalue now uses pqAddTuple to
grow the tuple table and has removed the remnants of an older idea that caused
the bug.

--
Andrew Chernow
eSilo, LLC
every bit counts
http://www.esilo.com/

Вложения

Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
On 6/3/2011 10:26 PM, Andrew Chernow wrote:
>
>>> I disagree -- I think the fix is a one-liner. line 446:
>>> if (tup_num == res->ntups&& !res->tuples[tup_num])
>>>
>>> should just become
>>> if (tup_num == res->ntups)
>>>
>>> also the memset of the tuple slots when the slot array is expanded can
>>> be removed. (in addition, the array tuple array expansion should
>>> really be abstracted, but that isn't strictly necessary here).
>>>
>>
>> All true. This is a cleaner fix to something that was in fact broken ;) You want
>
> Attached a patch that fixes the OP's issue. PQsetvalue now uses pqAddTuple to
> grow the tuple table and has removed the remnants of an older idea that caused
> the bug.
>

Sorry, I attached the wrong patch.  Here is the correct one.

--
Andrew Chernow
eSilo, LLC
every bit counts
http://www.esilo.com/

Вложения

Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Fri, Jun 3, 2011 at 10:36 PM, Andrew Chernow <ac@esilo.com> wrote:
> On 6/3/2011 10:26 PM, Andrew Chernow wrote:
>>
>>>> I disagree -- I think the fix is a one-liner. line 446:
>>>> if (tup_num == res->ntups&& !res->tuples[tup_num])
>>>>
>>>> should just become
>>>> if (tup_num == res->ntups)
>>>>
>>>> also the memset of the tuple slots when the slot array is expanded can
>>>> be removed. (in addition, the array tuple array expansion should
>>>> really be abstracted, but that isn't strictly necessary here).
>>>>
>>>
>>> All true. This is a cleaner fix to something that was in fact broken ;)
>>> You want
>>
>> Attached a patch that fixes the OP's issue. PQsetvalue now uses pqAddTuple
>> to
>> grow the tuple table and has removed the remnants of an older idea that
>> caused
>> the bug.
>>
>
> Sorry, I attached the wrong patch.  Here is the correct one.


This looks good.  Pavel, want to test it?

merlin


Re: Error in PQsetvalue

От
Pavel Golub
Дата:
Hello, guys.

You wrote:

MM> On Fri, Jun 3, 2011 at 10:36 PM, Andrew Chernow <ac@esilo.com> wrote:
>> On 6/3/2011 10:26 PM, Andrew Chernow wrote:
>>>
>>>>> I disagree -- I think the fix is a one-liner. line 446:
>>>>> if (tup_num == res->ntups&& !res->tuples[tup_num])
>>>>>
>>>>> should just become
>>>>> if (tup_num == res->ntups)
>>>>>
>>>>> also the memset of the tuple slots when the slot array is expanded can
>>>>> be removed. (in addition, the array tuple array expansion should
>>>>> really be abstracted, but that isn't strictly necessary here).
>>>>>
>>>>
>>>> All true. This is a cleaner fix to something that was in fact broken ;)
>>>> You want
>>>
>>> Attached a patch that fixes the OP's issue. PQsetvalue now uses pqAddTuple
>>> to
>>> grow the tuple table and has removed the remnants of an older idea that
>>> caused
>>> the bug.
>>>
>>
>> Sorry, I attached the wrong patch.  Here is the correct one.


MM> This looks good.  Pavel, want to test it?

Sorry for delay in answer. Yeah, I'm glad to. Should I apply this
patch by myself?

MM> merlin



-- 
With best wishes,Pavel                          mailto:pavel@gf.microolap.com



Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Mon, Jun 6, 2011 at 7:09 AM, Pavel Golub <pavel@microolap.com> wrote:
> Sorry for delay in answer. Yeah, I'm glad to. Should I apply this
> patch by myself?

sure, run it against your test case and make sure it works. if so, we
can pass it up the chain of command (hopefully as context diff).

merlin


Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Mon, Jun 6, 2011 at 1:42 PM, Merlin Moncure <mmoncure@gmail.com> wrote:
> On Mon, Jun 6, 2011 at 7:09 AM, Pavel Golub <pavel@microolap.com> wrote:
>> Sorry for delay in answer. Yeah, I'm glad to. Should I apply this
>> patch by myself?
>
> sure, run it against your test case and make sure it works. if so, we
> can pass it up the chain of command (hopefully as context diff).

I went ahead and tested andrew's second patch -- can we get this
reviewed and committed?

merlin


Re: Error in PQsetvalue

От
Tom Lane
Дата:
Merlin Moncure <mmoncure@gmail.com> writes:
> I went ahead and tested andrew's second patch -- can we get this
> reviewed and committed?

Add it to the upcoming commitfest.
        regards, tom lane


Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Wed, Jun 8, 2011 at 10:18 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Merlin Moncure <mmoncure@gmail.com> writes:
>> I went ahead and tested andrew's second patch -- can we get this
>> reviewed and committed?
>
> Add it to the upcoming commitfest.

It's a client crashing bug in PQsetvalue that goes back to 9.0 :(.  In
short (apologies for the non-context diff), PQsetvalue was
inappropriately using libpq tuple slots as a check to see if it should
allocate the per row tuple datums, and borked when setting values on a
non copied result (libpqtypes always copies results) because the
regular pqAddTuple does not null out the slots like copy result does.
The whole mechanism was basically unnecessary, so it was removed,
fixing the bug.

merlin


Re: Error in PQsetvalue

От
Tom Lane
Дата:
Merlin Moncure <mmoncure@gmail.com> writes:
> On Wed, Jun 8, 2011 at 10:18 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Merlin Moncure <mmoncure@gmail.com> writes:
>>> I went ahead and tested andrew's second patch -- can we get this
>>> reviewed and committed?

>> Add it to the upcoming commitfest.

> It's a client crashing bug in PQsetvalue that goes back to 9.0 :(.

I was under the impression that this was extending PQsetvalue to let it
be used in previously unsupported ways, ie, to modify a server-returned
PGresult.  That's a feature addition, not a bug fix.  I'm not even sure
it's a feature addition I approve of.  I think serious consideration
ought to be given to locking down returned results so PQsetvalue refuses
to touch them, instead.  Otherwise we're likely to find ourselves unable
to make future optimizations because we have to support this
barely-used-by-anybody corner case.
        regards, tom lane


Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Wed, Jun 8, 2011 at 11:03 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Merlin Moncure <mmoncure@gmail.com> writes:
>> On Wed, Jun 8, 2011 at 10:18 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>>> Merlin Moncure <mmoncure@gmail.com> writes:
>>>> I went ahead and tested andrew's second patch -- can we get this
>>>> reviewed and committed?
>
>>> Add it to the upcoming commitfest.
>
>> It's a client crashing bug in PQsetvalue that goes back to 9.0 :(.
>
> I was under the impression that this was extending PQsetvalue to let it
> be used in previously unsupported ways, ie, to modify a server-returned
> PGresult.  That's a feature addition, not a bug fix.

It's neither -- it's documented libpq behavior: "The function will
automatically grow the result's internal tuples array as needed.
However, the tup_num argument must be less than or equal to PQntuples,
meaning this function can only grow the tuples array one tuple at a
time. But any field of any existing tuple can be modified in any
order. "

Andrew was briefly flirting with a proposal to tweak this behavior,
but withdrew the idea.

> it's a feature addition I approve of.  I think serious consideration
> ought to be given to locking down returned results so PQsetvalue refuses
> to touch them, instead.  Otherwise we're likely to find ourselves unable
> to make future optimizations because we have to support this
> barely-used-by-anybody corner case.

I think that's debatable, but I'm not going to argue this yea or nea.
But I will say that maybe we shouldn't confuse behavior issues with
bug fix either way...patch the bug, and we can work up a patch to lock
down the behavior and the docs if you want it that way, but maybe we
could bikeshed a bit on that point.

merlin


Re: Error in PQsetvalue

От
Andrew Chernow
Дата:
On 6/8/2011 12:03 PM, Tom Lane wrote:
> Merlin Moncure<mmoncure@gmail.com>  writes:
>> On Wed, Jun 8, 2011 at 10:18 AM, Tom Lane<tgl@sss.pgh.pa.us>  wrote:
>>> Merlin Moncure<mmoncure@gmail.com>  writes:
>>>> I went ahead and tested andrew's second patch -- can we get this
>>>> reviewed and committed?
>
>>> Add it to the upcoming commitfest.
>
>> It's a client crashing bug in PQsetvalue that goes back to 9.0 :(.
>
> I was under the impression that this was extending PQsetvalue to let it
> be used in previously unsupported ways, ie, to modify a server-returned

Well, it was supposed to support that but the implementation is busted 
(sorry) and core dumps instead.

> PGresult.  That's a feature addition, not a bug fix.  I'm not even sure
> it's a feature addition I approve of.  I think serious consideration
> ought to be given to locking down returned results so PQsetvalue refuses

I don't disagree at all, but I do think this is a bit more involved of a 
change.  Several functions like PQmakeEmptyPGresult, PQsetvalue, 
PQcopyResult (one used by libpqtypes), the PGresult object needs a bool 
member and probably others things all must be aware of the distinction 
bwteen client and server generated results.  That is a little tricky 
because both use PQmakeEmptyPGresult that has no argument to indicate that.

Since libpqtypes only calls PQcopyResult, you could just set a flag on 
the result in that function that PQsetvalue uses as a guard.  However, 
this hard codes knowledge about the libpqtypes calling pattern which is 
rather weak.

Maybe it would be better to just apply the patch (since it also removes 
duplicate code from pqAddTuple in addition to fixing a crash) and update 
the docs to say this is an unsupported feature, don't do it.  If it 
happens to work forever or just for a while, than so be it.

-- 
Andrew Chernow
eSilo, LLC
global backup
http://www.esilo.com/


Re: Error in PQsetvalue

От
Pavel Golub
Дата:
Hello, Merlin.

You wrote:

MM> On Wed, Jun 8, 2011 at 11:03 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Merlin Moncure <mmoncure@gmail.com> writes:
>>> On Wed, Jun 8, 2011 at 10:18 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>>>> Merlin Moncure <mmoncure@gmail.com> writes:
>>>>> I went ahead and tested andrew's second patch -- can we get this
>>>>> reviewed and committed?
>>
>>>> Add it to the upcoming commitfest.
>>
>>> It's a client crashing bug in PQsetvalue that goes back to 9.0 :(.
>>
>> I was under the impression that this was extending PQsetvalue to let it
>> be used in previously unsupported ways, ie, to modify a server-returned
>> PGresult.  That's a feature addition, not a bug fix.

MM> It's neither -- it's documented libpq behavior: "The function will
MM> automatically grow the result's internal tuples array as needed.
MM> However, the tup_num argument must be less than or equal to PQntuples,
MM> meaning this function can only grow the tuples array one tuple at a
MM> time. But any field of any existing tuple can be modified in any
MM> order. "

MM> Andrew was briefly flirting with a proposal to tweak this behavior,
MM> but withdrew the idea.

>> it's a feature addition I approve of.  I think serious consideration
>> ought to be given to locking down returned results so PQsetvalue refuses
>> to touch them, instead.  Otherwise we're likely to find ourselves unable
>> to make future optimizations because we have to support this
>> barely-used-by-anybody corner case.

Do I understand correctly that there is no any chance at all to have function
like PQdeleteTuple in libpq? (see my message "PQdeleteTuple
function in libpq" on Wed, 1 Jun 2011)

MM> I think that's debatable, but I'm not going to argue this yea or nea.
MM> But I will say that maybe we shouldn't confuse behavior issues with
MM> bug fix either way...patch the bug, and we can work up a patch to lock
MM> down the behavior and the docs if you want it that way, but maybe we
MM> could bikeshed a bit on that point.

MM> merlin



-- 
With best wishes,Pavel                          mailto:pavel@gf.microolap.com



Re: Error in PQsetvalue

От
Merlin Moncure
Дата:
On Thu, Jun 9, 2011 at 12:48 AM, Pavel Golub <pavel@microolap.com> wrote:
>>> it's a feature addition I approve of.  I think serious consideration
>>> ought to be given to locking down returned results so PQsetvalue refuses
>>> to touch them, instead.  Otherwise we're likely to find ourselves unable
>>> to make future optimizations because we have to support this
>>> barely-used-by-anybody corner case.
>
> Do I understand correctly that there is no any chance at all to have function
> like PQdeleteTuple in libpq? (see my message "PQdeleteTuple
> function in libpq" on Wed, 1 Jun 2011)

It means the feature is on thin ice.  I'm personally in favor of
keeping it, and perhaps cautiously exploring ways to go further.  I'm
waiting for Tom to make a call...I see three options:

1) patch bug and leave behavior alone (apply andrew C's patch)
2) discuss behavior change in -hackers
3) patch bug and behavior immediately (get a new patch with doc change as well)

merlin


Re: Error in PQsetvalue

От
Pavel Golub
Дата:
Hello, Andrew.

I hope you don't mind I've added this patch to CommitFest:
https://commitfest.postgresql.org/action/patch_view?id=606

You wrote:

AC> On 6/3/2011 10:26 PM, Andrew Chernow wrote:
>>
>>>> I disagree -- I think the fix is a one-liner. line 446:
>>>> if (tup_num == res->ntups&& !res->tuples[tup_num])
>>>>
>>>> should just become
>>>> if (tup_num == res->ntups)
>>>>
>>>> also the memset of the tuple slots when the slot array is expanded can
>>>> be removed. (in addition, the array tuple array expansion should
>>>> really be abstracted, but that isn't strictly necessary here).
>>>>
>>>
>>> All true. This is a cleaner fix to something that was in fact broken ;) You want
>>
>> Attached a patch that fixes the OP's issue. PQsetvalue now uses pqAddTuple to
>> grow the tuple table and has removed the remnants of an older idea that caused
>> the bug.
>>

AC> Sorry, I attached the wrong patch.  Here is the correct one.




-- 
With best wishes,Pavel                          mailto:pavel@gf.microolap.com