
-- {
-- 
-- Return random TIDs in a table.
--
-- You can use like this:
--
--   SELECT * FROM lots_of_points WHERE ctid = ANY (
--      ARRAY[ (SELECT CDB_RandomTids('lots_of_points', 100000)) ]
--   );
--
-- NOTE:
-- It currently doesn't really do it random, but in a
-- equally-distributed way among all tuples.
--
--
-- }{
CREATE OR REPLACE FUNCTION CDB_RandomTids(in_table regclass, in_nsamples integer)
  RETURNS tid[]
AS $$
DECLARE
  class_info RECORD;
  tuples_per_page INTEGER;
  needed_pages INTEGER;
  skip_pages INTEGER;
  tidlist TID[];
  pnrec RECORD;
BEGIN

  -- (#) estimate pages and tuples-per-page
  --     HINT: pg_class.relpages, pg_class.reltuples
  SELECT relpages, reltuples 
    FROM pg_class WHERE oid = in_table
    INTO class_info;

  RAISE DEBUG 'Table % has % pages and % tuples',
    in_table::text, class_info.relpages, class_info.reltuples;

  IF in_nsamples > class_info.reltuples THEN
    RAISE WARNING 'Table has less tuples than requested';
    -- should just perform a sequencial scan here...
  END IF;

  tuples_per_page := floor(class_info.reltuples/class_info.relpages);
  needed_pages := ceil(in_nsamples::real/tuples_per_page);

  RAISE DEBUG '% tuples per page, we need % pages for % tuples',
    tuples_per_page, needed_pages, in_nsamples;

  -- (#) select random pages
  --     TODO: see how good this is first

  skip_pages := floor( (class_info.relpages-needed_pages)/(needed_pages+1) );

  RAISE DEBUG 'we are going to skip % pages at each iteration',
    skip_pages;

  SELECT array_agg(t) FROM (
    SELECT '(' || pn || ',' || tn || ')' as t
    FROM generate_series(1, tuples_per_page) x(tn),
         generate_series(skip_pages+1, class_info.relpages, skip_pages) y(pn) ) f
        INTO tidlist;

  RETURN tidlist;

END
$$ LANGUAGE 'plpgsql' STABLE STRICT PARALLEL SAFE;
-- }

