2010-07-14 3 views
26

Вопрос: Возможно ли использовать переменную в качестве имени таблицы без использования конструкторов строк?Имя переменной таблицы в sqlite


Информация:

Я работаю над проектом прямо сейчас, что каталоги данных из звезд моделирования шахты. Для этого я загружаю все данные в базу данных sqlite. Он работает очень хорошо, но я решил добавить намного большую гибкость, эффективность и удобство использования в свой db. Я планирую позже добавлять планету к моделированию и хотел бы иметь таблицу для каждой звезды. Таким образом, мне не нужно было бы запрашивать таблицу из 20 млн. Планетарных частиц для 1-4к в каждой солнечной системе.

Мне сказали, что использование конструкторов строк плохо, потому что оно оставляет меня уязвимым для атаки SQL-инъекции. Хотя это не так уж и важно, поскольку я единственный человек, имеющий доступ к этим dbs, я хотел бы следовать лучшим практикам. И также, если я делаю проект с аналогичной ситуацией, когда он открыт для публики, я знаю, что делать.

В настоящее время я делаю это:

cursor.execute("CREATE TABLE StarFrame"+self.name+" (etc etc)") 

Это работает, но я хотел бы сделать что-то подобное:

cursor.execute("CREATE TABLE StarFrame(?) (etc etc)",self.name) 

, хотя я понимаю, что это, вероятно, будет невозможно. хотя я бы согласиться на что-то вроде

cursor.execute("CREATE TABLE (?) (etc etc)",self.name) 

Если это вообще не возможно, я приму этот ответ, но если кто-нибудь знает способ сделать это, не сказать. :)

Я кодирую в python.

ответ

25

К сожалению, таблицы не могут быть объектом замены параметров (я не нашел никакого определенного источника, но я видел его на нескольких веб-форумах).

Если вы беспокоитесь об инъекции (вы, вероятно, должны быть), вы можете написать функцию, которая очищает строку перед ее передачей. Поскольку вы ищете только имя таблицы, вы должны быть в безопасности, просто принимая буквенно-цифровые символы, удаляя все знаки препинания, такие как )(][;, и пробельные символы. В основном, просто держите A-Z a-z 0-9.

def scrub(table_name): 
    return ''.join(chr for chr in table_name if chr.isalnum()) 

scrub('); drop tables --') # returns 'droptables' 
+1

Так что это невозможно. Это то, что мне нужно было знать. И ваш предложенный метод скраба выглядит очень хорошо. Благодаря! – Narcolapser

+13

Лично я бы выбрал исключение, если вместо этого появятся такие символы. Их не должно быть, поэтому что-то не так, и я бы предпочел узнать об этом. –

+1

-1; детали этого ответа кажутся ошибочными. Это чрезмерно ограничительный (не позволяя, например, подчеркивания в именах таблиц, которые довольно распространены), и, как отметил @JanHudec, если 'scrub()' когда-либо удаляет какие-либо символы, это почти наверняка сломает запрос ; это должно привести к тому, что исключение будет выбрано немедленно, а не ждать времени выполнения запроса. –

8

Я бы не разделил данные на несколько таблиц. Если вы создадите индекс в столбце звезды, у вас не будет проблем с эффективностью доступа к данным.

+0

Мне трудно поверить. Насколько я знаю, sqlite проходит через таблицу и проверяет, совпадает ли значение индекса, которое я хочу, и значение индекса звезды. если они выбирают другое, он продолжает и игнорирует его. Мне бы пришлось перебирать пару миллионов записей, чтобы найти нужную ему информацию. который с точки зрения процессора, не имеет большого значения. но мой hdd не сможет идти в ногу.
также, что бы я добавил 8 * (количество планетарных) байтов в уже большой файл. Мне не нравится звук этого. – Narcolapser

+2

Вам нужно узнать больше о том, как работают SQLite и все реляционные базы данных. Они используют индексы для быстрого поиска нужных строк. То, что вы описываете, называется «полным сканированием таблицы», и да, это ужасно. Но его можно легко избежать. Люди делают таблицы с миллионами строк все время и никогда не должны брать на себя расходы на полное сканирование таблицы. –

+0

+1 для уточнения значения индексов во избежание полного сканирования таблицы. – PaulMcG

-1

Как было сказано в других ответах, «таблицы не могут быть мишенью для замены параметров», но если вы оказываетесь в привязке, где у вас нет опции, здесь приведен метод тестирования, если имя таблицы указано действует.
Примечание: Я сделал имя таблицы настоящей свинью, пытаясь охватить все базы.

import sys 
import sqlite3 
def delim(s): 
    delims="\"'`" 
    use_delim = [] 
    for d in delims: 
    if d not in s: 
    use_delim.append(d) 
    return use_delim 

db_name = "some.db" 
db = sqlite3.connect(db_name) 
mycursor = db.cursor() 
table = 'so""m ][ `etable' 
delimiters = delim(table) 
if len(delimiters) < 1: 
    print "The name of the database will not allow this!" 
    sys.exit() 
use_delimiter = delimiters[0] 
print "Using delimiter ", use_delimiter 
mycursor.execute('SELECT name FROM sqlite_master where (name = ?)', [table]) 
row = mycursor.fetchall() 
valid_table = False 
if row: 
    print (table,"table name verified") 
    valid_table = True 
else: 
    print (table,"Table name not in database", db_name) 

if valid_table: 
    try: 
     mycursor.execute('insert into ' +use_delimiter+ table +use_delimiter+ ' (my_data,my_column_name) values (?,?) ',(1,"Name")); 
     db.commit() 
    except Exception as e: 
     print "Error:", str(e) 
    try: 
     mycursor.execute('UPDATE ' +use_delimiter+ table +use_delimiter+ ' set my_column_name = ? where my_data = ?', ["ReNamed",1]) 
     db.commit() 
    except Exception as e: 
     print "Error:", str(e) 
db.close() 
+0

Что делать, если моя таблица называется «моя таблица»? Это отлично 'valid_table', но ваше' UPDATE' потерпит неудачу. –

+0

@ har-wradim Да! Вы абсолютно правы. Если вы решили использовать имя таблицы, содержащее пробелы, точно так же, как имена полей, содержащие пробелы в sqlite, действительны, но вы не использовали бы их, если бы не хотели мира боли. –

+0

Я просто хотел подчеркнуть, что ваше решение не решает вопрос. Таблица может присутствовать в базе данных и одновременно иметь неудобное имя. –

-2

Вы можете передать строку в качестве команды SQL:

import sqlite3 
conn = sqlite3.connect('db.db') 
c = conn.cursor() 
tablename, field_data = 'some_table','some_data' 
query = 'SELECT * FROM '+tablename+' WHERE column1=\"'+field_data+"\"" 
c.execute(query) 
+7

Обязательно https://xkcd.com/327/ – Joe

0

Попробуйте со строкой форматирования:

sql_cmd = '''CREATE TABLE {}(id, column1, column2, column2)'''.format(
      'table_name') 
db.execute(sql_cmd) 

'table_name' Заменить с вашим желанием.

Смежные вопросы