Вы генерируете SQL в этом куске кода, и вы пытались создать правильный SQL.Это очень неудачная попытка избежать внедрения SQL.Это не очень эффективно и не нужно, так как драйвер базы данных уже знает, как позаботиться об этом, гораздо безопаснее!
Для баз данных SQL - правильный способ установки значений в параметры SQL.Параметры SQL состоят из двух компонентов: заполнителей и значений, передаваемых отдельно в метод .execute()
, который база данных должна обрабатывать без ошибок.Библиотека sqlite3
не является исключением, подробнее см. Метод cursor.execute()
.В вашем случае вы можете использовать именованные заполнители:
columns = [f'''"{name.replace('"', '""')}"''' for name in meta_data]
placeholders = [f':{name}' for name in meta_data]
sql = f'INSERT INTO Files ({", ".join(columns)}) VALUES ({", ".join(placeholders)})'
cur.execute(sql, meta_data)
Обратите внимание, что meta_data
передается в качестве второго аргумента;база данных принимает каждый заполнитель :name
и получает значение этого заполнителя из словаря meta_data
.
Я также правильно отформатировал имена столбцов, заключив их в двойные кавычки и удвоив любые символы "
в имени;см. документацию по ключевым словам SQLite :
'keyword' A keyword in single quotes is a string literal.
"keyword" A keyword in double-quotes is an identifier.
В вашем коде жестко заданы имена этих столбцов, и ни одно из них не является зарезервированным ключевым словом SQL, поэтому им не нужна эта защита, но этовсе еще хорошая практика.
Для вашего кода, где meta_data
имеет фиксированное количество ключей, приведенное выше строит эту строку sql
:
>>> columns = [f'''"{name.replace('"', '""')}"''' for name in meta_data]
>>> placeholders = [f':{name}' for name in meta_data]
>>> sql = f'INSERT INTO Files ({", ".join(columns)}) VALUES ({", ".join(placeholders)})'
>>> from pprint import pprint
>>> pprint(sql)
('INSERT INTO Files ("file_name", "file_path", "extension", "mode", "inode", '
'"file_size", "atime", "mtime", "ctime") VALUES (:file_name, :file_path, '
':extension, :mode, :inode, :file_size, :atime, :mtime, :ctime)')
Я бы также изменил способВы регистрируете ошибку вместо
logging.error('Could not gather data for file: ' + meta_data['file_path'] + e.__str__())
Я бы использовал
logging.exception('Could not gather data for file: %s', meta_data['file_path'])
и оставлял сбор ошибок в каркасе ведения журнала.Даже если вы включаете объект исключения, используйте str(e)
или %s
заполнитель.