changeset 892807681516 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset&node=892807681516
description:
        Escape identifiers in backend

        issue10245
        review317021002
diffstat:

 trytond/backend/postgresql/database.py |   66 +++++----
 trytond/backend/postgresql/table.py    |  232 +++++++++++++++++++++-----------
 trytond/backend/sqlite/table.py        |  101 ++++++++-----
 3 files changed, 243 insertions(+), 156 deletions(-)

diffs (738 lines):

diff -r 41723b243136 -r 892807681516 trytond/backend/postgresql/database.py
--- a/trytond/backend/postgresql/database.py    Mon Apr 12 22:08:36 2021 +0200
+++ b/trytond/backend/postgresql/database.py    Mon Apr 12 23:07:55 2021 +0200
@@ -17,6 +17,7 @@
 except ImportError:
     pass
 from psycopg2 import connect, Binary
+from psycopg2.sql import SQL, Identifier
 from psycopg2.pool import ThreadedConnectionPool, PoolError
 from psycopg2.extensions import cursor
 from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
@@ -295,14 +296,19 @@
     @classmethod
     def create(cls, connection, database_name, template='template0'):
         cursor = connection.cursor()
-        cursor.execute('CREATE DATABASE "' + database_name + '" '
-            'TEMPLATE "' + template + '" ENCODING \'unicode\'')
+        cursor.execute(
+            SQL(
+                "CREATE DATABASE {} TEMPLATE {} ENCODING 'unicode'")
+            .format(
+                Identifier(database_name),
+                Identifier(template)))
         connection.commit()
         cls._list_cache.clear()
 
     def drop(self, connection, database_name):
         cursor = connection.cursor()
-        cursor.execute('DROP DATABASE "' + database_name + '"')
+        cursor.execute(SQL("DROP DATABASE {}")
+            .format(Identifier(database_name)))
         self.__class__._list_cache.clear()
 
     def get_version(self, connection):
@@ -412,21 +418,23 @@
 
     def nextid(self, connection, table):
         cursor = connection.cursor()
-        cursor.execute("SELECT NEXTVAL('" + table + "_id_seq')")
+        cursor.execute("SELECT NEXTVAL(%s)", (table + '_id_seq',))
         return cursor.fetchone()[0]
 
     def setnextid(self, connection, table, value):
         cursor = connection.cursor()
-        cursor.execute("SELECT SETVAL('" + table + "_id_seq', %d)" % value)
+        cursor.execute("SELECT SETVAL(%s, %s)", (table + '_id_seq', value))
 
     def currid(self, connection, table):
         cursor = connection.cursor()
-        cursor.execute('SELECT last_value FROM "' + table + '_id_seq"')
+        cursor.execute(SQL("SELECT last_value FROM {}").format(
+                Identifier(table + '_id_seq')))
         return cursor.fetchone()[0]
 
     def lock(self, connection, table):
         cursor = connection.cursor()
-        cursor.execute('LOCK "%s" IN EXCLUSIVE MODE NOWAIT' % table)
+        cursor.execute(SQL('LOCK {} IN EXCLUSIVE MODE NOWAIT').format(
+                Identifier(table)))
 
     def lock_id(self, id, timeout=None):
         if not timeout:
@@ -660,35 +668,32 @@
             self, connection, name, number_increment=1, start_value=1):
         cursor = connection.cursor()
 
-        param = self.flavor.param
         cursor.execute(
-            'CREATE SEQUENCE "%s" '
-            'INCREMENT BY %s '
-            'START WITH %s'
-            % (name, param, param),
+            SQL("CREATE SEQUENCE {} INCREMENT BY %s START WITH %s").format(
+                Identifier(name)),
             (number_increment, start_value))
 
     def sequence_update(
             self, connection, name, number_increment=1, start_value=1):
         cursor = connection.cursor()
-        param = self.flavor.param
         cursor.execute(
-            'ALTER SEQUENCE "%s" '
-            'INCREMENT BY %s '
-            'RESTART WITH %s'
-            % (name, param, param),
+            SQL("ALTER SEQUENCE {} INCREMENT BY %s RESTART WITH %s").format(
+                Identifier(name)),
             (number_increment, start_value))
 
     def sequence_rename(self, connection, old_name, new_name):
         cursor = connection.cursor()
         if (self.sequence_exist(connection, old_name)
                 and not self.sequence_exist(connection, new_name)):
-            cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
-                % (old_name, new_name))
+            cursor.execute(
+                SQL("ALTER TABLE {} to {}").format(
+                    Identifier(old_name),
+                    Identifier(new_name)))
 
     def sequence_delete(self, connection, name):
         cursor = connection.cursor()
-        cursor.execute('DROP SEQUENCE "%s"' % name)
+        cursor.execute(SQL("DROP SEQUENCE {}").format(
+                Identifier(name)))
 
     def sequence_next_number(self, connection, name):
         cursor = connection.cursor()
@@ -697,22 +702,23 @@
             cursor.execute(
                 'SELECT increment_by '
                 'FROM pg_sequences '
-                'WHERE sequencename=%s '
-                % self.flavor.param,
+                'WHERE sequencename=%s',
                 (name,))
             increment, = cursor.fetchone()
             cursor.execute(
-                'SELECT CASE WHEN NOT is_called THEN last_value '
-                'ELSE last_value + %s '
-                'END '
-                'FROM "%s"' % (self.flavor.param, name),
+                SQL(
+                    'SELECT CASE WHEN NOT is_called THEN last_value '
+                    'ELSE last_value + %s '
+                    'END '
+                    'FROM {}').format(Identifier(name)),
                 (increment,))
         else:
             cursor.execute(
-                'SELECT CASE WHEN NOT is_called THEN last_value '
-                'ELSE last_value + increment_by '
-                'END '
-                'FROM "%s"' % name)
+                SQL(
+                    'SELECT CASE WHEN NOT is_called THEN last_value '
+                    'ELSE last_value + increment_by '
+                    'END '
+                    'FROM {}').format(sequence=Identifier(name)))
         return cursor.fetchone()[0]
 
     def has_channel(self):
diff -r 41723b243136 -r 892807681516 trytond/backend/postgresql/table.py
--- a/trytond/backend/postgresql/table.py       Mon Apr 12 22:08:36 2021 +0200
+++ b/trytond/backend/postgresql/table.py       Mon Apr 12 23:07:55 2021 +0200
@@ -3,6 +3,8 @@
 import re
 import logging
 
+from psycopg2.sql import SQL, Identifier, Composed
+
 from trytond.transaction import Transaction
 from trytond.backend.table import TableHandlerInterface
 
@@ -33,7 +35,8 @@
 
         # Create new table if necessary
         if not self.table_exist(self.table_name):
-            cursor.execute('CREATE TABLE "%s" ()' % self.table_name)
+            cursor.execute(SQL('CREATE TABLE {} ()').format(
+                    Identifier(self.table_name)))
         self.table_schema = transaction.database.get_table_schema(
             transaction.connection, self.table_name)
 
@@ -43,41 +46,52 @@
         self.is_owner, = cursor.fetchone()
 
         if model.__doc__ and self.is_owner:
-            cursor.execute('COMMENT ON TABLE "%s" IS \'%s\'' %
-                (self.table_name, model.__doc__.replace("'", "''")))
+            cursor.execute(SQL('COMMENT ON TABLE {} IS %s').format(
+                        Identifier(self.table_name)),
+                (model.__doc__,))
 
         self._update_definitions(columns=True)
         if 'id' not in self._columns:
             if not self.history:
