Skip to content

Commit c89efa5

Browse files
committed
Merge remote branch 'seven1m/master' into master
Conflicts: .gitignore Gemfile Gemfile.lock README.rdoc lib/mysql2psql/mysql_reader.rb lib/mysql2psql/postgres_writer.rb
2 parents 45739b5 + db137fa commit c89efa5

11 files changed

+64
-23
lines changed

Diff for: Gemfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
source 'http://rubygems.org'
1+
source :rubygems
22

33
group :development do
44
gem "bundler", "~> 1.0.21"
55
gem "jeweler", "~> 1.5.2"
66
end
77

8-
gemspec
8+
gemspec

Diff for: Gemfile.lock

-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ PATH
22
remote: .
33
specs:
44
mysql2psql (0.2.0)
5-
bundler (~> 1.0.21)
6-
jeweler (~> 1.5.2)
75
mysql (= 2.8.1)
86
mysql2psql
97
pg (~> 0.11.0)

Diff for: README.rdoc

+11-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ NB: With Ruby 1.8.x, the gem install will usually complain about "No definition
6161
* Make sure to add tests for it. This is important so no-one unintentionally breaks it in a future version.
6262
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so the gem maintainers can cherry-pick around it.
6363
* Send a pull request
64-
64+
6565
== Getting the source
6666
Mysql2psql was first produced by Max Lapshin <[email protected]> who maintains the master
6767
repository at https://github.com/maxlapshin/mysql2postgres
@@ -71,6 +71,15 @@ the repository is at https://github.com/tardate/mysql2postgres
7171

7272
Gem packaging is done with Jeweler. Note that on windows this means you must run under mingw or other shell that supports git to do the gem bundling (but you can gem install the built gem in the normal Windows shell).
7373

74+
== Setting up for development
75+
76+
The project includes a Gemfile so with bundler you can install gem dependencies with:
77+
78+
gem install bundler # if not already installed
79+
bundle install
80+
81+
Note comments 'Database driver dependencies' regarding issues that you may encounter with the mysql gem.
82+
7483
== Running tests
7584
If you fork/clone the project, you will want to run the test suite (and add to it if you are developing new features or fixing bugs).
7685

