Skip to content

Commit

Permalink
Add hdb_catalog.current_setting abstraction for reading Hasura settings
Browse files Browse the repository at this point in the history
As the comment in the function’s definition explains, this is needed to
work around an awkward Postgres behavior.
  • Loading branch information
lexi-lambda committed Aug 4, 2020
1 parent bf37b39 commit 66e85ab
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 25 deletions.
2 changes: 1 addition & 1 deletion server/src-lib/Hasura/RQL/DML/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ sessVarFromCurrentSetting' ty sessVar =
[currentSession, S.SELit $ sessionVariableToText sessVar]

currentSession :: S.SQLExp
currentSession = S.SEUnsafe "current_setting('hasura.user')::json"
currentSession = S.SEUnsafe "hdb_catalog.current_setting('user')"

checkSelPerm
:: (UserInfoM m, QErrM m, CacheRM m)
Expand Down
2 changes: 1 addition & 1 deletion server/src-rsr/catalog_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
37
38
55 changes: 32 additions & 23 deletions server/src-rsr/initialise.sql
Original file line number Diff line number Diff line change
Expand Up @@ -596,46 +596,55 @@ CREATE VIEW hdb_catalog.hdb_function_info_agg AS (
hdb_catalog.hdb_function_agg
);

CREATE OR REPLACE FUNCTION
hdb_catalog.insert_event_log(schema_name text, table_name text, trigger_name text, op text, row_data json)
RETURNS text AS $$
CREATE FUNCTION hdb_catalog.current_setting(setting_name text) RETURNS json
LANGUAGE plpgsql AS $$
DECLARE
id text;
payload json;
session_variables json;
server_version_num int;
trace_context json;
setting_value text;
BEGIN
id := gen_random_uuid();
server_version_num := current_setting('server_version_num');
IF server_version_num >= 90600 THEN
session_variables := current_setting('hasura.user', 't');
trace_context := current_setting('hasura.tracecontext', 't');
setting_value := current_setting('hasura.' || setting_name, true);
ELSE
-- We still support Postgres 9.5, which doesn’t support the second
-- argument to current_setting, so emulate it by just catching the error.
BEGIN
session_variables := current_setting('hasura.user');
EXCEPTION WHEN OTHERS THEN
session_variables := NULL;
END;
BEGIN
trace_context := current_setting('hasura.tracecontext');
setting_value := current_setting('hasura.' || setting_name);
EXCEPTION WHEN OTHERS THEN
trace_context := NULL;
setting_value := NULL;
END;
END IF;
-- Note: we test for the empty string here to work around a Postgres bug.
-- When SET LOCAL is used to set the value of a setting that does not
-- currently exist, Postgres implicitly creates a /session-wide/ definition
-- of the setting with the empty string as its value. This is annoying, but
-- fortunately an empty string is not a legal JSON value, so it always means
-- no value was set in the current transaction.
IF setting_value IS NULL OR setting_value = '' THEN
RETURN NULL;
ELSE
RETURN setting_value::json;
END IF;
END $$;

CREATE OR REPLACE FUNCTION hdb_catalog.insert_event_log(schema_name text, table_name text, trigger_name text, op text, row_data json)
RETURNS text LANGUAGE plpgsql AS $$
DECLARE
id text;
payload json;
BEGIN
id := gen_random_uuid();
payload := json_build_object(
'op', op,
'data', row_data,
'session_variables', session_variables,
'trace_context', trace_context
'session_variables', hdb_catalog.current_setting('user'),
'trace_context', hdb_catalog.current_setting('tracecontext')
);
INSERT INTO hdb_catalog.event_log
(id, schema_name, table_name, trigger_name, payload)
VALUES
(id, schema_name, table_name, trigger_name, payload);
VALUES (id, schema_name, table_name, trigger_name, payload);
RETURN id;
END;
$$ LANGUAGE plpgsql;
END $$;

CREATE TABLE hdb_catalog.hdb_query_collection
(
Expand Down
49 changes: 49 additions & 0 deletions server/src-rsr/migrations/37_to_38.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
CREATE FUNCTION hdb_catalog.current_setting(setting_name text) RETURNS json
LANGUAGE plpgsql AS $$
DECLARE
server_version_num int;
setting_value text;
BEGIN
server_version_num := current_setting('server_version_num');
IF server_version_num >= 90600 THEN
setting_value := current_setting('hasura.' || setting_name, true);
ELSE
-- We still support Postgres 9.5, which doesn’t support the second
-- argument to current_setting, so emulate it by just catching the error.
BEGIN
setting_value := current_setting('hasura.' || setting_name);
EXCEPTION WHEN OTHERS THEN
setting_value := NULL;
END;
END IF;
-- Note: we test for the empty string here to work around a Postgres bug.
-- When SET LOCAL is used to set the value of a setting that does not
-- currently exist, Postgres implicitly creates a /session-wide/ definition
-- of the setting with the empty string as its value. This is annoying, but
-- fortunately an empty string is not a legal JSON value, so it always means
-- no value was set in the current transaction.
IF setting_value IS NULL OR setting_value = '' THEN
RETURN NULL;
ELSE
RETURN setting_value::json;
END IF;
END $$;

CREATE OR REPLACE FUNCTION hdb_catalog.insert_event_log(schema_name text, table_name text, trigger_name text, op text, row_data json)
RETURNS text LANGUAGE plpgsql AS $$
DECLARE
id text;
payload json;
BEGIN
id := gen_random_uuid();
payload := json_build_object(
'op', op,
'data', row_data,
'session_variables', hdb_catalog.current_setting('user'),
'trace_context', hdb_catalog.current_setting('tracecontext')
);
INSERT INTO hdb_catalog.event_log
(id, schema_name, table_name, trigger_name, payload)
VALUES (id, schema_name, table_name, trigger_name, payload);
RETURN id;
END $$;
41 changes: 41 additions & 0 deletions server/src-rsr/migrations/38_to_37.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
CREATE OR REPLACE FUNCTION hdb_catalog.insert_event_log(schema_name text, table_name text, trigger_name text, op text, row_data json)
RETURNS text AS $$
DECLARE
id text;
payload json;
session_variables json;
server_version_num int;
trace_context json;
BEGIN
id := gen_random_uuid();
server_version_num := current_setting('server_version_num');
IF server_version_num >= 90600 THEN
session_variables := current_setting('hasura.user', 't');
trace_context := current_setting('hasura.tracecontext', 't');
ELSE
BEGIN
session_variables := current_setting('hasura.user');
EXCEPTION WHEN OTHERS THEN
session_variables := NULL;
END;
BEGIN
trace_context := current_setting('hasura.tracecontext');
EXCEPTION WHEN OTHERS THEN
trace_context := NULL;
END;
END IF;
payload := json_build_object(
'op', op,
'data', row_data,
'session_variables', session_variables,
'trace_context', trace_context
);
INSERT INTO hdb_catalog.event_log
(id, schema_name, table_name, trigger_name, payload)
VALUES
(id, schema_name, table_name, trigger_name, payload);
RETURN id;
END;
$$ LANGUAGE plpgsql;

DROP FUNCTION hdb_catalog.current_setting(text);

0 comments on commit 66e85ab

Please sign in to comment.