refactored tool a lot
authorMax Lapshin <max@maxidoors.ru>
Mon, 8 Dec 2008 19:48:48 +0000 (22:48 +0300)
committerMax Lapshin <max@maxidoors.ru>
Mon, 8 Dec 2008 19:48:48 +0000 (22:48 +0300)
mysql2psql

index 5243d8c..60c1e1b 100755 (executable)
@@ -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 "*"