Simple SQL Change  Management with Sqitch                                                        David E. Wheeler         ...
Whats Wrong with  Migrations?
Whats Wrong with    Migrations?Incomplete mini-language
Whats Wrong with     Migrations?Incomplete mini-languageNo logical replication integration
Whats Wrong with     Migrations?Incomplete mini-languageNo logical replication integrationNumbered scripts hard to track
Whats Wrong with     Migrations?Incomplete mini-languageNo logical replication integrationNumbered scripts hard to trackNo...
What about SQL      Migrations?Incomplete mini-languageNo logical replication integrationNumbered scripts hard to trackNo ...
What about SQL      Migrations?———————————————Incomplete mini-languageNo logical replication integrationNumbered scripts h...
What about SQL      Migrations?———————————————Incomplete mini-language———————————————————No logical replication integratio...
What about SQL      Migrations?———————————————Incomplete mini-language———————————————————No logical replication integratio...
Imagine this Change>
Imagine this Change>git diffdiff --git a/sql/deploy/recur.sql b/sql/deploy/recur.sqlindex 622d52e..56e419e 100644--- a/sql...
Imagine this Change>git diffdiff --git a/sql/deploy/recur.sql b/sql/deploy/recur.sqlindex 622d52e..56e419e 100644--- a/sql...
Not So Much
Not So MuchPaste entire function to new “up” script
Not So MuchPaste entire function to new “up” scriptEdit the new file
Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” script
Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” scriptThree copies...
Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” scriptThree copies...
Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” scriptThree copies...
What about Liquibase?filename
What about Liquibase?<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbcha...
What about Liquibase?<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbcha...
What about Liquibase?<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbcha...
depesz’s Versioning?
depesz’s Versioning?https:/      /github.com/depesz/versioning
depesz’s Versioning?https:/      /github.com/depesz/versioningNice dependency specification
depesz’s Versioning?https:/      /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integration
depesz’s Versioning?https:/      /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integrationNo ...
depesz’s Versioning?https:/      /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integrationNo ...
depesz’s Versioning?https:/      /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integrationNo ...
Introducing   Sqitch
Sq—what?SQL ch anges
Sq—what?SQ ch
Sq—what?SQitch
Sq—what?SQitch There is no “u”
Sqitch Philosophy
Sqitch PhilosophyNo opinions
Sqitch PhilosophyNo opinionsNative scripting
Sqitch PhilosophyNo opinionsNative scriptingVCS integration
Sqitch PhilosophyNo opinionsNative scriptingVCS integrationDependency resolution
Sqitch PhilosophyNo opinionsNative scriptingVCS integrationDependency resolutionNo numbering
Sqitch PhilosophyNo opinionsNative scriptingVCS integrationDependency resolutionNo numberingDistribution bundling
Sqitch Philosophy
Sqitch PhilosophyReduced duplication
Sqitch PhilosophyReduced duplicationBuilt-in configuration
Sqitch PhilosophyReduced duplicationBuilt-in configurationDeployment planning
Sqitch PhilosophyReduced duplicationBuilt-in configurationDeployment planningGit-style interface
Sqitch PhilosophyReduced duplicationBuilt-in configurationDeployment planningGit-style interfaceDeployment tagging
Sqitch Terminology
Sqitch Terminologystep
Sqitch Terminologysteptag
Sqitch Terminologysteptagplan
Sqitch Terminologysteptagplandeploy
Sqitch Terminologysteptagplandeployrevert
Caveats
Caveats
CaveatsUnder heavy development
CaveatsUnder heavy developmentv0.30 Testing release today
CaveatsUnder heavy developmentv0.30 Testing release todayFunctionality rapidly evolving
CaveatsUnder heavy developmentv0.30 Testing release todayFunctionality rapidly evolvingSome gaps still to be filled in
CaveatsUnder heavy developmentv0.30 Testing release todayFunctionality rapidly evolvingSome gaps still to be filled inVCS ...
How it Works>
How it Works>mkdir flipr> cd flipr> git init .Initialized empty Git repository in /flipr/.git/> touch README.md> git add .> g...
How it Works>mkdir flipr> cd flipr> git init .Initialized empty Git repository in /flipr/.git/> touch README.md> git add .> g...
How it Works>mkdir flipr> cd flipr> git init .Initialized empty Git repository in /flipr/.git/> touch README.md> git add .> g...
sqitch.conf[core]   engine = pg   # plan_file = sqitch.plan   # sql_dir = sql   # deploy_dir = sql/deploy   # revert_dir = ...
sqitch.conf[core]    engine = pg                       --engine pg    # plan_file = sqitch.plan   # sql_dir = sql   # deplo...
Add User Config>
Add User Config>sqitch config --user core.pg.client /var/lib/pgsql/bin/psql>
Add User Config>sqitch config --user core.pg.client /var/lib/pgsql/bin/psql>
Add User Config>sqitch config --user core.pg.client /var/lib/pgsql/bin/psql>emacs ~/.sqitch/sqitch.conf
~/          .sqitch/sqitch.conf[core "pg"]   client = /var/lib/pgsql/bin/psql  ~/.sqitch/sqitc
~/          .sqitch/sqitch.conf[core "pg"]   client = /var/lib/pgsql/bin/psql                    Good for                 ...
Make It So>
Make It So>git add .> git commit -am Initialize Sqitch configuration.[master (root-commit) a22000d] Initialize Sqitchconfigu...
First Deployment>
First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appu...
First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appu...
First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appu...
sql/deploy/appuser.sql-- Deploy appuserBEGIN;-- XXX Add DDLs here.COMMIT;  sql/deploy/appu
sql/deploy/appuser.sql-- Deploy appuserBEGIN;CREATE ROLE flipr WITH LOGIN;COMMIT;  sql/deploy/appu
First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appu...
First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appu...
sql/revert/appuser.sql-- Revert appuserBEGIN;-- XXX Add DDLs here.COMMIT;  sql/deploy/appu
sql/revert/appuser.sql-- Revert appuserBEGIN;DROP ROLE flipr;COMMIT;  sql/deploy/appu
Make it So!>
Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying ...
Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying ...
Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying ...
Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying ...
Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying ...
How’s it Look?>
How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#No...
How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#No...
How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#No...
How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#No...
Go Back>
Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test - appuser>
Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test - appuser>
Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test - appuser>
Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test  - appuser>psql -d flipr_test -c du flipr     ...
What’s The Status?>
What’s The Status?>sqitch -d flipr_test status --untracked# On database flipr_test# Nothing deployed.## Changes not deployed...
What’s The Status?>sqitch -d flipr_test status --untracked# On database flipr_test# Nothing deployed.## Changes not deployed...
History>
History>sqitch -d flipr_test logstep appuser revertedBy: davidDate: 2012-05-18 17:15:23Tag: HEAD+step appuser deployedBy: d...
History>sqitch -d flipr_test logstep appuser revertedBy: davidDate: 2012-05-18 17:15:23Tag: HEAD+step appuser deployedBy: d...
History>sqitch -d flipr_test logstep appuser revertedBy: davidDate: 2012-05-18 17:15:23Tag: HEAD+step appuser deployedBy: d...
Commit It!>
Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mod...
Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mod...
Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mod...
Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mod...
Status Update>
Status Update> sqitch -d flipr_test status# On database flipr_test# Tag: 36acafd# Step: appuser# Date: 2012-05-18 17:21:54#N...
Save My Fingers>
Save My Fingers>sqitch config core.pg.db_name flipr_test>
Save My Fingers>sqitch config core.pg.db_name flipr_test>sqitch status# On database flipr_test# Tag: 36acafd                 ...
Dependencies!>
Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql      -- requires: appuserCreated sql/r...
Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql      -- requires: appuserCreated sql/r...
Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql      -- requires: appuserCreated sql/r...
sql/deploy/users.sql-- Deploy users-- :requires: appuserBEGIN;-- XXX Add DDLs here.COMMIT;  sql/deploy/user
sql/deploy/users.sql-- Deploy users-- :requires: appuserBEGIN;-- XXX Add DDLs here.COMMIT;  sql/deploy/user
sql/deploy/users.sql-- Deploy users-- :requires: appuserBEGIN;CREATE TABLE users (   nickname TEXT     PRIMARY KEY,   pass...
Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql      -- requires: appuserCreated sql/r...
Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql      -- requires: appuserCreated sql/r...
sql/revert/users-- Revert usersBEGIN;-- XXX Add DDLs here.COMMIT;  sql/deploy/user
sql/revert/users-- Revert usersBEGIN;DROP TABLE users;COMMIT;  sql/deploy/user
Make Users>
Make Users>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + users>
Make Users>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + users>
Make Users>sqitch deploy --untrackedDeploying HEAD+ to flipr_test  + users> psql -d flipr_test -c d users             Table ...
Status Update>
Status Update> sqitch status# On database flipr_test# Tag: HEAD+# Step: users# Date: 2012-05-18 17:25:39#Nothing to deploy ...
Status Update> sqitch status# On database flipr_test# Tag: HEAD+# Step: users# Date: 2012-05-18 17:25:39#Nothing to deploy ...
Status Update> sqitch status# On database flipr_test# Tag: HEAD+# Step: users# Date: 2012-05-18 17:25:39#Nothing to deploy ...
Check in and Deploy>
Check in and Deploy>git add .> git commit -am Add users table.[master fa650af] Add users table. 2 files changed, 16 inserti...
Check in and Deploy>git add .> git commit -am Add users table.[master fa650af] Add users table. 2 files changed, 16 inserti...
Up to Date>
Up to Date> sqitch status --show tags# On database flipr_test# Tag: fa650af# Step: users# Date: 2012-05-18 17:31:23## Tags:...
Up to Date> sqitch status --show tags# On database flipr_test# Tag: fa650af# Step: users# Date: 2012-05-18 17:31:23## Tags:...
Up to Date> sqitch status --show tags# On database flipr_test# Tag: fa650af# Step: users# Date: 2012-05-18 17:31:23## Tags:...
A Twofer>
A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql    -- requires: users, appuserAd...
A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql    -- requires: users, appuserAd...
A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql    -- requires: users, appuserAd...
A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql    -- requires: users, appuserAd...
A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql    -- requires: users, appuserAd...
sql/deploy/                    insert_user.sql-- Deploy insert_user-- :requires: appuser-- :requires: usersBEGIN;-- XXX Ad...
sql/deploy/                    insert_user.sql-- Deploy insert_user-- :requires: appuser-- :requires: usersBEGIN;-- XXX Ad...
sql/deploy/                    insert_user.sql-- Deploy insert_user-- :requires: appuser-- :requires: usersBEGIN;CREATE OR...
A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql    -- requires: users, appuserAd...
A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql    -- requires: users, appuserAd...
sql/deploy/                   change_pass.sql-- Deploy change_pass-- :requires: appuser-- :requires: usersBEGIN;-- XXX Add...
sql/deploy/                   change_pass.sql-- Deploy change_pass-- :requires: appuser-- :requires: usersBEGIN;CREATE OR ...
Deploy Functions>
Deploy Functions>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + change_pass + insert_user>
Deploy Functions>sqitch deploy --untrackedDeploying HEAD+ to flipr_test  + change_pass  + insert_user>psql -d flipr_test -c ...
Commit It
Commit Itsqitch revert --to HEAD
Commit Itsqitch revert --to HEADgit add && git commit
Commit Itsqitch revert --to HEADgit add && git commitsqitch deploy
Commit Itsqitch revert --to HEADgit add && git commitsqitch deployAnd now…
Stage It>
Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>
Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>createdb flipr_dev> sqitch --db-name flipr_dev deployDeploying 36acafd to fl...
Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>createdb flipr_dev> sqitch --db-name flipr_dev deployDeploying 36acafd to fl...
Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>createdb flipr_dev> sqitch --db-name flipr_dev deployDeploying 36acafd to fl...
Stage Status?>
Stage Status?>sqitch --db-name flipr_dev status --show tags# On database flipr_dev# Tags: 803e6b8, v1.0.0-dev1# Step: change...
Distribution Bundling
Distribution BundlingBundle plan + scripts for deployment
Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS history
Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as
Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as  RPM
Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as  RPM  Debian Package
Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as  RPM  Debian Package...
Ship It!>
Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - u...
Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - u...
Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - u...
Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - u...
Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - u...
The Plan, Man[v1.0.0-dev1]appuseruserschange_passinsert_user  bundle/sqitch.p
Kick the Tires>
Kick the Tires>cd bundle> createdb flipr_staging> sqitch --db-name flipr_staging deployDeploying v1.0.0-dev1 to flipr_prod + ...
Kick the Tires>cd bundle> createdb flipr_staging> sqitch --db-name flipr_staging deployDeploying v1.0.0-dev1 to flipr_prod + ...
Ch-Check it Out>
Ch-Check it Out>sqitch --db-name flipr_prod status --show tags# On database flipr_prod# Tag: v1.0.0-dev1# Step: change_pass#...
Ch-Check it Out>sqitch --db-name flipr_prod status --show tags# On database flipr_prod# Tag: v1.0.0-dev1# Step: change_pass ...
Ruh-Roh>
Ruh-Roh>psql -d flipr_test -c "   SELECT insert_user(foo, secr3t),       insert_user(bar, secr3t);   SELECT nickname, passw...
Ruh-Roh>psql -d flipr_test -c "   SELECT insert_user(foo, secr3t),       insert_user(bar, secr3t);   SELECT nickname, passw...
Add pgcrypto>
Add pgcrypto>sqitch add-step pgcryptoAdding sql/deploy/pgcrypto.sqlAdding sql/revert/pgcrypto.sqlAdding sql/test/pgcrypto....
Add pgcrypto>sqitch add-step pgcryptoAdding sql/deploy/pgcrypto.sqlAdding sql/revert/pgcrypto.sqlAdding sql/test/pgcrypto....
ssql/deploy/pgcrypto.sql-- Deploy pgcryptoBEGIN;-- XXX Add DDLs here.COMMIT;  sql/deploy/pgcr
ssql/deploy/pgcrypto.sql-- Deploy pgcryptoBEGIN;CREATE EXTENSION pgcrypto;COMMIT;  sql/deploy/pgcr
How to Modify?
How to Modify?Copy insert_user.sql to new deploy file
How to Modify?Copy insert_user.sql to new deploy fileChange that new file
How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert file
How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert fileTest it
How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert fileTest itDo ...
How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert fileTest itDo ...
>
> git diff HEAD^diff --git a/sql/deploy/insert_user_crypt.sql b/sql/deploy/insert_user_crnew file mode 100644index 0000000....
> git diff HEAD^diff --git a/sql/deploy/insert_user_crypt.sql b/sql/deploy/insert_user_crnew file mode 100644index 0000000....
Use the VCS, Luke
Use the VCS, LukeJust modify deploy scripts directly
Use the VCS, LukeJust modify deploy scripts directlyRequirement:
Use the VCS, LukeJust modify deploy scripts directlyRequirement:  Change must be idempotent
Use the VCS, LukeJust modify deploy scripts directlyRequirement:  Change must be idempotent  Same result no matter how oft...
Use the VCS, LukeJust modify deploy scripts directlyRequirement:  Change must be idempotent  Same result no matter how oft...
Use the VCS, LukeJust modify deploy scripts directlyRequirement:  Change must be idempotent  Same result no matter how oft...
What’s the Diff?>
What’s the Diff?>diff -u sql/deploy/insert_user.sql@@ -1,8 +1,8 @@--- requires: users, appuser+-- requires: users, appuser...
What’s the Diff?>
What’s the Diff?>diff -u sql/deploy/change_pass.sql@@ -1,4 +1,4 @@--- requires: users, appuser+-- requires: users, appuser...
Send it Up!>
Send it Up!>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + insert_user + change_pass>
Send it Up!>sqitch deploy --untrackedDeploying HEAD+ to flipr_test  + insert_user  + change_pass>psql -d flipr_test -c "   D...
Send it Up!>sqitch deploy --untrackedDeploying HEAD+ to flipr_test  + insert_user  + change_pass>psql -d flipr_test -c "    ...
Can We Go Back?>
Can We Go Back?>sqitch revert --to HEADReverting HEAD+ from flipr_test - change_pass - insert_user>
Can We Go Back?>sqitch revert --to HEADReverting HEAD+ from flipr_test  - change_pass  - insert_user>psql -d flipr_test -c "...
What About Bundling?>
What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bu...
What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bu...
What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bu...
What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bu...
What’s the Plan?[v1.0.0-dev1]  appuser  users  change_pass  insert_user[v1.0.0-b1]  change_pass_v2  insert_user_v2  filename
Make it So>
Make it So>cd bundle> sqitch -d flipr_staging deployDeploying v1.0.0-b1 to flipr_staging + change_pass_v2 + insert_user_v2>
Make it So>cd bundle> sqitch -d flipr_staging deployDeploying v1.0.0-b1 to flipr_staging  + change_pass_v2  + insert_user_v2...
Ship It!
Other Commands
Other Commandslog - Like git log
Other Commandslog - Like git logcheck - Validate plan & database
Other Commandslog - Like git logcheck - Validate plan & databasetest - Test deployment success
Other Commandslog - Like git logcheck - Validate plan & databasetest - Test deployment successhelp - Get it
Current Status
Current StatusWorking on it full time
Current StatusWorking on it full timeRethinking VCS integration
Current StatusWorking on it full timeRethinking VCS integration  Rely more on plan file
Current StatusWorking on it full timeRethinking VCS integration  Rely more on plan file  Complement with VCS history
Current StatusWorking on it full timeRethinking VCS integration  Rely more on plan file  Complement with VCS historyTools ...
Fork It
Fork Ithttp:/     /sqitch.org/
Fork Ithttp:/     /sqitch.org/https:/      /github.com/theory/sqitch/
Fork Ithttp:/     /sqitch.org/https:/      /github.com/theory/sqitch/Opinions wanted
Fork Ithttp:/     /sqitch.org/https:/      /github.com/theory/sqitch/Opinions wantedCoders wanted
Fork Ithttp:/     /sqitch.org/https:/      /github.com/theory/sqitch/Opinions wantedCoders wantedDoc writers and web desig...
Fork Ithttp:/     /sqitch.org/https:/      /github.com/theory/sqitch/Opinions wantedCoders wantedDoc writers and web desig...
Thank you.
Simple SQL Change  Management with Sqitch                                                       David E. Wheeler          ...
Simple SQL Change Management with Sqitch
Upcoming SlideShare
Loading in …5
×

Simple SQL Change Management with Sqitch

7,108 views

Published on

SQL change management has always sucked. This talk introduces Sqitch, the VCS-aware SQL change management application that doesn’t suck. Come see how it works, learn the few simple rules you need to get the most out of it, and liberate yourself from the suckitude.

Published in: Technology, Business
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,108
On SlideShare
0
From Embeds
0
Number of Embeds
112
Actions
Shares
0
Downloads
43
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide
  • TODO:\n&amp;#x2022; Add more privilege stuff?\n&amp;#x2022; Add example of renaming `flips.timestamp`?\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • TODO:\n&amp;#x2022; Add more privilege stuff?\n&amp;#x2022; Add example of renaming `flips.timestamp`?\n
  • Simple SQL Change Management with Sqitch

    1. Simple SQL Change Management with Sqitch David E. Wheeler PGCon 2012 Ottawa, CanadaText: Attribution-Noncommercial-Share Alike 3.0 United States:http://creativecommons.org/licenses/by-nc-sa/3.0/us/Images licensed independently and © Their respective owners.
    2. Whats Wrong with Migrations?
    3. Whats Wrong with Migrations?Incomplete mini-language
    4. Whats Wrong with Migrations?Incomplete mini-languageNo logical replication integration
    5. Whats Wrong with Migrations?Incomplete mini-languageNo logical replication integrationNumbered scripts hard to track
    6. Whats Wrong with Migrations?Incomplete mini-languageNo logical replication integrationNumbered scripts hard to trackNo VCS awareness
    7. What about SQL Migrations?Incomplete mini-languageNo logical replication integrationNumbered scripts hard to trackNo VCS awareness
    8. What about SQL Migrations?———————————————Incomplete mini-languageNo logical replication integrationNumbered scripts hard to trackNo VCS awareness
    9. What about SQL Migrations?———————————————Incomplete mini-language———————————————————No logical replication integrationNumbered scripts hard to trackNo VCS awareness
    10. What about SQL Migrations?———————————————Incomplete mini-language———————————————————No logical replication integrationNumbered scripts hard to trackNo VCS awarenessManaging procedures is a PITA
    11. Imagine this Change>
    12. Imagine this Change>git diffdiff --git a/sql/deploy/recur.sql b/sql/deploy/recur.sqlindex 622d52e..56e419e 100644--- a/sql/deploy/recur.sql+++ b/sql/deploy/recur.sql@@ -22,7 +22,10 @@ recurrence <> none OR ( recurrence = none- AND starts_at BETWEEN range_start AND range_end+ AND (+ starts_at BETWEEN range_start AND range_end+ OR ends_at BETWEEN range_start AND range_end+ ) ) ) LOOP
    13. Imagine this Change>git diffdiff --git a/sql/deploy/recur.sql b/sql/deploy/recur.sqlindex 622d52e..56e419e 100644--- a/sql/deploy/recur.sql+++ b/sql/deploy/recur.sql@@ -22,7 +22,10 @@ recurrence <> none OR ( recurrence = none- AND starts_at BETWEEN range_start AND range_end+ AND (+ starts_at BETWEEN range_start AND range_end+ OR ends_at BETWEEN range_start AND range_end+ ) ) Simple, right? ) LOOP
    14. Not So Much
    15. Not So MuchPaste entire function to new “up” script
    16. Not So MuchPaste entire function to new “up” scriptEdit the new file
    17. Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” script
    18. Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” scriptThree copies of the function!
    19. Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” scriptThree copies of the function!No real source code management
    20. Not So MuchPaste entire function to new “up” scriptEdit the new fileCopy the function to the new “down” scriptThree copies of the function!No real source code managementThis sucks
    21. What about Liquibase?filename
    22. What about Liquibase?<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.6 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.6.xsd"> <changeSet id="1" author="me"> <createTable tableName="first_table"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> <column name="name" type="varchar(50)"> <constraints nullable="false"/> </column> </createTable> <createTable tableName="new_table"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> </createTable> </changeSet></databaseChangeLog> filename
    23. What about Liquibase?<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.6 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.6.xsd"> <changeSet id="1" author="me"> <createTable tableName="first_table"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> <column name="name" type="varchar(50)"> Whaaaa? <constraints nullable="false"/> </column> </createTable> <createTable tableName="new_table"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> </createTable> </changeSet></databaseChangeLog> filename
    24. What about Liquibase?<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.6 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.6.xsd"> <changeSet id="1" author="me"> <createTable tableName="first_table"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> <column name="name" type="varchar(50)"> Whaaaa? <constraints nullable="false"/> </column> </createTable> <createTable tableName="new_table"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> GTFO! </column> </createTable> </changeSet></databaseChangeLog> filename
    25. depesz’s Versioning?
    26. depesz’s Versioning?https:/ /github.com/depesz/versioning
    27. depesz’s Versioning?https:/ /github.com/depesz/versioningNice dependency specification
    28. depesz’s Versioning?https:/ /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integration
    29. depesz’s Versioning?https:/ /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integrationNo VCS integration
    30. depesz’s Versioning?https:/ /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integrationNo VCS integrationNo tools
    31. depesz’s Versioning?https:/ /github.com/depesz/versioningNice dependency specificationTight PostgreSQL integrationNo VCS integrationNo toolsManaging procedures still a PITA
    32. Introducing Sqitch
    33. Sq—what?SQL ch anges
    34. Sq—what?SQ ch
    35. Sq—what?SQitch
    36. Sq—what?SQitch There is no “u”
    37. Sqitch Philosophy
    38. Sqitch PhilosophyNo opinions
    39. Sqitch PhilosophyNo opinionsNative scripting
    40. Sqitch PhilosophyNo opinionsNative scriptingVCS integration
    41. Sqitch PhilosophyNo opinionsNative scriptingVCS integrationDependency resolution
    42. Sqitch PhilosophyNo opinionsNative scriptingVCS integrationDependency resolutionNo numbering
    43. Sqitch PhilosophyNo opinionsNative scriptingVCS integrationDependency resolutionNo numberingDistribution bundling
    44. Sqitch Philosophy
    45. Sqitch PhilosophyReduced duplication
    46. Sqitch PhilosophyReduced duplicationBuilt-in configuration
    47. Sqitch PhilosophyReduced duplicationBuilt-in configurationDeployment planning
    48. Sqitch PhilosophyReduced duplicationBuilt-in configurationDeployment planningGit-style interface
    49. Sqitch PhilosophyReduced duplicationBuilt-in configurationDeployment planningGit-style interfaceDeployment tagging
    50. Sqitch Terminology
    51. Sqitch Terminologystep
    52. Sqitch Terminologysteptag
    53. Sqitch Terminologysteptagplan
    54. Sqitch Terminologysteptagplandeploy
    55. Sqitch Terminologysteptagplandeployrevert
    56. Caveats
    57. Caveats
    58. CaveatsUnder heavy development
    59. CaveatsUnder heavy developmentv0.30 Testing release today
    60. CaveatsUnder heavy developmentv0.30 Testing release todayFunctionality rapidly evolving
    61. CaveatsUnder heavy developmentv0.30 Testing release todayFunctionality rapidly evolvingSome gaps still to be filled in
    62. CaveatsUnder heavy developmentv0.30 Testing release todayFunctionality rapidly evolvingSome gaps still to be filled inVCS integration in flux
    63. How it Works>
    64. How it Works>mkdir flipr> cd flipr> git init .Initialized empty Git repository in /flipr/.git/> touch README.md> git add .> git commit -am Fist post!>
    65. How it Works>mkdir flipr> cd flipr> git init .Initialized empty Git repository in /flipr/.git/> touch README.md> git add .> git commit -am Fist post!>sqitch --engine pg initCreated sql/deployCreated sql/revertCreated sql/testCreated sqitch.conf>
    66. How it Works>mkdir flipr> cd flipr> git init .Initialized empty Git repository in /flipr/.git/> touch README.md> git add .> git commit -am Fist post!>sqitch --engine pg initCreated sql/deployCreated sql/revertCreated sql/testCreated sqitch.conf>emacs sqitch.conf
    67. sqitch.conf[core] engine = pg # plan_file = sqitch.plan # sql_dir = sql # deploy_dir = sql/deploy # revert_dir = sql/revert # test_dir = sql/test # extension = sql# [core "pg"] # db_name = # client = psql # sqitch_schema = sqitch # password = # port = # host = # username = sqitch.conf
    68. sqitch.conf[core] engine = pg --engine pg # plan_file = sqitch.plan # sql_dir = sql # deploy_dir = sql/deploy # revert_dir = sql/revert # test_dir = sql/test # extension = sql# [core "pg"] # db_name = # client = psql # sqitch_schema = sqitch # password = # port = # host = # username = sqitch.conf
    69. Add User Config>
    70. Add User Config>sqitch config --user core.pg.client /var/lib/pgsql/bin/psql>
    71. Add User Config>sqitch config --user core.pg.client /var/lib/pgsql/bin/psql>
    72. Add User Config>sqitch config --user core.pg.client /var/lib/pgsql/bin/psql>emacs ~/.sqitch/sqitch.conf
    73. ~/ .sqitch/sqitch.conf[core "pg"] client = /var/lib/pgsql/bin/psql ~/.sqitch/sqitc
    74. ~/ .sqitch/sqitch.conf[core "pg"] client = /var/lib/pgsql/bin/psql Good for all projects ~/.sqitch/sqitc
    75. Make It So>
    76. Make It So>git add .> git commit -am Initialize Sqitch configuration.[master (root-commit) a22000d] Initialize Sqitchconfiguration. 1 file changed, 16 insertions(+) create mode 100644 sqitch.conf>
    77. First Deployment>
    78. First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appuser.sql>
    79. First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appuser.sql>
    80. First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appuser.sql>emacs sql/deploy/appuser.sql
    81. sql/deploy/appuser.sql-- Deploy appuserBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/appu
    82. sql/deploy/appuser.sql-- Deploy appuserBEGIN;CREATE ROLE flipr WITH LOGIN;COMMIT; sql/deploy/appu
    83. First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appuser.sql> emacs sql/deploy/appuser.sql>
    84. First Deployment> sqitch add-step appuserCreated sql/deploy/appuser.sqlCreated sql/revert/appuser.sqlCreated sql/test/appuser.sql> emacs sql/deploy/appuser.sql>emacs sql/revert/appuser.sql
    85. sql/revert/appuser.sql-- Revert appuserBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/appu
    86. sql/revert/appuser.sql-- Revert appuserBEGIN;DROP ROLE flipr;COMMIT; sql/deploy/appu
    87. Make it So!>
    88. Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying HEAD+ to flipr_test + appuser>
    89. Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying HEAD+ to flipr_test + appuser>
    90. Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying HEAD+ to flipr_test + appuser>
    91. Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying HEAD+ to flipr_test + appuser>
    92. Make it So!>createdb flipr_test> sqitch --db-name flipr_test deploy --untrackedAdding metadata tables to flipr_testDeploying HEAD+ to flipr_test + appuser>psql -d flipr_test -c du flipr List of roles Role name | Attributes | Member of-----------+------------+----------- flipr | | {}>
    93. How’s it Look?>
    94. How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#Nothing to deploy (up-to-date)>
    95. How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#Nothing to deploy (up-to-date)>
    96. How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#Nothing to deploy (up-to-date)>
    97. How’s it Look?> sqitch -d flipr_test status# On database flipr_test# Tag: HEAD+# Step: appuser# Date: 2012-05-18 17:15:23#Nothing to deploy (up-to-date)> Proposed
    98. Go Back>
    99. Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test - appuser>
    100. Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test - appuser>
    101. Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test - appuser>
    102. Go Back>sqitch --db-name flipr_test revertReverting all changes from flipr_test - appuser>psql -d flipr_test -c du flipr List of roles Role name | Attributes | Member of-----------+------------+----------->
    103. What’s The Status?>
    104. What’s The Status?>sqitch -d flipr_test status --untracked# On database flipr_test# Nothing deployed.## Changes not deployed:# * HEAD+# appuser#Use "sqitch deploy --untracked" to deploy thesechanges>
    105. What’s The Status?>sqitch -d flipr_test status --untracked# On database flipr_test# Nothing deployed.## Changes not deployed:# * HEAD+# appuser#Use "sqitch deploy --untracked" to deploy thesechanges>
    106. History>
    107. History>sqitch -d flipr_test logstep appuser revertedBy: davidDate: 2012-05-18 17:15:23Tag: HEAD+step appuser deployedBy: davidDate: 2012-05-18 17:18:12Tag: HEAD+>
    108. History>sqitch -d flipr_test logstep appuser revertedBy: davidDate: 2012-05-18 17:15:23Tag: HEAD+step appuser deployedBy: davidDate: 2012-05-18 17:18:12Tag: HEAD+>
    109. History>sqitch -d flipr_test logstep appuser revertedBy: davidDate: 2012-05-18 17:15:23Tag: HEAD+step appuser deployedBy: davidDate: 2012-05-18 17:18:12Tag: HEAD+>
    110. Commit It!>
    111. Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mode 100644 sql/deploy/appuser.sql create mode 100644 sql/revert/appuser.sql create mode 100644 sql/test/appuser.sql>
    112. Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mode 100644 sql/deploy/appuser.sql create mode 100644 sql/revert/appuser.sql create mode 100644 sql/test/appuser.sql>sqitch --db-name flipr_test deployDeploying 36acafd to flipr_test + appuser>
    113. Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mode 100644 sql/deploy/appuser.sql create mode 100644 sql/revert/appuser.sql create mode 100644 sql/test/appuser.sql>sqitch --db-name flipr_test deployDeploying 36acafd to flipr_test + appuser>
    114. Commit It!>git add .> git commit -m Add app user.[master 36acafd] Add app user. 2 files changed, 2 insertions(+) create mode 100644 sql/deploy/appuser.sql create mode 100644 sql/revert/appuser.sql create mode 100644 sql/test/appuser.sql>sqitch --db-name flipr_test deployDeploying 36acafd to flipr_test + appuser>psql -d flipr_test -c du flipr List of roles Role name | Attributes | Member of-----------+------------+----------- flipr | | {}
    115. Status Update>
    116. Status Update> sqitch -d flipr_test status# On database flipr_test# Tag: 36acafd# Step: appuser# Date: 2012-05-18 17:21:54#Nothing to deploy (up-to-date)>
    117. Save My Fingers>
    118. Save My Fingers>sqitch config core.pg.db_name flipr_test>
    119. Save My Fingers>sqitch config core.pg.db_name flipr_test>sqitch status# On database flipr_test# Tag: 36acafd No --db-name# Step: appuser# Date: 2012-05-18 17:21:54#Nothing to deploy (up-to-date)>
    120. Dependencies!>
    121. Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql -- requires: appuserCreated sql/revert/users.sqlCreated sql/test/users.sql>
    122. Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql -- requires: appuserCreated sql/revert/users.sqlCreated sql/test/users.sql>
    123. Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql -- requires: appuserCreated sql/revert/users.sqlCreated sql/test/users.sql>emacs sql/deploy/users.sql
    124. sql/deploy/users.sql-- Deploy users-- :requires: appuserBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/user
    125. sql/deploy/users.sql-- Deploy users-- :requires: appuserBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/user
    126. sql/deploy/users.sql-- Deploy users-- :requires: appuserBEGIN;CREATE TABLE users ( nickname TEXT PRIMARY KEY, password TEXT NOT NULL, timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW());GRANT SELECT ON users TO flipr;COMMIT; sql/deploy/user
    127. Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql -- requires: appuserCreated sql/revert/users.sqlCreated sql/test/users.sql> emacs sql/deploy/users.sql>
    128. Dependencies!> sqitch add-step users --requires appuserCreated sql/deploy/users.sql -- requires: appuserCreated sql/revert/users.sqlCreated sql/test/users.sql> emacs sql/deploy/users.sql>emacs sql/revert/users.sql
    129. sql/revert/users-- Revert usersBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/user
    130. sql/revert/users-- Revert usersBEGIN;DROP TABLE users;COMMIT; sql/deploy/user
    131. Make Users>
    132. Make Users>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + users>
    133. Make Users>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + users>
    134. Make Users>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + users> psql -d flipr_test -c d users Table "public.users" Column | Type | Modifiers-----------+-------------+------------------------ nickname | text | not null password | text | not null timestamp | timestamptz | not null default now()Indexes: "users_pkey" PRIMARY KEY, btree (nickname)>
    135. Status Update>
    136. Status Update> sqitch status# On database flipr_test# Tag: HEAD+# Step: users# Date: 2012-05-18 17:25:39#Nothing to deploy (up-to-date)>
    137. Status Update> sqitch status# On database flipr_test# Tag: HEAD+# Step: users# Date: 2012-05-18 17:25:39#Nothing to deploy (up-to-date)>sqitch revert --to HEADReverting HEAD+ from flipr_test - users>
    138. Status Update> sqitch status# On database flipr_test# Tag: HEAD+# Step: users# Date: 2012-05-18 17:25:39#Nothing to deploy (up-to-date)>sqitch revert --to HEADReverting HEAD+ from flipr_test - users>
    139. Check in and Deploy>
    140. Check in and Deploy>git add .> git commit -am Add users table.[master fa650af] Add users table. 2 files changed, 16 insertions(+) create mode 100644 sql/deploy/users.sql create mode 100644 sql/revert/users.sql create mode 100644 sql/test/users.sql>
    141. Check in and Deploy>git add .> git commit -am Add users table.[master fa650af] Add users table. 2 files changed, 16 insertions(+) create mode 100644 sql/deploy/users.sql create mode 100644 sql/revert/users.sql create mode 100644 sql/test/users.sql>sqitch deployDeploying fa650af to flipr_test + users>
    142. Up to Date>
    143. Up to Date> sqitch status --show tags# On database flipr_test# Tag: fa650af# Step: users# Date: 2012-05-18 17:31:23## Tags:# fa650af - 2012-05-18 17:31:23 - david# 36acafd - 2012-05-18 17:25:39 - david#Nothing to deploy (up-to-date)>
    144. Up to Date> sqitch status --show tags# On database flipr_test# Tag: fa650af# Step: users# Date: 2012-05-18 17:31:23## Tags:# fa650af - 2012-05-18 17:31:23 - david# 36acafd - 2012-05-18 17:25:39 - david#Nothing to deploy (up-to-date)>
    145. Up to Date> sqitch status --show tags# On database flipr_test# Tag: fa650af# Step: users# Date: 2012-05-18 17:31:23## Tags:# fa650af - 2012-05-18 17:31:23 - david# 36acafd - 2012-05-18 17:25:39 - david#Nothing to deploy (up-to-date)>
    146. A Twofer>
    147. A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql -- requires: users, appuserAdding sql/revert/insert_user.sqlAdding sql/test/insert_user.sql>
    148. A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql -- requires: users, appuserAdding sql/revert/insert_user.sqlAdding sql/test/insert_user.sql>
    149. A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql -- requires: users, appuserAdding sql/revert/insert_user.sqlAdding sql/test/insert_user.sql> sqitch add-step change_pass -r users -r appuserAdding sql/deploy/change_pass.sql -- requires: users, appuserAdding sql/revert/change_pass.sqlAdding sql/test/change_pass.sql>
    150. A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql -- requires: users, appuserAdding sql/revert/insert_user.sqlAdding sql/test/insert_user.sql> sqitch add-step change_pass -r users -r appuserAdding sql/deploy/change_pass.sql -- requires: users, appuserAdding sql/revert/change_pass.sqlAdding sql/test/change_pass.sql>
    151. A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql -- requires: users, appuserAdding sql/revert/insert_user.sqlAdding sql/test/insert_user.sql> sqitch add-step change_pass -r users -r appuserAdding sql/deploy/change_pass.sql -- requires: users, appuserAdding sql/revert/change_pass.sqlAdding sql/test/change_pass.sql>emacs sql/deploy/insert_user.sql
    152. sql/deploy/ insert_user.sql-- Deploy insert_user-- :requires: appuser-- :requires: usersBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/inse
    153. sql/deploy/ insert_user.sql-- Deploy insert_user-- :requires: appuser-- :requires: usersBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/inse
    154. sql/deploy/ insert_user.sql-- Deploy insert_user-- :requires: appuser-- :requires: usersBEGIN;CREATE OR REPLACE FUNCTION insert_user( nickname TEXT, password TEXT) RETURNS VOID LANGUAGE SQL SECURITY DEFINER AS $$ INSERT INTO users VALUES($1, md5($2));$$;GRANT EXECUTE ON FUNCTION insert_user(TEXT, TEXT) TO flipr;COMMIT; sql/deploy/inse
    155. A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql -- requires: users, appuserAdding sql/revert/insert_user.sqlAdding sql/test/insert_user.sql> sqitch add-step change_pass -r users -r appuserAdding sql/deploy/change_pass.sql -- requires: users, appuserAdding sql/revert/change_pass.sqlAdding sql/test/change_pass.sql>emacs sql/deploy/insert_user.sql>
    156. A Twofer>sqitch add-step insert_user -r users -r appuserAdding sql/deploy/insert_user.sql -- requires: users, appuserAdding sql/revert/insert_user.sqlAdding sql/test/insert_user.sql> sqitch add-step change_pass -r users -r appuserAdding sql/deploy/change_pass.sql -- requires: users, appuserAdding sql/revert/change_pass.sqlAdding sql/test/change_pass.sql>emacs sql/deploy/insert_user.sql>emacs sql/deploy/change_pass.sql
    157. sql/deploy/ change_pass.sql-- Deploy change_pass-- :requires: appuser-- :requires: usersBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/chan
    158. sql/deploy/ change_pass.sql-- Deploy change_pass-- :requires: appuser-- :requires: usersBEGIN;CREATE OR REPLACE FUNCTION change_pass( nick TEXT, oldpass TEXT, newpass TEXT) RETURNS BOOLEAN LANGUAGE plpgsql SECURITY DEFINER AS $$BEGIN UPDATE users SET password = md5($3) WHERE nickname = $1 AND password = md5($2); RETURN FOUND;END;$$;GRANT EXECUTE ON FUNCTION change_pass(TEXT, TEXT, TEXT)TO flipr;COMMIT; sql/deploy/chan
    159. Deploy Functions>
    160. Deploy Functions>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + change_pass + insert_user>
    161. Deploy Functions>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + change_pass + insert_user>psql -d flipr_test -c df List of function Schema | Name | Result data type |--------+-------------+------------------+---------- public | change_pass | boolean | nick text public | insert_user | void | nickname>
    162. Commit It
    163. Commit Itsqitch revert --to HEAD
    164. Commit Itsqitch revert --to HEADgit add && git commit
    165. Commit Itsqitch revert --to HEADgit add && git commitsqitch deploy
    166. Commit Itsqitch revert --to HEADgit add && git commitsqitch deployAnd now…
    167. Stage It>
    168. Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>
    169. Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>createdb flipr_dev> sqitch --db-name flipr_dev deployDeploying 36acafd to flipr_dev + appuserDeploying fa650af to flipr_dev + usersDeploying 803e6b8, v1.0.0-dev1 to flipr_dev + insert_user + change_pass>
    170. Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>createdb flipr_dev> sqitch --db-name flipr_dev deployDeploying 36acafd to flipr_dev + appuserDeploying fa650af to flipr_dev + usersDeploying 803e6b8, v1.0.0-dev1 to flipr_dev + insert_user + change_pass>
    171. Stage It>git tag v1.0.0-dev1 -am Tag v1.0.0-dev1>createdb flipr_dev> sqitch --db-name flipr_dev deployDeploying 36acafd to flipr_dev + appuserDeploying fa650af to flipr_dev + usersDeploying 803e6b8, v1.0.0-dev1 to flipr_dev + insert_user + change_pass>
    172. Stage Status?>
    173. Stage Status?>sqitch --db-name flipr_dev status --show tags# On database flipr_dev# Tags: 803e6b8, v1.0.0-dev1# Step: change_pass# Date: 2012-05-18 17:38:28## Tags:# 803e6b8, v1.0.0-dev1 - 2012-05-18 17:38:28 - david# fa650af - 2012-05-18 17:38:21 - david# 36acafd - 2012-05-18 17:38:15 - david#Nothing to deploy (up-to-date)>
    174. Distribution Bundling
    175. Distribution BundlingBundle plan + scripts for deployment
    176. Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS history
    177. Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as
    178. Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as RPM
    179. Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as RPM Debian Package
    180. Distribution BundlingBundle plan + scripts for deploymentPlan generated from VCS historyPackage up as RPM Debian Package Gem
    181. Ship It!>
    182. Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userPlan written to bundle/sqitch.plan>
    183. Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userPlan written to bundle/sqitch.plan>
    184. Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userPlan written to bundle/sqitch.plan>
    185. Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userPlan written to bundle/sqitch.plan>
    186. Ship It!>sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userPlan written to bundle/sqitch.plan>emacs bundle/sqitch.plan
    187. The Plan, Man[v1.0.0-dev1]appuseruserschange_passinsert_user bundle/sqitch.p
    188. Kick the Tires>
    189. Kick the Tires>cd bundle> createdb flipr_staging> sqitch --db-name flipr_staging deployDeploying v1.0.0-dev1 to flipr_prod + appuser + users + insert_user + change_pass>
    190. Kick the Tires>cd bundle> createdb flipr_staging> sqitch --db-name flipr_staging deployDeploying v1.0.0-dev1 to flipr_prod + appuser + users + insert_user + change_pass>
    191. Ch-Check it Out>
    192. Ch-Check it Out>sqitch --db-name flipr_prod status --show tags# On database flipr_prod# Tag: v1.0.0-dev1# Step: change_pass# Date: 2012-04-09 22:17:38## Tags:# v1.0.0-dev1 - 2012-05-18 17:40:00 - david#Nothing to deploy (up-to-date)>
    193. Ch-Check it Out>sqitch --db-name flipr_prod status --show tags# On database flipr_prod# Tag: v1.0.0-dev1# Step: change_pass No SHA1s# Date: 2012-04-09 22:17:38## Tags:# v1.0.0-dev1 - 2012-05-18 17:40:00 - david#Nothing to deploy (up-to-date)>
    194. Ruh-Roh>
    195. Ruh-Roh>psql -d flipr_test -c " SELECT insert_user(foo, secr3t), insert_user(bar, secr3t); SELECT nickname, password FROM users;" nickname | password----------+---------------------------------- foo | 9695da4dd567a19f9b92065f240c6725 bar | 9695da4dd567a19f9b92065f240c6725
    196. Ruh-Roh>psql -d flipr_test -c " SELECT insert_user(foo, secr3t), insert_user(bar, secr3t); SELECT nickname, password FROM users;" nickname | password----------+---------------------------------- foo | 9695da4dd567a19f9b92065f240c6725 bar | 9695da4dd567a19f9b92065f240c6725 Not good.
    197. Add pgcrypto>
    198. Add pgcrypto>sqitch add-step pgcryptoAdding sql/deploy/pgcrypto.sqlAdding sql/revert/pgcrypto.sqlAdding sql/test/pgcrypto.sql>
    199. Add pgcrypto>sqitch add-step pgcryptoAdding sql/deploy/pgcrypto.sqlAdding sql/revert/pgcrypto.sqlAdding sql/test/pgcrypto.sql>emacs sql/deploy/pgcrpyto.sql
    200. ssql/deploy/pgcrypto.sql-- Deploy pgcryptoBEGIN;-- XXX Add DDLs here.COMMIT; sql/deploy/pgcr
    201. ssql/deploy/pgcrypto.sql-- Deploy pgcryptoBEGIN;CREATE EXTENSION pgcrypto;COMMIT; sql/deploy/pgcr
    202. How to Modify?
    203. How to Modify?Copy insert_user.sql to new deploy file
    204. How to Modify?Copy insert_user.sql to new deploy fileChange that new file
    205. How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert file
    206. How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert fileTest it
    207. How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert fileTest itDo the same for change_pass.sql
    208. How to Modify?Copy insert_user.sql to new deploy fileChange that new fileCopy insert_user.sql to new revert fileTest itDo the same for change_pass.sqlThe problem with that…
    209. >
    210. > git diff HEAD^diff --git a/sql/deploy/insert_user_crypt.sql b/sql/deploy/insert_user_crnew file mode 100644index 0000000..fa8d0c6--- /dev/null+++ b/sql/deploy/insert_user_crypt.sql@@ -0,0 +1,8 @@+-- requires: users, appuser, pgcrypto++CREATE OR REPLACE FUNCTION insert_user(+ nickname TEXT,+ password TEXT+) RETURNS VOID LANGUAGE SQL AS $$+ INSERT INTO users values($1, crypt($2, gen_salt(md5)));+$$;diff --git a/sql/revert/insert_user_crypt.sql b/sql/revert/insert_user_crnew file mode 100644index 0000000..a7f4e31--- /dev/null+++ b/sql/revert/insert_user_crypt.sql@@ -0,0 +1,8 @@+-- requires: users, appuser++CREATE OR REPLACE FUNCTION insert_user(+ nickname TEXT,+ password TEXT+) RETURNS VOID LANGUAGE SQL AS $$+ INSERT INTO users values($1, md5($2));+$$;
    211. > git diff HEAD^diff --git a/sql/deploy/insert_user_crypt.sql b/sql/deploy/insert_user_crnew file mode 100644index 0000000..fa8d0c6--- /dev/null+++ b/sql/deploy/insert_user_crypt.sql@@ -0,0 +1,8 @@+-- requires: users, appuser, pgcrypto++CREATE OR REPLACE FUNCTION insert_user(+ nickname TEXT,+ password TEXT+) RETURNS VOID LANGUAGE SQL AS $$+ INSERT INTO users values($1, crypt($2, gen_salt(md5)));+$$;diff --git a/sql/revert/insert_user_crypt.sql b/sql/revert/insert_user_crnew file mode 100644index 0000000..a7f4e31--- /dev/null+++ b/sql/revert/insert_user_crypt.sql@@ -0,0 +1,8 @@+-- requires: users, appuser++CREATE OR REPLACE FUNCTION insert_user(+ nickname TEXT,+ password TEXT+) RETURNS VOID LANGUAGE SQL AS $$+ INSERT INTO users values($1, md5($2));+$$; Oy.
    212. Use the VCS, Luke
    213. Use the VCS, LukeJust modify deploy scripts directly
    214. Use the VCS, LukeJust modify deploy scripts directlyRequirement:
    215. Use the VCS, LukeJust modify deploy scripts directlyRequirement: Change must be idempotent
    216. Use the VCS, LukeJust modify deploy scripts directlyRequirement: Change must be idempotent Same result no matter how often applied
    217. Use the VCS, LukeJust modify deploy scripts directlyRequirement: Change must be idempotent Same result no matter how often appliedCREATE OR REPLACE FUNCTION is idempotent
    218. Use the VCS, LukeJust modify deploy scripts directlyRequirement: Change must be idempotent Same result no matter how often appliedCREATE OR REPLACE FUNCTION is idempotentSo change procedures in place!
    219. What’s the Diff?>
    220. What’s the Diff?>diff -u sql/deploy/insert_user.sql@@ -1,8 +1,8 @@--- requires: users, appuser+-- requires: users, appuser, pgcrypto CREATE OR REPLACE FUNCTION insert_user( nickname TEXT, password TEXT ) RETURNS VOID LANGUAGE SQL AS $$- INSERT INTO users values($1, md5($2));+ INSERT INTO users values($1, crypt($2, gen_salt(md5))); $$;
    221. What’s the Diff?>
    222. What’s the Diff?>diff -u sql/deploy/change_pass.sql@@ -1,4 +1,4 @@--- requires: users, appuser+-- requires: users, appuser, pgcrypto CREATE OR REPLACE FUNCTION change_pass( nick TEXT,@@ -7,9 +7,9 @@ CREATE OR REPLACE FUNCTION change_pass( ) RETURNS BOOLEAN LANGUAGE plpgsql AS $$ BEGIN UPDATE users- SET password = md5($3)+ SET password = crypt($3, gen_salt(md5)) WHERE nickname = $1- AND password = md5($2);+ AND password = crypt($2, password); RETURN FOUND; END;
    223. Send it Up!>
    224. Send it Up!>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + insert_user + change_pass>
    225. Send it Up!>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + insert_user + change_pass>psql -d flipr_test -c " DELETE FROM users; SELECT insert_user(foo, secr3t), insert_user(bar, secr3t); SELECT nickname, password FROM users;" nickname | password----------+------------------------------------ foo | $1$l6OEKyF3$kv5ae7505ROub75d9QKTh/ bar | $1$J4NJDgaJ$578i9Lt6b8ohJwi6WhNNO1>
    226. Send it Up!>sqitch deploy --untrackedDeploying HEAD+ to flipr_test + insert_user + change_pass>psql -d flipr_test -c " o/ DELETE FROM users; SELECT insert_user(foo, secr3t), insert_user(bar, secr3t); SELECT nickname, password FROM users;" nickname | password----------+------------------------------------ foo | $1$l6OEKyF3$kv5ae7505ROub75d9QKTh/ bar | $1$J4NJDgaJ$578i9Lt6b8ohJwi6WhNNO1>
    227. Can We Go Back?>
    228. Can We Go Back?>sqitch revert --to HEADReverting HEAD+ from flipr_test - change_pass - insert_user>
    229. Can We Go Back?>sqitch revert --to HEADReverting HEAD+ from flipr_test - change_pass - insert_user>psql -d flipr_test -c " DELETE FROM users; SELECT insert_user(foo, secr3t), insert_user(bar, secr3t); SELECT nickname, password FROM users;" nickname | password----------+---------------------------------- foo | 9695da4dd567a19f9b92065f240c6725 bar | 9695da4dd567a19f9b92065f240c6725>
    230. What About Bundling?>
    231. What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userBundling v1.0.0-b1 - change_pass_v2 - insert_user_v2Plan written to bundle/sqitch.plan>
    232. What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userBundling v1.0.0-b1 - change_pass_v2 - insert_user_v2Plan written to bundle/sqitch.plan>
    233. What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userBundling v1.0.0-b1 - change_pass_v2 - insert_user_v2Plan written to bundle/sqitch.plan>
    234. What About Bundling?> git tag v1.0.0-b1 -am Tag v1.0.0-b1> sqitch bundle --tags-onlyBundling in bundle/Config written to bundle/sqitch.confBundling v1.0.0-dev1 - appuser - users - change_pass - insert_userBundling v1.0.0-b1 - change_pass_v2 - insert_user_v2Plan written to bundle/sqitch.plan>emacs bundle/sqitch.plan
    235. What’s the Plan?[v1.0.0-dev1] appuser users change_pass insert_user[v1.0.0-b1] change_pass_v2 insert_user_v2 filename
    236. Make it So>
    237. Make it So>cd bundle> sqitch -d flipr_staging deployDeploying v1.0.0-b1 to flipr_staging + change_pass_v2 + insert_user_v2>
    238. Make it So>cd bundle> sqitch -d flipr_staging deployDeploying v1.0.0-b1 to flipr_staging + change_pass_v2 + insert_user_v2> sqitch -d flipr_staging status# On database flipr_staging# Tag: v1.0.0-b1# Step: insert_user_v2# Date: 2012-05-18 17:51:35#Nothing to deploy (up-to-date)>
    239. Ship It!
    240. Other Commands
    241. Other Commandslog - Like git log
    242. Other Commandslog - Like git logcheck - Validate plan & database
    243. Other Commandslog - Like git logcheck - Validate plan & databasetest - Test deployment success
    244. Other Commandslog - Like git logcheck - Validate plan & databasetest - Test deployment successhelp - Get it
    245. Current Status
    246. Current StatusWorking on it full time
    247. Current StatusWorking on it full timeRethinking VCS integration
    248. Current StatusWorking on it full timeRethinking VCS integration Rely more on plan file
    249. Current StatusWorking on it full timeRethinking VCS integration Rely more on plan file Complement with VCS history
    250. Current StatusWorking on it full timeRethinking VCS integration Rely more on plan file Complement with VCS historyTools for plan file management
    251. Fork It
    252. Fork Ithttp:/ /sqitch.org/
    253. Fork Ithttp:/ /sqitch.org/https:/ /github.com/theory/sqitch/
    254. Fork Ithttp:/ /sqitch.org/https:/ /github.com/theory/sqitch/Opinions wanted
    255. Fork Ithttp:/ /sqitch.org/https:/ /github.com/theory/sqitch/Opinions wantedCoders wanted
    256. Fork Ithttp:/ /sqitch.org/https:/ /github.com/theory/sqitch/Opinions wantedCoders wantedDoc writers and web designers wanted!
    257. Fork Ithttp:/ /sqitch.org/https:/ /github.com/theory/sqitch/Opinions wantedCoders wantedDoc writers and web designers wanted!Make it great!
    258. Thank you.
    259. Simple SQL Change Management with Sqitch David E. Wheeler http:/ /sqitch.org/ PGCon 2012 Ottawa, CanadaText: Attribution-Noncommercial-Share Alike 3.0 United States:http://creativecommons.org/licenses/by-nc-sa/3.0/us/Images licensed independently and © Their respective owners.

    ×