From: Max Lapshin Date: Mon, 8 Dec 2008 19:48:48 +0000 (+0300) Subject: refactored tool a lot X-Git-Url: http://git.neszt.hu/?a=commitdiff_plain;h=6a6077f4fdfe01e0afb05069d00fd29cf3f6f6be;p=mysql2postgres refactored tool a lot --- diff --git a/mysql2psql b/mysql2psql index 5243d8c..60c1e1b 100755 --- a/mysql2psql +++ b/mysql2psql @@ -144,7 +144,74 @@ end class Writer end -class PostgresFileWriter < Writer + +class PostgresWriter < Writer + def column_description(column) + "#{PGconn.quote_ident(column[:name])} #{column_type_info(column)}" + end + + def column_type(column) + column_type_info(column).split(" ").first + end + + def column_type_info(column) + if column[:primary_key] && column[:name] == "id" + return "integer DEFAULT nextval('#{column[:table_name]}_#{column[:name]}_seq'::regclass) NOT NULL" + end + + default = column[:default] ? " DEFAULT #{column[:default] == nil ? 'NULL' : "'"+column[:default]+"'"}" : nil + null = column[:null] ? "" : " NOT NULL" + type = + case column[:type] + when "var_string" + default = default + "::character varying" if default + "character varying(#{column[:length]})" + when "long" + default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default + "bigint" + when "longlong" + default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default + "bigint" + when "datetime" + default = nil + "timestamp without time zone" + when "date" + default = nil + "date" + when "char" + if column[:length] == 1 + if default + default = " DEFAULT #{column[:default].to_i == 1 ? 'true' : 'false'}" + end + "boolean" + else + default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default + "int" + end + when "blob" + "bytea" + when "text" + "text" + when "float" + default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default + "numeric(#{column[:length] + column[:decimals]}, #{column[:decimals]})" + when "decimal" + default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default + "numeric(#{column[:length] + column[:decimals]}, #{column[:decimals]})" + when "int24" + default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default + "int" + else + puts "Unknown #{column.inspect}" + column[:type].inspect + return "" + end + "#{type}#{default}#{null}" + end + +end + +class PostgresFileWriter < PostgresWriter def initialize(file) @f = File.open(file, "w+") @f << <<-EOF @@ -236,57 +303,6 @@ EOF end - def column_description(column) - "#{PGconn.quote_ident(column[:name])} #{column_type(column)}" - end - - def column_type(column) - case - when column[:primary_key] && column[:name] == "id" - "integer DEFAULT nextval('#{column[:table_name]}_#{column[:name]}_seq'::regclass) NOT NULL" - else - default = column[:default] ? " DEFAULT #{column[:default] == nil ? 'NULL' : "'"+column[:default]+"'"}" : nil - null = column[:null] ? "" : " NOT NULL" - type = - case column[:type] - when "var_string" - default = default + "::character varying" if default - "character varying(#{column[:length]})" - when "long" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "bigint" - when "longlong" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "bigint" - when "datetime" - default = nil - "timestamp without time zone" - when "date" - default = nil - "date" - when "char" - if default - default = " DEFAULT #{column[:default].to_i == 1 ? 'true' : 'false'}" - end - "boolean" - when "blob" - "bytea" - when "text" - "text" - when "float" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "numeric(#{column[:length] + column[:decimals]}, #{column[:decimals]})" - when "decimal" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "numeric(#{column[:length] + column[:decimals]}, #{column[:decimals]})" - else - puts column.inspect - column[:type].inspect - end - "#{type}#{default}#{null}" - end - end - def write_contents(table, reader) @f << <<-EOF -- @@ -323,10 +339,14 @@ EOF end end -class PostgresDbWriter < Writer - def initialize(hostname, login, password, database) +class PostgresDbWriter < PostgresWriter + def connection(hostname, login, password, database) require 'postgres' @conn = PGconn.open('host' => hostname, 'user' => login, 'password' => password, 'dbname' => database) + end + + def initialize(hostname, login, password, database) + @conn = connection(hostname, login, password, database) @conn.exec("SET client_encoding = 'UTF8'") @conn.exec("SET standard_conforming_strings = off") @conn.exec("SET check_function_bodies = false") @@ -391,60 +411,6 @@ class PostgresDbWriter < Writer end end - def column_description(column) - "#{PGconn.quote_ident(column[:name])} #{column_type(column)}" - end - - def column_type(column) - case - when column[:primary_key] && column[:name] == "id" - "integer DEFAULT nextval('#{column[:table_name]}_#{column[:name]}_seq'::regclass) NOT NULL" - else - default = column[:default] ? " DEFAULT #{column[:default] == nil ? 'NULL' : "'"+column[:default]+"'"}" : nil - null = column[:null] ? "" : " NOT NULL" - type = - case column[:type] - when "var_string" - default = default + "::character varying" if default - "character varying(#{column[:length]})" - when "long" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "bigint" - when "longlong" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "bigint" - when "datetime" - default = nil - "timestamp without time zone" - when "date" - default = nil - "date" - when "char" - if default - default = " DEFAULT #{column[:default].to_i == 1 ? 'true' : 'false'}" - end - "boolean" - when "blob" - "bytea" - when "text" - "text" - when "float" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "numeric(#{column[:length] + column[:decimals]}, #{column[:decimals]})" - when "decimal" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "numeric(#{column[:length] + column[:decimals]}, #{column[:decimals]})" - when "int24" - default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default - "int" - else - puts column.inspect - column[:type].inspect - end - "#{type}#{default}#{null}" - end - end - def write_contents(table, reader) _time1 = Time.now copy_line = "COPY #{table.name} (#{table.columns.map {|column| PGconn.quote_ident(column[:name])}.join(", ")}) FROM stdin;" @@ -454,15 +420,29 @@ class PostgresDbWriter < Writer _counter = reader.paginated_read(table, 1000) do |row, counter| line = [] table.columns.each_with_index do |column, index| - row[index] = row[index].to_s if row[index].is_a?(Mysql::Time) - if column[:type] == "char" + if !row[index] + row[index] = '\N' + next + end + if row[index].is_a?(Mysql::Time) + row[index] = row[index].to_s + next + end + + if column_type(column) == "boolean" row[index] = row[index] == 1 ? 't' : row[index] == 0 ? 'f' : row[index] + next + end + + if row[index].is_a?(String) + if column_type(column) == "bytea" + row[index] = PGconn.quote(row[index]) + else + row[index] = row[index].gsub(/\\/, '\\\\\\').gsub(/\n/,'\n').gsub(/\t/,'\t').gsub(/\r/,'\r') + end end - row[index] = row[index].gsub(/\\/, '\\\\\\').gsub(/\n/,'\n').gsub(/\t/,'\t').gsub(/\r/,'\r') if row[index].is_a?(String) - row[index] = '\N' if !row[index] - row[index] end - @conn.putline row.join("\t") + "\n" + @conn.putline(row.join("\t") + "\n") if counter % 5000 == 0 print "*"