Versioning

Fork/mirror of https://gitlab.com/depesz/Versioning
git clone https://ccx.te2000.cz/git/Versioning
Log | Files | Refs | README | LICENSE

commit 86bcac9fa93079fe8b264a28530712bdb09d685f
parent c1b2f723f023a2daa5e086eed176ac19483ad3a7
Author: Hubert depesz Lubaczewski <depesz@depesz.com>
Date:   Mon,  7 Aug 2017 16:38:11 +0200

Add "what current user is" assert functions

In process also add proper README

Diffstat:
MCHANGES | 4++++
DREADME | 18------------------
AREADME.md | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minstall.versioning.sql | 37+++++++++++++++++++++++++++++++++++++
4 files changed, 155 insertions(+), 18 deletions(-)

diff --git a/CHANGES b/CHANGES @@ -1,2 +1,6 @@ +2017-08-07 : +- Added functions to assert that user (loading patch) is either superuser, or + is not superuser, or is one of listed users. + 2010-08-22 : - Initial release to github.com : http://github.com/depesz/Versioning diff --git a/README b/README @@ -1,18 +0,0 @@ -Versioning - -This project strives to provide simple way to manage changes to -database. - -Instead of making changes on development server, then finding -differences between production and development, deciding which ones -should be installed on production, and finding a way to install them - -you start with writing diffs themselves! - -More detailed description is (so far) in here: -http://www.depesz.com/index.php/2010/08/22/versioning/ - -To install versioning simply run install.versioning.sql in your database -(all of them: production, stage, test, devel, ...). - -If you'd like to suggest new functionality or ask anything - please use -contact form on http://www.depesz.com/ diff --git a/README.md b/README.md @@ -0,0 +1,114 @@ +# NAME + +**Versioning** - simplistic take on tracking and applying changes to databases. + +# DESCRIPTION + +This project strives to provide simple way to manage changes to +database. + +Instead of making changes on development server, then finding +differences between production and development, deciding which ones +should be installed on production, and finding a way to install them - +you start with writing diffs themselves! + +# INSTALLATION + +To install versioning simply run install.versioning.sql in your database +(all of them: production, stage, test, devel, ...). + +# USAGE + +In your files with patches to database, put whole logic in single +transaction, and use \_v.\* functions - usually \_v.register_patch() at +least to make sure everything is OK. + +For example. Let's assume you have patch files: + +## 000-base.sql: + +``` +create table users (id serial primary key, username text); +``` + +## 001-users.sql: + +``` +insert into users (username) values ('depesz'); +``` + +To change it to use versioning you would change the files, to this +state: + +## 000-base.sql: + +``` +BEGIN; +select _v.register_patch('000-base', NULL, NULL); +create table users (id serial primary key, username text); +COMMIT; +``` + +## 001-users.sql: + +``` +BEGIN; +select _v.register_patch('001-users', ARRAY['000-base'], NULL); +insert into users (username) values ('depesz'); +COMMIT; +``` + +This will make sure that patch 001-users can only be applied after +000-base. + +# AVAILABLE FUNCTIONS + +## \_v.register_patch( TEXT ) + +Registers named patch, or dies if it is already registered. + +Returns integer which is id of patch in \_v.patches table - only if it +succeeded. + +## \_v.register_patch( TEXT, TEXT[] ) + +Same as \_v.register_patch( TEXT ), but checks is all given patches (given as +array in second argument) are already registered. + +## \_v.register_patch( TEXT, TEXT[], TEXT[] ) + +Same as \_v.register_patch( TEXT, TEXT[] ), but also checks if there are no conflicts with preexisting patches. + +Third argument is array of names of patches that conflict with current one. So +if any of them is installed - register_patch will error out. + +## \_v.unregister_patch( TEXT ) + +Removes information about given patch from the versioning data. + +It doesn't remove objects that were created by this patch - just removes +metainformation. + +## \_v.assert_user_is_superuser() + +Make sure that current patch is being loaded by superuser. + +If it's not - it will raise exception, and break transaction. + +## \_v.assert_user_is_not_superuser() + +Make sure that current patch is not being loaded by superuser. + +If it is - it will raise exception, and break transaction. + +## \_v.assert_user_is_one_of(TEXT, TEXT, ... ) + +Make sure that current patch is being loaded by one of listed users. + +If ```current_user``` is not listed as one of arguments - function will raise +exception and break the transaction. + +# SUPPORT + +If you'd like to suggest new functionality or ask anything - please use +contact information from https://depesz.com/ diff --git a/install.versioning.sql b/install.versioning.sql @@ -94,4 +94,41 @@ END; $$ language plpgsql; COMMENT ON FUNCTION _v.unregister_patch( TEXT ) IS 'Function to unregister patches in database. Dies if the patch is not registered, or if unregistering it would break dependencies.'; +CREATE OR REPLACE FUNCTION _v.assert_user_is_superuser() RETURNS TEXT as $$ +DECLARE + v_super bool; +BEGIN + SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user; + IF v_super THEN + RETURN 'assert_user_is_superuser: OK'; + END IF; + RAISE EXCEPTION 'Current user is not superuser - cannot continue.'; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.assert_user_is_superuser() IS 'Function that can be used to make sure that patch is being applied using superuser account.'; + +CREATE OR REPLACE FUNCTION _v.assert_user_is_not_superuser() RETURNS TEXT as $$ +DECLARE + v_super bool; +BEGIN + SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user; + IF v_super THEN + RAISE EXCEPTION 'Current user is superuser - cannot continue.'; + END IF; + RETURN 'assert_user_is_not_superuser: OK'; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.assert_user_is_not_superuser() IS 'Function that can be used to make sure that patch is being applied using normal (not superuser) account.'; + +CREATE OR REPLACE FUNCTION _v.assert_user_is_one_of(VARIADIC p_acceptable_users TEXT[] ) RETURNS TEXT as $$ +DECLARE +BEGIN + IF current_user = any( p_acceptable_users ) THEN + RETURN 'assert_user_is_one_of: OK'; + END IF; + RAISE EXCEPTION 'User is not one of: % - cannot continue.', p_acceptable_users; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.assert_user_is_one_of(TEXT[]) IS 'Function that can be used to make sure that patch is being applied by one of defined users.'; + COMMIT;