Jak poradzić sobie z niemożnością eskapowania nazw kolumn w dynamycznych zapytaniach sql

Dynamiczne zapytaniach sql

Realizując codzienne zadania w drupalowej agencji, w której podejmujemy się prac z zakresu Drupal developmentu, natrafiamy często na różne wyzwania. 

Ostatnio, przeprowadzając migrację do Drupala, zidentyfikowałem nowy problem z drupalową warstwą abstrakcyjną sql. Okazuje się, że dynamiczne zapytania do bazy danych nie są eskapowane.

Ten problem wprawdzie nie dotyczy wszystkich rodzajów baz danych, ale zdecydowanie dotyczy mysql.

$query = Database::getConnection('default', 'legacy') ->select('prod_group', 'pg') ->fields('pg', array('porductid, 'active', 'order'));

wygeneruje następujące zapytanie:

SELECT pg.productid AS productid, pg.active AS active, pg.order AS order  FROM {prod_group} pg;

Brakuje `` naokoło pól a w tym wypadku mamy bardzo nieporęczną nazwę jednej kolumny "order" - słowo zarezerwowane w mysql do sortowania zapytań ORDER BY. Mysql tak je interpretuje i wyrzuca błąd:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax;

Żeby tego uniknąć, powinniśmy zadawać zapytania z nazwami kolumn zawiniętymi w odwrotne apostrofy:

SELECT pg.productid AS `productid`, pg.active AS `active`, pg.order AS `order` FROM {prod_group} pg;

Drupal niestety w przypadku zapytań dynamicznych tego nie wspiera tego nie wspiera a zapytania dynamiczne to jedyne jakie są dozwolone w przypadku modułu migrate.

Rozwiązanie - aliasy pól

Drupal wspiera aliasy. Używa ich domyślnie co widać w powyższym zapytaniu: "pg.order AS order" gdzie pole order jest aliasowane, o tyle że niefortunnie wciąż swoją własną nazwą - zastrzerzoną..

Swój własny alias możemy nadać ręcznie przy pomocy SelectQueryInterface::addField.

$query = Database::getConnection('default', 'legacy') ->select('prod_group', 'pg') ->fields('pg', array('groupid', 'active')) ->addField('pg', 'order', 'escaped_order');

co daje nam zapytanie bez zarezerwowanego słowa order:

SELECT pg.productid AS productid, pg.active AS active, pg.order AS escaped_order FROM {prod_group} pg;.

To rozwiązuje problem. Należy tylko pamiętać, że w wynikach zapytań pole order będzie się nazywało escaped_order.