Skip to content

Библиотека конструирования SQL-запросов с помощью типизированных меток-плейсхолдеров

License

Notifications You must be signed in to change notification settings

davidmz/yaff-db

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

\Yaff\db\Quoter и \Yaff\db\Db

Класс Quoter предназначен для безопасного конструирования SQL-запросов из шаблонов с использованием типизированных меток-плейсхолдеров (placeholders), далее — просто «меток».

Класс Db является наследником стандартного класса PDO и расширяет его несколькими сервисными функциями. В этих функциях используются шаблоны с типизированными метками.

О типизированных метках

Метка — это место в шаблоне SQL-запроса, на место которой будут вставлены реальные данные. Например, в шаблоне select * from users where id = ? or login = ? символы ? является метками. Реальный SQL-запрос из этого шаблона будет конструироваться, например, так $sql = $quoter->format("select * from users where id = ? or login = ?", array(42, "admin"));. Результатом этого вызова будет строка select * from users where id = 42 or login='admin'.

SQL-шаблоны с метками нужны для того, чтобы правильно форматировать данные перед вставкой в SQL-запрос. Например, в примере выше число (42) вставляется в запрос без дополнительной обработки, а строка ("admin") заключается в одинарные кавычки. Для других типов данных есть другие правила преобразования. Часто определение типа производится автоматически, на основании типа входных данных. Это определение не всегда происходит правильно (например, из GET- и POST-параметров всегда приходят только строки). Поскольку SQL — типизированный язык, важно соблидать тип данных и не сравнивать, например, строку с логической величиной. Для этого и придуманы типизированные метки, которые в самом шаблоне указывают, каким должен быть тип данных в это месте.

С типизированными метками шаблон, приведённый выше, выглядит так: select * from users where id = ?i or login = ?s. Метка ?i означает, что в шаблон надо вставить целое число, метка ?s означает строку. Теперь можно написать так: $sql = $quoter->format("select * from users where id = ? or login = ?", array("42", "admin")); и всё равно получить корректный результат.

Подробно об идее и теории типизированных меток можно прочесть в статьях http://habrahabr.ru/post/148701/ и http://dklab.ru/lib/DbSimple/manual.html.

Синтаксис меток

Все метки в данной библиотеке основаны на символе ?, после которого следует тип метки. Если нужно просто вставить символ ? в запрос, без интерпретации его как метки, то используйте удвоение: ??.

Скалярные метки

Скалярные метки предназначены для вставки в запрос скалярных величин — строк, чисел и т. д.

? — автотип — форматирование осуществляется на основании типа входных данных;

?s — строка;

?i — целое число;

?f — дробное число;

?b — логическое значение;

?t — строка-идентификатор объекта базы данных (имя таблицы, колонки и т. п.);

?! — raw-метка — значение вставляется в запрос как есть, без форматирования. Полезно для вставки уже отформатированных SQL-фрагментов.

Пример шаблона, использующего скалярные метки: select * from ?t where id = ?i and ?b.

Если в качестве данных передано некорректное для данного типа значение (например, нечисловая строка передана в метку с типом ?i), то используется «нулевое» значение данного типа (пустая строка, ноль, false). Если в шаблон передан null, он вставляется в результат как SQL-значение NULL или UNKNOWN.

Исключением являются типы ?t и ?! — первый требует на входе строго непустые строки, в противном случае выбрасывается исключение, а второй любое значение приводит к строке и вставляет без изменения.

У значения NULL (UNKNOWN) есть особенность — в SQL его нельзя сравнивать при помощи оператора = или <>. Поэтому при вставке NULL-а проверяется предшествующий ему оператор, и = заменяется на IS, а <> — на IS NOT. Таким образом, a = ? заменяется на a IS NULL.

Метки-массивы

Метки-массивы нужны для вставки в запросы сложных структур — массивов и хэшей.

?@[тип] — типизированный массив для операторов IN / NOT IN. Массив предполагается однородным — заполненным величинами одного типа, этот тип указывается после символа @. Если тип не указан, то он выводится из типа входных данных. Пример: ?@i — метка для массива целых чисел.

