Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-29 Thread Michael Paquier
On Fri, Jan 30, 2015 at 10:32 AM, Tom Lane t...@sss.pgh.pa.us wrote:
 [blah]
 What I did about this was to leave the behavior alone in back branches,
 but insist on a type match in HEAD.  I think we can reasonably tighten
 the type requirements in a new major release, but doing it in minor
 releases is probably a bad idea.
Hm. OK. I am fine with that for the back branches. Thanks for
tightening things on master as well.

 * I thought it was odd to throw an error for NULL input, especially
 an infinite recursion error.  However, even with your patch the code
 would've dumped core on a null current_key value (since it would've
 passed a null start_with down to the next recursion level).  What I
 changed it to was to omit the recursion test (and hence print the row)
 and then not recurse at a null.  This seems consistent and reasonable.
This sounds reasonable to me as well.

 * I made a few other minor cleanups as well, in particular getting
 rid of some unnecessary pstrdup() steps.
Thanks!
-- 
Michael


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


Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-29 Thread Tom Lane
Michael Paquier michael.paqu...@gmail.com writes:
 So, I have been poking at this code a bit more and as the values of
 the parameters are passed as-is to the SQL queries that connectby
 generates internally (this is as well mentioned in the documentation
 here: http://www.postgresql.org/docs/devel/static/tablefunc.html), you
 can do quite fancy things by passing for example values of the type
 foo FROM table; -- or similar. Particularly, by enforcing a query
 returning only one column, or NULL values I am even able to crash the
 server. The interesting part is that even if compatConnectbyTupleDescs
 is enabled for each level, it is still possible to crash the server by
 passing for example NULL values casted to the same type, like that
 'NULL::text, NULL::text; --'.
 The attached patch fixes all those things, I have also enabled
 compatConnectbyTupleDescs to run at each level. I'll add it to the
 next CF as well to not lose track of it. This behavior has been like
 that forever...

Since this is a potential-core-dump fix, I went ahead and dealt with it
rather than waiting for the next CF.  I made a few adjustments:

* I thought that the way you changed the type compatibility tests was
overcomplicated and unnecessary.  As the code stands, there's no great
need to insist on type compatibility at all: if the printed form of
the constructed query's results is acceptable to the outer query's types,
it'll work, and otherwise will throw a reasonably intelligible error.
Now, we might well want to improve this code to skip the conversion to
text and back at some point, in which case we would need to insist on
a type match.  But in neither of those cases does it seem helpful to
ask whether there is a SQL type cast, as your patch was doing.  The
existence of a cast does not imply I/O representation compatibility,
so it's not in line with the current behavior, and if we want to skip
text conversion we'd prefer it's exactly the same type, which is the
check as it originally existed before it accidentally got broken.

What I did about this was to leave the behavior alone in back branches,
but insist on a type match in HEAD.  I think we can reasonably tighten
the type requirements in a new major release, but doing it in minor
releases is probably a bad idea.

* I thought it was odd to throw an error for NULL input, especially
an infinite recursion error.  However, even with your patch the code
would've dumped core on a null current_key value (since it would've
passed a null start_with down to the next recursion level).  What I
changed it to was to omit the recursion test (and hence print the row)
and then not recurse at a null.  This seems consistent and reasonable.

* I made a few other minor cleanups as well, in particular getting
rid of some unnecessary pstrdup() steps.

regards, tom lane


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


Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-25 Thread Michael Paquier
On Sat, Jan 17, 2015 at 11:16 PM, Michael Paquier
michael.paqu...@gmail.com wrote:
 Patch is attached. Comments welcome.
