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.