pgdiff 1.0.1 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.rdoc +7 -2
- data/README.rdoc +29 -14
- data/Rakefile +11 -1
- data/bin/pgdiff +43 -7
- data/lib/pgdiff.rb +21 -9
- metadata +67 -21
- data/lib/attribute.rb +0 -23
- data/lib/database.rb +0 -112
- data/lib/diff.rb +0 -345
- data/lib/function.rb +0 -56
- data/lib/rule.rb +0 -15
- data/lib/sequence.rb +0 -11
- data/lib/table.rb +0 -90
- data/lib/trigger.rb +0 -15
- data/lib/view.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 633c03ef3f939faad6c41e2714fa2ed0913a8dcae53dffb55464dd589d1819a9
|
4
|
+
data.tar.gz: ec25fe04644ce6e75de45b6445f83962c97f64f63c4eb0f5adf2821d583c1579
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 703cd30da3b358aef33b409d83022a371f89b8810a0305dce5be657acdff03758ab4dedc5687c1b9350583ffea1440d5396c673ba2c45dc545f172e3b8d05233
|
7
|
+
data.tar.gz: 64147cd571163edd3a6ba14ca9bee9a05d1d37a44796838ba5f41700973c183dceb3c131f4753a4fe1328f78ab55a4de02cd0e092c15a05a8708605474aed051
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
= Changelog
|
2
2
|
|
3
|
-
===
|
4
|
-
*
|
3
|
+
=== 2.0.1 (June 2, 2023)
|
4
|
+
* Fix incorrect quoting of system schemas
|
5
|
+
|
6
|
+
=== 2.0.0 (June 1, 2023)
|
7
|
+
* Add new command line arguments
|
8
|
+
* Significantly improve performance
|
9
|
+
* Rewrite to imporove modularity
|
5
10
|
|
6
11
|
=== 1.0.0 (January 31, 2015)
|
7
12
|
* Improve constraint checking
|
data/README.rdoc
CHANGED
@@ -2,15 +2,14 @@
|
|
2
2
|
|
3
3
|
== Overview
|
4
4
|
|
5
|
-
This
|
6
|
-
their structures the same. The original version was posted at http://www.dzone.com/snippets/pgdiff-compare-two-postgresql.
|
5
|
+
This pgdiff gem compares two PostgreSQL databases and generates SQL statements to update the source database to match the target datbase.
|
7
6
|
|
8
7
|
The script detects differences in:
|
9
8
|
|
10
|
-
* Domains
|
11
9
|
* Schemas
|
10
|
+
* Extensions
|
11
|
+
* Domains
|
12
12
|
* Tables
|
13
|
-
* Table field order
|
14
13
|
* Sequences
|
15
14
|
* Views
|
16
15
|
* Constraints
|
@@ -21,29 +20,45 @@ The script detects differences in:
|
|
21
20
|
|
22
21
|
Two objects with the same name are considered equal if they have the same definitions.
|
23
22
|
|
24
|
-
pgdiff does not currently compare ownership, user rights, object dependencies, table inheritance, type casts, aggregates
|
25
|
-
or operators. Patches are welcome to add this functionality.
|
23
|
+
pgdiff does not currently compare ownership, user rights, object dependencies, table inheritance, type casts, aggregates or operators. Patches are welcome to add this functionality.
|
26
24
|
|
27
25
|
== Installation
|
28
26
|
|
29
|
-
Install pgdiff
|
27
|
+
Install pgdiff:
|
30
28
|
|
31
|
-
gem install
|
29
|
+
gem install pgdiff
|
32
30
|
|
33
31
|
== Usage
|
34
32
|
|
35
33
|
To use pgdiff open a command prompt and runn the following command:
|
36
34
|
|
37
|
-
pg_diff "source_connection_string" "destination_connection_string"
|
35
|
+
pg_diff --source "source_connection_string" --target "destination_connection_string"
|
36
|
+
|
37
|
+
The format of the connection strings are documented in the Ruby PG gem at https://www.rubydoc.info/gems/pg/PG/Connection.new.
|
38
|
+
|
39
|
+
For eample:
|
40
|
+
"host=localhost dbname=a_database user=a_user password=a_password"
|
41
|
+
|
42
|
+
== Ignore Schemas
|
43
|
+
By default, pgdiff will not process the following system schemas:
|
38
44
|
|
39
|
-
|
40
|
-
|
45
|
+
* pg_catalog
|
46
|
+
* pg_toast
|
47
|
+
* information_schema
|
48
|
+
|
49
|
+
You may specify additions schemas to ingore using the `--ingore-schemas` flag:
|
50
|
+
|
51
|
+
pgdiff --ignore_schemas=schema1,schema2
|
41
52
|
|
42
53
|
== Output
|
54
|
+
By default, pgdiff will output results to stdout. You may also specify a file path via the `--output` command line parameter:
|
55
|
+
|
56
|
+
pgdiff --ouput=/tmp/diff.sql
|
57
|
+
|
58
|
+
You can then run this sql script against your database.
|
43
59
|
|
44
|
-
|
45
|
-
|
46
|
-
it is always possible the script has bugs.
|
60
|
+
== Run The Script
|
61
|
+
The sql script generated by pgdiff will change your database. It is YOUR responsibility to verify the script before running it. pgdiff may have bugs, which could result in catastrophic, unrecoverable changes to your database. DO NOT RUN THIS ON A PRODUCTION DATABASE WITHOUT BACKING UP AND TESTING FIRST.
|
47
62
|
|
48
63
|
== Support
|
49
64
|
|
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'rubygems/package_task'
|
5
|
+
require 'rake/testtask'
|
5
6
|
|
6
7
|
GEM_NAME = 'pgdiff'
|
7
8
|
|
@@ -12,4 +13,13 @@ spec = Gem::Specification.load("#{GEM_NAME}.gemspec")
|
|
12
13
|
Gem::PackageTask.new(spec) do |pkg|
|
13
14
|
pkg.package_dir = 'pkg'
|
14
15
|
pkg.need_tar = false
|
15
|
-
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Rake::TestTask.new do |task|
|
19
|
+
task.libs << "test"
|
20
|
+
task.test_files = FileList['test/test*.rb']
|
21
|
+
task.verbose = true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Add task to create test database
|
25
|
+
load 'test/fixtures/database.rake'
|
data/bin/pgdiff
CHANGED
@@ -13,16 +13,52 @@
|
|
13
13
|
# ./pg_diff source_connection_string destination_connection_string
|
14
14
|
#
|
15
15
|
# The format of the connection strings is documented in the Ruby pg gem
|
16
|
-
# at
|
16
|
+
# at https://www.rubydoc.info/gems/pg/PG/Connection.new
|
17
|
+
|
18
|
+
lib_path = File.expand_path(File.join(__dir__, '..', 'lib'))
|
19
|
+
$LOAD_PATH.unshift(File.expand_path(lib_path))
|
17
20
|
|
18
21
|
require 'pg'
|
19
22
|
require 'pgdiff'
|
23
|
+
require 'optparse'
|
24
|
+
require 'ostruct'
|
25
|
+
|
26
|
+
options = OpenStruct.new
|
27
|
+
options.source = nil
|
28
|
+
options.target = nil
|
29
|
+
options.ignore_schemas = []
|
30
|
+
|
31
|
+
args = OptionParser.new do |parser|
|
32
|
+
parser.version = PgDiff::VERSION
|
33
|
+
|
34
|
+
parser.banner = "Usage: pgdiff --source --target"
|
35
|
+
|
36
|
+
parser.on("-s", "--source=connection_string", "Source connection string. See https://www.rubydoc.info/gems/pg/PG/Connection.new") do |source|
|
37
|
+
options.source = source
|
38
|
+
end
|
39
|
+
|
40
|
+
parser.on("-t", "--target=connection_string", "Target connection string. See see https://www.rubydoc.info/gems/pg/PG/Connection.new") do |target|
|
41
|
+
options.target = target
|
42
|
+
end
|
43
|
+
|
44
|
+
parser.on("--ignore_schemas=schema1,schema2", "Schemas to ignore. Comma separated string") do |ignore_schemas|
|
45
|
+
options.ignore_schemas = ignore_schemas.split(',').map {|schema_name| schema_name.strip}
|
46
|
+
end
|
47
|
+
|
48
|
+
parser.on("--output=file_path", "Save output to file. Otherwise printed to stdout") do |path|
|
49
|
+
options.path = path
|
50
|
+
end
|
20
51
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
52
|
+
parser.on("-h", "--help", "Prints this help") do
|
53
|
+
puts parser
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
end.parse!
|
25
57
|
|
26
|
-
|
58
|
+
output = if options.path.nil?
|
59
|
+
STDOUT
|
60
|
+
else
|
61
|
+
File.open(options.path)
|
62
|
+
end
|
63
|
+
diff = PgDiff::Diff.new(output, options.source, options.target, ignore_schemas: options.ignore_schemas)
|
27
64
|
diff.run_compare
|
28
|
-
puts diff.output
|
data/lib/pgdiff.rb
CHANGED
@@ -1,9 +1,21 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'attribute'
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
7
|
-
require '
|
8
|
-
require '
|
9
|
-
require 'diff'
|
1
|
+
require 'set'
|
2
|
+
require 'pg'
|
3
|
+
require 'pgdiff/attribute'
|
4
|
+
require 'pgdiff/attributes'
|
5
|
+
require 'pgdiff/collation'
|
6
|
+
require 'pgdiff/constraint'
|
7
|
+
require 'pgdiff/constraints'
|
8
|
+
require 'pgdiff/database'
|
9
|
+
require 'pgdiff/diff'
|
10
|
+
require 'pgdiff/domain'
|
11
|
+
require 'pgdiff/extension'
|
12
|
+
require 'pgdiff/function'
|
13
|
+
require 'pgdiff/index'
|
14
|
+
require 'pgdiff/indexes'
|
15
|
+
require 'pgdiff/rule'
|
16
|
+
require 'pgdiff/schema'
|
17
|
+
require 'pgdiff/sequence'
|
18
|
+
require 'pgdiff/table'
|
19
|
+
require 'pgdiff/trigger'
|
20
|
+
require 'pgdiff/view'
|
21
|
+
require 'pgdiff/version'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pgdiff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Savage
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -16,19 +16,75 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.17.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.17.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: diff-lcs
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yaml
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
27
83
|
description: 'Compares two PostgreSQL databases and generates the SQL statements needed
|
28
84
|
to make their structure the same.
|
29
85
|
|
30
|
-
'
|
31
|
-
email:
|
86
|
+
'
|
87
|
+
email:
|
32
88
|
executables:
|
33
89
|
- pgdiff
|
34
90
|
extensions: []
|
@@ -38,21 +94,12 @@ files:
|
|
38
94
|
- README.rdoc
|
39
95
|
- Rakefile
|
40
96
|
- bin/pgdiff
|
41
|
-
- lib/attribute.rb
|
42
|
-
- lib/database.rb
|
43
|
-
- lib/diff.rb
|
44
|
-
- lib/function.rb
|
45
97
|
- lib/pgdiff.rb
|
46
|
-
- lib/rule.rb
|
47
|
-
- lib/sequence.rb
|
48
|
-
- lib/table.rb
|
49
|
-
- lib/trigger.rb
|
50
|
-
- lib/view.rb
|
51
98
|
homepage: https://github.com/cfis/pgdiff.git
|
52
99
|
licenses:
|
53
100
|
- MIT
|
54
101
|
metadata: {}
|
55
|
-
post_install_message:
|
102
|
+
post_install_message:
|
56
103
|
rdoc_options: []
|
57
104
|
require_paths:
|
58
105
|
- lib
|
@@ -60,16 +107,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
107
|
requirements:
|
61
108
|
- - ">="
|
62
109
|
- !ruby/object:Gem::Version
|
63
|
-
version:
|
110
|
+
version: 1.9.3
|
64
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
112
|
requirements:
|
66
113
|
- - ">="
|
67
114
|
- !ruby/object:Gem::Version
|
68
115
|
version: '0'
|
69
116
|
requirements: []
|
70
|
-
|
71
|
-
|
72
|
-
signing_key:
|
117
|
+
rubygems_version: 3.3.26
|
118
|
+
signing_key:
|
73
119
|
specification_version: 4
|
74
120
|
summary: Provides a ruby script that compares two PostgreSQL databases and generates
|
75
121
|
the SQL statements needed to make their structure the same. The original version
|
data/lib/attribute.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class Attribute
|
3
|
-
attr_accessor :name, :type_def, :notnull, :default
|
4
|
-
|
5
|
-
def initialize(name, typedef, notnull, default)
|
6
|
-
@name = name
|
7
|
-
@type_def = typedef
|
8
|
-
@notnull = notnull
|
9
|
-
@default = default
|
10
|
-
end
|
11
|
-
|
12
|
-
def definition
|
13
|
-
out = [' ', @name, @type_def]
|
14
|
-
out << 'NOT NULL' if @notnull
|
15
|
-
out << 'DEFAULT ' + @default if @default
|
16
|
-
out.join(" ")
|
17
|
-
end
|
18
|
-
|
19
|
-
def == (other)
|
20
|
-
definition == other.definition
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/lib/database.rb
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class Database
|
3
|
-
attr_accessor :tables, :views, :sequences, :schemas, :domains, :rules, :functions, :triggers
|
4
|
-
|
5
|
-
def initialize(conn)
|
6
|
-
cls_query = <<-EOT
|
7
|
-
SELECT n.nspname, c.relname, c.relkind
|
8
|
-
FROM pg_catalog.pg_class c
|
9
|
-
LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
|
10
|
-
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
11
|
-
WHERE c.relkind IN ('r','S','v')
|
12
|
-
AND n.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema')
|
13
|
-
ORDER BY 1,2;
|
14
|
-
EOT
|
15
|
-
@views = {}
|
16
|
-
@tables = {}
|
17
|
-
@sequences = {}
|
18
|
-
@schemas = {}
|
19
|
-
@domains = {}
|
20
|
-
@functions = {}
|
21
|
-
@rules = {}
|
22
|
-
@triggers = {}
|
23
|
-
|
24
|
-
conn.query(cls_query).each do |tuple|
|
25
|
-
schema = tuple['nspname']
|
26
|
-
relname = tuple['relname']
|
27
|
-
relkind = tuple['relkind']
|
28
|
-
case relkind
|
29
|
-
when 'r'
|
30
|
-
@tables["#{schema}.#{relname}"] = Table.new(conn, schema, relname)
|
31
|
-
when 'v'
|
32
|
-
@views["#{schema}.#{relname}"] = View.new(conn, schema, relname)
|
33
|
-
when 'S'
|
34
|
-
@sequences["#{schema}.#{relname}"] = Sequence.new(conn, schema, relname)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
domain_qry = <<-EOT
|
39
|
-
SELECT n.nspname, t.typname, pg_catalog.format_type(t.typbasetype, t.typtypmod) || ' ' ||
|
40
|
-
CASE WHEN t.typnotnull AND t.typdefault IS NOT NULL THEN 'not null default '||t.typdefault
|
41
|
-
WHEN t.typnotnull AND t.typdefault IS NULL THEN 'not null'
|
42
|
-
WHEN NOT t.typnotnull AND t.typdefault IS NOT NULL THEN 'default '|| t.typdefault
|
43
|
-
ELSE ''
|
44
|
-
END AS def
|
45
|
-
FROM pg_catalog.pg_type t
|
46
|
-
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
47
|
-
WHERE t.typtype = 'd'
|
48
|
-
ORDER BY 1, 2
|
49
|
-
EOT
|
50
|
-
conn.query(domain_qry).each do |tuple|
|
51
|
-
schema = tuple['nspname']
|
52
|
-
typename = tuple['typname']
|
53
|
-
value = tuple['def']
|
54
|
-
@domains["#{schema}.#{typename}"] = value
|
55
|
-
end
|
56
|
-
|
57
|
-
schema_qry = <<-EOT
|
58
|
-
select nspname from pg_namespace
|
59
|
-
EOT
|
60
|
-
conn.query(schema_qry).each do |tuple|
|
61
|
-
schema = tuple['nspname']
|
62
|
-
@schemas[schema] = schema
|
63
|
-
end
|
64
|
-
|
65
|
-
func_query = <<-EOT
|
66
|
-
SELECT proname AS function_name
|
67
|
-
, nspname AS namespace
|
68
|
-
, lanname AS language_name
|
69
|
-
, pg_catalog.obj_description(pg_proc.oid, 'pg_proc') AS comment
|
70
|
-
, proargtypes AS function_args
|
71
|
-
, proargnames AS function_arg_names
|
72
|
-
, prosrc AS source_code
|
73
|
-
, proretset AS returns_set
|
74
|
-
, prorettype AS return_type,
|
75
|
-
provolatile, proisstrict, prosecdef
|
76
|
-
FROM pg_catalog.pg_proc
|
77
|
-
JOIN pg_catalog.pg_language ON (pg_language.oid = prolang)
|
78
|
-
JOIN pg_catalog.pg_namespace ON (pronamespace = pg_namespace.oid)
|
79
|
-
JOIN pg_catalog.pg_type ON (prorettype = pg_type.oid)
|
80
|
-
WHERE pg_namespace.nspname !~ 'pg_catalog|information_schema'
|
81
|
-
AND proname != 'plpgsql_call_handler'
|
82
|
-
AND proname != 'plpgsql_validator'
|
83
|
-
EOT
|
84
|
-
|
85
|
-
conn.exec(func_query).each_with_index do |tuple, i|
|
86
|
-
func = Function.new(conn, tuple)
|
87
|
-
@functions[func.signature] = func
|
88
|
-
end
|
89
|
-
|
90
|
-
rule_query = <<-EOT
|
91
|
-
select schemaname || '.' || tablename || '.' || rulename as rule_name,
|
92
|
-
schemaname || '.' || tablename as tab_name,
|
93
|
-
rulename, definition
|
94
|
-
from pg_rules
|
95
|
-
where schemaname !~ 'pg_catalog|information_schema'
|
96
|
-
EOT
|
97
|
-
conn.exec(rule_query).each do |tuple|
|
98
|
-
@rules[tuple['rule_name']] = Rule.new(tuple['tab_name'], tuple['rulename'], tuple['definition'])
|
99
|
-
end
|
100
|
-
|
101
|
-
trigger_query = <<-EOT
|
102
|
-
select nspname || '.' || relname as tgtable, tgname, pg_get_triggerdef(t.oid) as tg_def
|
103
|
-
from pg_trigger t join pg_class c ON (tgrelid = c.oid ) JOIN pg_namespace n ON (c.relnamespace = n.oid)
|
104
|
-
where not tgisinternal
|
105
|
-
and nspname !~ 'pg_catalog|information_schema'
|
106
|
-
EOT
|
107
|
-
conn.exec(trigger_query).each do |tuple|
|
108
|
-
@triggers[tuple['tgtable'] + "." + tuple['tgname']] = Trigger.new(tuple['tgtable'], tuple['tgname'], tuple['tg_def'])
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
data/lib/diff.rb
DELETED
@@ -1,345 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class Diff
|
3
|
-
def initialize(old_db_spec, new_db_spec)
|
4
|
-
@old_conn = PG::Connection.new(old_db_spec)
|
5
|
-
@new_conn = PG::Connection.new(new_db_spec)
|
6
|
-
@sections = [
|
7
|
-
:domains_drop,
|
8
|
-
:domains_create,
|
9
|
-
:schemas_drop,
|
10
|
-
:schemas_create,
|
11
|
-
:tables_drop,
|
12
|
-
:tables_change,
|
13
|
-
:tables_create,
|
14
|
-
:sequences_drop,
|
15
|
-
:sequences_create,
|
16
|
-
:views_drop,
|
17
|
-
:views_create,
|
18
|
-
:constraints_drop,
|
19
|
-
:constraints_change,
|
20
|
-
:constraints_create,
|
21
|
-
:indices_drop,
|
22
|
-
:indices_create,
|
23
|
-
:functions_drop,
|
24
|
-
:functions_create ,
|
25
|
-
:triggers_drop,
|
26
|
-
:triggers_create ,
|
27
|
-
:rules_drop,
|
28
|
-
:rules_create
|
29
|
-
]
|
30
|
-
@script = {}
|
31
|
-
@sections.each {|s| @script[s] = []}
|
32
|
-
end
|
33
|
-
|
34
|
-
def run_compare
|
35
|
-
@old_database = Database.new(@old_conn)
|
36
|
-
@new_database = Database.new(@new_conn)
|
37
|
-
compare_schemas
|
38
|
-
compare_domains
|
39
|
-
compare_sequences
|
40
|
-
compare_triggers_drop
|
41
|
-
compare_rules_drop
|
42
|
-
compare_views_drop
|
43
|
-
compare_table_attrs
|
44
|
-
compare_views_create
|
45
|
-
compare_functions
|
46
|
-
compare_rules_create
|
47
|
-
compare_triggers_create
|
48
|
-
compare_table_constraints
|
49
|
-
end
|
50
|
-
|
51
|
-
def add_script(section, statement)
|
52
|
-
@script[section] << statement
|
53
|
-
end
|
54
|
-
|
55
|
-
def compare_schemas
|
56
|
-
@old_database.schemas.keys.each do |name|
|
57
|
-
add_script(:schemas_drop , "DROP SCHEMA #{name};") unless @new_database.schemas.has_key?(name)
|
58
|
-
end
|
59
|
-
@new_database.schemas.keys.each do |name|
|
60
|
-
add_script(:schemas_create , "CREATE SCHEMA #{name};") unless @old_database.schemas.has_key?(name)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def compare_domains
|
65
|
-
@old_database.domains.keys.each do |name|
|
66
|
-
add_script(:domains_drop , "DROP DOMAIN #{name} CASCADE;") unless @new_database.domains.has_key?(name)
|
67
|
-
end
|
68
|
-
@new_database.domains.each do |name, df|
|
69
|
-
add_script(:domains_create , "CREATE DOMAIN #{name} AS #{df};") unless @old_database.domains.has_key?(name)
|
70
|
-
old_domain = @old_database.domains[name]
|
71
|
-
if old_domain && old_domain != df
|
72
|
-
add_script(:domains_drop, "DROP DOMAIN #{name} CASCADE;")
|
73
|
-
add_script(:domains_create, "-- [changed domain] :")
|
74
|
-
add_script(:domains_create, "-- OLD: #{old_domain}")
|
75
|
-
add_script(:domains_create, "CREATE DOMAIN #{name} AS #{df};")
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def compare_sequences
|
81
|
-
@old_database.sequences.keys.each do |name|
|
82
|
-
add_script(:sequences_drop , "DROP SEQUENCE #{name} CASCADE;") unless @new_database.sequences.has_key?(name)
|
83
|
-
end
|
84
|
-
@new_database.sequences.keys.each do |name|
|
85
|
-
add_script(:sequences_create , "CREATE SEQUENCE #{name};") unless @old_database.sequences.has_key?(name)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def compare_functions
|
90
|
-
@old_database.functions.keys.each do |name|
|
91
|
-
add_script(:functions_drop , "DROP FUNCTION #{name} CASCADE;") unless @new_database.functions.has_key?(name)
|
92
|
-
end
|
93
|
-
@new_database.functions.each do |name, func|
|
94
|
-
add_script(:functions_create , func.definition) unless @old_database.functions.has_key?(name)
|
95
|
-
old_function = @old_database.functions[name]
|
96
|
-
if old_function && old_function.definition != func.definition
|
97
|
-
add_script(:functions_create , '-- [changed function] :')
|
98
|
-
add_script(:functions_create , '-- OLD :')
|
99
|
-
add_script(:functions_create , old_function.definition.gsub(/^/, "--> ") )
|
100
|
-
add_script(:functions_create , func.definition)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def compare_rules_drop
|
106
|
-
@old_database.rules.each do |name, rule|
|
107
|
-
add_script(:rules_drop , "DROP RULE #{rule.name} ON #{rule.table_name} CASCADE;") unless @new_database.rules.has_key?(name)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def compare_rules_create
|
112
|
-
@new_database.rules.each do |name, rule|
|
113
|
-
add_script(:rules_create , rule.definition) unless @old_database.rules.has_key?(name)
|
114
|
-
old_rule = @old_database.rules[name]
|
115
|
-
if old_rule && old_rule != rule
|
116
|
-
add_script(:rules_drop , "DROP RULE #{rule.name} ON #{rule.table_name} CASCADE;")
|
117
|
-
add_script(:rules_create , "-- [changed rule] :")
|
118
|
-
add_script(:rules_create , "-- OLD: #{old_rule.definition}")
|
119
|
-
add_script(:rules_create , rule.definition )
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def compare_triggers_drop
|
125
|
-
@old_database.triggers.each do |name, trigger|
|
126
|
-
add_script(:triggers_drop , "DROP trigger #{trigger.name} ON #{trigger.table_name} CASCADE;") unless @new_database.triggers.has_key?(name)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def compare_triggers_create
|
131
|
-
@new_database.triggers.each do |name, trigger|
|
132
|
-
add_script(:triggers_create , trigger.definition) unless @old_database.triggers.has_key?(name)
|
133
|
-
old_trigger = @old_database.triggers[name]
|
134
|
-
if old_trigger && old_trigger != trigger
|
135
|
-
add_script(:triggers_drop , "DROP trigger #{trigger.name} ON #{trigger.table_name} CASCADE;")
|
136
|
-
add_script(:triggers_create , "-- [changed trigger] :")
|
137
|
-
add_script(:triggers_create , "-- OLD #{old_trigger.definition}")
|
138
|
-
add_script(:triggers_create , trigger.definition)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def compare_views_drop
|
144
|
-
@old_database.views.keys.each do |name|
|
145
|
-
add_script(:views_drop , "DROP VIEW #{name};") unless @new_database.views.has_key?(name)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def compare_views_create
|
150
|
-
@new_database.views.each do |name, df|
|
151
|
-
add_script(:views_create , df.definition) unless @old_database.views.has_key?(name)
|
152
|
-
old_view = @old_database.views[name]
|
153
|
-
if old_view && df.definition != old_view.definition
|
154
|
-
add_script(:views_drop , "DROP VIEW #{name};")
|
155
|
-
add_script(:views_create , "-- [changed view] :")
|
156
|
-
add_script(:views_create , "-- #{old_view.definition.gsub(/\n/, ' ')}")
|
157
|
-
add_script(:views_create , df.definition)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def compare_table_attrs
|
163
|
-
@old_database.tables.each do |name, table|
|
164
|
-
add_script(:tables_drop, "DROP TABLE #{name} CASCADE;") unless @new_database.tables.has_key?(name)
|
165
|
-
end
|
166
|
-
@to_compare = []
|
167
|
-
@new_database.tables.each do |name, table|
|
168
|
-
unless @old_database.tables.has_key?(name)
|
169
|
-
add_script(:tables_create , table.table_creation)
|
170
|
-
add_script(:indices_create , table.index_creation) unless table.indexes.empty?
|
171
|
-
@to_compare << name
|
172
|
-
else
|
173
|
-
diff_attributes(@old_database.tables[name], table)
|
174
|
-
diff_indexes(@old_database.tables[name], table)
|
175
|
-
@to_compare << name
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
def compare_table_constraints
|
181
|
-
@c_check = []
|
182
|
-
@c_primary = []
|
183
|
-
@c_unique = []
|
184
|
-
@c_foreign = []
|
185
|
-
@to_compare.each do |name|
|
186
|
-
if @old_database.tables[name]
|
187
|
-
diff_constraints(@old_database.tables[name], @new_database.tables[name])
|
188
|
-
else
|
189
|
-
@new_database.tables[name].constraints.each do |cname, cdef|
|
190
|
-
add_cnstr(name, cname, cdef)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
@script[:constraints_create] += @c_check
|
195
|
-
@script[:constraints_create] += @c_primary
|
196
|
-
@script[:constraints_create] += @c_unique
|
197
|
-
@script[:constraints_create] += @c_foreign
|
198
|
-
end
|
199
|
-
|
200
|
-
def output
|
201
|
-
out = []
|
202
|
-
@sections.each do |sect|
|
203
|
-
if @script[sect].empty?
|
204
|
-
out << "-- [SKIP SECTION : #{sect.to_s.upcase}] : no changes\n"
|
205
|
-
else
|
206
|
-
out << "-- [START SECTION : #{sect.to_s.upcase}]"
|
207
|
-
out += @script[sect]
|
208
|
-
out << "-- [END SECTION : #{sect.to_s.upcase}]\n"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
out.join("\n")
|
212
|
-
end
|
213
|
-
|
214
|
-
def diff_attributes(old_table, new_table)
|
215
|
-
dropped = []
|
216
|
-
added = []
|
217
|
-
changed = []
|
218
|
-
|
219
|
-
order = []
|
220
|
-
old_table.attributes.keys.each do |attname|
|
221
|
-
if new_table.has_attribute?(attname)
|
222
|
-
changed << attname if old_table.attributes[attname] != new_table.attributes[attname]
|
223
|
-
else
|
224
|
-
dropped << attname
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
old_table.attributes.keys.each do |attname|
|
229
|
-
if new_table.has_attribute?(attname)
|
230
|
-
old_index = old_table.attribute_index(attname)
|
231
|
-
new_index = new_table.attribute_index(attname)
|
232
|
-
order << attname if old_index != new_index
|
233
|
-
end
|
234
|
-
end
|
235
|
-
new_table.attributes.keys.each do |attname|
|
236
|
-
added << attname unless old_table.has_attribute?(attname)
|
237
|
-
end
|
238
|
-
add_script(:tables_change , "-- [#{old_table.name}] dropped attributes") unless dropped.empty?
|
239
|
-
dropped.each do |attname|
|
240
|
-
add_script(:tables_change , "ALTER TABLE #{old_table.name} DROP COLUMN #{attname} CASCADE;")
|
241
|
-
end
|
242
|
-
add_script(:tables_change , "-- [#{old_table.name}] added attributes") unless added.empty?
|
243
|
-
added.each do |attname|
|
244
|
-
add_script(:tables_change , "ALTER TABLE #{old_table.name} ADD COLUMN #{new_table.attributes[attname].definition};")
|
245
|
-
end
|
246
|
-
add_script(:tables_change , "-- [#{old_table.name}] changed attributes") unless changed.empty?
|
247
|
-
changed.each do |attname|
|
248
|
-
old_att = old_table.attributes[attname]
|
249
|
-
new_att = new_table.attributes[attname]
|
250
|
-
add_script(:tables_change , "-- attribute: #{attname}")
|
251
|
-
add_script(:tables_change , "-- OLD : #{old_att.definition}")
|
252
|
-
add_script(:tables_change , "-- NEW : #{new_att.definition}")
|
253
|
-
if old_att.type_def != new_att.type_def
|
254
|
-
add_script(:tables_change , "ALTER TABLE #{old_table.name} ALTER COLUMN #{attname} TYPE #{new_att.type_def};")
|
255
|
-
end
|
256
|
-
if old_att.default != new_att.default
|
257
|
-
if new_att.default.nil?
|
258
|
-
add_script(:tables_change , "ALTER TABLE #{old_table.name} ALTER COLUMN #{attname} DROP DEFAULT;")
|
259
|
-
else
|
260
|
-
add_script(:tables_change , "ALTER TABLE #{old_table.name} ALTER COLUMN #{attname} SET DEFAULT #{new_att.default};")
|
261
|
-
end
|
262
|
-
end
|
263
|
-
if old_att.notnull != new_att.notnull
|
264
|
-
add_script(:tables_change , "ALTER TABLE #{old_table.name} ALTER COLUMN #{attname} #{new_att.notnull ? 'SET' : 'DROP'} NOT NULL;")
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
add_script(:tables_change , "-- [#{old_table.name}] attribute order changed") unless order.empty?
|
269
|
-
order.each do |attname|
|
270
|
-
add_script(:tables_change , " #{attname}. Old index: #{old_table.attribute_index(attname)}, New index: #{new_table.attribute_index(attname)}")
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
def diff_constraints(old_table, new_table)
|
275
|
-
dropped = []
|
276
|
-
added = []
|
277
|
-
changed = []
|
278
|
-
|
279
|
-
old_table.constraints.keys.each do |conname|
|
280
|
-
if new_table.has_constraint?(conname)
|
281
|
-
if old_table.constraints[conname] != new_table.constraints[conname]
|
282
|
-
changed << conname
|
283
|
-
end
|
284
|
-
else
|
285
|
-
dropped << conname
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
new_table.constraints.keys.each do |conname|
|
290
|
-
added << conname unless old_table.has_constraint?(conname)
|
291
|
-
end
|
292
|
-
|
293
|
-
dropped.each do |name|
|
294
|
-
add_script(:constraints_drop , "ALTER TABLE #{old_table.name} DROP CONSTRAINT #{name};")
|
295
|
-
end
|
296
|
-
|
297
|
-
added.each do |name|
|
298
|
-
add_cnstr(old_table.name, name, new_table.constraints[name])
|
299
|
-
end
|
300
|
-
|
301
|
-
changed.each do |name|
|
302
|
-
add_script(:constraints_change,
|
303
|
-
"-- Previous: #{old_table.constraints[name]}\n" +
|
304
|
-
"ALTER TABLE #{old_table.name} DROP CONSTRAINT #{name};\n" +
|
305
|
-
"ALTER TABLE #{new_table.name} ADD CONSTRAINT #{name} #{new_table.constraints[name]};\n")
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def add_cnstr(tablename, cnstrname, cnstrdef)
|
310
|
-
c_string = "ALTER TABLE #{tablename} ADD CONSTRAINT #{cnstrname} #{cnstrdef} ;"
|
311
|
-
case cnstrdef
|
312
|
-
when /^CHECK / then @c_check << c_string
|
313
|
-
when /^PRIMARY / then @c_primary << c_string
|
314
|
-
when /^FOREIGN / then @c_foreign << c_string
|
315
|
-
when /^UNIQUE / then @c_unique << c_string
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
def diff_indexes(old_table, new_table)
|
320
|
-
dropped = []
|
321
|
-
added = []
|
322
|
-
|
323
|
-
old_table.indexes.keys.each do |name|
|
324
|
-
if new_table.has_index?(name)
|
325
|
-
if old_table.indexes[name] != new_table.indexes[name]
|
326
|
-
dropped << name
|
327
|
-
added << name
|
328
|
-
end
|
329
|
-
else
|
330
|
-
dropped << name
|
331
|
-
end
|
332
|
-
end
|
333
|
-
new_table.indexes.keys.each do |name|
|
334
|
-
added << name unless old_table.has_index?(name)
|
335
|
-
end
|
336
|
-
|
337
|
-
dropped.each do |name|
|
338
|
-
add_script(:indices_drop , "DROP INDEX #{name};")
|
339
|
-
end
|
340
|
-
added.each do |name|
|
341
|
-
add_script(:indices_create , (new_table.indexes[name] + ";")) if new_table.indexes[name]
|
342
|
-
end
|
343
|
-
end
|
344
|
-
end
|
345
|
-
end
|
data/lib/function.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class Function
|
3
|
-
def initialize(conn, tuple)
|
4
|
-
@name = tuple['namespace'] + "." + tuple['function_name']
|
5
|
-
@language = tuple['language_name']
|
6
|
-
@src = tuple['source_code']
|
7
|
-
@returns_set = tuple['returns_set']
|
8
|
-
@return_type = format_type(conn, tuple['return_type'])
|
9
|
-
@tipes = tuple['function_args'].split(" ")
|
10
|
-
if tuple['function_arg_names'] && tuple['function_arg_names'] =~ /^\{(.*)\}$/
|
11
|
-
@arnames = $1.split(',')
|
12
|
-
elsif tuple['function_arg_names'].is_a? Array # my version of ruby-postgres
|
13
|
-
@arnames = tuple['function_arg_names']
|
14
|
-
else
|
15
|
-
@arnames = [""] * @tipes.length
|
16
|
-
end
|
17
|
-
alist = []
|
18
|
-
@tipes.each_with_index do |typ,idx|
|
19
|
-
alist << (@arnames[idx] + " " + format_type(conn, typ))
|
20
|
-
end
|
21
|
-
@arglist = alist.join(" , ")
|
22
|
-
@strict = tuple['proisstrict'] ? ' STRICT' : ''
|
23
|
-
@secdef = tuple['prosecdef'] ? ' SECURITY DEFINER' : ''
|
24
|
-
@volatile = case tuple['provolatile']
|
25
|
-
when 'i' then ' IMMUTABLE'
|
26
|
-
when 's' then ' STABLE'
|
27
|
-
else ''
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def signature
|
32
|
-
"#{@name}(#{@arglist})"
|
33
|
-
end
|
34
|
-
|
35
|
-
def definition
|
36
|
-
<<-EOT
|
37
|
-
CREATE OR REPLACE FUNCTION #{@name} (#{@arglist}) RETURNS #{@returns_set ? 'SETOF' : ''} #{@return_type} AS $_$#{@src}$_$ LANGUAGE '#{@language}' #{@volatile}#{@strict}#{@secdef};
|
38
|
-
EOT
|
39
|
-
end
|
40
|
-
|
41
|
-
def == (other)
|
42
|
-
definition == other.definition
|
43
|
-
end
|
44
|
-
|
45
|
-
def format_type(conn, oid)
|
46
|
-
t_query = <<-EOT
|
47
|
-
SELECT pg_catalog.format_type(pg_type.oid, typtypmod) AS type_name
|
48
|
-
FROM pg_catalog.pg_type
|
49
|
-
JOIN pg_catalog.pg_namespace ON (pg_namespace.oid = typnamespace)
|
50
|
-
WHERE pg_type.oid =
|
51
|
-
EOT
|
52
|
-
tuple = conn.query(t_query + oid.to_s).first
|
53
|
-
tuple['type_name']
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/lib/rule.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class Rule
|
3
|
-
attr_reader :table_name, :name, :definition
|
4
|
-
|
5
|
-
def initialize(table_name, name, df)
|
6
|
-
@table_name = table_name
|
7
|
-
@name = name
|
8
|
-
@definition = df
|
9
|
-
end
|
10
|
-
|
11
|
-
def == (other)
|
12
|
-
other.definition == definition
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
data/lib/sequence.rb
DELETED
data/lib/table.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class Table
|
3
|
-
attr_accessor :table_name, :schema, :attributes, :constraints, :indexes
|
4
|
-
|
5
|
-
def initialize(conn, schema, table_name)
|
6
|
-
@schema = schema
|
7
|
-
@table_name = table_name
|
8
|
-
@attributes = {}
|
9
|
-
@constraints = {}
|
10
|
-
@indexes = {}
|
11
|
-
@atlist = []
|
12
|
-
|
13
|
-
att_query = <<-EOT
|
14
|
-
select attname, format_type(atttypid, atttypmod) as a_type, attnotnull, pg_get_expr(adbin, attrelid) as a_default
|
15
|
-
from pg_attribute left join pg_attrdef on (adrelid = attrelid and adnum = attnum)
|
16
|
-
where attrelid = '#{schema}.#{table_name}'::regclass and not attisdropped and attnum > 0
|
17
|
-
order by attnum
|
18
|
-
EOT
|
19
|
-
conn.query(att_query).each do |tuple|
|
20
|
-
attname = tuple['attname']
|
21
|
-
typedef = tuple['a_type']
|
22
|
-
notnull = tuple['attnotnull']
|
23
|
-
default = tuple['a_default']
|
24
|
-
@attributes[attname] = Attribute.new(attname, typedef, notnull, default)
|
25
|
-
@atlist << attname
|
26
|
-
end
|
27
|
-
|
28
|
-
ind_query = <<-EOT
|
29
|
-
select indexrelid::regclass as indname, pg_get_indexdef(indexrelid) as def
|
30
|
-
from pg_index where indrelid = '#{schema}.#{table_name}'::regclass and not indisprimary
|
31
|
-
EOT
|
32
|
-
conn.query(ind_query).each do |tuple|
|
33
|
-
name = tuple['indname']
|
34
|
-
value = tuple['def']
|
35
|
-
@indexes[name] = value
|
36
|
-
end
|
37
|
-
|
38
|
-
cons_query = <<-EOT
|
39
|
-
select conname, pg_get_constraintdef(oid) from pg_constraint where conrelid = '#{schema}.#{table_name}'::regclass
|
40
|
-
EOT
|
41
|
-
conn.query(cons_query).each do |tuple|
|
42
|
-
name = tuple['conname']
|
43
|
-
value = tuple['pg_get_constraintdef']
|
44
|
-
@constraints[name] = value
|
45
|
-
end
|
46
|
-
@constraints.keys.each do |cname|
|
47
|
-
@indexes.delete("#{schema}.#{cname}") if has_index?(cname)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def has_attribute?(name)
|
52
|
-
@attributes.has_key?(name)
|
53
|
-
end
|
54
|
-
|
55
|
-
def attribute_index(name)
|
56
|
-
@atlist.index(name)
|
57
|
-
end
|
58
|
-
|
59
|
-
def has_index?(name)
|
60
|
-
@indexes.has_key?(name) || @indexes.has_key?("#{schema}.#{name}")
|
61
|
-
end
|
62
|
-
|
63
|
-
def has_constraint?(name)
|
64
|
-
@constraints.has_key?(name)
|
65
|
-
end
|
66
|
-
|
67
|
-
def table_creation
|
68
|
-
out = ["CREATE TABLE #{name} ("]
|
69
|
-
stmt = []
|
70
|
-
@atlist.each do |attname|
|
71
|
-
stmt << @attributes[attname].definition
|
72
|
-
end
|
73
|
-
out << stmt.join(",\n")
|
74
|
-
out << ");"
|
75
|
-
out.join("\n")
|
76
|
-
end
|
77
|
-
|
78
|
-
def name
|
79
|
-
"#{schema}.#{table_name}"
|
80
|
-
end
|
81
|
-
|
82
|
-
def index_creation
|
83
|
-
out = []
|
84
|
-
@indexes.values.each do |c|
|
85
|
-
out << (c+";")
|
86
|
-
end
|
87
|
-
out.join("\n")
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
data/lib/trigger.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class Trigger
|
3
|
-
attr_reader :table_name, :name, :definition
|
4
|
-
|
5
|
-
def initialize(table_name, name, df)
|
6
|
-
@table_name = table_name
|
7
|
-
@name = name
|
8
|
-
@definition = df + ";"
|
9
|
-
end
|
10
|
-
|
11
|
-
def == (other)
|
12
|
-
other.definition == definition
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
data/lib/view.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
module PgDiff
|
2
|
-
class View
|
3
|
-
attr_reader :def, :name
|
4
|
-
|
5
|
-
def initialize(conn, sch, relname)
|
6
|
-
@name = "#{sch}.#{relname}"
|
7
|
-
view_qery = <<-EOT
|
8
|
-
SELECT pg_catalog.pg_get_viewdef('#{@name}'::regclass, true)
|
9
|
-
EOT
|
10
|
-
tuple = conn.query(view_qery).first
|
11
|
-
@def = tuple['pg_get_viewdef']
|
12
|
-
end
|
13
|
-
|
14
|
-
def definition
|
15
|
-
"CREATE VIEW #{@name} AS #{@def}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|