So, I have been poking at this code a bit more and as the values of
the parameters are passed as-is to the SQL queries that connectby
generates internally (this is as well mentioned in the documentation
here: http://www.postgresql.org/docs/devel/static/tablefunc.html), you
can do quite fancy things by passing for example values of the type
foo FROM table; -- or similar. Particularly, by enforcing a query
returning only one column, or NULL values I am even able to crash the
server. The interesting part is that even if compatConnectbyTupleDescs
is enabled for each level, it is still possible to crash the server by
passing for example NULL values casted to the same type, like that
'NULL::text, NULL::text; --'.
The attached patch fixes all those things, I have also enabled
compatConnectbyTupleDescs to run at each level. I'll add it to the
next CF as well to not lose track of it. This behavior has been like
that forever...
-- 
Michael
From 40ef6b9fa378af588712c0fc98d4e44047f9756c Mon Sep 17 00:00:00 2001
From: Michael Paquier mich...@otacoo.com
Date: Mon, 26 Jan 2015 15:17:23 +0900
Subject: [PATCH] Fix crashes and tuple compatibility checks in connectby()

Coverity has pointed out that compatConnectbyTupleDescs has been dead code
since commit 08c33c4 of 2003. However, after further analysis, it happens
that it is even possible to crash the server as values passed by connectby
are used as-is by the process generating SELECT queries, with for example
values like that '1; --' or that 'column::text, NULL FROM foo; --'. It is
even possible to bypass compatConnectbyTupleDescs by enforcing the types
of the attributes returned as with NULL values as key and parent key
processing did not have checks to see if a value could be NULL. It is already
specified in the documentation that any kind of values can be used by callers
of connectby(), so this commit tightens check around tuple compatibility to
ensure that no callers can crash the server by either enforcing NULL values,
in which case value used is really NULL or when having a query returning only
one column, in which case process simply errors out because a parent key cannot
be defined.
---
 contrib/tablefunc/expected/tablefunc.out |  22 +++
 contrib/tablefunc/sql/tablefunc.sql  |  16 +
 contrib/tablefunc/tablefunc.c| 101 +++
 3 files changed, 101 insertions(+), 38 deletions(-)

diff --git a/contrib/tablefunc/expected/tablefunc.out b/contrib/tablefunc/expected/tablefunc.out
index 0437ecf..7bf7d6d 100644
--- a/contrib/tablefunc/expected/tablefunc.out
+++ b/contrib/tablefunc/expected/tablefunc.out
@@ -376,6 +376,28 @@ SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 4, '~') A
 11 |   10 | 4 | 2~5~9~10~11
 (8 rows)
 
+-- should fail as first two columns must have the same type
+SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') AS t(keyid text, parent_keyid int, level int, branch text);
+ERROR:  invalid return type
+DETAIL:  First two columns must be the same type.
+-- should fail as key field datatype should match return datatype
+SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') AS t(keyid json, parent_keyid json, level int, branch text);
+ERROR:  invalid return type
+DETAIL:  Failed to cast integer to json
+-- tests for values using custom queries
+-- query with one column - failed
+SELECT * FROM connectby('connectby_int', '1; --', 'parent_keyid', '2', 0) AS t(keyid int, parent_keyid int, level int);
+ERROR:  invalid return type
+DETAIL:  Return tuple needs at least two columns.
+-- query with two columns first value as NULL - infinite recursion
+SELECT * FROM connectby('connectby_int', 'NULL::text, 1::text; --', 'parent_keyid', '2', 0) AS t(keyid int, parent_keyid int, level int);
+ERROR:  infinite recursion detected
+-- query with two columns first value as NULL - infinite recursion
+SELECT * FROM connectby('connectby_int', '1::text, NULL::text; --', 'parent_keyid', '2', 0) AS t(keyid int, parent_keyid int, level int);
+ERROR:  infinite recursion detected
+-- query with two columns, both values as NULL - infinite recursion
+SELECT * FROM connectby('connectby_int', 'NULL::text, NULL::text; --', 'parent_keyid', '2', 0) AS t(keyid int, parent_keyid int, level int);
+ERROR:  infinite recursion detected
 -- test for falsely detected recursion
 DROP TABLE connectby_int;
 CREATE TABLE connectby_int(keyid int, parent_keyid int);
