Skip to content
This repository was archived by the owner on May 10, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ to edit. For the impatient, here is what the file contains.
# if index_prefix is given, indexes will be created whith a name prefixed with index_prefix
index_prefix:

# if name_quoted is true, all table_name and column_name will be double quoted
name_quoted: false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a good choice? I manually added quotes everywhere so that script would work correctly. By unquoting everything by default you had undone my changes (by default).


Pretty self explainitory right? A couple things to note, first if
`destination -> file` is populated all output will be dumped to the
specified location regardless of what is contained in `destination ->
Expand Down
5 changes: 4 additions & 1 deletion mysql2pgsql/lib/postgres_db_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ def query(self, sql, args=(), one=False):

def execute(self, sql, args=(), many=False):
with closing(self.conn.cursor()) as cur:
# avoid to execute empty sql
if not sql or sql.strip() == '':
return
if many:
cur.executemany(sql, args)
else:
Expand Down Expand Up @@ -203,4 +206,4 @@ def write_contents(self, table, reader):
Returns None
"""
f = self.FileObjFaker(table, reader.read(table), self.process_row, self.verbose)
self.copy_from(f, '"%s"' % table.name, ['"%s"' % c['name'] for c in table.columns])
self.copy_from(f, '"%s"' % table.name, ['%s' % self.quoted_name(c['name']) for c in table.columns])
6 changes: 3 additions & 3 deletions mysql2pgsql/lib/postgres_file_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,10 @@ def write_contents(self, table, reader):
-- Data for Name: %(table_name)s; Type: TABLE DATA;
--

COPY "%(table_name)s" (%(column_names)s) FROM stdin;
COPY %(table_name)s (%(column_names)s) FROM stdin;
""" % {
'table_name': table.name,
'column_names': ', '.join(('"%s"' % col['name']) for col in table.columns)})
'table_name': self.quoted_name(table.name),
'column_names': ', '.join(('%s' % self.quoted_name(col['name'])) for col in table.columns)})
if verbose:
tt = time.time
start_time = tt()
Expand Down
47 changes: 27 additions & 20 deletions mysql2pgsql/lib/postgres_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ class PostgresWriter(object):
"""Base class for :py:class:`mysql2pgsql.lib.postgres_file_writer.PostgresFileWriter`
and :py:class:`mysql2pgsql.lib.postgres_db_writer.PostgresDbWriter`.
"""
def __init__(self, tz=False, index_prefix=''):
def __init__(self, tz=False, index_prefix='', isNameQuoted=False):
self.column_types = {}
self.index_prefix = index_prefix
self.isNameQuoted = isNameQuoted
if tz:
self.tz = timezone('UTC')
self.tz_offset = '+00:00'
Expand All @@ -23,8 +24,13 @@ def __init__(self, tz=False, index_prefix=''):
self.tz_offset = ''

def column_description(self, column):
return '"%s" %s' % (column['name'], self.column_type_info(column))
return '%s %s' % (self.quoted_name(column['name']), self.column_type_info(column))

def quoted_name(self, value):
quote_tag = '"'
if not self.isNameQuoted:
quote_tag=''
return quote_tag + value + quote_tag
def column_type(self, column):
hash_key = hash(frozenset(column.items()))
self.column_types[hash_key] = self.column_type_info(column).split(" ")[0]
Expand Down Expand Up @@ -141,12 +147,12 @@ def table_comments(self, table):

def column_comment(self, tablename, column):
if not column['comment']:
return (' COMMENT ON COLUMN %s.%s is %s;' % ( tablename, column['name'], QuotedString(column['comment']).getquoted()))
return (' COMMENT ON COLUMN %s.%s is %s;' % ( self.quoted_name(tablename), self.quoted_name(column['name']), QuotedString(column['comment'].encode('utf8')).getquoted()))
else:
return ''

def table_comment(self, tablename, comment):
return (' COMMENT ON TABLE %s is %s;' % ( tablename, QuotedString(comment).getquoted()))
return (' COMMENT ON TABLE %s is %s;' % ( self.quoted_name(tablename), QuotedString(comment.encode('utf8')).getquoted()))

def process_row(self, table, row):
"""Examines row data from MySQL and alters
Expand Down Expand Up @@ -215,12 +221,12 @@ def truncate(self, table):
serial_key = column['name']
maxval = 1 if column['maxval'] < 1 else column['maxval'] + 1

truncate_sql = 'TRUNCATE "%s" CASCADE;' % table.name
truncate_sql = 'TRUNCATE %s CASCADE;' % self.quoted_name(table.name)
serial_key_sql = None

if serial_key:
serial_key_sql = "SELECT pg_catalog.setval(pg_get_serial_sequence(%(table_name)s, %(serial_key)s), %(maxval)s, true);" % {
'table_name': QuotedString('"%s"' % table.name).getquoted(),
'table_name': QuotedString('%s' % self.quoted_name(table.name)).getquoted(),
'serial_key': QuotedString(serial_key).getquoted(),
'maxval': maxval}

Expand All @@ -237,8 +243,9 @@ def write_table(self, table):
NO MAXVALUE NO MINVALUE CACHE 1;""" % serial_key_seq)
serial_key_sql.append('SELECT pg_catalog.setval(\'"%s"\', %s, true);' % (serial_key_seq, maxval))

table_sql.append('DROP TABLE IF EXISTS "%s" CASCADE;' % table.name)
table_sql.append('CREATE TABLE "%s" (\n%s\n)\nWITHOUT OIDS;' % (table.name.encode('utf8'), columns))

table_sql.append('DROP TABLE IF EXISTS %s CASCADE;' % self.quoted_name(table.name))
table_sql.append('CREATE TABLE %s (\n%s\n)\nWITHOUT OIDS;' % (self.quoted_name(table.name.encode('utf8')), columns))
table_sql.append( self.table_comments(table))
return (table_sql, serial_key_sql)

Expand All @@ -247,36 +254,36 @@ def write_indexes(self, table):
primary_index = [idx for idx in table.indexes if idx.get('primary', None)]
index_prefix = self.index_prefix
if primary_index:
index_sql.append('ALTER TABLE "%(table_name)s" ADD CONSTRAINT "%(index_name)s_pkey" PRIMARY KEY(%(column_names)s);' % {
'table_name': table.name,
index_sql.append('ALTER TABLE %(table_name)s ADD CONSTRAINT "%(index_name)s_pkey" PRIMARY KEY(%(column_names)s);' % {
'table_name': self.quoted_name(table.name),
'index_name': '%s%s_%s' % (index_prefix, table.name,
'_'.join(primary_index[0]['columns'])),
'column_names': ', '.join('"%s"' % col for col in primary_index[0]['columns']),
'column_names': ', '.join('%s' % self.quoted_name(col) for col in primary_index[0]['columns']),
})
for index in table.indexes:
if 'primary' in index:
continue
unique = 'UNIQUE ' if index.get('unique', None) else ''
index_name = '%s%s_%s' % (index_prefix, table.name, '_'.join(index['columns']))
index_sql.append('DROP INDEX IF EXISTS "%s" CASCADE;' % index_name)
index_sql.append('CREATE %(unique)sINDEX "%(index_name)s" ON "%(table_name)s" (%(column_names)s);' % {
index_sql.append('CREATE %(unique)sINDEX "%(index_name)s" ON %(table_name)s (%(column_names)s);' % {
'unique': unique,
'index_name': index_name,
'table_name': table.name,
'column_names': ', '.join('"%s"' % col for col in index['columns']),
'table_name': self.quoted_name(table.name),
'column_names': ', '.join('%s' % self.quoted_name(col) for col in index['columns']),
})

return index_sql

def write_constraints(self, table):
constraint_sql = []
for key in table.foreign_keys:
constraint_sql.append("""ALTER TABLE "%(table_name)s" ADD FOREIGN KEY ("%(column_name)s")
REFERENCES "%(ref_table_name)s"(%(ref_column_name)s);""" % {
'table_name': table.name,
'column_name': key['column'],
'ref_table_name': key['ref_table'],
'ref_column_name': key['ref_column']})
constraint_sql.append("""ALTER TABLE %(table_name)s ADD FOREIGN KEY (%(column_name)s)
REFERENCES %(ref_table_name)s(%(ref_column_name)s);""" % {
'table_name': self.quoted_name(table.name),
'column_name': self.quoted_name(key['column']),
'ref_table_name': self.quoted_name(key['ref_table']),
'ref_column_name': self.quoted_name(key['ref_column'])})
return constraint_sql

def write_triggers(self, table):
Expand Down
8 changes: 5 additions & 3 deletions mysql2pgsql/mysql2pgsql.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@ def __init__(self, options):

def convert(self):
reader = MysqlReader(self.file_options['mysql'])

# isNameQuoted indicate that we need to add extra quotes on table and column name
if self.file_options['destination']['file']:
writer = PostgresFileWriter(self._get_file(self.file_options['destination']['file']),
self.run_options.verbose,
tz=self.file_options.get('timezone', False),
index_prefix=self.file_options.get("index_prefix", ''))
index_prefix=self.file_options.get("index_prefix", ''),
isNameQuoted=self.file_options.get("name_quoted", False))
else:
writer = PostgresDbWriter(self.file_options['destination']['postgres'],
self.run_options.verbose,
tz=self.file_options.get('timezone', False),
index_prefix=self.file_options.get("index_prefix", ''))
index_prefix=self.file_options.get("index_prefix", ''),
isNameQuoted=self.file_options.get("name_quoted", False))

Converter(reader, writer, self.file_options, self.run_options.verbose).convert()

Expand Down
3 changes: 3 additions & 0 deletions tests/mysql2pgsql-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ supress_ddl: false

# if force_truncate is true, forces a table truncate before table loading
force_truncate: false

# if name_quoted is true, all table_name and column_name will be double quoted
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

table_name's, column_name's?

name_quoted: false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not that good with YaML to know would it barf at "no newline".

3 changes: 3 additions & 0 deletions tests/mysql2pgsql-test.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ supress_ddl: false

# if force_truncate is true, forces a table truncate before table loading
force_truncate: false

# if name_quoted is true, all table_name and column_name will be double quoted
name_quoted: false