Bug? Prepared queries continue to use search_path from their preparation time

Started by Toby Corkindaleover 13 years ago7 messagesgeneral
Jump to latest
#1Toby Corkindale
toby.corkindale@strategicdata.com.au

Hi,
I've encountered something that might be a bug in DBD::Pg, or might be a
feature of PostgreSQL itself.

The issue occurs when you have server-side prepared queries enabled, and
then change the search_path parameter after creating a prepared query.
Future executions of that query still seem to be using the original
search_path.

To replicate the issue, do the following:

$ createdb bug
$ psql bug
CREATE SCHEMA foo;
CREATE SCHEMA bar;
CREATE TABLE foo.example (id integer primary key);
CREATE TABLE bar.example (id integer primary key);
INSERT INTO foo.example (id) values (123);

Then run the following script:

#!/usr/bin/env perl
use 5.14.1;
use warnings;
use DBI;
# Requires DBD::Pg to be installed too

my $dbh = DBI->connect('dbi:Pg:dbname=bug', undef, undef,
{ pg_server_prepare => 1 }
);

$dbh->do("set search_path = foo,public");

my $q = $dbh->prepare("select count(*) from example where id = ?");

$q->execute(123);
my ($row) = $q->fetchrow_array;
say "First result: $row";

$dbh->do("set search_path = bar,public");
$q->execute(123);
($row) = $q->fetchrow_array;
say "First result: $row";

The output indicates that a row was found in both cases, however in the
second case, it should not have found anything because the search path
had changed.