diff --git a/contrib/tablefunc/sql/tablefunc.sql b/contrib/tablefunc/sql/tablefunc.sql
index bf874f2..835eb28 100644
--- a/contrib/tablefunc/sql/tablefunc.sql
+++ b/contrib/tablefunc/sql/tablefunc.sql
@@ -179,6 +179,22 @@ SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') A
 -- infinite recursion failure avoided by depth limit
 SELECT * FROM 

Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-21 Thread Michael Paquier
On Tue, Jan 20, 2015 at 4:05 PM, Michael Paquier
michael.paqu...@gmail.com wrote:
 On Tue, Jan 20, 2015 at 8:47 AM, Michael Paquier
 michael.paqu...@gmail.com wrote:
 On Mon, Jan 19, 2015 at 11:06 PM, Joe Conway m...@joeconway.com wrote:
 -BEGIN PGP SIGNED MESSAGE-
 Hash: SHA1

 On 01/19/2015 08:16 AM, Alvaro Herrera wrote:
 Haven't looked at this patch, but I wonder if it would be better
 to replace the innards of connectby with a rewrite of the query to
 use standard WITH queries.  Maybe we can remove a couple hundred
 lines from tablefunc.c?

 Seems like a good idea -- connectby is really obsolete for quite a
 while now other than as an SRF example. I guess we only keep it around
 for backwards compatibility?
 For master, yes we could brush up things a bit. Now do we really do
 the same for back-branches? I would think that the answer there is
 something close to the patch I sent.

 So, using a WITH RECURSIVE, here is a query equivalent to what connectby does:
 [...]
 Thoughts?
Looking at this stuff, actually I do not think that it is possible for
now to support orderby_fld at the same level with WITH RECURSIVE in
connectby because we need to reorder the items of the base table
within the 2nd query of the UNION ALL to give something like that and
WITH RECURSIVE does not support ORDER BY (and mutual recursion between
WITH items).

Another thing to note is that WITH RECURSIVE weakens the infinite
recursion detection. I don't think it would be good to weaken that...
Attached is a result of this random hacking, resulting in some cleanup
btw:
 1 file changed, 110 insertions(+), 264 deletions(-)
Regards,
-- 
Michael
diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c
index 3388fab..e7c3674 100644
--- a/contrib/tablefunc/tablefunc.c
+++ b/contrib/tablefunc/tablefunc.c
@@ -54,7 +54,6 @@ static Tuplestorestate *get_crosstab_tuplestore(char *sql,
 		bool randomAccess);
 static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial);
 static bool compatCrosstabTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