@@ -135,3 +144,4 @@ Contributors (roughly git log order):
135144
- {James Coleman}[https://github.com/jcoleman] <[email protected]>
136145
- {Aaron Peckham}[https://github.com/apeckham]
137146
- {James Tippett}[https://github.com/jtippett]
147+
- {Tim Morgan}[https://github.com/seven1m]

Diff for: Rakefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ begin
3030
"Paul Gallagher <[email protected]>",
3131
"James Coleman <[email protected]>",
3232
"Aaron Peckham",
33-
"James Tippett"
33+
"James Tippett",
34+
"Tim Morgan"
3435
]
3536
gem.add_dependency "mysql", "= 2.8.1"
3637
gem.add_dependency "pg", "~> 0.11.0"

Diff for: lib/mysql2psql/converter.rb

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def convert
5454
return 0
5555
rescue => e
5656
$stderr.puts "Mysql2psql: conversion failed: #{e.to_s}"
57+
$stderr.puts e.backtrace
5758
return -1
5859
end
5960
end

Diff for: lib/mysql2psql/mysql_reader.rb

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'mysql'
2+
require 'csv'
23

34
class Mysql2psql
45

@@ -46,7 +47,7 @@ def convert_type(type)
4647
when /varchar/
4748
"varchar"
4849
when /char/
49-
"char"
50+
"char"
5051
when /decimal/
5152
"decimal"
5253
when /float/
@@ -55,7 +56,7 @@ def convert_type(type)
5556
"double precision"
5657
else
5758
type
58-
end
59+
end
5960
end
6061

6162
def load_columns
@@ -94,7 +95,7 @@ def load_columns
9495

9596
def indexes
9697
load_indexes unless @indexes
97-
@indexes
98+
@indexes
9899
end
99100

100101
def foreign_keys
@@ -111,11 +112,26 @@ def load_indexes
111112
explain.split(/\n/).each do |line|
112113
next unless line =~ / KEY /
113114
index = {}
114-
if match_data = /CONSTRAINT `(\w+)` FOREIGN KEY \(`(\w+)`\) REFERENCES `(\w+)` \(`(\w+)`\)/.match(line)
115+
if match_data = /CONSTRAINT `(\w+)` FOREIGN KEY \((.*?)\) REFERENCES `(\w+)` \((.*?)\)(.*)/.match(line)
115116
index[:name] = match_data[1]
116-
index[:column] = match_data[2]
117+
index[:column] = match_data[2].parse_csv(:quote_char => '`',:col_sep => ', ')
117118
index[:ref_table] = match_data[3]
118-
index[:ref_column] = match_data[4]
119+
index[:ref_column] = match_data[4].parse_csv(:quote_char => '`',:col_sep => ', ')
120+
121+
the_rest = match_data[5]
122+
123+
if match_data = /ON DELETE (SET NULL|SET DEFAULT|RESTRICT|NO ACTION|CASCADE)/.match(the_rest)
124+
index[:on_delete] = match_data[1]
125+
else
126+
index[:on_delete] ||= 'RESTRICT'
127+
end
128+
129+
if match_data = /ON UPDATE (SET NULL|SET DEFAULT|RESTRICT|NO ACTION|CASCADE)/.match(the_rest)
130+
index[:on_update] = match_data[1]
131+
else
132+
index[:on_update] ||= 'RESTRICT'
133+
end
134+
119135
@foreign_keys << index
120136
elsif match_data = /KEY `(\w+)` \((.*)\)/.match(line)
121137
index[:name] = match_data[1]
@@ -138,7 +154,7 @@ def count_rows
138154
end
139155

140156
def has_id?
141-
!!columns.find {|col| col[:name] == "id"}
157+
!!columns.find {|col| col[:name] == "id"}
142158
end
143159

144160
def count_for_pager
@@ -166,10 +182,13 @@ def reconnect
166182
end
167183

168184
def initialize(options)
169-
@host, @user, @passwd, @db, @port, @sock, @flag =
170-
options.mysqlhostname('localhost'), options.mysqlusername,
171-
options.mysqlpassword, options.mysqldatabase,
172-
options.mysqlport, options.mysqlsocket(nil)
185+
@host, @user, @passwd, @db, @port, @sock, @flag =
186+
options.mysqlhostname('localhost'), options.mysqlusername,
187+
options.mysqlpassword, options.mysqldatabase,
188+
options.mysqlport, options.mysqlsocket
189+
@port = nil if @port == "" # for things like Amazon's RDS you don't have a port and connect fails with "" for a value
190+
@sock = nil if @sock == ""
191+
@flag = nil if @flag == ""
173192
connect
174193
end
175194

Diff for: lib/mysql2psql/postgres_db_writer.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def write_indexes(table)
116116

117117
def write_constraints(table)
118118
table.foreign_keys.each do |key|
119-
key_sql = "ALTER TABLE #{PGconn.quote_ident(table.name)} ADD FOREIGN KEY (#{PGconn.quote_ident(key[:column])}) REFERENCES #{PGconn.quote_ident(key[:ref_table])}(#{PGconn.quote_ident(key[:ref_column])})"
119+
key_sql = "ALTER TABLE #{PGconn.quote_ident(table.name)} ADD FOREIGN KEY (#{key[:column].map{|c|PGconn.quote_ident(c)}.join(', ')}) REFERENCES #{PGconn.quote_ident(key[:ref_table])}(#{key[:ref_column].map{|c|PGconn.quote_ident(c)}.join(', ')}) ON UPDATE #{key[:on_update]} ON DELETE #{key[:on_delete]}"
120120
begin
121121
@conn.exec(key_sql)
122122
rescue Exception => e

Diff for: lib/mysql2psql/postgres_file_writer.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def write_indexes(table)
122122

123123
def write_constraints(table)
124124
table.foreign_keys.each do |key|
125-
@f << "ALTER TABLE #{PGconn.quote_ident(table.name)} ADD FOREIGN KEY (#{PGconn.quote_ident(key[:column])}) REFERENCES #{PGconn.quote_ident(key[:ref_table])}(#{PGconn.quote_ident(key[:ref_column])});\n"
125+
@f << "ALTER TABLE #{PGconn.quote_ident(table.name)} ADD FOREIGN KEY (#{key[:column].map{|c|PGconn.quote_ident(c)}.join(', ')}) REFERENCES #{PGconn.quote_ident(key[:ref_table])}(#{key[:ref_column].map{|c|PGconn.quote_ident(c)}.join(', ')}) ON UPDATE #{key[:on_update]} ON DELETE #{key[:on_delete]};\n"
126126
end
127127
end
128128

Diff for: lib/mysql2psql/postgres_writer.rb

+8-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def column_type(column, options={})
2323
when 'real', /float/, 'double precision'
2424
'double precision'
2525
when 'decimal'
26-
"numeric(#{column[:length] || 10}, #{column[:decimals] || 0})"
26+
# TODO: seven1m thinks "real" instead?
27+
"numeric(#{column[:length] || 10}, #{column[:decimals] || 5})"
2728
when 'datetime', 'timestamp'
2829
"timestamp with#{options[:use_timezones] ? '' : 'out'} time zone"
2930
when 'time'
@@ -107,7 +108,11 @@ def column_type_info(column, options)
107108
def process_row(table, row)
108109
table.columns.each_with_index do |column, index|
109110
if column[:type] == 'time'
110-
row[index] = "%02d:%02d:%02d" % [row[index].hour, row[index].minute, row[index].second]
111+
begin
112+
row[index] = "%02d:%02d:%02d" % [row[index].hour, row[index].minute, row[index].second]
113+
rescue
114+
# Don't fail on nil date/time.
115+
end
111116
elsif row[index].is_a?(Mysql::Time)
112117
row[index] = row[index].to_s.gsub('0000-00-00 00:00', '1970-01-01 00:00')
113118
row[index] = row[index].to_s.gsub('0000-00-00 00:00:00', '1970-01-01 00:00:00')
@@ -142,7 +147,7 @@ def process_row(table, row)
142147
elsif row[index].nil?
143148
# Note: '\N' not "\N" is correct here:
144149
# The string containing the literal backslash followed by 'N'
145-
# represents database NULL value in PostgreSQL's text mode.
150+
# represents database NULL value in PostgreSQL's text mode.
146151
row[index] = '\N'
147152
end
148153
end

Diff for: test/integration/convert_to_db_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def test_index_conversion
112112

113113
def test_foreign_keys
114114
result = exec_sql_on_psql("SELECT conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef FROM pg_catalog.pg_constraint r WHERE r.conrelid = 'test_foreign_keys_child'::regclass")
115-
expected = {"condef" => "FOREIGN KEY (test_foreign_keys_parent_id) REFERENCES test_foreign_keys_parent(id)", "conname" => "test_foreign_keys_child_test_foreign_keys_parent_id_fkey"}
115+
expected = {"condef" => "FOREIGN KEY (test_foreign_keys_parent_id) REFERENCES test_foreign_keys_parent(id) ON UPDATE RESTRICT ON DELETE CASCADE", "conname" => "test_foreign_keys_child_test_foreign_keys_parent_id_fkey"}
116116
assert_equal expected, result.first
117117
end
118118

Diff for: test/integration/mysql_reader_base_test.rb

+7
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,11 @@ def test_mysql_reconnect
2424
reader.reconnect
2525
end
2626
end
27+
def test_mysql_connection_without_port
28+
assert_nothing_raised do
29+
@options.mysqlport = ""
30+
@options.mysqlsocket = ""
31+
reader = Mysql2psql::MysqlReader.new(@options)
32+
end
33+
end
2734
end

0 commit comments

Comments
 (0)