-Toby

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Toby Corkindale (#1)
Re: Bug? Prepared queries continue to use search_path from their preparation time

Toby Corkindale <toby.corkindale@strategicdata.com.au> writes:

The issue occurs when you have server-side prepared queries enabled, and
then change the search_path parameter after creating a prepared query.
Future executions of that query still seem to be using the original
search_path.

This behavior is intentional.

regards, tom lane

#3Jerry Sievers
gsievers19@comcast.net
In reply to: Toby Corkindale (#1)
Re: Bug? Prepared queries continue to use search_path from their preparation time

Toby Corkindale <toby.corkindale@strategicdata.com.au> writes:

Hi,
I've encountered something that might be a bug in DBD::Pg, or might be
a feature of PostgreSQL itself.

The issue occurs when you have server-side prepared queries enabled,
and then change the search_path parameter after creating a prepared
query. Future executions of that query still seem to be using the
original search_path.

To replicate the issue, do the following:

$ createdb bug
$ psql bug
CREATE SCHEMA foo;
CREATE SCHEMA bar;
CREATE TABLE foo.example (id integer primary key);
CREATE TABLE bar.example (id integer primary key);
INSERT INTO foo.example (id) values (123);

Then run the following script:

#!/usr/bin/env perl
use 5.14.1;
use warnings;
use DBI;
# Requires DBD::Pg to be installed too

my $dbh = DBI->connect('dbi:Pg:dbname=bug', undef, undef,
{ pg_server_prepare => 1 }
);

$dbh->do("set search_path = foo,public");

my $q = $dbh->prepare("select count(*) from example where id = ?");

$q->execute(123);
my ($row) = $q->fetchrow_array;
say "First result: $row";

$dbh->do("set search_path = bar,public");
$q->execute(123);
($row) = $q->fetchrow_array;
say "First result: $row";

The output indicates that a row was found in both cases, however in
the second case, it should not have found anything because the search
path had changed.

No, not a bug if you understand that prepared statements resolve
symbolic things like schema/object names into OIDs that are frozen by
the prepare.

You didn't mention what version you're on.

I did a similar test though using plain SQL prepared statements and
was surprised though to find that the DISCARD PLANS statement issued
after changing the search_path did nothing to change this behavior.

To wit;

create schema s1;
create schema s2;

create table s1.t (a int);
insert into s1.t values (1);

create table s2.t (a int);

set search_path to s1;

prepare foo as select a from t;

execute foo;

set search_path to s2;

discard plans;

execute foo;

drop schema s1 cascade;
drop schema s2 cascade;

----

sj$ psql --no-psqlrc -f s
CREATE SCHEMA
CREATE SCHEMA
CREATE TABLE
INSERT 0 1
CREATE TABLE
SET
PREPARE
a
---
1
(1 row)

SET
DISCARD PLANS
a
---
1 <--- was not expecting to see this here
(1 row)

DROP SCHEMA
DROP SCHEMA
sj$

-Toby

--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general

--
Jerry Sievers
e: jerry.sievers@comcast.net
p: 732.216.7255

#4Jerry Sievers
jerry.sievers@comcast.net
In reply to: Toby Corkindale (#1)
Re: Bug? Prepared queries continue to use search_path from their preparation time

Toby Corkindale <toby.corkindale@strategicdata.com.au> writes:

Hi,
I've encountered something that might be a bug in DBD::Pg, or might be
a feature of PostgreSQL itself.

The issue occurs when you have server-side prepared queries enabled,
and then change the search_path parameter after creating a prepared
query. Future executions of that query still seem to be using the
original search_path.

To replicate the issue, do the following:

$ createdb bug
$ psql bug
CREATE SCHEMA foo;
CREATE SCHEMA bar;
CREATE TABLE foo.example (id integer primary key);
CREATE TABLE bar.example (id integer primary key);
INSERT INTO foo.example (id) values (123);

Then run the following script:

#!/usr/bin/env perl
use 5.14.1;
use warnings;
use DBI;
# Requires DBD::Pg to be installed too

my $dbh = DBI->connect('dbi:Pg:dbname=bug', undef, undef,
{ pg_server_prepare => 1 }
);

$dbh->do("set search_path = foo,public");

my $q = $dbh->prepare("select count(*) from example where id = ?");

$q->execute(123);
my ($row) = $q->fetchrow_array;
say "First result: $row";

$dbh->do("set search_path = bar,public");
$q->execute(123);
($row) = $q->fetchrow_array;
say "First result: $row";

The output indicates that a row was found in both cases, however in
the second case, it should not have found anything because the search
path had changed.

No, not a bug if you understand that prepared statements resolve
symbolic things like schema/object names into OIDs that are frozen by
the prepare.

You didn't mention what version you're on.

I did a similar test though using plain SQL prepared statements and
was surprised though to find that the DISCARD PLANS statement issued
after changing the search_path did nothing to change this behavior.

To wit;

create schema s1;
create schema s2;

create table s1.t (a int);
insert into s1.t values (1);

create table s2.t (a int);

set search_path to s1;

prepare foo as select a from t;

execute foo;

set search_path to s2;

discard plans;

execute foo;

drop schema s1 cascade;
drop schema s2 cascade;

----

sj$ psql --no-psqlrc -f s
CREATE SCHEMA
CREATE SCHEMA
CREATE TABLE
INSERT 0 1
CREATE TABLE
SET
PREPARE
a
---
1
(1 row)

SET
DISCARD PLANS
a
---
1 <--- was not expecting to see this here
(1 row)

DROP SCHEMA
DROP SCHEMA
sj$

-Toby

--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general

--
Jerry Sievers
e: jerry.sievers@comcast.net
p: 732.216.7255

#5Toby Corkindale
toby.corkindale@strategicdata.com.au
In reply to: Tom Lane (#2)
Re: Bug? Prepared queries continue to use search_path from their preparation time

On 12/07/12 00:07, Tom Lane wrote:

Toby Corkindale <toby.corkindale@strategicdata.com.au> writes:

The issue occurs when you have server-side prepared queries enabled, and
then change the search_path parameter after creating a prepared query.
Future executions of that query still seem to be using the original
search_path.

This behavior is intentional.

In that case, the error lies with the Perl libraries that automatically
prepare and cache queries, but do not include the search_path in the
cache keys.

I'll bring it up with them.

thanks for your advice,
Toby

#6Greg Sabino Mullane
greg@turnstep.com
In reply to: Toby Corkindale (#5)
Re: Bug? Prepared queries continue to use search_path from their preparation time

-----BEGIN PGP SIGNED MESSAGE-----
Hash: RIPEMD160

This behavior is intentional.

In that case, the error lies with the Perl libraries that automatically
prepare and cache queries, but do not include the search_path in the
cache keys.

You have lost me there. Which Perl libraries are those?

- --
Greg Sabino Mullane greg@turnstep.com
End Point Corporation http://www.endpoint.com/
PGP Key: 0x14964AC8 201207121257
http://biglumber.com/x/web?pk=2529DF6AB8F79407E94445B4BC9B906714964AC8
-----BEGIN PGP SIGNATURE-----

iEYEAREDAAYFAk//AlQACgkQvJuQZxSWSsj6IACgzQJlK5Y1u1Pr3KDyR6ax3Elb
4ycAoOPo5XJn0Uxx7Lvg30u3iCBoibp6
=oKaV
-----END PGP SIGNATURE-----

#7Toby Corkindale
toby.corkindale@strategicdata.com.au
In reply to: Greg Sabino Mullane (#6)
Re: Bug? Prepared queries continue to use search_path from their preparation time

On 13/07/12 02:59, Greg Sabino Mullane wrote:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: RIPEMD160

This behavior is intentional.

In that case, the error lies with the Perl libraries that automatically
prepare and cache queries, but do not include the search_path in the
cache keys.

You have lost me there. Which Perl libraries are those?

I was thinking of DBIx::Class, which will automatically use the DBI
function prepare_cached() for all the queries it generates.

However I discovered this warning hidden deep in the documentation:

"[..] once your schema is instantiated, you should not change the
PostgreSQL schema search path for that schema's database connection. If
you do, Bad Things may happen."

So they are aware of the problem, but unfortunately I hadn't seen that
warning (and I suspect most users won't) until after they've encountered
the problem.

I guess for now I chalk this up to experience and remember not to do it
again! :)