dbdiff 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/CHANGELOG +6 -0
  2. data/LICENSE +58 -0
  3. data/README +29 -0
  4. data/lib/dbdiff/column.rb +69 -0
  5. data/lib/dbdiff/database.rb +169 -0
  6. data/lib/dbdiff/delta.rb +266 -0
  7. data/lib/dbdiff/foreign_key.rb +68 -0
  8. data/lib/dbdiff/key.rb +69 -0
  9. data/lib/dbdiff/row.rb +32 -0
  10. data/lib/dbdiff/table.rb +50 -0
  11. data/lib/dbdiff/table_element.rb +16 -0
  12. data/lib/dbdiff.rb +207 -0
  13. data/test/ai_column/source.sql +10 -0
  14. data/test/ai_column/target.sql +7 -0
  15. data/test/change_pk/source.sql +11 -0
  16. data/test/change_pk/target.sql +8 -0
  17. data/test/column/source.sql +10 -0
  18. data/test/column/target.sql +9 -0
  19. data/test/fk/source.sql +19 -0
  20. data/test/fk/target.sql +20 -0
  21. data/test/key/source.sql +11 -0
  22. data/test/key/target.sql +10 -0
  23. data/test/modify_column/source.sql +9 -0
  24. data/test/modify_column/target.sql +10 -0
  25. data/test/modify_fk/source.sql +20 -0
  26. data/test/modify_fk/target.sql +22 -0
  27. data/test/modify_key_fk/source.sql +19 -0
  28. data/test/modify_key_fk/target.sql +20 -0
  29. data/test/modify_key_fk_ref/source.sql +18 -0
  30. data/test/modify_key_fk_ref/target.sql +20 -0
  31. data/test/modify_row/source.sql +8 -0
  32. data/test/modify_row/target.sql +9 -0
  33. data/test/modify_table/source.sql +8 -0
  34. data/test/modify_table/target.sql +9 -0
  35. data/test/multi_fk/source.sql +22 -0
  36. data/test/multi_fk/target.sql +20 -0
  37. data/test/multi_key/source.sql +11 -0
  38. data/test/multi_key/target.sql +10 -0
  39. data/test/multi_unique_key/source.sql +11 -0
  40. data/test/multi_unique_key/target.sql +10 -0
  41. data/test/row/source.sql +8 -0
  42. data/test/row/target.sql +6 -0
  43. data/test/suite.rb +7 -0
  44. data/test/table/source.sql +9 -0
  45. data/test/table/target.sql +0 -0
  46. data/test/table_fk/source.sql +13 -0
  47. data/test/table_fk/target.sql +20 -0
  48. data/test/table_fk2/source.sql +17 -0
  49. data/test/table_fk2/target.sql +5 -0
  50. data/test/test_column.rb +93 -0
  51. data/test/test_dbdiff.rb +92 -0
  52. data/test/test_foreign_key.rb +136 -0
  53. data/test/test_key.rb +116 -0
  54. data/test/test_row.rb +84 -0
  55. data/test/test_table.rb +30 -0
  56. data/test/unique_key/source.sql +11 -0
  57. data/test/unique_key/target.sql +9 -0
  58. metadata +127 -0
