-- Add function to retrieve sequence/shotpoint from timestamps and vice-versa -- -- New schema version: 0.2.1 -- -- ATTENTION: -- -- ENSURE YOU HAVE BACKED UP THE DATABASE BEFORE RUNNING THIS SCRIPT. -- -- -- NOTE: This upgrade affects the public schema. -- NOTE: Each application starts a transaction, which must be committed -- or rolled back. -- -- Two new functions are defined: -- -- sequence_shot_from_tstamp(tstamp, [tolerance]) → sequence, point, delta -- -- Returns a sequence + shotpoint if one falls within `tolerance` seconds -- of `tstamp`. The tolerance may be omitted in which case it defaults to -- three seconds. If multiple values match, it returns the closest in time. -- -- tstamp_from_sequence_shot(sequence, point) → tstamp -- -- Returns a timestamp given a sequence and point number. -- -- NOTE: This last function must be called from a search path including a -- project schema, as it accesses the raw_shots table. -- -- To apply, run as the dougal user: -- -- psql < p ORDER BY point ASC LIMIT 1; RETURN (ts1-ts0)/abs(pt1-pt0)*abs(p-pt0)+ts0; END; $inner$ LANGUAGE PLPGSQL; COMMENT ON FUNCTION tstamp_interpolate(numeric, numeric) IS 'Interpolate a timestamp given sequence and point values. It will try to find the points immediately before and after in the sequence and interpolate into the gap, which may consist of multiple missed shots. If called on an existing shotpoint it will return an interpolated timestamp as if the shotpoint did not exist, as opposed to returning its actual timestamp. Returns NULL if it is not possible to interpolate.'; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE PROCEDURE pg_temp.upgrade_database () AS $$ DECLARE row RECORD; BEGIN CREATE OR REPLACE FUNCTION public.sequence_shot_from_tstamp( IN ts timestamptz, IN tolerance numeric, OUT "sequence" numeric, OUT "point" numeric, OUT "delta" numeric) AS $inner$ SELECT (meta->>'_sequence')::numeric AS sequence, (meta->>'_point')::numeric AS point, extract('epoch' FROM (meta->>'tstamp')::timestamptz - ts ) AS delta FROM real_time_inputs WHERE meta ? '_sequence' AND abs(extract('epoch' FROM (meta->>'tstamp')::timestamptz - ts )) < tolerance ORDER BY abs(extract('epoch' FROM (meta->>'tstamp')::timestamptz - ts )) LIMIT 1; $inner$ LANGUAGE SQL; COMMENT ON FUNCTION public.sequence_shot_from_tstamp(timestamptz, numeric) IS 'Get sequence and shotpoint from timestamp. Given a timestamp this function returns the closest shot to it within the given tolerance value. This uses the `real_time_inputs` table and it does not give an indication of which project the shotpoint belongs to. It is assumed that a single project is being acquired at a given time.'; CREATE OR REPLACE FUNCTION public.sequence_shot_from_tstamp( IN ts timestamptz, OUT "sequence" numeric, OUT "point" numeric, OUT "delta" numeric) AS $inner$ SELECT * FROM public.sequence_shot_from_tstamp(ts, 3); $inner$ LANGUAGE SQL; COMMENT ON FUNCTION public.sequence_shot_from_tstamp(timestamptz) IS 'Get sequence and shotpoint from timestamp. Overloaded form in which the tolerance value is implied and defaults to three seconds.'; FOR row IN SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE 'survey_%' ORDER BY schema_name LOOP CALL pg_temp.upgrade_survey_schema(row.schema_name); END LOOP; END; $$ LANGUAGE plpgsql; CALL pg_temp.upgrade_database(); CALL show_notice('Cleaning up'); DROP PROCEDURE pg_temp.upgrade_survey_schema (schema_name text); DROP PROCEDURE pg_temp.upgrade_database (); CALL show_notice('Updating db_schema version'); INSERT INTO public.info VALUES ('version', '{"db_schema": "0.2.1"}') ON CONFLICT (key) DO UPDATE SET value = public.info.value || '{"db_schema": "0.2.1"}' WHERE public.info.key = 'version'; -- --NOTE Run `COMMIT;` now if all went well --