mysql2psql 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,143 @@
1
+ require 'pg'
2
+
3
+ require 'mysql2psql/writer'
4
+
5
+ class Mysql2psql
6
+
7
+ class PostgresWriter < Writer
8
+ def column_description(column)
9
+ "#{PGconn.quote_ident(column[:name])} #{column_type_info(column)}"
10
+ end
11
+
12
+ def column_type(column)
13
+ column_type_info(column).split(" ").first
14
+ end
15
+
16
+ def column_type_info(column)
17
+ if column[:auto_increment]
18
+ return "integer DEFAULT nextval('#{column[:table_name]}_#{column[:name]}_seq'::regclass) NOT NULL"
19
+ end
20
+
21
+ default = column[:default] ? " DEFAULT #{column[:default] == nil ? 'NULL' : "'"+PGconn.escape(column[:default])+"'"}" : nil
22
+ null = column[:null] ? "" : " NOT NULL"
23
+ type =
24
+ case column[:type]
25
+
26
+ # String types
27
+ when "char"
28
+ default = default + "::char" if default
29
+ "character(#{column[:length]})"
30
+ when "varchar"
31
+ default = default + "::character varying" if default
32
+ # puts "VARCHAR: #{column.inspect}"
33
+ "character varying(#{column[:length]})"
34
+
35
+ # Integer and numeric types
36
+ when "integer"
37
+ default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default].to_i}" if default
38
+ "integer"
39
+ when "bigint"
40
+ default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default].to_i}" if default
41
+ "bigint"
42
+ when "tinyint"
43
+ default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default].to_i}" if default
44
+ "smallint"
45
+
46
+ when "boolean"
47
+ default = " DEFAULT #{column[:default].to_i == 1 ? 'true' : 'false'}" if default
48
+ "boolean"
49
+ when "float"
50
+ default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default].to_f}" if default
51
+ "real"
52
+ when "float unsigned"
53
+ default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default].to_f}" if default
54
+ "real"
55
+ when "decimal"
56
+ default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default
57
+ "numeric(#{column[:length] || 10}, #{column[:decimals] || 0})"
58
+
59
+ when "double precision"
60
+ default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default
61
+ "double precision"
62
+
63
+ # Mysql datetime fields
64
+ when "datetime"
65
+ default = nil
66
+ "timestamp without time zone"
67
+ when "date"
68
+ default = nil
69
+ "date"
70
+ when "timestamp"
71
+ default = " DEFAULT CURRENT_TIMESTAMP" if column[:default] == "CURRENT_TIMESTAMP"
72
+ default = " DEFAULT '1970-01-01 00:00'" if column[:default] == "0000-00-00 00:00"
73
+ default = " DEFAULT '1970-01-01 00:00:00'" if column[:default] == "0000-00-00 00:00:00"
74
+ "timestamp without time zone"
75
+ when "time"
76
+ default = " DEFAULT NOW()" if default
77
+ "time without time zone"
78
+
79
+ when "tinyblob"
80
+ "bytea"
81
+ when "mediumblob"
82
+ "bytea"
83
+ when "longblob"
84
+ "bytea"
85
+ when "blob"
86
+ "bytea"
87
+ when "varbinary"
88
+ "bytea"
89
+ when "tinytext"
90
+ "text"
91
+ when "mediumtext"
92
+ "text"
93
+ when "longtext"
94
+ "text"
95
+ when "text"
96
+ "text"
97
+ when /^enum/
98
+ default = default + "::character varying" if default
99
+ enum = column[:type].gsub(/enum|\(|\)/, '')
100
+ max_enum_size = enum.split(',').map{ |check| check.size() -2}.sort[-1]
101
+ "character varying(#{max_enum_size}) check( #{column[:name]} in (#{enum}))"
102
+ else
103
+ puts "Unknown #{column.inspect}"
104
+ column[:type].inspect
105
+ return ""
106
+ end
107
+ "#{type}#{default}#{null}"
108
+ end
109
+
110
+ def process_row(table, row)
111
+ table.columns.each_with_index do |column, index|
112
+
113
+ if column[:type] == "time"
114
+ row[index] = "%02d:%02d:%02d" % [row[index].hour, row[index].minute, row[index].second]
115
+ end
116
+
117
+ if row[index].is_a?(Mysql::Time)
118
+ row[index] = row[index].to_s.gsub('0000-00-00 00:00', '1970-01-01 00:00')
119
+ row[index] = row[index].to_s.gsub('0000-00-00 00:00:00', '1970-01-01 00:00:00')
120
+ end
121
+
122
+ if column_type(column) == "boolean"
123
+ row[index] = row[index] == 1 ? 't' : row[index] == 0 ? 'f' : row[index]
124
+ end
125
+
126
+ if row[index].is_a?(String)
127
+ if column_type(column) == "bytea"
128
+ row[index] = PGconn.escape_bytea(row[index])
129
+ else
130
+ row[index] = row[index].gsub(/\\/, '\\\\\\').gsub(/\n/,'\n').gsub(/\t/,'\t').gsub(/\r/,'\r').gsub(/\0/, '')
131
+ end
132
+ end
133
+
134
+ row[index] = '\N' if !row[index]
135
+ end
136
+ end
137
+
138
+ def truncate(table)
139
+ end
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,9 @@
1
+ class Mysql2psql
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+
7
+ STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ class Mysql2psql
2
+
3
+ class Writer
4
+ end
5
+
6
+ end
@@ -0,0 +1,91 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{mysql2psql}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Max Lapshin <max@maxidoors.ru>", "Anton Ageev <anton@ageev.name>", "Samuel Tribehou <cracoucax@gmail.com>", "Marco Nenciarini <marco.nenciarini@devise.it>", "James Nobis <jnobis@jnobis.controldocs.com>", "quel <github@quelrod.net>", "Holger Amann <keeney@fehu.org>", "Maxim Dobriakov <closer.main@gmail.com>", "Michael Kimsal <mgkimsal@gmail.com>", "Jacob Coby <jcoby@portallabs.com>", "Neszt Tibor <neszt@tvnetwork.hu>", "Miroslav Kratochvil <exa.exa@gmail.com>", "Paul Gallagher <gallagher.paul@gmail.com>"]
12
+ s.date = %q{2010-09-19}
13
+ s.default_executable = %q{mysql2psql}
14
+ s.description = %q{It can create postgresql dump from mysql database or directly load data from mysql to
15
+ postgresql (at about 100 000 records per minute). Translates most data types and indexes.}
16
+ s.email = %q{gallagher.paul@gmail.com}
17
+ s.executables = ["mysql2psql"]
18
+ s.extra_rdoc_files = [
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".gitignore",
23
+ "MIT-LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "bin/mysql2psql",
27
+ "lib/mysql2psql.rb",
28
+ "lib/mysql2psql/config.rb",
29
+ "lib/mysql2psql/config_base.rb",
30
+ "lib/mysql2psql/converter.rb",
31
+ "lib/mysql2psql/errors.rb",
32
+ "lib/mysql2psql/mysql_reader.rb",
33
+ "lib/mysql2psql/postgres_db_writer.rb",
34
+ "lib/mysql2psql/postgres_file_writer.rb",
35
+ "lib/mysql2psql/postgres_writer.rb",
36
+ "lib/mysql2psql/version.rb",
37
+ "lib/mysql2psql/writer.rb",
38
+ "mysql2psql.gemspec",
39
+ "test/fixtures/config_all_options.yml",
40
+ "test/fixtures/seed_integration_tests.sql",
41
+ "test/integration/convert_to_db_test.rb",
42
+ "test/integration/convert_to_file_test.rb",
43
+ "test/integration/converter_test.rb",
44
+ "test/integration/mysql_reader_base_test.rb",
45
+ "test/integration/mysql_reader_test.rb",
46
+ "test/integration/postgres_db_writer_base_test.rb",
47
+ "test/lib/ext_test_unit.rb",
48
+ "test/lib/test_helper.rb",
49
+ "test/units/config_base_test.rb",
50
+ "test/units/config_test.rb",
51
+ "test/units/postgres_file_writer_test.rb"
52
+ ]
53
+ s.homepage = %q{http://github.com/tardate/mysql2postgresql}
54
+ s.rdoc_options = ["--charset=UTF-8"]
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = %q{1.3.7}
57
+ s.summary = %q{Tool for converting mysql database to postgresql}
58
+ s.test_files = [
59
+ "test/integration/convert_to_db_test.rb",
60
+ "test/integration/convert_to_file_test.rb",
61
+ "test/integration/converter_test.rb",
62
+ "test/integration/mysql_reader_base_test.rb",
63
+ "test/integration/mysql_reader_test.rb",
64
+ "test/integration/postgres_db_writer_base_test.rb",
65
+ "test/lib/ext_test_unit.rb",
66
+ "test/lib/test_helper.rb",
67
+ "test/units/config_base_test.rb",
68
+ "test/units/config_test.rb",
69
+ "test/units/postgres_file_writer_test.rb"
70
+ ]
71
+
72
+ if s.respond_to? :specification_version then
73
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
74
+ s.specification_version = 3
75
+
76
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
77
+ s.add_runtime_dependency(%q<mysql>, ["= 2.8.1"])
78
+ s.add_runtime_dependency(%q<pg>, ["= 0.9.0"])
79
+ s.add_development_dependency(%q<test-unit>, [">= 2.1.1"])
80
+ else
81
+ s.add_dependency(%q<mysql>, ["= 2.8.1"])
82
+ s.add_dependency(%q<pg>, ["= 0.9.0"])
83
+ s.add_dependency(%q<test-unit>, [">= 2.1.1"])
84
+ end
85
+ else
86
+ s.add_dependency(%q<mysql>, ["= 2.8.1"])
87
+ s.add_dependency(%q<pg>, ["= 0.9.0"])
88
+ s.add_dependency(%q<test-unit>, [">= 2.1.1"])
89
+ end
90
+ end
91
+
@@ -0,0 +1,24 @@
1
+ -- seed data for integration tests
2
+
3
+ DROP TABLE IF EXISTS numeric_types_basics;
4
+ CREATE TABLE numeric_types_basics (
5
+ id int,
6
+ f_tinyint TINYINT,
7
+ f_smallint SMALLINT,
8
+ f_mediumint MEDIUMINT,
9
+ f_int INT,
10
+ f_integer INTEGER,
11
+ f_bigint BIGINT,
12
+ f_real REAL,
13
+ f_double DOUBLE,
14
+ f_float FLOAT,
15
+ f_decimal DECIMAL,
16
+ f_numeric NUMERIC
17
+ );
18
+
19
+ INSERT INTO numeric_types_basics VALUES
20
+ (1,1,1,1,1,1,1,1,1,1,1,1),
21
+ (2,2,2,2,2,2,2,2,2,2,2,2),
22
+ (23,23,23,23,23,23,23,23,23,23,23,23);
23
+
24
+
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ require 'mysql2psql'
4
+
5
+ class ConvertToDbTest < Test::Unit::TestCase
6
+
7
+ class << self
8
+ def startup
9
+ seed_test_database
10
+ @@options=get_test_config_by_label(:localmysql_to_db_convert_all)
11
+ @@mysql2psql = Mysql2psql.new([@@options.filepath])
12
+ @@mysql2psql.convert
13
+ @@mysql2psql.writer.open
14
+ end
15
+ def shutdown
16
+ @@mysql2psql.writer.close
17
+ delete_files_for_test_config(@@options)
18
+ end
19
+ end
20
+ def setup
21
+ end
22
+ def teardown
23
+ end
24
+
25
+ def test_table_creation
26
+ assert_true @@mysql2psql.writer.exists?('numeric_types_basics')
27
+ end
28
+
29
+ end
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+
3
+ require 'mysql2psql'
4
+
5
+ class ConvertToFileTest < Test::Unit::TestCase
6
+
7
+ class << self
8
+ def startup
9
+ seed_test_database
10
+ @@options=get_test_config_by_label(:localmysql_to_file_convert_all)
11
+ @@mysql2psql = Mysql2psql.new([@@options.filepath])
12
+ @@mysql2psql.convert
13
+ @@content = IO.read(@@mysql2psql.options.destfile)
14
+ end
15
+ def shutdown
16
+ delete_files_for_test_config(@@options)
17
+ end
18
+ end
19
+ def setup
20
+ end
21
+ def teardown
22
+ end
23
+ def content
24
+ @@content
25
+ end
26
+
27
+ def test_table_creation
28
+ assert_not_nil content.match('DROP TABLE IF EXISTS "numeric_types_basics" CASCADE')
29
+ assert_not_nil content.match(/CREATE TABLE "numeric_types_basics"/)
30
+ end
31
+
32
+ def test_basic_numerics_tinyint
33
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_tinyint" smallint,.*\)', Regexp::MULTILINE).match( content )
34
+ end
35
+ def test_basic_numerics_smallint
36
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_smallint" integer,.*\)', Regexp::MULTILINE).match( content )
37
+ end
38
+ def test_basic_numerics_mediumint
39
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_mediumint" integer,.*\)', Regexp::MULTILINE).match( content )
40
+ end
41
+ def test_basic_numerics_int
42
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_int" integer,.*\)', Regexp::MULTILINE).match( content )
43
+ end
44
+ def test_basic_numerics_integer
45
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_integer" integer,.*\)', Regexp::MULTILINE).match( content )
46
+ end
47
+ def test_basic_numerics_bigint
48
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_bigint" bigint,.*\)', Regexp::MULTILINE).match( content )
49
+ end
50
+ def test_basic_numerics_real
51
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_real" double precision,.*\)', Regexp::MULTILINE).match( content )
52
+ end
53
+ def test_basic_numerics_double
54
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_double" double precision,.*\)', Regexp::MULTILINE).match( content )
55
+ end
56
+ def test_basic_numerics_float
57
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_float" numeric\(20, 0\),.*\)', Regexp::MULTILINE).match( content )
58
+ end
59
+ def test_basic_numerics_decimal
60
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_decimal" numeric\(10, 0\),.*\)', Regexp::MULTILINE).match( content )
61
+ end
62
+ def test_basic_numerics_numeric
63
+ assert_not_nil Regexp.new('CREATE TABLE "numeric_types_basics".*"f_numeric" numeric\(10, 0\)[\w\n]*\)', Regexp::MULTILINE).match( content )
64
+ end
65
+
66
+ end
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ require 'mysql2psql/converter'
4
+
5
+ class ConverterTest < Test::Unit::TestCase
6
+
7
+ class << self
8
+ def startup
9
+ seed_test_database
10
+ @@options=get_test_config_by_label(:localmysql_to_file_convert_nothing)
11
+ end
12
+ def shutdown
13
+ delete_files_for_test_config(@@options)
14
+ end
15
+ end
16
+ def setup
17
+ end
18
+ def teardown
19
+ end
20
+ def options
21
+ @@options
22
+ end
23
+
24
+ def test_new_converter
25
+ assert_nothing_raised do
26
+ reader=get_test_reader(options)
27
+ writer=get_test_file_writer(options)
28
+ converter=Mysql2psql::Converter.new(reader,writer,options)
29
+ assert_equal 0,converter.convert
30
+ end
31
+ end
32
+
33
+
34
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ require 'mysql2psql/mysql_reader'
4
+
5
+ class MysqlReaderBaseTest < Test::Unit::TestCase
6
+
7
+ class << self
8
+ def startup
9
+ seed_test_database
10
+ @@options = get_test_config_by_label(:localmysql_to_file_convert_nothing)
11
+ end
12
+ def shutdown
13
+ delete_files_for_test_config(@@options)
14
+ end
15
+ end
16
+ def setup
17
+ end
18
+ def teardown
19
+ end
20
+ def options
21
+ @@options
22
+ end
23
+
24
+ def test_mysql_connection
25
+ assert_nothing_raised do
26
+ reader = Mysql2psql::MysqlReader.new(options)
27
+ end
28
+ end
29
+ def test_mysql_reconnect
30
+ assert_nothing_raised do
31
+ reader = Mysql2psql::MysqlReader.new(options)
32
+ reader.reconnect
33
+ end
34
+ end
35
+ end