1

I am trying to execute SQL statements that exist within a column of a database table.

The records of this table has 'tests' in each row.

sid  name     sql
1    test1    SELECT source_system_name, Count(*), CASE WHEN Count(*) BETWEEN 500 AND 2000 THEN true ELSE false END AS valid FROM prod.listing WHERE source_record_status = 'active' AND modified_on BETWEEN %L AND(%L - interval '24 hours') GROUP BY source_system_name;
2    test2    SELECT source_system_name, ....;

the output from the SQL inside sql column generates 3 columns - source_system_name, count, and valid. Whenever function validation() is run I want to output the result - when valid = false

I wrote code for the innermost logic i.e. whenever there is false in value column.

CREATE OR REPLACE FUNCTION validation()
   RETURNS text AS $$
DECLARE
 show_log TEXT DEFAULT '';
 rec_val RECORD;
 cur_val CURSOR
  FOR SELECT   source_system_name,
         Count(*),
         CASE
                  WHEN Count(*) BETWEEN 500 AND 2000 THEN CAST(true AS BOOLEAN)
                  ELSE CAST(false AS BOOLEAN)
         END AS valid
      FROM     prod.listing
      WHERE    source_record_status = 'active'
      AND      modified_on BETWEEN '2001-06-29'::TIMESTAMP AND     (
                        '2017-06-29'::TIMESTAMP - interval '24 hours')
      GROUP BY source_system_name;
BEGIN
   -- Open the cursor
   OPEN cur_val;

   LOOP
    -- fetch row into the rec_val
      FETCH cur_val INTO rec_val;
    -- exit when no more row to fetch
      EXIT WHEN NOT FOUND;

    -- build the output
      IF rec_val.valid =  false THEN
         show_log := rec_val.source_system_name;
      END IF;
   END LOOP;

   -- Close the cursor
   CLOSE cur_val;

   RETURN show_log;
END; $$

LANGUAGE plpgsql;

I am a bit confused as in how to use this logic for all the statements in sql column.

3
  • Does every sql return three columns typed the same way? Commented Sep 14, 2017 at 21:16
  • @EvanCarroll yes, that will be the format I will be following to keep things simple for now. Commented Sep 14, 2017 at 21:17
  • I assume you are aware that this architecture is a gaping hole for SQL injection attacks? Anyone who can write to this column can get arbitrary code to execution with the permissions of whoever executes the function. Commented Sep 15, 2017 at 3:43

1 Answer 1

4

You don't put the condition inside the procedure, you call a procedure only when the condition is true. The calling context should look something like

SELECT id, name, rs.*
FROM tests AS t
CROSS JOIN LATERAL myDynamic3ColExec(sql) AS rs
WHERE EXISTS (
      SELECT 1
      FROM     prod.listing
      WHERE    t.name = listing.source_system_name
      AND      source_record_status = 'active'
      AND      modified_on BETWEEN '2001-06-29'::TIMESTAMP AND                        ('2017-06-29'::TIMESTAMP - interval '24 hours')
      GROUP BY source_system_name
      HAVING Count(*) BETWEEN 500 AND 2000
);

Now you have to create a type, and create a function that returns the type given a sql statement as text.

CREATE TYPE mytype AS ( sid int, name text, sql text );

CREATE FUNCTION myDynamic3ColExec(sql text)
RETURNS setof mytype
AS $$
  RETURN QUERY EXECUTE sql;
$$ LANGUAGE plpgsql
VOLATILE;
1
  • Thanks Evan. I don't have just prod.listing table in the tests table. I will have SQL statements for different tables in that sqlcolumn. Commented Sep 15, 2017 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.