Below query returns the wrong result when join getting pushdown to the remote server.
(PFA fdw_setup.sql, to create objects for the test) postgres=# select e, e.empno, d.deptno, d.dname from f_emp e left join f_dept d on e.deptno = d.deptno and e.sal > 3000 order by 2, 3 limit 10; e | empno | deptno | dname -----------------------------------------------------------+-------+--------+------------ | 7369 | | (7499,ALLEN,SALESMAN,7698,1981-02-20,1600.00,300.00,30) | 7499 | | (7521,WARD,SALESMAN,7698,1981-02-22,1250.00,500.00,30) | 7521 | | | 7566 | | (7654,MARTIN,SALESMAN,7698,1981-09-28,1250.00,1400.00,30) | 7654 | | | 7698 | | | 7782 | | | 7788 | | | 7839 | 10 | ACCOUNTING (7844,TURNER,SALESMAN,7698,1981-09-08,1500.00,0.00,30) | 7844 | | (10 rows) Here, wholerow is coming as NULL even though with non-null empno. If we remove limit clause from the query - that will not push the query to the remote side and in such case getting correct output. postgres=# select e, e.empno, d.deptno, d.dname from f_emp e left join f_dept d on e.deptno = d.deptno and e.sal > 3000 order by 2, 3; e | empno | deptno | dname -----------------------------------------------------------+-------+--------+------------ (7369,SMITH,CLERK,7902,1980-12-17,800.00,,20) | 7369 | | (7499,ALLEN,SALESMAN,7698,1981-02-20,1600.00,300.00,30) | 7499 | | (7521,WARD,SALESMAN,7698,1981-02-22,1250.00,500.00,30) | 7521 | | (7566,JONES,MANAGER,7839,1981-04-02,2975.00,,20) | 7566 | | (7654,MARTIN,SALESMAN,7698,1981-09-28,1250.00,1400.00,30) | 7654 | | (7698,BLAKE,MANAGER,7839,1981-05-01,2850.00,,30) | 7698 | | (7782,CLARK,MANAGER,7839,1981-06-09,2450.00,,10) | 7782 | | (7788,SCOTT,ANALYST,7566,1987-04-19,3000.00,,20) | 7788 | | (7839,KING,PRESIDENT,,1981-11-17,5000.00,,10) | 7839 | 10 | ACCOUNTING (7844,TURNER,SALESMAN,7698,1981-09-08,1500.00,0.00,30) | 7844 | | (7876,ADAMS,CLERK,7788,1987-05-23,1100.00,,20) | 7876 | | (7900,JAMES,CLERK,7698,1981-12-03,950.00,,30) | 7900 | | (7902,FORD,ANALYST,7566,1981-12-03,3000.00,,20) | 7902 | | (7934,MILLER,CLERK,7782,1982-01-23,1300.00,,10) | 7934 | | (14 rows) Explain verbose output for the query with LIMIT clause is: postgres=# explain verbose select e, e.empno, d.deptno, d.dname from f_emp e left join f_dept d on e.deptno = d.deptno and e.sal > 3000 order by 2, 3 limit 10; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------- Limit (cost=100.00..136.86 rows=10 width=236) Output: e.*, e.empno, d.deptno, d.dname -> Foreign Scan (cost=100.00..2304.10 rows=598 width=236) Output: e.*, e.empno, d.deptno, d.dname Relations: (public.f_emp e) LEFT JOIN (public.f_dept d) Remote SQL: SELECT CASE WHEN r1.* IS NOT NULL THEN ROW(r1.empno, r1.ename, r1.job, r1.mgr, r1.hiredate, r1.sal, r1.comm, r1.deptno) END, r1.empno, r2 .deptno, r2.dname FROM (public.emp r1 LEFT JOIN public.dept r2 ON (((r1.sal > 3000::numeric)) AND ((r1.deptno = r2.deptno)))) ORDER BY r1.empno ASC NULLS LAST , r2.deptno ASC NULLS LAST (6 rows) Further looking I found that here problem is because we converting wholerow reference with ROW - and binding it with CASE clause. So, in the above example reference to "r" is converted with "CASE WHEN r1.* IS NOT NULL THEN ROW(r1.empno, r1.ename, r1.job, r1.mgr, r1.hiredate, r1.sal, r1.comm, r1.deptno) END" Here r1.* IS NOT NULL is behaving strange, it return TRUE only when all the elements in the wholerow is NOT NULL. Example with normal table (not postgres_fdw involded): postgres=# select r, r.* is null as isnull, r.* is not null as isnotnull from emp r; r | isnull | isnotnull -----------------------------------------------------------+--------+----------- (7369,SMITH,CLERK,7902,1980-12-17,800.00,,20) | f | f (7499,ALLEN,SALESMAN,7698,1981-02-20,1600.00,300.00,30) | f | t (7521,WARD,SALESMAN,7698,1981-02-22,1250.00,500.00,30) | f | t (7566,JONES,MANAGER,7839,1981-04-02,2975.00,,20) | f | f (7654,MARTIN,SALESMAN,7698,1981-09-28,1250.00,1400.00,30) | f | t (7698,BLAKE,MANAGER,7839,1981-05-01,2850.00,,30) | f | f (7782,CLARK,MANAGER,7839,1981-06-09,2450.00,,10) | f | f (7788,SCOTT,ANALYST,7566,1987-04-19,3000.00,,20) | f | f (7839,KING,PRESIDENT,,1981-11-17,5000.00,,10) | f | f (7844,TURNER,SALESMAN,7698,1981-09-08,1500.00,0.00,30) | f | t (7876,ADAMS,CLERK,7788,1987-05-23,1100.00,,20) | f | f (7900,JAMES,CLERK,7698,1981-12-03,950.00,,30) | f | f (7902,FORD,ANALYST,7566,1981-12-03,3000.00,,20) | f | f (7934,MILLER,CLERK,7782,1982-01-23,1300.00,,10) | f | f (14 rows) Now I was under impression the IS NOT NULL should be always in inverse of IS NULL, but clearly here its not the case with wholerow. But further looking at the document its saying different thing for wholerow: https://www.postgresql.org/docs/9.5/static/functions-comparison.html Note: If the expression is row-valued, then IS NULL is true when the row expression itself is null or when all the row's fields are null, while IS NOT NULL is true when the row expression itself is non-null and all the row's fields are non-null. Because of this behavior, IS NULL and IS NOT NULL do not always return inverse results for row-valued expressions, i.e., a row-valued expression that contains both NULL and non-null values will return false for both tests. This definition conforms to the SQL standard, and is a change from the inconsistent behavior exhibited by PostgreSQL versions prior to 8.2. And as above documentation clearly says that IS NULL and IS NOT NULL do not always return inverse results for row-valued expressions. So need to change the deparse logic into postgres_fdw - how ? May be to use IS NULL rather then IS NOT NULL? Input/thought? Regards Rushabh Lathia www.EnterpriseDB.com
CREATE TABLE dept ( deptno numeric(2) NOT NULL CONSTRAINT dept_pk PRIMARY KEY, dname varchar(14) CONSTRAINT dept_dname_uq UNIQUE, loc varchar(13) ); CREATE TABLE emp ( empno numeric(4) NOT NULL CONSTRAINT emp_pk PRIMARY KEY, ename varchar(10), job varchar(9), mgr numeric(4), hiredate DATE, sal numeric(7,2) CONSTRAINT emp_sal_ck CHECK (sal > 0), comm numeric(7,2), deptno numeric(2) CONSTRAINT emp_ref_dept_fk REFERENCES dept(deptno) ); INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK'); INSERT INTO dept VALUES (20,'RESEARCH','DALLAS'); INSERT INTO dept VALUES (30,'SALES','CHICAGO'); INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON'); INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20); INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30); INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30); INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'02-APR-81',2975,NULL,20); INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30); INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,'01-MAY-81',2850,NULL,30); INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'09-JUN-81',2450,NULL,10); INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,'19-APR-87',3000,NULL,20); INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000,NULL,10); INSERT INTO emp VALUES (7844,'TURNER','SALESMAN',7698,'08-SEP-81',1500,0,30); INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,'23-MAY-87',1100,NULL,20); INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,'03-DEC-81',950,NULL,30); INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,'03-DEC-81',3000,NULL,20); INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,'23-JAN-82',1300,NULL,10); CREATE EXTENSION postgres_fdw; CREATE SERVER s1 FOREIGN DATA WRAPPER postgres_fdw options (dbname 'postgres'); CREATE USER MAPPING FOR CURRENT_USER SERVER s1; CREATE foreign TABLE f_dept ( deptno numeric(2), dname varchar(14), loc varchar(13) ) SERVER s1 options (table_name 'dept'); CREATE foreign TABLE f_emp ( empno numeric(4), ename varchar(10), job varchar(9), mgr numeric(4), hiredate DATE, sal numeric(7,2), comm numeric(7,2), deptno numeric(2) ) SERVER s1 options (table_name 'emp');
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers