CREATE EXTENSION sqlite_fdw;
CREATE SERVER sqlite_svr FOREIGN DATA WRAPPER sqlite_fdw
OPTIONS (database '/tmp/sqlitefdw_test.db');
CREATE FOREIGN TABLE department(department_id int OPTIONS (key 'true'), department_name text) SERVER sqlite_svr; 
CREATE FOREIGN TABLE employee(emp_id int OPTIONS (key 'true'), emp_name text, emp_dept_id int) SERVER sqlite_svr;
CREATE FOREIGN TABLE empdata(emp_id int OPTIONS (key 'true'), emp_dat bytea) SERVER sqlite_svr;
CREATE FOREIGN TABLE numbers(a int OPTIONS (key 'true'), b varchar(255)) SERVER sqlite_svr;
CREATE FOREIGN TABLE multiprimary(a int, b int OPTIONS (key 'true'), c int OPTIONS(key 'true')) SERVER sqlite_svr;

SELECT * FROM department LIMIT 10;
SELECT * FROM employee LIMIT 10;
SELECT * FROM empdata LIMIT 10;

INSERT INTO department VALUES(generate_series(1,100), 'dept - ' || generate_series(1,100));
INSERT INTO employee VALUES(generate_series(1,100), 'emp - ' || generate_series(1,100), generate_series(1,100));
INSERT INTO empdata  VALUES(1, decode ('01234567', 'hex'));

INSERT INTO numbers VALUES(1, 'One');
INSERT INTO numbers VALUES(2, 'Two');
INSERT INTO numbers VALUES(3, 'Three');
INSERT INTO numbers VALUES(4, 'Four');
INSERT INTO numbers VALUES(5, 'Five');
INSERT INTO numbers VALUES(6, 'Six');
INSERT INTO numbers VALUES(7, 'Seven');
INSERT INTO numbers VALUES(8, 'Eight');
INSERT INTO numbers VALUES(9, 'Nine');

SELECT count(*) FROM department;
SELECT count(*) FROM employee;
SELECT count(*) FROM empdata;

EXPLAIN (COSTS FALSE) SELECT * FROM department d, employee e WHERE d.department_id = e.emp_dept_id LIMIT 10;

EXPLAIN (COSTS FALSE) SELECT * FROM department d, employee e WHERE d.department_id IN (SELECT department_id FROM department) LIMIT 10;

SELECT * FROM department d, employee e WHERE d.department_id = e.emp_dept_id LIMIT 10;
SELECT * FROM department d, employee e WHERE d.department_id IN (SELECT department_id FROM department) LIMIT 10;
SELECT * FROM empdata;

DELETE FROM employee WHERE emp_id = 10;

SELECT COUNT(*) FROM department LIMIT 10;
SELECT COUNT(*) FROM employee WHERE emp_id = 10;

UPDATE employee SET emp_name = 'UPDATEd emp' WHERE emp_id = 20;
SELECT emp_id, emp_name FROM employee WHERE emp_name like 'UPDATEd emp';

UPDATE empdata SET emp_dat = decode ('0123', 'hex');
SELECT * FROM empdata;

SELECT * FROM employee LIMIT 10;
SELECT * FROM employee WHERE emp_id IN (1);
SELECT * FROM employee WHERE emp_id IN (1,3,4,5);
SELECT * FROM employee WHERE emp_id IN (10000,1000);

SELECT * FROM employee WHERE emp_id NOT IN (1) LIMIT 5;
SELECT * FROM employee WHERE emp_id NOT IN (1,3,4,5) LIMIT 5;
SELECT * FROM employee WHERE emp_id NOT IN (10000,1000) LIMIT 5;

SELECT * FROM employee WHERE emp_id NOT IN (SELECT emp_id FROM employee WHERE emp_id IN (1,10));
SELECT * FROM employee WHERE emp_name NOT IN ('emp - 1', 'emp - 2') LIMIT 5;
SELECT * FROM employee WHERE emp_name NOT IN ('emp - 10') LIMIT 5;

SELECT * FROM numbers WHERE (CASE WHEN a % 2 = 0 THEN 1 WHEN a % 5 = 0 THEN 1 ELSE 0 END) = 1;
SELECT * FROM numbers WHERE (CASE b WHEN 'Two' THEN 1 WHEN 'Six' THEN 1 ELSE 0 END) = 1;

create or replace function test_param_WHERE() returns void as $$
DECLARE
  n varchar;
BEGIN
  FOR x IN 1..9 LOOP
    SELECT b INTO n from numbers WHERE a=x;
    raise notice 'Found number %', n;
  end loop;
  return;
END
$$ LANGUAGE plpgsql;
SELECT test_param_WHERE();

SELECT b from numbers WHERE a=1;
EXPLAIN(COSTS OFF) SELECT b from numbers WHERE a=1;

SELECT a FROM numbers WHERE b = (SELECT NULL::text);


PREPARE stmt1 (int, int) AS
  SELECT * FROM numbers WHERE a=$1 or a=$2;