-static bool compatConnectbyTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
 static void get_normal_pair(float8 *x1, float8 *x2);
 static Tuplestorestate *connectby(char *relname,
 		  char *key_fld,
@@ -68,21 +67,6 @@ static Tuplestorestate *connectby(char *relname,
 		  MemoryContext per_query_ctx,
 		  bool randomAccess,
 		  AttInMetadata *attinmeta);
-static Tuplestorestate *build_tuplestore_recursively(char *key_fld,
-			 char *parent_key_fld,
-			 char *relname,
-			 char *orderby_fld,
-			 char *branch_delim,
-			 char *start_with,
-			 char *branch,
-			 int level,
-			 int *serial,
-			 int max_depth,
-			 bool show_branch,
-			 bool show_serial,
-			 MemoryContext per_query_ctx,
-			 AttInMetadata *attinmeta,
-			 Tuplestorestate *tupstore);
 
 typedef struct
 {
@@ -1161,14 +1145,16 @@ connectby(char *relname,
 	Tuplestorestate *tupstore = NULL;
 	int			ret;
 	MemoryContext oldcontext;
-
-	int			serial = 1;
+	StringInfoData inner_sql, outer_sql, orderby_sql;
+	char	  **values;
+	int			num_cols;
 
 	/* Connect to SPI manager */
 	if ((ret = SPI_connect())  0)
 		/* internal error */
 		elog(ERROR, connectby: SPI_connect returned %d, ret);
 
+
 	/* switch to longer term context to create the tuple store */
 	oldcontext = MemoryContextSwitchTo(per_query_ctx);
 
@@ -1177,244 +1163,137 @@ connectby(char *relname,
 
 	MemoryContextSwitchTo(oldcontext);
 
-	/* now go get the whole tree */
-	tupstore = build_tuplestore_recursively(key_fld,
-			parent_key_fld,
-			relname,
-			orderby_fld,
-			branch_delim,
-			start_with,
-			start_with, /* current_branch */
-			0,	/* initial level is 0 */
-			serial,	/* initial serial is 1 */
-			max_depth,
-			show_branch,
-			show_serial,
-			per_query_ctx,
-			attinmeta,
-			tupstore);
-
-	SPI_finish();
-
-	return tupstore;
-}
-
-static Tuplestorestate *
-build_tuplestore_recursively(char *key_fld,
-			 char *parent_key_fld,
-			 char *relname,
-			 char *orderby_fld,
-			 char *branch_delim,
-			 char *start_with,
-			 char *branch,
-			 int level,
-			 int *serial,
-			 int max_depth,
-			 bool show_branch,
-			 bool show_serial,
-			 MemoryContext per_query_ctx,
-			 AttInMetadata *attinmeta,
-			 Tuplestorestate *tupstore)
-{
-	TupleDesc	tupdesc = attinmeta-tupdesc;
-	int			ret;
-	int			proc;
-	int			serial_column;
-	StringInfoData sql;
-	char	  **values;
-	char	   *current_key;
-	char	   *current_key_parent;
-	char		current_level[INT32_STRLEN];
-	char		serial_str[INT32_STRLEN];
-	char	   *current_branch;
-	HeapTuple	tuple;
-
-	if (max_depth  0  level  max_depth)
-		return tupstore;
-
-	initStringInfo(sql);
-
-	/* Build initial sql statement */
-	if (!show_serial)
-	{
-		

Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-19 Thread Michael Paquier
On Mon, Jan 19, 2015 at 11:06 PM, Joe Conway m...@joeconway.com wrote:
 -BEGIN PGP SIGNED MESSAGE-
 Hash: SHA1

 On 01/19/2015 08:16 AM, Alvaro Herrera wrote:
 Haven't looked at this patch, but I wonder if it would be better
 to replace the innards of connectby with a rewrite of the query to
 use standard WITH queries.  Maybe we can remove a couple hundred
 lines from tablefunc.c?

 Seems like a good idea -- connectby is really obsolete for quite a
 while now other than as an SRF example. I guess we only keep it around
 for backwards compatibility?
For master, yes we could brush up things a bit. Now do we really do
the same for back-branches? I would think that the answer there is
something close to the patch I sent.
-- 
Michael


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


Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-19 Thread Michael Paquier
On Tue, Jan 20, 2015 at 8:47 AM, Michael Paquier
michael.paqu...@gmail.com wrote:
 On Mon, Jan 19, 2015 at 11:06 PM, Joe Conway m...@joeconway.com wrote:
 -BEGIN PGP SIGNED MESSAGE-
 Hash: SHA1

 On 01/19/2015 08:16 AM, Alvaro Herrera wrote:
 Haven't looked at this patch, but I wonder if it would be better
 to replace the innards of connectby with a rewrite of the query to
 use standard WITH queries.  Maybe we can remove a couple hundred
 lines from tablefunc.c?

 Seems like a good idea -- connectby is really obsolete for quite a
 while now other than as an SRF example. I guess we only keep it around
 for backwards compatibility?
 For master, yes we could brush up things a bit. Now do we really do
 the same for back-branches? I would think that the answer there is
 something close to the patch I sent.

So, using a WITH RECURSIVE, here is a query equivalent to what connectby does:
=# SELECT * FROM connectby_text;
 keyid | parent_keyid | pos
---+--+-
 row2  | row1 |   0
 row3  | row1 |   0
 row4  | row2 |   1
 row5  | row2 |   0
 row6  | row4 |   0
 row7  | row3 |   0
 row8  | row6 |   0
 row9  | row5 |   0
 row1  | null |   0
(9 rows)
=# SELECT * FROM
connectby('connectby_text', 'keyid', 'parent_keyid', 'row1', 3, '~') AS
t(keyid text, parent_keyid text, level int, branch text);
 keyid | parent_keyid | level |   branch
---+--+---+-
 row1  | null | 0 | row1
 row2  | row1 | 1 | row1~row2
 row4  | row2 | 2 | row1~row2~row4
 row6  | row4 | 3 | row1~row2~row4~row6
 row5  | row2 | 2 | row1~row2~row5
 row9  | row5 | 3 | row1~row2~row5~row9
 row3  | row1 | 1 | row1~row3
 row7  | row3 | 2 | row1~row3~row7
(8 rows)
=# WITH RECURSIVE connectby_tree AS
(
 SELECT keyid, 0::int AS level, parent_keyid, keyid as
ct_full_list -- root portion
 FROM connectby_text
 WHERE keyid = 'row1' -- start point
 UNION ALL
 SELECT ctext.keyid,
(ctree.level + 1)::int AS level,
ctext.parent_keyid,
CAST(ctree.ct_full_list || '~' || ctext.keyid AS text) AS ct_full_list
 FROM connectby_text AS ctext
 INNER JOIN connectby_tree AS ctree
 ON (ctext.parent_keyid = ctree.keyid) -- connect by
 WHERE ctree.level = 2 -- limit of level
 )
 SELECT keyid, parent_keyid, level, ct_full_list
 FROM connectby_tree ORDER BY ct_full_list;
 keyid | parent_keyid | level |ct_full_list
---+--+---+-
 row1  | null | 0 | row1
 row2  | row1 | 1 | row1~row2
 row4  | row2 | 2 | row1~row2~row4
 row6  | row4 | 3 | row1~row2~row4~row6
 row5  | row2 | 2 | row1~row2~row5
 row9  | row5 | 3 | row1~row2~row5~row9
 row3  | row1 | 1 | row1~row3
 row7  | row3 | 2 | row1~row3~row7
(8 rows)
Using that we got a couple of options:
- Parametrize this query in some set of plpgsql functions and dump
tablefunc to 1.1
- Integrate directly this query in the existing C code and use SPI,
without dumping tablefunc.
Thoughts?
-- 
Michael


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


Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-19 Thread Alvaro Herrera
Haven't looked at this patch, but I wonder if it would be better to
replace the innards of connectby with a rewrite of the query to use
standard WITH queries.  Maybe we can remove a couple hundred lines from
tablefunc.c?

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training  Services


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


Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-19 Thread Joe Conway
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 01/19/2015 08:16 AM, Alvaro Herrera wrote:
 Haven't looked at this patch, but I wonder if it would be better
 to replace the innards of connectby with a rewrite of the query to
 use standard WITH queries.  Maybe we can remove a couple hundred
 lines from tablefunc.c?

Seems like a good idea -- connectby is really obsolete for quite a
while now other than as an SRF example. I guess we only keep it around
for backwards compatibility?

Joe

- -- 
Joe Conway
credativ LLC: http://www.credativ.us
Linux, PostgreSQL, and general Open Source
Training, Service, Consulting,  24x7 Support
-BEGIN PGP SIGNATURE-
Version: GnuPG v1

iQIcBAEBAgAGBQJUvQ9RAAoJEDfy90M199hlRBwP/0KvbDh8x7PpRtqpjSpH7riL
5MMF12XBOJ1UaUcEDKnEFiFj/DBQs/CRva+GB1ahwo3dqNmD733+w9RsSpdEHM7e
7s8K9zUTrlQYnqMs2GXgoi/DK7qzBgPTkAF+9gp7WPbjCqs/G9f7wlCyxM+2Sg0+
UUEGvI0rSvPObsyKjHMOQMTaMaOiQWvvcQ1aKiTBNl2lg5vb8yNUBbqq5/tlx2Cd
OMlJi+PFRkCo7aKjT6HRojYVJCbK+QzXZp1UvXOAWzt1ecR695XR3HDAP/d8IInc
gAZJsZbYMw8VuWQa8W6brZd2c+3sU21sMSV50dgBpO5nGBnqryKlLs9bP91+BNu6
doUB2sVDaimcYoN8pML/4lrxhQrr2tm9SBmRJMAJEhKUHnjPB3AGwwB2InDKdusK
voIFKS12yduqAI7ZQ8ZcpmxCoOesV6a1himdIH/WikPan1ITkCD+toGtmniEuUNv
QwDFPCueswlRJEBEq3pbh07ZN7FBeNYxZMVIcdDmomj2BffoDDwovK9mqm2SgpJq
WNCT8388lak0eNyZkt8O/6n514Ensn6KAWD/FunMQPVBwgFn8J6fDChZ9z6aw85X
9RgIb3OyjK7tICpTZ4GXkY5xUma3I3LMogzsnkqFc3FaVVCVJ9eCKZ8l2TEil2Uz
5X498pFhQWaut8ptlS9c
=OQdT
-END PGP SIGNATURE-


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


Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-17 Thread Michael Paquier
Alvaro Herrera wrote:
 Michael Paquier wrote:

 As mentioned in $subject, commit 08c33c4 of 2003 has made the
 following block of code dead in tablefunc.c:1320 because level is
 incremented to at least 1:
 /* First time through, do a little more setup */
 if (level == 0)
 {

 Uh.  This means the error case has no test coverage ...
And looking at that more closely things are a bit more tricky than it
seems. The problem is here related especially to connectby in the
checks done to determine if the input and return key fields are
compatible or not by comparing directly some type OIDs in
compatConnectbyTupleDescs.

Note that if we simply enable this check as-is, connectby would fail
for example with test cases like this one simply because text !=
varchar:
CREATE TABLE connectby_tree(keyid text, parent_keyid text, pos int);
INSERT INTO connectby_tree VALUES('row1',NULL, 0);
INSERT INTO connectby_tree VALUES('row2','row1', 0);
INSERT INTO connectby_tree VALUES('row3','row1', 0);
INSERT INTO connectby_tree VALUES('row4','row2', 1);
INSERT INTO connectby_tree VALUES('row5','row2', 0);
SELECT * FROM connectby('connectby_tree', 'keyid', 'parent_keyid',
'pos', 'row2', 0) AS
t(keyid varchar(256), parent_keyid varchar(256), level int, pos int);

Hence, what I am proposing as a fix is to replace the old check by
something checking if there is a possible cast between the input and
output types, and to error out if types are not compatible. This way,
compatibility is preserved in HEAD and back-branches, and IMO I think
that it would be good to check this compatibility in connectby. New
regression tests are added as well.

Patch is attached. Comments welcome.
-- 
Michael
From 5d63ecc1642818f4de006faf0c39c23124d1c0e5 Mon Sep 17 00:00:00 2001
From: Michael Paquier mich...@otacoo.com
Date: Sat, 17 Jan 2015 22:52:16 +0900
Subject: [PATCH] Fix compatibility checks of connectby in tablefunc

Coverity has pointed out a block of dead code that was used to check the
compatibility of the input and return types of connectby. The check done
simply compared the input and output OIDs, returning an error if the type
OIDs do not match, however it seems more solid to check for a cast between
those two types, to avoid at the same time errors related to data input.
---
 contrib/tablefunc/expected/tablefunc.out |  8 
 contrib/tablefunc/sql/tablefunc.sql  |  6 +++
 contrib/tablefunc/tablefunc.c| 64 ++--
 3 files changed, 50 insertions(+), 28 deletions(-)

diff --git a/contrib/tablefunc/expected/tablefunc.out b/contrib/tablefunc/expected/tablefunc.out
index 0437ecf..75eff3e 100644
--- a/contrib/tablefunc/expected/tablefunc.out
+++ b/contrib/tablefunc/expected/tablefunc.out
@@ -376,6 +376,14 @@ SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 4, '~') A
 11 |   10 | 4 | 2~5~9~10~11
 (8 rows)
 
+-- should fail as first two columns must have the same type
+SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') AS t(keyid text, parent_keyid int, level int, branch text);
+ERROR:  invalid return type
+DETAIL:  First two columns must be the same type.
+-- should fail as key field datatype should match return datatype
+SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') AS t(keyid json, parent_keyid json, level int, branch text);
+ERROR:  invalid return type
+DETAIL:  Failed to cast integer to json
 -- test for falsely detected recursion
 DROP TABLE connectby_int;
 CREATE TABLE connectby_int(keyid int, parent_keyid int);
diff --git a/contrib/tablefunc/sql/tablefunc.sql b/contrib/tablefunc/sql/tablefunc.sql
index bf874f2..aff0699 100644
--- a/contrib/tablefunc/sql/tablefunc.sql
+++ b/contrib/tablefunc/sql/tablefunc.sql
@@ -179,6 +179,12 @@ SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') A
 -- infinite recursion failure avoided by depth limit
 SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 4, '~') AS t(keyid int, parent_keyid int, level int, branch text);
 
+-- should fail as first two columns must have the same type
+SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') AS t(keyid text, parent_keyid int, level int, branch text);
+
+-- should fail as key field datatype should match return datatype
+SELECT * FROM connectby('connectby_int', 'keyid', 'parent_keyid', '2', 0, '~') AS t(keyid json, parent_keyid json, level int, branch text);
+
 -- test for falsely detected recursion
 DROP TABLE connectby_int;
 CREATE TABLE connectby_int(keyid int, parent_keyid int);
diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c
index 3388fab..3677d96 100644
--- a/contrib/tablefunc/tablefunc.c
+++ b/contrib/tablefunc/tablefunc.c
@@ -40,7 +40,10 @@
 #include funcapi.h
 #include lib/stringinfo.h
 #include miscadmin.h
+#include nodes/makefuncs.h

[HACKERS] Error check always bypassed in tablefunc.c

2015-01-16 Thread Michael Paquier
Hi all,

As mentioned in $subject, commit 08c33c4 of 2003 has made the
following block of code dead in tablefunc.c:1320 because level is
incremented to at least 1:
/* First time through, do a little more setup */
if (level == 0)
{
/*
 * Check that return tupdesc is compatible
with the one we got
 * from the query, but only at level 0 -- no
need to check more
 * than once
 */

if (!compatConnectbyTupleDescs(tupdesc, spi_tupdesc))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
 errmsg(invalid return type),
 errdetail(Return and
SQL tuple descriptions are  \

incompatible.)));
}

A simple fix is simply to change level == 0 to level == 1 to check
for this error, like in the patch attached. This issue has been
spotted by Coverity.
Regards,
-- 
Michael
diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c
index 3388fab..878255e 100644
--- a/contrib/tablefunc/tablefunc.c
+++ b/contrib/tablefunc/tablefunc.c
@@ -1317,12 +1317,12 @@ build_tuplestore_recursively(char *key_fld,
 		StringInfoData chk_current_key;
 
 		/* First time through, do a little more setup */
-		if (level == 0)
+		if (level == 1)
 		{
 			/*
 			 * Check that return tupdesc is compatible with the one we got
-			 * from the query, but only at level 0 -- no need to check more
-			 * than once
+			 * from the query, but only at the first level -- no need to check
+			 * more than once
 			 */
 
 			if (!compatConnectbyTupleDescs(tupdesc, spi_tupdesc))

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


Re: [HACKERS] Error check always bypassed in tablefunc.c

2015-01-16 Thread Alvaro Herrera
Michael Paquier wrote:

 As mentioned in $subject, commit 08c33c4 of 2003 has made the
 following block of code dead in tablefunc.c:1320 because level is
 incremented to at least 1:
 /* First time through, do a little more setup */
 if (level == 0)
 {

Uh.  This means the error case has no test coverage ...

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training  Services


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