data/lib/dbdiff/key.rb ADDED
@@ -0,0 +1,69 @@
1
+ class DbDiff
2
+ class Key < TableElement
3
+ attr_reader :column_data, :unique, :primary
4
+
5
+ def initialize(table_name, info= {})
6
+ @table_name = table_name
7
+
8
+
9
+ # XXX need to work on tihs
10
+ @name = info['Key_name']
11
+
12
+ @primary = (@name == 'PRIMARY' ? true : false)
13
+ seq_index = info['Seq_in_index'].to_i - 1
14
+ @unique = (info['Non_unique'].to_i == 1 ? false : true)
15
+ @column_data = {}
16
+ @column_data[seq_index] = info['Column_name']
17
+ end
18
+
19
+ def columns
20
+ @column_data.keys.sort.map {|k| @column_data[k]}
21
+ end
22
+
23
+ def merge(key)
24
+
25
+ unless key.name == self.name
26
+ raise "Error - names don't match #{key.name} #{self.name}"
27
+ end
28
+
29
+ @column_data.merge!(key.column_data)
30
+ end
31
+
32
+ def definition
33
+
34
+ sql = ""
35
+ if @primary
36
+ sql += " PRIMARY KEY "
37
+ elsif @unique
38
+ sql += " UNIQUE KEY `%s`" % self.name
39
+ else
40
+ sql += " KEY `%s`" % self.name
41
+ end
42
+
43
+ sql += " (" + self.columns.map{|c| '`' + c + '`' }.join(",") + " )"
44
+
45
+ sql
46
+ end
47
+
48
+ def modify_delta(new_element)
49
+ Delta::ModifyKey.new(new_element)
50
+ end
51
+
52
+ def drop_delta
53
+ Delta::DropKey.new(self)
54
+ end
55
+
56
+ def add_delta
57
+ Delta::AddKey.new(self)
58
+ end
59
+
60
+ def ==(other)
61
+ self.columns == other.columns &&
62
+ self.table_name == other.table_name &&
63
+ self.primary == other.primary &&
64
+ self.unique == other.unique &&
65
+ self.name == other.name
66
+ end
67
+
68
+ end
69
+ end
data/lib/dbdiff/row.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'dbdiff/table_element'
2
+
3
+ class DbDiff
4
+
5
+ class Row < TableElement
6
+ attr_reader :primary_key, :data
7
+
8
+ def initialize(table, info = {})
9
+ @data = info.dup
10
+ @primary_key = table.primary_key
11
+ @name = @primary_key.map {|k|@data[k] }.join("|") # XXX fix this to be more unique of a name
12
+ @table_name = table.name
13
+ end
14
+
15
+
16
+ def add_delta
17
+ Delta::AddRow.new(self)
18
+ end
19
+
20
+ def modify_delta(new_element)
21
+ Delta::ModifyRow.new(new_element)
22
+ end
23
+
24
+ def drop_delta
25
+ Delta::DropRow.new(self)
26
+ end
27
+
28
+ def ==(other)
29
+ self.data == other.data
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,50 @@
1
+ class DbDiff
2
+ class Table
3
+ attr_reader :name
4
+ attr_accessor :charset, :rows, :keys, :foreign_keys, :columns, :collation, :engine
5
+
6
+ def initialize(info = {})
7
+ @data = {}
8
+
9
+ @rows = []
10
+ @foreign_keys = []
11
+ @keys = []
12
+ @columns = []
13
+
14
+ @engine = info['ENGINE']
15
+ @collation = info['TABLE_COLLATION']
16
+ @name = info['TABLE_NAME']
17
+ end
18
+
19
+ alias :table_name :name
20
+
21
+ def primary_key
22
+ pk = keys.find{|k| k.primary}
23
+ return (pk ? pk.columns : nil)
24
+ end
25
+
26
+ def ==(other)
27
+ self.engine == other.engine &&
28
+ self.collation == other.collation &&
29
+ self.name == other.name
30
+ end
31
+
32
+ def deep_clone
33
+ t = Marshal::load(Marshal.dump(self))
34
+ # must clear rows out since they won't necessary be in the copy
35
+ end
36
+
37
+ def add_delta
38
+ Delta::AddTable.new(self)
39
+ end
40
+
41
+ def modify_delta(new_element)
42
+ Delta::ModifyTable.new(new_element)
43
+ end
44
+
45
+ def drop_delta
46
+ Delta::DropTable.new(self)
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,16 @@
1
+ class DbDiff
2
+ class TableElement
3
+ attr_reader :name, :table_name
4
+
5
+ def initialize(info = {})
6
+ @table_name = info['TABLE_NAME']
7
+ end
8
+
9
+
10
+ def deep_clone
11
+ Marshal::load(Marshal.dump(self))
12
+ end
13
+
14
+ end
15
+ end
16
+
data/lib/dbdiff.rb ADDED
@@ -0,0 +1,207 @@
1
+ require 'dbdiff/database'
2
+ require 'logger'
3
+
4
+ # = Synopsis
5
+ # DbDiff allows you to compare two different databases (currently MySQL),
6
+ # determine the differences between the two, and apply the deltas.
7
+ # Currently the following types of deltas are supported: tables,
8
+ # columns, keys, foreign keys and rows.
9
+ #
10
+ # Specifying tables in the constructor causes these tables to be
11
+ # replicated.
12
+ #
13
+ # Nothing in dropped or removed unless you explicitly pass :drop_row,
14
+ # :drop_column or :drop_table.
15
+ #
16
+ # By default, calling apply_diffs does nothing - you must explicitly
17
+ # set dry_run to false on the dbdiff object.
18
+ #
19
+ #
20
+ # == Example
21
+ # require 'rubygems'
22
+ # require 'dbdiff'
23
+ #
24
+ # dbdiff = DbDiff.new( {:host => 127.0.0.1, :password => nil, :user => 'root', :name => 'source_db'},
25
+ # {:host => 127.0.0.1, :password => nil, :user => 'root', :name => 'target_db'},
26
+ # :logger => Logger.new(STDOUT),
27
+ # :tables => %w(authors books)
28
+ # )
29
+ # # don't actually execute any SQL against the target
30
+ # dbdiff.dry_run = true
31
+ #
32
+ # # perform diff between source and target
33
+ # dbiff.diff
34
+ #
35
+ # # process diffs - arguments indicate that drop_column, drop_row (only for replicated tables),
36
+ # # and drop_table are allowed within diffs
37
+ # # are allowed
38
+ # diff.apply_diffs(:drop_column, :drop_row, :drop_table)
39
+ #
40
+
41
+ class DbDiff
42
+ attr_reader :source, :target, :tables, :logger
43
+ attr_accessor :dry_run
44
+
45
+ # Creates a new dbdiff object with the connect strings s/t (source/target)
46
+ def initialize(s, t, params = {})
47
+ @source = DbDiff::Database.new(s)
48
+ @target = DbDiff::Database.new(t)
49
+ @tables = params[:tables] || []
50
+ @logger = params[:logger] || Logger.new(nil)
51
+
52
+ @source.load_rows(@tables)
53
+ @target.load_rows(@tables)
54
+ @dry_run = true
55
+ end
56
+
57
+ # Compare tables and all elements (columns, rows, keys, foreign keys)
58
+ # differences are stored on the deltas attribute of the target
59
+ # database
60
+ def diff
61
+ compare_tables
62
+ compare_elements(:columns, :rows, :keys, :foreign_keys)
63
+ end
64
+
65
+ # Apply deltas stored on the target
66
+ # all SQL executed will be sent to the logger as info messages
67
+ def apply_diffs (*allowed_deltas)
68
+
69
+
70
+ # these deltas must be manually
71
+ # resolved or explicitly allowed
72
+ confirm_deltas = {
73
+ :drop_row => DbDiff::Delta::DropRow,
74
+ :drop_column => DbDiff::Delta::DropColumn,
75
+ :drop_table => DbDiff::Delta::DropTable
76
+ }
77
+
78
+ confirm_deltas = confirm_deltas.delete_if {|k,v| allowed_deltas.include?(k)}
79
+
80
+
81
+ delta_order = [
82
+ DbDiff::Delta::AddTable,
83
+ DbDiff::Delta::ModifyTable,
84
+ DbDiff::Delta::DropForeignKey,
85
+ DbDiff::Delta::DropTable, # can only drop a table after foreign keys have been dropped
86
+
87
+ DbDiff::Delta::AddColumn,
88
+
89
+ DbDiff::Delta::ModifyColumnRemoveAI, # ai must be removed before we can drop/modify a pk
90
+
91
+ DbDiff::Delta::ModifyKey, # must have columns exist prior to adding a key
92
+ DbDiff::Delta::AddKey, # must have new keys before old ones can be dropped
93
+ # to support FKs
94
+
95
+ DbDiff::Delta::DropKey, # must have FK dropped before we drop a key
96
+
97
+ DbDiff::Delta::ModifyColumnAddAI, # ai must be added before we can add a pk
98
+
99
+ DbDiff::Delta::DropRow,
100
+ DbDiff::Delta::ModifyColumn,
101
+
102
+ DbDiff::Delta::AddForeignKey,
103
+ DbDiff::Delta::DropColumn,
104
+ DbDiff::Delta::AddRow,
105
+ DbDiff::Delta::ModifyRow
106
+ ]
107
+
108
+ drop_deltas = target.deltas.find_all {|d| confirm_deltas.values.include?(d.class) }
109
+
110
+ if drop_deltas && drop_deltas.size > 0
111
+ message = "The following deltas must be either handled by a rename or explicitly allowed"
112
+ drop_deltas.each do|d|
113
+ message += "\n #{d.class.name}: " + d.sql
114
+ end
115
+ raise message
116
+ end
117
+
118
+ target.dbh.query("SET FOREIGN_KEY_CHECKS = 0")
119
+
120
+ target.deltas.sort_by {|d| delta_order.index(d.class) }.each do |d|
121
+ logger.info("processing #{d.sql}")
122
+ d.process(target)
123
+ run_sql(d.sql) unless @dry_run
124
+ end
125
+
126
+ target.dbh.query("SET FOREIGN_KEY_CHECKS = 1")
127
+
128
+ target.deltas = []
129
+ end
130
+
131
+ private
132
+
133
+ def run_sql(sql)
134
+ begin
135
+ target.dbh.select_db(target.name)
136
+ logger.info("executing #{sql}")
137
+ result = target.dbh.query(sql)
138
+ rescue => e
139
+ raise "error executing query '#{sql}': #{e}"
140
+ end
141
+ end
142
+
143
+ def compare_elements(*elements)
144
+
145
+ elements.each do |e|
146
+ diff_table_elements(source, target, e, :diff_add_modify)
147
+ diff_table_elements(target, source, e, :diff_drop)
148
+ end
149
+ end
150
+
151
+ def compare_tables
152
+
153
+ # only handle modify/add
154
+ source.tables.each do |t|
155
+ # XXX add authors2
156
+ diff_add_modify(source, target, t, target.tables.find{|x| x.name == t.name})
157
+ end
158
+
159
+ ## only handle removals here
160
+ target.tables.each do |t|
161
+ # xxx drop authors
162
+ diff_drop(target, source, t, source.tables.find{|x| x.name == t.name})
163
+ end
164
+
165
+ end
166
+
167
+ def diff_drop(a, b, element, target_element)
168
+ if !target_element
169
+ # source is actually the target database
170
+ logger.info("dropping #{element.class.name} #{element.name} #{element.table_name} from #{a.class.name} #{a.name}")
171
+ a.drop(element)
172
+ end
173
+ end
174
+
175
+ def diff_add_modify(a, b, element, target_element)
176
+
177
+ if !target_element
178
+ logger.info("adding element #{element.class.name} #{element.name} #{element.table_name} > #{b.name}")
179
+ b.add(element)
180
+ elsif target_element != element
181
+ logger.info("modifying element #{element.class.name} #{element.name} #{element.table_name} > #{b.name}")
182
+ b.modify(target_element, element)
183
+ end
184
+
185
+ end
186
+
187
+ def diff_table_elements(a, b, table_method, diff_method)
188
+
189
+
190
+ # all_tables allows us to add the FKs after adding the tables
191
+ # otherwise the table won't be there to add the FK
192
+ a.all_tables.each do |at|
193
+ bt = b.all_tables.find{|z| z.name == at.name}
194
+ # XXX possibly skip this and make the add check determine whether
195
+ # we can skip the add because we have already encountered the add
196
+ next unless bt
197
+
198
+ at.send(table_method).each do |ae|
199
+ be = bt.send(table_method).find{|x| x.name == ae.name}
200
+ send(diff_method, a, b, ae, be)
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+
@@ -0,0 +1,10 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ `address1` char(60) NOT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
9
+
10
+
@@ -0,0 +1,7 @@
1
+
2
+ CREATE TABLE authors (
3
+ `name` char(60) NOT NULL,
4
+ `address1` char(60) NOT NULL
5
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
6
+
7
+
@@ -0,0 +1,11 @@
1
+ CREATE TABLE authors (
2
+ dim_id int not null,
3
+ res_id int not null,
4
+ name char(60) NOT NULL,
5
+ address1 char(60) NOT NULL,
6
+ PRIMARY KEY (`dim_id`, `res_id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+
10
+
11
+
@@ -0,0 +1,8 @@
1
+ CREATE TABLE authors (
2
+ id int(11) NOT NULL auto_increment,
3
+ dim_id int not null,
4
+ res_id int not null,
5
+ name char(60) NOT NULL,
6
+ address1 char(60) NOT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
@@ -0,0 +1,10 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ `address1` char(60) NOT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
9
+
10
+
@@ -0,0 +1,9 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+
@@ -0,0 +1,19 @@
1
+
2
+ CREATE TABLE authors (
3
+ `id` int(11) NOT NULL auto_increment,
4
+ `name` char(60) NOT NULL,
5
+ `address1` char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+ CREATE TABLE books (
10
+ id int(11) NOT NULL auto_increment,
11
+ author_id int not null,
12
+ name char(60) NOT NULL,
13
+ pages int not null,
14
+ FOREIGN KEY (author_id) references authors(id),
15
+ PRIMARY KEY (`id`)
16
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
17
+
18
+
19
+
@@ -0,0 +1,20 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ `address1` char(60) NOT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
9
+
10
+ CREATE TABLE books (
11
+ id int(11) NOT NULL auto_increment,
12
+ author_id int not null,
13
+ name char(60) NOT NULL,
14
+ pages int not null,
15
+ PRIMARY KEY (`id`)
16
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
17
+
18
+
19
+
20
+
@@ -0,0 +1,11 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ `address1` char(60) NOT NULL,
7
+ index(name),
8
+ PRIMARY KEY (`id`)
9
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
10
+
11
+
@@ -0,0 +1,10 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ `address1` char(60) NOT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
9
+
10
+
@@ -0,0 +1,9 @@
1
+
2
+ CREATE TABLE authors (
3
+ `id` int(11) NOT NULL auto_increment,
4
+ `name` char(60) NOT NULL,
5
+ `address1` char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+
@@ -0,0 +1,10 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ `address1` char(40) NOT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
9
+
10
+
@@ -0,0 +1,20 @@
1
+
2
+ CREATE TABLE authors (
3
+ `id` int(11) NOT NULL auto_increment,
4
+ `name` char(60) NOT NULL,
5
+ `address1` char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+ CREATE TABLE books (
10
+ id int(11) NOT NULL auto_increment,
11
+ author_id int not null,
12
+ new_id int not null,
13
+ name char(60) NOT NULL,
14
+ pages int not null,
15
+ CONSTRAINT `author_fk1` FOREIGN KEY (new_id) references authors(id),
16
+ PRIMARY KEY (`id`)
17
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
18
+
19
+
20
+
@@ -0,0 +1,22 @@
1
+ DROP TABLE IF EXISTS `authors`;
2
+
3
+ CREATE TABLE authors (
4
+ `id` int(11) NOT NULL auto_increment,
5
+ `name` char(60) NOT NULL,
6
+ `address1` char(60) NOT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
9
+
10
+ CREATE TABLE books (
11
+ id int(11) NOT NULL auto_increment,
12
+ author_id int not null,
13
+ new_id int not null,
14
+ name char(60) NOT NULL,
15
+ pages int not null,
16
+ CONSTRAINT `author_fk1` FOREIGN KEY (author_id) references authors(id),
17
+ PRIMARY KEY (`id`)
18
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
19
+
20
+
21
+
22
+
@@ -0,0 +1,19 @@
1
+
2
+ CREATE TABLE authors (
3
+ id int(11) NOT NULL auto_increment,
4
+ name char(60) NOT NULL,
5
+ address1 char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+ CREATE TABLE books (
10
+ id int(11) NOT NULL auto_increment,
11
+ author_id int not null,
12
+ name char(60) NOT NULL,
13
+ unique(author_id),
14
+ FOREIGN KEY (author_id) references authors(id),
15
+ PRIMARY KEY (`id`)
16
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
17
+
18
+
19
+
@@ -0,0 +1,20 @@
1
+
2
+ CREATE TABLE authors (
3
+ id int(11) NOT NULL auto_increment,
4
+ name char(60) NOT NULL,
5
+ address1 char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+ CREATE TABLE books (
10
+ id int(11) NOT NULL auto_increment,
11
+ author_id int not null,
12
+ name char(60) NOT NULL,
13
+ index(author_id),
14
+ FOREIGN KEY (author_id) references authors(id),
15
+ PRIMARY KEY (`id`)
16
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
17
+
18
+
19
+
20
+
@@ -0,0 +1,18 @@
1
+
2
+ CREATE TABLE authors (
3
+ id int(11) NOT NULL auto_increment,
4
+ name char(60) NOT NULL,
5
+ address1 char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+ CREATE TABLE books (
10
+ id int(11) NOT NULL auto_increment,
11
+ author_id int not null,
12
+ address_id int not null,
13
+ name char(60) NOT NULL,
14
+ unique(author_id),
15
+ FOREIGN KEY (author_id) references authors(id),
16
+ PRIMARY KEY (`id`)
17
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
18
+
@@ -0,0 +1,20 @@
1
+
2
+ CREATE TABLE authors (
3
+ id int(11) NOT NULL auto_increment,
4
+ name char(60) NOT NULL,
5
+ address1 char(60) NOT NULL,
6
+ PRIMARY KEY (`id`)
7
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
8
+
9
+ CREATE TABLE books (
10
+ id int(11) NOT NULL auto_increment,
11
+ author_id int not null,
12
+ name char(60) NOT NULL,
13
+ index(author_id),
14
+ FOREIGN KEY (author_id) references authors(id),
15
+ PRIMARY KEY (`id`)
16
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
17
+
18
+
19
+
20
+
@@ -0,0 +1,8 @@
1
+ CREATE TABLE authors (
2
+ `id` int(11) NOT NULL auto_increment,
3
+ `name` char(60) NOT NULL,
4
+ `address` char(60) NULL,
5
+ PRIMARY KEY (`id`)
6
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
7
+
8
+ INSERT INTO authors (id, name,address) values (1, 'FOO', NULL);
@@ -0,0 +1,9 @@
1
+ CREATE TABLE authors (
2
+ `id` int(11) NOT NULL auto_increment,
3
+ `name` char(60) NOT NULL,
4
+ `address` char(60) NULL,
5
+ PRIMARY KEY (`id`)
6
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
7
+
8
+ INSERT INTO authors (id, name, address) values (1, 'BAR', 'BLAh');
9
+
@@ -0,0 +1,8 @@
1
+
2
+ CREATE TABLE authors (
3
+ `id` int(11) NOT NULL auto_increment,
4
+ `name` char(60) NOT NULL,
5
+ PRIMARY KEY (`id`)
6
+ ) ENGINE=innodb DEFAULT CHARSET=latin1;
7
+
8
+