Если переданный массив не пуст, то в запрос вставляются значения из массива, разделённые запятыми. Если массив пуст или передан не массив, то вставляется NULL.

Пример: $quoter->format("… where id in (?@i)", array(array(1, 2, 3))); вернёт … where id in (1, 2, 3).

?#v — хэш значений для оператора INSERT. Тип ключей всегда ?t, тип значений выводится автоматически. Если передан хэш array(k1 => v1, k2 => v2, …), то в запрос вставится (k1, k2, …) values (v1, v2, …). Если хэш пуст, вставляется строка default values, если значение некорректно, то выбрасывется исключение.

?#u — хэш значений для оператора UPDATE. Тип ключей всегда ?t, тип значений выводится автоматически. Если передан хэш array(k1 => v1, k2 => v2, …), то в запрос вставится k1=v1, k2=v2, …. Если хэш пуст или значение некорректно, то выбрасывется исключение.

Примеры: insert into users ?#v, update users set ?#u where id = ?i.

Именованные и нумерованные метки

SQL-запрос формируется из строки-шаблона и массива параметров, значения которых вставляются в места меток шаблона. Массив параметров может быть ассоциативным, тогда для работы с ним следует использовать именованные метки. Имя метки совпадает с ключом в массиве параметров и записывается перед символом метки (?) без пробела. Допустимые имена меток имеют формат [a-zA-Z_][a-zA-Z0-9_]*. Пример:

$quoter->format("select * from users where id = userId?i", array("userId" => 42));

Если массив параметров не ассоциативный, то вместо имени метки можно использовать порядковый номер параметра в массиве (нумерация с единицы). Например:

$quoter->format("select * from users where id = 1?i", array(42));

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

Пустое имя/номер метки обрабатывается как автоматически увеличивающийся номер параметра с числовым ключом. То есть, первая (по ходу шаблона) метка с пустым именем соответствует параметру на позиции 1, вторая — 2 и т. д.

Если в параметрах нет какого-либо из требуемых ключей или есть лишние, то выбрасывается исключение.

Класс Quoter

\Yaff\db\Quoter — абстрактный класс, имеющий (пока что) две реализации: QuoterSQL — минимальный стандартный SQL-синтаксис и QuoterPostgres — синтаксис PostgreSQL.

Основным методом Quoter-а является метод format($query, array $args = array()). Аргумент $query — это шаблон запроса с типизированными метками, а $args — массив аргументов, которые будут подставлены на место меток. Метод возвращает собранную из шаблона и аргументов SQL-строку.

$quoter = new \Yaff\db\QuoterSQL();
$sql = $quoter->format("select * from users where id = ?i", array(42));

Результатом будет строка select * from users where id = 42.

Класс Db

Класс \Yaff\db\Db предназначен для упрощения наиболее частых операций с базой данных. Он является наследником библиотечного класса PDO и использует внутри себя Quoter для подстановки данных в шаблоны. Класс предлагает следующие дополнительные сервисные методы (почти все они принимают SQL-шаблон $sqlTpl и массив аргументов $args):

perform($sqlTpl, array $args = array()) — выполнить запрос, не возвращая результат;

performInsert($tableName, array $values = array()) — выполнить INSERT-запрос в таблицу $tableName;

getRow($sqlTpl, array $args = array()) — вернуть первую строку результата запроса как ассоциативный массив;

getAll($sqlTpl, array $args = array()) — вернуть все строки результата запроса как массив ассоциативных массивов;

getOne($sqlTpl, array $args = array()) — вернуть значение первой колонки первой строки результата запроса;

getCol($sqlTpl, array $args = array(), $n = 0) — вернуть $n-ю колонку из результатов запроса в виде массива;

getAssoc($sqlTpl, array $args = array(), $forceArray = false) — вернуть результаты запроса в виде ассоциативного массива, в котором первая колонка каждой строки является ключом, а последующие — значением (массивом). Если в результате всего две колонки, то значение не преобразуется в массив, это можно изменить, выставив последний параметр метода в TRUE.

About

Библиотека конструирования SQL-запросов с помощью типизированных меток-плейсхолдеров

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages