2016-01-01 12 views
5

Sto usando SQLAlchemy e MySQL, con una tabella files per archiviare i file. Quel tavolo è definito come segue:Il blob binario SQLAlchemy/MySQL è codificato in utf-8?

mysql> show full columns in files; 
+---------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+ 
| Field | Type   | Collation  | Null | Key | Default | Extra | Privileges      | Comment | 
+---------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+ 
| id  | varchar(32) | utf8_general_ci | NO | PRI | NULL |  | select,insert,update,references |   | 
| created | datetime  | NULL   | YES |  | NULL |  | select,insert,update,references |   | 
| updated | datetime  | NULL   | YES |  | NULL |  | select,insert,update,references |   | 
| content | mediumblob | NULL   | YES |  | NULL |  | select,insert,update,references |   | 
| name | varchar(500) | utf8_general_ci | YES |  | NULL |  | select,insert,update,references |   | 
+---------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+ 

La colonna contenuto di tipo MEDIUMBLOB è dove i file sono memorizzati. In SQLAlchemy quella colonna è dichiarato come:

__maxsize__ = 12582912 # 12MiB                                
content = Column(LargeBinary(length=__maxsize__))       

io non sono abbastanza sicuro circa la differenza tra BINARY tipo di SQLAlchemy e LargeBinary tipo. O la differenza tra il tipo VARBINARY di MySQL e il tipo BLOB. E non sono abbastanza sicuro se questo è importante qui.

Domanda: Ogni volta che memorizzare un file binario vero e proprio in tale tabella, vale a dire un oggetto Python bytes o b'', allora ottengo il seguente avvertimento

.../python3.4/site-packages/sqlalchemy/engine/default.py:451: Warning: Invalid utf8 character string: 'BCB121' 
    cursor.execute(statement, parameters) 

non voglio ignorare semplicemente l'avviso , ma sembra che i file siano intatti. Come gestisco questo avviso con garbo, come posso risolvere la sua causa?

Nota a margine:This question sembra essere correlato, e sembra essere un bug di MySQL che si cerca di convertire tutti i dati in entrata in UTF-8 (this answer).

+0

Sembra che tu stia eseguendo Python. Le due "note a margine" si riferiscono ai problemi di PHP e Perl. Qualcosa in _Python_ non sta rispettando la tua richiesta di utilizzare i dati "blob". –

+0

@RickJames: Sì, tutto Python. Il link "[questa risposta] (http://stackoverflow.com/questions/14734812/is-a-blob-converted-using-the-current-default-charset-in-mysql#14745685)" nella nota laterale, tuttavia, sembra indicare che questo è un problema di MySQL. Se questo è un problema di Python, mi piacerebbe comunque capire cosa mi manca qui ... – Jens

+0

Se il _client_ (PHP, Python, ecc.) Tratta la stringa come "caratteri", allora questo problema può sorgere. Se lo tratta come "byte" arbitrari, il problema non si verifica. Memorizzare in un 'BLOB' MySQL non esegue il controllo di utf8; memorizzare in un 'TEXT'. –

risposta

0

Si scopre che questo era un problema di driver. Apparentemente il driver predefinito MySQL incappa con il supporto per Py3 e utf8. L'installazione di cymysql nell'ambiente Python virtuale ha risolto questo problema e gli avvisi scompaiono.

La correzione: Verificare se MySQL si connette tramite socket o porta (vedere here), quindi modificare la stringa di connessione di conseguenza. Nel mio caso utilizzando una connessione socket:

mysql+cymysql://user:[email protected]/database?unix_socket=/var/run/mysqld/mysqld.sock 

utilizzare l'argomento port altrimenti.

Modifica: Mentre il problema precedente ha risolto il problema di codifica, ne è derivato un altro: dimensione del blob. A causa di a bug in CyMySQL blob di dimensioni superiori a 8 M non riescono a eseguire il commit. Passando a PyMySQL risolto questo problema, anche se sembra avere un similar issue con grandi blob.

+0

In realtà, è apparentemente il server MySQL che sta generando questo avviso, e il modo per aggirarlo è usare '_binary' per dire che la cosa che stai inserendo non dovrebbe essere interpretata. Vedi https://bugs.mysql.com/bug.php?id=79317 – Wodin

0

Non sicuro, ma il tuo problema potrebbe avere le stesse radici di quello che avevo diversi anni fa in python 2.7: https://stackoverflow.com/a/9535736/68998. In breve, l'interfaccia di Mysql non ti consente di essere certo se stai lavorando con una vera stringa binaria o con un testo in un confronto binario (usato a causa della mancanza di regole di confronto utf8 con distinzione tra maiuscole e minuscole). Pertanto, un legame MySQL ha le seguenti opzioni:

  • di ritorno tutti i campi stringa come stringhe binarie, e lasciare la decodifica a voi
  • decodifica solo i campi che non hanno una bandiera binario (così divertente quando alcuni dei campi sono unicode e altri sono str)
  • hanno la possibilità di forzare la decodifica a unicode per tutti i campi di stringa, anche vero binario

mia ipotesi è che nel tuo caso, la terza opzione è da qualche parte abilitato i n il legame Mysql sottostante. E il primo sospetto è la tua stringa di connessione (parametri di connessione).

+0

La mia stringa di connessione corrente è: 'mysql: // utente @ localhost/database? Charset = utf8'. Secondo la [documentazione] (https://dev.mysql.com/doc/connector-net/en/connector-net-connection-options.html) l'opzione 'charset'" Specifica il set di caratteri che dovrebbe essere usato per codificare tutte le query inviate al server. "Hmm-encode * all * query? – Jens