From 01b42ce1cd99f2ddfae0587841860f4629642a0b Mon Sep 17 00:00:00 2001 From: Artemy Kolchinsky Date: Wed, 3 Jun 2015 16:55:44 -0400 Subject: [PATCH] BUG: Should allow numeric mysql table/column names Doc fix --- doc/source/whatsnew/v0.16.2.txt | 2 ++ pandas/io/sql.py | 2 -- pandas/io/tests/test_sql.py | 21 ++++++++++++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/doc/source/whatsnew/v0.16.2.txt b/doc/source/whatsnew/v0.16.2.txt index ddfe6fa0b2f74..c1bf3b9252428 100644 --- a/doc/source/whatsnew/v0.16.2.txt +++ b/doc/source/whatsnew/v0.16.2.txt @@ -88,3 +88,5 @@ Bug Fixes - Bug where infer_freq infers timerule (WOM-5XXX) unsupported by to_offset (:issue:`9425`) - Bug to handle masking empty ``DataFrame``(:issue:`10126`) +- Bug where MySQL interface could not handle numeric table/column names (:issue:`10255`) + diff --git a/pandas/io/sql.py b/pandas/io/sql.py index ad88d74a5aa91..b4e8c7de2b4e1 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -1283,8 +1283,6 @@ def _get_valid_mysql_name(name): if not re.match(basere, c): if not (0x80 < ord(c) < 0xFFFF): raise ValueError("Invalid MySQL identifier '%s'" % uname) - if not re.match(r'[^0-9]', uname): - raise ValueError('MySQL identifier cannot be entirely numeric') return '`' + uname + '`' diff --git a/pandas/io/tests/test_sql.py b/pandas/io/tests/test_sql.py index 9576f80696350..a848917196e62 100644 --- a/pandas/io/tests/test_sql.py +++ b/pandas/io/tests/test_sql.py @@ -1738,7 +1738,8 @@ def test_illegal_names(self): for ndx, weird_name in enumerate(['test_weird_name]','test_weird_name[', 'test_weird_name`','test_weird_name"', 'test_weird_name\'', - '_b.test_weird_name_01-30', '"_b.test_weird_name_01-30"']): + '_b.test_weird_name_01-30', '"_b.test_weird_name_01-30"', + '12345','12345blah']): df.to_sql(weird_name, self.conn, flavor=self.flavor) sql.table_exists(weird_name, self.conn) @@ -1839,16 +1840,30 @@ def test_to_sql_save_index(self): self._to_sql_save_index() def test_illegal_names(self): + df = DataFrame([[1, 2], [3, 4]], columns=['a', 'b']) + + # These tables and columns should be ok + for ndx, ok_name in enumerate(['99beginswithnumber','12345']): + df.to_sql(ok_name, self.conn, flavor=self.flavor, index=False, + if_exists='replace') + self.conn.cursor().execute("DROP TABLE `%s`" % ok_name) + self.conn.commit() + df2 = DataFrame([[1, 2], [3, 4]], columns=['a', ok_name]) + c_tbl = 'test_ok_col_name%d'%ndx + df2.to_sql(c_tbl, self.conn, flavor=self.flavor, index=False, + if_exists='replace') + self.conn.cursor().execute("DROP TABLE `%s`" % c_tbl) + self.conn.commit() + # For MySQL, these should raise ValueError for ndx, illegal_name in enumerate(['test_illegal_name]','test_illegal_name[', 'test_illegal_name`','test_illegal_name"', 'test_illegal_name\'', '']): - df = DataFrame([[1, 2], [3, 4]], columns=['a', 'b']) self.assertRaises(ValueError, df.to_sql, illegal_name, self.conn, flavor=self.flavor, index=False) df2 = DataFrame([[1, 2], [3, 4]], columns=['a', illegal_name]) c_tbl = 'test_illegal_col_name%d'%ndx - self.assertRaises(ValueError, df2.to_sql, 'test_illegal_col_name', + self.assertRaises(ValueError, df2.to_sql, c_tbl, self.conn, flavor=self.flavor, index=False)