kvesteri / postgresql-audit

Audit trigger for PostgreSQL
BSD 2-Clause "Simplified" License
126 stars 28 forks source link

Postgresql-audit is incompatible with postgres 9.5 #12

Closed adarshk7 closed 8 years ago

adarshk7 commented 8 years ago
E   sqlalchemy.exc.InternalError: (psycopg2.InternalError) cannot drop operator -(jsonb,text) because it is required by the database system
E    [SQL: '-- http://schinckel.net/2014/09/29/adding-json%%28b%%29-operators-to-postgresql/\nCREATE OR REPLACE FUNCTION "jsonb_subtract"(\n  "json" jsonb,\n  "key_to_remove" TEXT\n)\n  RETURNS jsonb\n  LANGUAGE sql\n  IMMUTABLE\n  STRICT\nAS $function$\nSELECT CASE WHEN "json" ? "key_to_remove" THEN COALESCE(\n  (SELECT (\'{\' || string_agg(to_json("key")::text || \':\' || "value", \',\') || \'}\')\n     FROM jsonb_each("json")\n    WHERE "key" <> "key_to_remove"),\n  \'{}\'\n)::jsonb\nELSE "json"\nEND\n$function$;\n\nDROP OPERATOR IF EXISTS - (jsonb, text);\nCREATE OPERATOR - (\n  LEFTARG = jsonb,\n  RIGHTARG = text,\n  PROCEDURE = jsonb_subtract\n);\n\n\nCREATE OR REPLACE FUNCTION "jsonb_subtract"(\n  "json" jsonb,\n  "keys" TEXT[]\n)\n  RETURNS jsonb\n  LANGUAGE sql\n  IMMUTABLE\n  STRICT\nAS $function$\nSELECT CASE WHEN "json" ?| "keys" THEN COALESCE(\n  (SELECT (\'{\' || string_agg(to_json("key")::text || \':\' || "value", \',\') || \'}\')\n     FROM jsonb_each("json")\n    WHERE "key" <> ALL ("keys")),\n  \'{}\'\n)::jsonb\nELSE "json"\nEND\n$function$;\n\nDROP OPERATOR IF EXISTS - (jsonb, text[]);\nCREATE OPERATOR - (\n  LEFTARG = jsonb,\n  RIGHTARG = text[],\n  PROCEDURE = jsonb_subtract\n);\n\nCREATE OR REPLACE FUNCTION "jsonb_subtract"(\n  "json" jsonb,\n  "remove" jsonb\n)\n  RETURNS jsonb\n  LANGUAGE sql\n  IMMUTABLE\n  STRICT\nAS $function$\nSELECT COALESCE(\n  (\n    SELECT (\'{\' || string_agg(to_json("key")::text || \':\' || "value", \',\') || \'}\')\n    FROM jsonb_each("json")\n    WHERE NOT\n      (\'{\' || to_json("key")::text || \':\' || "value" || \'}\')::jsonb <@ "remove"\n      -- Note: updated using code from http://8kb.co.uk/blog/2015/01/16/wanting-for-a-hstore-style-delete-operator-in-jsonb/\n  ),\n  \'{}\'\n)::jsonb\n$function$;\n\nDROP OPERATOR IF EXISTS - (jsonb, jsonb);\n\nCREATE OPERATOR - (\n  LEFTARG = jsonb,\n  RIGHTARG = jsonb,\n  PROCEDURE = jsonb_subtract\n);\n\nCREATE OR REPLACE FUNCTION public.jsonb_merge(data jsonb, merge_data jsonb)\nRETURNS jsonb\nIMMUTABLE\nLANGUAGE sql\nAS $$\n    SELECT (\'{\'||string_agg(to_json(key)||\':\'||value, \',\')||\'}\')::jsonb\n    FROM (\n        WITH to_merge AS (\n            SELECT * FROM jsonb_each(merge_data)\n        )\n        SELECT *\n        FROM jsonb_each(data)\n        WHERE key NOT IN (SELECT key FROM to_merge)\n        UNION ALL\n        SELECT * FROM to_merge\n    ) t;\n$$;\n\nCREATE OR REPLACE FUNCTION public.jsonb_change_key_name(data jsonb, old_key text, new_key text)\nRETURNS jsonb\nIMMUTABLE\nLANGUAGE sql\nAS $$\n    SELECT (\'{\'||string_agg(to_json(CASE WHEN key = old_key THEN new_key ELSE key END)||\':\'||value, \',\')||\'}\')::jsonb\n    FROM (\n        SELECT *\n        FROM jsonb_each(data)\n    ) t;\n$$;\n\nCREATE OR REPLACE FUNCTION audit.create_activity() RETURNS TRIGGER AS $body$\nDECLARE\n    audit_row audit.activity;\n    audit_row_values audit.activity;\n    excluded_cols text[] = ARRAY[]::text[];\nBEGIN\n    IF TG_WHEN <> \'AFTER\' THEN\n        RAISE EXCEPTION \'audit.create_activity() may only run as an AFTER trigger\';\n    END IF;\n\n    BEGIN\n        SELECT * FROM activity_values INTO audit_row_values LIMIT 1;\n    EXCEPTION WHEN others THEN\n    END;\n\n    audit_row.id = nextval(\'audit.activity_id_seq\');\n    audit_row.schema_name = TG_TABLE_SCHEMA::text;\n    audit_row.table_name = TG_TABLE_NAME::text;\n    audit_row.relid = TG_RELID;\n    audit_row.issued_at = COALESCE(\n        audit_row_values.issued_at,\n        statement_timestamp()\n    );\n    audit_row.transaction_id = COALESCE(\n        audit_row_values.transaction_id,\n        txid_current()\n    );\n    audit_row.client_addr = COALESCE(\n        audit_row_values.client_addr,\n        inet_client_addr()\n    );\n    audit_row.verb = COALESCE(audit_row_values.verb, LOWER(TG_OP));\n    audit_row.actor_id = audit_row_values.actor_id;\n    audit_row.target_id = audit_row_values.target_id;\n    audit_row.old_data = NULL;\n    audit_row.changed_data = NULL;\n\n    IF TG_ARGV[0] IS NOT NULL THEN\n        excluded_cols = TG_ARGV[0]::text[];\n    END IF;\n\n    IF (TG_OP = \'UPDATE\' AND TG_LEVEL = \'ROW\') THEN\n        audit_row.old_data = row_to_json(OLD.*)::jsonb - excluded_cols;\n        audit_row.changed_data = (\n            row_to_json(NEW.*)::jsonb - audit_row.old_data - excluded_cols\n        );\n        IF audit_row.changed_data = \'{}\'::jsonb THEN\n            -- All changed fields are ignored. Skip this update.\n            RETURN NULL;\n        END IF;\n    ELSIF (TG_OP = \'DELETE\' AND TG_LEVEL = \'ROW\') THEN\n        audit_row.old_data = row_to_json(OLD.*)::jsonb - excluded_cols;\n    ELSIF (TG_OP = \'INSERT\' AND TG_LEVEL = \'ROW\') THEN\n        audit_row.changed_data = row_to_json(NEW.*)::jsonb - excluded_cols;\n    ELSE\n        RAISE EXCEPTION \'[audit.create_activity] - Trigger func added as trigger for unhandled case: %%, %%\', TG_OP, TG_LEVEL;\n        RETURN NULL;\n    END IF;\n    INSERT INTO audit.activity VALUES (audit_row.*);\n    RETURN NULL;\nEND;\n$body$\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = pg_catalog, public;\n\n\nCOMMENT ON FUNCTION audit.create_activity() IS $body$\nTrack changes to a table at the statement and/or row level.\n\nOptional parameters to trigger in CREATE TRIGGER call:\n\nparam 0: boolean, whether to log the query text. Default \'t\'.\n\nparam 1: text[], columns to ignore in updates. Default [].\n\n         Updates to ignored cols are omitted from changed_fields.\n\n         Updates with only ignored cols changed are not inserted\n         into the audit log.\n\n         Almost all the processing work is still done for updates\n         that ignored. If you need to save the load, you need to use\n         WHEN clause on the trigger instead.\n\n         No warning or error is issued if ignored_cols contains columns\n         that do not exist in the target table. This lets you specify\n         a standard set of ignored columns.\n\nThere is no parameter to disable logging of values. Add this trigger as\na \'FOR EACH STATEMENT\' rather than \'FOR EACH ROW\' trigger if you do not\nwant to log row values.\n\nNote that the user name logged is the login role for the session. The audit trigger\ncannot obtain the active role because it is reset by the SECURITY DEFINER invocation\nof the audit trigger its self.\n$body$;\nCREATE OR REPLACE FUNCTION audit.audit_table(target_table regclass, ignored_cols text[]) RETURNS void AS $body$\nDECLARE\n    stm_targets text = \'INSERT OR UPDATE OR DELETE OR TRUNCATE\';\n    _q_txt text;\n    _ignored_cols_snip text = \'\';\nBEGIN\n    EXECUTE \'DROP TRIGGER IF EXISTS audit_trigger_row ON \' || target_table;\n    EXECUTE \'DROP TRIGGER IF EXISTS audit_trigger_stm ON \' || target_table;\n\n    IF array_length(ignored_cols, 1) > 0 THEN\n        _ignored_cols_snip = \', \' || quote_literal(ignored_cols);\n    END IF;\n    _q_txt = \'CREATE TRIGGER audit_trigger_row AFTER INSERT OR UPDATE OR DELETE ON \' ||\n             target_table ||\n             \' FOR EACH ROW EXECUTE PROCEDURE audit.create_activity(\' ||\n             _ignored_cols_snip ||\n             \');\';\n    RAISE NOTICE \'%%\',_q_txt;\n    EXECUTE _q_txt;\n    stm_targets = \'TRUNCATE\';\nEND;\n$body$\nlanguage \'plpgsql\';\n\nCOMMENT ON FUNCTION audit.audit_table(regclass, text[]) IS $body$\nAdd auditing support to a table.\n\nArguments:\n   target_table:     Table name, schema qualified if not on search_path\n   ignored_cols:     Columns to exclude from update diffs, ignore updates that change only ignored cols.\n$body$;\n\n\nCREATE OR REPLACE FUNCTION audit.audit_table(target_table regclass) RETURNS void AS $body$\nSELECT audit.audit_table($1, ARRAY[]::text[]);\n$body$ LANGUAGE SQL;\n\n\nCOMMENT ON FUNCTION audit.audit_table(regclass) IS $body$\nAdd auditing support to the given tab
kvesteri commented 8 years ago

Fixed as of #14