2010-07-14 17 views
26

Pregunta: ¿Es posible usar una variable como nombre de la tabla sin tener que usar constructores de cadenas para hacerlo?Nombre de la tabla de variables en sqlite


Info:

Estoy trabajando en un proyecto en este momento que los catálogos de datos de una simulación estrella de la mía. Para hacerlo, estoy cargando todos los datos en una base de datos sqlite. Está funcionando bastante bien, pero he decidido agregar mucha más flexibilidad, eficiencia y facilidad de uso a mi db. Planeo luego agregar planetoides a la simulación, y quería tener una tabla para cada estrella. De esta forma no tendría que consultar una tabla de 20m de algunos planetoides para el 1-4k en cada sistema solar.

Me han dicho que el uso de constructores de cadenas es malo porque me deja vulnerable a un ataque de inyección SQL. Si bien eso no es un gran problema aquí ya que soy la única persona con acceso a estos db, me gustaría seguir las mejores prácticas. Y también de esta manera, si hago un proyecto con una situación similar en la que esté abierto al público, sé qué hacer.

Actualmente estoy haciendo esto:

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

Esto funciona, pero me gustaría hacer algo más como:

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

aunque entiendo que esto probablemente sería imposible. aunque me conformaría con algo así como

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

Si esto no es posible, voy a aceptar esa respuesta, pero si alguien conoce una manera de hacer esto, digo. :)

Estoy codificando en python.

Respuesta

25

Desafortunadamente, las tablas no pueden ser el objetivo de la sustitución de parámetros (no encontré ninguna fuente definitiva, pero la he visto en algunos foros web).

Si le preocupa la inyección (probablemente deba hacerlo), puede escribir una función que limpie la cuerda antes de pasarla. Como busca solo el nombre de una tabla, debe estar seguro al aceptar caracteres alfanuméricos, eliminando todos los signos de puntuación, como )(][;, y espacios en blanco. Básicamente, solo guarde 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

Así que no es posible. Eso es lo que necesitaba saber. Y su método de limpieza propuesto se ve muy bien. ¡Gracias! – Narcolapser

+13

Personalmente, lanzaría una excepción si se ven esos personajes en su lugar. No deben estar allí, entonces algo está mal y preferiría saberlo. –

+1

-1; los detalles de esta respuesta parecen defectuosos. Es demasiado restrictivo (no permite, por ejemplo, subrayar los nombres de las tablas, que son bastante comunes) y, como @JanHudec ha señalado, si 'scrub()' alguna vez elimina algún carácter, es casi seguro que habrá roto la consulta ; eso debería provocar que se lanzara una excepción inmediatamente en lugar de esperar a que se produzca el tiempo de ejecución de la consulta. –

8

No separaría los datos en más de una tabla. Si crea un índice en la columna de la estrella, no tendrá problemas para acceder de manera eficiente a los datos.

+0

Me resulta difícil de creer. A mi leal saber y entender, sqlite se ejecuta en la tabla y comprueba si el valor del índice que quiero y el valor del índice de una estrella son los mismos. si lo son, selecciona de otro modo, continúa y lo ignora. Eso me tendría que repetir a través del par de millones de entradas para encontrar la información que necesita. que desde el punto de vista del procesador, no es un gran problema. pero mi disco duro no podrá mantenerse al día.
también, eso me daría la adición de 8 * (número de planetoides) bytes al archivo ya de gran tamaño. No me gusta el sonido de eso. – Narcolapser

+2

Necesita aprender más sobre cómo funcionan SQLite y todas las bases de datos relacionales. Usan índices para encontrar rápidamente las filas que desea. Lo que describes se llama "exploración de tabla completa" y sí, es horrible. Pero se puede evitar fácilmente. Las personas crean tablas con millones de filas todo el tiempo, y nunca tienen que incurrir en los costos de escaneos completos de tablas. –

+0

+1 para aclarar el valor de los índices para evitar exploraciones de tablas completas. – PaulMcG

-1

Como se ha dicho en las otras respuestas, "las tablas no pueden ser el objetivo de la sustitución de parámetros", pero si se encuentra en un enlace donde no tiene opción, aquí hay un método para probar si el nombre de la tabla es válida.
Nota: He convertido el nombre de la tabla en un verdadero cerdo en un intento de cubrir todas las bases.

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

¿Qué pasa si mi tabla se llama 'mi mesa'? Es perfectamente 'valid_table', pero su' UPDATE' fallará. –

+0

@ har-wradim ¡Sí! Usted es absolutamente correcto. Si decidió usar un nombre de tabla que contenga espacios, al igual que los nombres de campo que contienen espacios en sqlite son válidos, pero no los usaría a menos que quisiera un mundo de dolor. –

+0

Solo quería recalcar que su solución no aborda la cuestión. Una tabla puede estar presente en la base de datos y tener un nombre inconveniente al mismo tiempo. –

-2

Puede pasar una cadena que el comando 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

Obligatorio https://xkcd.com/327/ – Joe

0

intento con el formato de cadenas:

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

Reemplazar 'table_name' con su deseo.

Cuestiones relacionadas