EXECUTE stmt1(1,2);
EXECUTE stmt1(2,2); 
EXECUTE stmt1(3,2); 
EXECUTE stmt1(4,2);
-- generic plan
EXECUTE stmt1(5,2); 
EXECUTE stmt1(6,2); 
EXECUTE stmt1(7,2); 

DELETE FROM employee;
DELETE FROM department;
DELETE FROM empdata;
DELETE FROM numbers;

BEGIN;
INSERT INTO numbers VALUES(1, 'One');
INSERT INTO numbers VALUES(2, 'Two');
COMMIT;

SELECT * from numbers;

BEGIN;
INSERT INTO numbers VALUES(3, 'Three');
ROLLBACK;
SELECT * from numbers;

BEGIN;
INSERT INTO numbers VALUES(4, 'Four');
SAVEPOINT my_savepoint;
INSERT INTO numbers VALUES(5, 'Five');
ROLLBACK TO SAVEPOINT my_savepoint;
INSERT INTO numbers VALUES(6, 'Six');
COMMIT;

SELECT * from numbers;

-- duplicate key
INSERT INTO numbers VALUES(1, 'One');
DELETE from numbers;

BEGIN;
INSERT INTO numbers VALUES(1, 'One');
INSERT INTO numbers VALUES(2, 'Two');
COMMIT;
-- violate unique constraint
UPDATE numbers SET b='Two' WHERE a = 1; 
SELECT * from numbers;

-- push down
explain (costs off) SELECT * from numbers WHERE  a = any(ARRAY[2,3,4,5]::int[]);
-- (1,2,3) is pushed down
explain (costs off) SELECT * from numbers WHERE a in (1,2,3) AND (1,2) < (a,5);

-- not push down
explain (costs off) SELECT * from numbers WHERE a in (a+2*a,5);
-- not push down
explain (costs off) SELECT * from numbers WHERE  a = any(ARRAY[1,2,a]::int[]);

SELECT * from numbers WHERE  a = any(ARRAY[2,3,4,5]::int[]);
SELECT * from numbers WHERE  a = any(ARRAY[1,2,a]::int[]);

INSERT INTO multiprimary VALUES(1,2,3);
INSERT INTO multiprimary VALUES(1,2,4);
UPDATE multiprimary SET b = 10 WHERE c = 3;
SELECT * from multiprimary;
UPDATE multiprimary SET a = 10 WHERE a = 1;
SELECT * from multiprimary;
UPDATE multiprimary SET a = 100, b=200, c=300 WHERE a=10 AND b=10;
SELECT * from multiprimary;
UPDATE multiprimary SET a = 1234;
SELECT * from multiprimary;
UPDATE multiprimary SET a = a+1, b=b+1 WHERE b=200 AND c=300;

SELECT * from multiprimary;
DELETE from multiprimary WHERE a = 1235;
SELECT * from multiprimary;
DELETE from multiprimary WHERE b = 2;
SELECT * from multiprimary;

INSERT INTO multiprimary VALUES(1,2,3);
INSERT INTO multiprimary VALUES(1,2,4);
INSERT INTO multiprimary VALUES(1,10,20);
INSERT INTO multiprimary VALUES(2,20,40);



SELECT count(distinct a) from multiprimary;
SELECT sum(b),max(b), min(b) from multiprimary;
SELECT sum(b+5)+2 from multiprimary group by b/2 order by b/2;
SELECT sum(a) from multiprimary group by b having sum(a) > 0 order by sum(a);
SELECT sum(a) A from multiprimary group by b having avg(abs(a)) > 0 AND sum(a) > 0 order by A;
SELECT count(nullif(a, 1)) FROM multiprimary;

SELECT * from multiprimary, numbers WHERE multiprimary.a=numbers.a;

INSERT INTO numbers VALUES(4, 'Four');

-- All where clauses are pushed down
SELECT * FROM numbers WHERE abs(a) = 4 AND upper(b) = 'FOUR' AND lower(b) = 'four';
EXPLAIN (verbose, costs off)  SELECT b, length(b) FROM numbers WHERE abs(a) = 4 AND upper(b) = 'FOUR' AND lower(b) = 'four';

-- Only "length(b) = 4" are pushed down
SELECT b, length(b) FROM numbers WHERE length(b) = 4 AND power(1, a) != 0 AND length(reverse(b)) = 4;
EXPLAIN (verbose, costs off) SELECT b, length(b) FROM numbers WHERE length(b) = 4 AND power(1, a) != 0 AND length(reverse(b)) = 4;

INSERT INTO multiprimary (b,c) VALUES (99, 100);
SELECT c FROM multiprimary WHERE COALESCE(a,b,c) = 99;

DROP FUNCTION test_param_WHERE();
DROP FOREIGN TABLE numbers;
DROP FOREIGN TABLE department;
DROP FOREIGN TABLE employee;
DROP FOREIGN TABLE empdata;
DROP FOREIGN TABLE multiprimary;
DROP SERVER sqlite_svr;
DROP EXTENSION sqlite_fdw CASCADE;