-                cursor.execute('ALTER TABLE "%s" '
-                    'ADD COLUMN id INTEGER '
-                    'DEFAULT nextval(\'"%s"\') NOT NULL'
-                    % (self.table_name, self.sequence_name))
-                cursor.execute('ALTER TABLE "%s" '
-                    'ADD PRIMARY KEY(id)' % self.table_name)
+                cursor.execute(
+                    SQL(
+                        "ALTER TABLE {} ADD COLUMN id INTEGER "
+                        "DEFAULT nextval(%s) NOT NULL").format(
+                        Identifier(self.table_name)),
+                    (self.sequence_name,))
+                cursor.execute(
+                    SQL('ALTER TABLE {} ADD PRIMARY KEY(id)')
+                    .format(Identifier(self.table_name)))
             else:
-                cursor.execute('ALTER TABLE "%s" '
-                    'ADD COLUMN id INTEGER' % self.table_name)
+                cursor.execute(
+                    SQL('ALTER TABLE {} ADD COLUMN id INTEGER')
+                    .format(Identifier(self.table_name)))
             self._update_definitions(columns=True)
         if self.history and '__id' not in self._columns:
-            cursor.execute('ALTER TABLE "%s" '
-                'ADD COLUMN __id INTEGER '
-                'DEFAULT nextval(\'"%s"\') NOT NULL' %
-                (self.table_name, self.sequence_name))
-            cursor.execute('ALTER TABLE "%s" '
-                'ADD PRIMARY KEY(__id)' % self.table_name)
+            cursor.execute(
+                SQL(
+                    "ALTER TABLE {} ADD COLUMN __id INTEGER "
+                    "DEFAULT nextval(%s) NOT NULL").format(
+                        Identifier(self.table_name)),
+                (self.sequence_name,))
+            cursor.execute(
+                SQL('ALTER TABLE {} ADD PRIMARY KEY(__id)')
+                .format(Identifier(self.table_name)))
         else:
             default = "nextval('%s'::regclass)" % self.sequence_name
             if self.history:
                 if self._columns['__id']['default'] != default:
-                    cursor.execute('ALTER TABLE "%s" '
-                        'ALTER __id SET DEFAULT %s'
-                        % (self.table_name, default))
+                    cursor.execute(
+                        SQL("ALTER TABLE {} "
+                            "ALTER __id SET DEFAULT nextval(%s::regclass)")
+                        .format(Identifier(self.table_name)),
+                        (self.sequence_name,))
             if self._columns['id']['default'] != default:
                 cursor.execute(
-                    'ALTER TABLE "%s" '
-                    'ALTER id SET DEFAULT %s'
-                    % (self.table_name, default))
+                    SQL("ALTER TABLE {} "
+                        "ALTER id SET DEFAULT nextval(%s::regclass)")
+                    .format(Identifier(self.table_name)),
+                    (self.sequence_name,))
         self._update_definitions()
 
     @staticmethod
@@ -93,8 +107,8 @@
         # Rename table
         if (TableHandler.table_exist(old_name)
                 and not TableHandler.table_exist(new_name)):
-            cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
-                % (old_name, new_name))
+            cursor.execute(SQL('ALTER TABLE {} RENAME TO {}').format(
+                    Identifier(old_name), Identifier(new_name)))
         # Rename sequence
         old_sequence = old_name + '_id_seq'
         new_sequence = new_name + '_id_seq'
@@ -115,9 +129,11 @@
         cursor = Transaction().connection.cursor()
         if self.column_exist(old_name):
             if not self.column_exist(new_name):
