Как добавить запрос PostgreSQL к другому запросу в Python 3 и предотвратить внедрение SQL? - PullRequest
2 голосов
/ 03 мая 2020

Я пишу несколько скриптов в Python 3 и мне нужно прочитать данные из базы PostgreSQL. В сценарии мне нужно добавить запрос к другому запросу, а также предотвратить SQL внедрение. Я пробовал разные способы (строка формата, sql. SQL), но безуспешно. Ниже приведен код, который я использовал:

data = {
    'id': 14, 
    'user_id': (16, 'Administrator'), 
    'from_date': datetime.datetime(2019, 1, 6, 5, 45, 15), 
    'to_date': datetime.datetime(2020, 5, 3, 5, 45, 15), 
    'state': 'to_be_review', 
    'language': 'english',
}
query = " AND hr.unit_identification_code_id IN (%s)" % ','.join(map(str, uic_ids))
user_id = data.get('user_id') and data.get('user_id')[0] or 0
    if uic_ids:
        if data.get('state') != 'reject_submit':
            self._cr.execute(sql.SQL("""
                                    SELECT
                                        elh.id 
                                    FROM
                                        employee_log_history elh 
                                        LEFT JOIN
                                            hr_employee hr 
                                            ON elh.hr_employee_id = hr.id 
                                    WHERE
                                        elh.create_date >= %s 
                                        AND elh.create_date <=%s 
                                        AND elh.create_uid = %s 
                                        AND elh.state = %s {}
                                    """).format(sql.Identifier(query)), (data.get('from_date'), data.get('to_date'), user_id, data.get('state'),)  
                                )

, но когда я запускаю скрипт в результате, я получаю первый запрос в двойных кавычках и с ошибкой ниже:

psycopg2.ProgrammingError: syntax error at or near "" AND hr.unit_identification_code_id IN (33,34,35,36,37,38,39,40,41,42,49,47,60,61,63,64,62,43,46,58,59,50,57,48,44,51,52)""
LINE 13: ...                   AND elh.state = 'to_be_review' " AND hr.u...

Теперь мне интересно, Можно ли выполнить этот запрос и предотвратить ввод SQL, а также добавить первый запрос во второй?

1 Ответ

2 голосов
/ 04 мая 2020

sql .Identifier предназначен для цитирования идентификаторов, таких как имена таблиц или столбцов, а не для адаптации фрагментов SQL. Чтобы сделать то, что вы хотите, используйте sql. SQL.

Вот упрощенный пример добавления дополнительного условия к предложению WHERE:

import psycopg2
from psycopg2 import sql

conn = psycopg2.connect(database='test')
cur = conn.cursor()

stmt1 = "SELECT name, password FROM users WHERE name = %s"
stmt2 = ' AND {} = %s'

composed = sql.SQL(stmt2).format('password')

print(composed)
Composed([SQL(' AND '), Identifier('password'), SQL(' = %s')])

print(repr(composed.as_string(cur)))
' AND "password" = %s'

cur.mogrify(stmt1 + composed.as_string(cur), ('Alice', 'secret'))
b'SELECT name, password FROM users WHERE name = \'Alice\' AND "password" = \'secret\''

Смешивание строк (stmt) и объектов (composed) выглядит немного странно. Возможно, вы захотите использовать объекты последовательно в своем коде, но это ваше дело.

...