-                cursor.execute('ALTER TABLE "%s" '
-                    'RENAME COLUMN "%s" TO "%s"'
-                    % (self.table_name, old_name, new_name))
+                cursor.execute(SQL(
+                        'ALTER TABLE {} RENAME COLUMN {} TO {}').format(
+                        Identifier(self.table_name),
+                        Identifier(old_name),
+                        Identifier(new_name)))
                 self._update_definitions(columns=True)
             else:
                 logger.warning(
@@ -201,24 +217,31 @@
 
     def alter_size(self, column_name, column_type):
         cursor = Transaction().connection.cursor()
-        cursor.execute("ALTER TABLE \"%s\" "
-            "RENAME COLUMN \"%s\" TO _temp_change_size"
-            % (self.table_name, column_name))
-        cursor.execute("ALTER TABLE \"%s\" "
-            "ADD COLUMN \"%s\" %s"
-            % (self.table_name, column_name, column_type))
-        cursor.execute("UPDATE \"%s\" "
-            "SET \"%s\" = _temp_change_size::%s"
-            % (self.table_name, column_name, column_type))
-        cursor.execute("ALTER TABLE \"%s\" "
-            "DROP COLUMN _temp_change_size"
-            % (self.table_name,))
+        cursor.execute(
+            SQL(
+                "ALTER TABLE {} RENAME COLUMN {} TO _temp_change_size").format(
+                Identifier(self.table_name),
+                Identifier(column_name)))
+        cursor.execute(SQL("ALTER TABLE {} ADD COLUMN {} {}").format(
+                Identifier(self.table_name),
+                Identifier(column_name),
+                SQL(column_type)))
+        cursor.execute(
+            SQL("UPDATE {} SET {} = _temp_change_size::%s").format(
+                Identifier(self.table_name),
+                Identifier(column_name),
+                SQL(column_type)))
+        cursor.execute(
+            SQL("ALTER TABLE {} " "DROP COLUMN _temp_change_size")
+            .format(Identifier(self.table_name)))
         self._update_definitions(columns=True)
 
     def alter_type(self, column_name, column_type):
         cursor = Transaction().connection.cursor()
-        cursor.execute('ALTER TABLE "' + self.table_name + '" '
-            'ALTER "' + column_name + '" TYPE ' + column_type)
+        cursor.execute(SQL('ALTER TABLE {} ALTER {} TYPE {}').format(
+                Identifier(self.table_name),
+                Identifier(column_name),
+                SQL(column_type)))
         self._update_definitions(columns=True)
 
     def column_is_type(self, column_name, type_, *, size=-1):
@@ -240,8 +263,11 @@
             test = value
         if self._columns[column_name]['default'] != test:
             cursor = Transaction().connection.cursor()
-            cursor.execute('ALTER TABLE "' + self.table_name + '" '
-                'ALTER COLUMN "' + column_name + '" SET DEFAULT %s',
+            cursor.execute(
+                SQL(
+                    'ALTER TABLE {} ALTER COLUMN {} SET DEFAULT %s').format(
+                    Identifier(self.table_name),
+                    Identifier(column_name)),
                 (value,))
 
     def add_column(self, column_name, sql_type, default=None, comment=''):
@@ -254,14 +280,22 @@
 
         def add_comment():
             if comment and self.is_owner:
-                cursor.execute('COMMENT ON COLUMN "%s"."%s" IS \'%s\'' %
-                    (self.table_name, column_name, comment.replace("'", "''")))
+                cursor.execute(
+                    SQL('COMMENT ON COLUMN {}.{} IS %s').format(
+                        Identifier(self.table_name),
+                        Identifier(column_name)),
+                    (comment,))
         if self.column_exist(column_name):
             if (column_name in ('create_date', 'write_date')
                     and column_type[1].lower() != 'timestamp(6)'):
                 # Migrate dates from timestamp(0) to timestamp
-                cursor.execute('ALTER TABLE "' + self.table_name + '" '
-                    'ALTER COLUMN "' + column_name + '" TYPE timestamp')
+                cursor.execute(
+                    SQL(
+                        'ALTER TABLE {} ALTER COLUMN {} TYPE timestamp')
+                    .format(
+                        Identifier(self.table_name),
+                        Identifier(column_name)))
+
             add_comment()
             base_type = column_type[0].lower()
             if base_type != self._columns[column_name]['typname']:
@@ -300,8 +334,11 @@
             return
 
         column_type = column_type[1]
-        cursor.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s'
-            % (self.table_name, column_name, column_type))
+        cursor.execute(
+            SQL('ALTER TABLE {} ADD COLUMN {} {}').format(
+                Identifier(self.table_name),
+                Identifier(column_name),
+                SQL(column_type)))
         add_comment()
 
         if default:
@@ -309,8 +346,11 @@
             cursor.execute('SELECT 1 FROM "%s" limit 1' % self.table_name)
             if cursor.rowcount:
                 # Populate column with default values:
-                cursor.execute('UPDATE "' + self.table_name + '" '
-                    'SET "' + column_name + '" = %s', (default(),))
+                cursor.execute(
+                    SQL('UPDATE {} SET {} = %s').format(
+                        Identifier(self.table_name),
+                        Identifier(column_name)),
+                    (default(),))
 
         self._update_definitions(columns=True)
 
@@ -331,11 +371,19 @@
         else:
             add = True
         if add:
-            cursor.execute('ALTER TABLE "' + self.table_name + '" '
-                'ADD CONSTRAINT "' + name + '" '
-                'FOREIGN KEY ("' + column_name + '") '
-                'REFERENCES "' + reference + '" '
-                'ON DELETE ' + on_delete)
+            cursor.execute(
+                SQL(
+                    "ALTER TABLE {table} "
+                    "ADD CONSTRAINT {constraint} "
+                    "FOREIGN KEY ({column}) REFERENCES {reference} "
+                    "ON DELETE {action}"
+                    )
+                .format(
+                    table=Identifier(self.table_name),
+                    constraint=Identifier(name),
+                    column=Identifier(column_name),
+                    reference=Identifier(reference),
+                    action=SQL(on_delete)))
         self._update_definitions(constraints=True)
 
     def drop_fk(self, column_name, table=None):
@@ -366,20 +414,23 @@
             if action == 'add':
                 if index_name in self._indexes:
                     return
-                columns_quoted = []
-                for column in columns:
-                    if isinstance(column, str):
-                        columns_quoted.append('"%s"' % column)
-                    else:
-                        columns_quoted.append(str(column))
                 params = sum(
                     (c.params for c in columns if hasattr(c, 'params')), ())
                 if where:
                     params += where.params
                     where = ' WHERE %s' % where
-                cursor.execute('CREATE INDEX "' + index_name + '" '
-                    'ON "' + self.table_name + '" '
-                    + '(' + ','.join(columns_quoted) + ')' + where,
+                cursor.execute(Composed([
+                            SQL('CREATE INDEX {name} ON {table} ({columns})')
+                            .format(
+                                name=Identifier(index_name),
+                                table=Identifier(self.table_name),
+                                columns=SQL(',').join(
+                                    (Identifier(c) if isinstance(c, str)
+                                        else SQL(str(c)))
+                                    for c in columns
+                                    )),
+                            SQL(where)
+                            ]),
                     params)
                 self._update_definitions(indexes=True)
             elif action == 'remove':
@@ -389,7 +440,8 @@
                         return
 
                 if index_name in self._indexes:
-                    cursor.execute('DROP INDEX "%s" ' % (index_name,))
+                    cursor.execute(SQL('DROP INDEX {}').format(
+                            Identifier(index_name)))
                     self._update_definitions(indexes=True)
             else:
                 raise Exception('Index action not supported!')
@@ -402,12 +454,17 @@
             if action == 'add':
                 if self._columns[column_name]['notnull']:
                     return
-                cursor.execute('SELECT id FROM "%s" '
-                    'WHERE "%s" IS NULL'
-                    % (self.table_name, column_name))
+                cursor.execute(SQL(
+                        'SELECT id FROM {} WHERE {} IS NULL').format(
+                        Identifier(self.table_name),
+                        Identifier(column_name)))
                 if not cursor.rowcount:
-                    cursor.execute('ALTER TABLE "' + self.table_name + '" '
-                        'ALTER COLUMN "' + column_name + '" SET NOT NULL')
+                    cursor.execute(
+                        SQL(
+                            'ALTER TABLE {} ALTER COLUMN {} SET NOT NULL')
+                        .format(
+                            Identifier(self.table_name),
+                            Identifier(column_name)))
                     self._update_definitions(columns=True)
                 else:
                     logger.warning(
@@ -426,9 +483,11 @@
                 if (self._field2module.get(column_name, self.module_name)
                         != self.module_name):
                     return
-                cursor.execute('ALTER TABLE "%s" '
-                    'ALTER COLUMN "%s" DROP NOT NULL'
-                    % (self.table_name, column_name))
+                cursor.execute(
+                    SQL('ALTER TABLE {} ALTER COLUMN {} DROP NOT NULL')
+                    .format(
+                        Identifier(self.table_name),
+                        Identifier(column_name)))
                 self._update_definitions(columns=True)
             else:
                 raise Exception('Not null action not supported!')
@@ -439,8 +498,12 @@
             # This constrain already exist
             return
         cursor = Transaction().connection.cursor()
-        cursor.execute('ALTER TABLE "%s" ADD CONSTRAINT "%s" %s'
-            % (self.table_name, ident, constraint), constraint.params)
+        cursor.execute(
+            SQL('ALTER TABLE {} ADD CONSTRAINT {} {}').format(
+                Identifier(self.table_name),
+                Identifier(ident),
+                SQL(str(constraint))),
+            constraint.params)
         self._update_definitions(constraints=True)
 
     def drop_constraint(self, ident, table=None):
@@ -448,25 +511,26 @@
         if ident not in self._constraints:
             return
         cursor = Transaction().connection.cursor()
-        cursor.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"'
-            % (self.table_name, ident))
+        cursor.execute(
+            SQL('ALTER TABLE {} DROP CONSTRAINT {}').format(
+                Identifier(self.table_name), Identifier(ident)))
         self._update_definitions(constraints=True)
 
     def drop_column(self, column_name):
         if not self.column_exist(column_name):
             return
         cursor = Transaction().connection.cursor()
-        cursor.execute('ALTER TABLE "%s" DROP COLUMN "%s"'
-            % (self.table_name, column_name))
+        cursor.execute(SQL('ALTER TABLE {} DROP COLUMN {}').format(
+                Identifier(self.table_name),
+                Identifier(column_name)))
         self._update_definitions(columns=True)
 
     @staticmethod
     def drop_table(model, table, cascade=False):
         cursor = Transaction().connection.cursor()
-        cursor.execute('DELETE FROM ir_model_data '
-            'WHERE model = \'%s\'' % model)
+        cursor.execute('DELETE FROM ir_model_data WHERE model = %s', (model,))
 
-        query = 'DROP TABLE "%s"' % table
+        query = SQL('DROP TABLE {}').format(Identifier(table))
         if cascade:
             query = query + ' CASCADE'
         cursor.execute(query)
diff -r 41723b243136 -r 892807681516 trytond/backend/sqlite/table.py
--- a/trytond/backend/sqlite/table.py   Mon Apr 12 22:08:36 2021 +0200
+++ b/trytond/backend/sqlite/table.py   Mon Apr 12 23:07:55 2021 +0200
@@ -13,6 +13,10 @@
 VARCHAR_SIZE_RE = re.compile(r'VARCHAR\(([0-9]+)\)')
 
 
+def _escape_identifier(name):
+    return '"%s"' % name.replace('"', '""')
+
+
 class TableHandler(TableHandlerInterface):
     def __init__(self, model, module_name=None, history=False):
         super(TableHandler, self).__init__(model,
@@ -27,13 +31,13 @@
         # Create new table if necessary
         if not self.table_exist(self.table_name):
             if not self.history:
-                cursor.execute('CREATE TABLE "%s" '
+                cursor.execute('CREATE TABLE %s '
                     '(id INTEGER PRIMARY KEY AUTOINCREMENT)'
-                    % self.table_name)
+                    % _escape_identifier(self.table_name))
             else:
-                cursor.execute('CREATE TABLE "%s" '
+                cursor.execute('CREATE TABLE %s '
                     '(__id INTEGER PRIMARY KEY AUTOINCREMENT, '
-                    'id INTEGER)' % self.table_name)
+                    'id INTEGER)' % _escape_identifier(self.table_name))
 
         self._update_definitions()
 
@@ -54,12 +58,15 @@
             temp_sql = sql.replace(table_name, '_temp_%s' % table_name)
             cursor.execute(temp_sql)
             cursor.execute('PRAGMA table_info("' + table_name + '")')
-            columns = ['"%s"' % column for _, column, _, _, _, _ in cursor]
-            cursor.execute(('INSERT INTO "_temp_%s" '
+            columns = [_escape_identifier(column)
+                for _, column, _, _, _, _ in cursor]
+            cursor.execute(('INSERT INTO %s '
                     '(' + ','.join(columns) + ') '
                     'SELECT ' + ','.join(columns)
-                    + ' FROM "%s"') % (table_name, table_name))
-            cursor.execute('DROP TABLE "%s"' % table_name)
+                    + ' FROM %s') % (
+                    _escape_identifier('_temp_' + table_name),
+                    _escape_identifier(table_name)))
+            cursor.execute('DROP TABLE %s' % _escape_identifier(table_name))
             new_sql = sql.replace('PRIMARY KEY',
                     'PRIMARY KEY AUTOINCREMENT')
             cursor.execute(new_sql)
@@ -75,15 +82,16 @@
         cursor = Transaction().connection.cursor()
         if (TableHandler.table_exist(old_name)
                 and not TableHandler.table_exist(new_name)):
-            cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
-                % (old_name, new_name))
+            cursor.execute('ALTER TABLE %s RENAME TO %s'
+                % (_escape_identifier(old_name), _escape_identifier(new_name)))
         # Rename history table
         old_history = old_name + "__history"
         new_history = new_name + "__history"
         if (TableHandler.table_exist(old_history)
                 and not TableHandler.table_exist(new_history)):
-            cursor.execute('ALTER TABLE "%s" RENAME TO "%s"'
-                % (old_history, new_history))
+            cursor.execute('ALTER TABLE %s RENAME TO %s'
+                % (_escape_identifier(old_history),
+                    _escape_identifier(new_history)))
 
     def column_exist(self, column_name):
         return column_name in self._columns
@@ -105,12 +113,14 @@
                 new_column, database.sql_type(typname), field_size=size)
             columns.append(new_column)
             old_columns.append(column)
-        cursor.execute(('INSERT INTO "%s" ('
-                + ','.join('"%s"' % x for x in columns)
+        cursor.execute(('INSERT INTO %s ('
+                + ','.join(_escape_identifier(x) for x in columns)
                 + ') SELECT '
-                + ','.join('"%s"' % x for x in old_columns) + ' '
-                + 'FROM "%s"') % (self.table_name, temp_table))
-        cursor.execute('DROP TABLE "%s"' % temp_table)
+                + ','.join(_escape_identifier(x) for x in old_columns)
+                + ' FROM %s') % (
+                _escape_identifier(self.table_name),
+                _escape_identifier(temp_table)))
+        cursor.execute('DROP TABLE %s' % _escape_identifier(temp_table))
         self._update_definitions()
 
     def column_rename(self, old_name, new_name):
@@ -235,16 +245,20 @@
 
         cursor = Transaction().connection.cursor()
         column_type = column_type[1]
-        cursor.execute(('ALTER TABLE "%s" ADD COLUMN "%s" %s') %
-                       (self.table_name, column_name, column_type))
+        cursor.execute(('ALTER TABLE %s ADD COLUMN %s %s') % (
+                _escape_identifier(self.table_name),
+                _escape_identifier(column_name),
+                column_type))
 
         if default:
             # check if table is non-empty:
-            cursor.execute('SELECT 1 FROM "%s" limit 1' % self.table_name)
+            cursor.execute('SELECT 1 FROM %s limit 1'
+                % _escape_identifier(self.table_name))
             if cursor.fetchone():
                 # Populate column with default values:
-                cursor.execute('UPDATE "' + self.table_name + '" '
-                    'SET "' + column_name + '" = ?', (default(),))
+                cursor.execute('UPDATE ' + _escape_identifier(self.table_name)
+                    + ' SET ' + _escape_identifier(column_name) + ' = ?',
+                    (default(),))
 
         self._update_definitions(columns=True)
 
@@ -264,7 +278,6 @@
             else:
                 return ('_'.join(
                         map(str, (column,) + column.params))
-                    .replace('"', '')
                     .replace('?', '__'))
 
         name = [table or self.table_name]
@@ -279,12 +292,6 @@
         if action == 'add':
             if index_name in self._indexes:
                 return
-            columns_quoted = []
-            for column in columns:
-                if isinstance(column, str):
-                    columns_quoted.append('"%s"' % column)
-                else:
-                    columns_quoted.append(str(column))
             params = sum(
                 (c.params for c in columns if hasattr(c, 'params')), ())
             if where:
@@ -293,9 +300,14 @@
             if params:
                 warnings.warn('Unable to create index with parameters')
                 return
-            cursor.execute('CREATE INDEX "' + index_name + '" '
-                'ON "' + self.table_name + '" '
-                + '(' + ','.join(columns_quoted) + ')' + where,
+            cursor.execute(
+                'CREATE INDEX %s ON %s (%s)' % (
+                    _escape_identifier(index_name),
+                    _escape_identifier(self.table_name),
+                    ','.join(
+                        _escape_identifier(c) if isinstance(c, str) else str(c)
+                        for c in columns)
+                    ) + where,
                 params)
             self._update_definitions(indexes=True)
         elif action == 'remove':
@@ -305,7 +317,8 @@
                     return
 
             if index_name in self._indexes:
-                cursor.execute('DROP INDEX "%s" ' % (index_name,))
+                cursor.execute('DROP INDEX %s'
+                    % (_escape_identifier(index_name),))
                 self._update_definitions(indexes=True)
         else:
             raise Exception('Index action not supported!')
@@ -343,21 +356,25 @@
                 new_table._add_raw_column(
                     name, database.sql_type(typname), field_size=size)
         columns_name = list(new_table._columns.keys())
-        cursor.execute(('INSERT INTO "%s" ('
-                        + ','.join('"%s"' % c for c in columns_name)
-                        + ') SELECT '
-                        + ','.join('"%s"' % c for c in columns_name) + ' '
-                        + 'FROM "%s"') % (self.table_name, temp_table))
-        cursor.execute('DROP TABLE "%s"' % temp_table)
+        cursor.execute(
+            ('INSERT INTO %s ('
+                + ','.join(str(_escape_identifier(c))
+                    for c in columns_name)
+                + ') SELECT '
+                + ','.join(_escape_identifier(c) for c in columns_name)
+                + ' FROM %s')
+            % (_escape_identifier(self.table_name),
+                _escape_identifier(temp_table)))
+        cursor.execute('DROP TABLE %s' % _escape_identifier(temp_table))
         self._update_definitions()
 
     @staticmethod
     def drop_table(model, table, cascade=False):
         cursor = Transaction().connection.cursor()
-        cursor.execute('DELETE from ir_model_data where '
-            'model = \'%s\'' % model)
+        cursor.execute('DELETE from ir_model_data where model = %s',
+            (model,))
 
-        query = 'DROP TABLE "%s"' % table
+        query = 'DROP TABLE %s' % _escape_identifier(table)
         if cascade:
             query = query + ' CASCADE'
         cursor.execute(query)

Reply via email to