function select($fields, $filter = NULL, array $options = NULL, $ttl = 0)
{
if (!$options) {
$options = [];
}
$options += ['group' => NULL, 'order' => NULL, 'limit' => 0, 'offset' => 0];
$db = $this->db;
$sql = 'SELECT ' . $fields . ' FROM ' . $this->table;
$args = [];
if (is_array($filter)) {
$args = isset($filter[1]) && is_array($filter[1]) ? $filter[1] : array_slice($filter, 1, NULL, TRUE);
$args = is_array($args) ? $args : [1 => $args];
list($filter) = $filter;
}
if ($filter) {
$sql .= ' WHERE ' . $filter;
}
if ($options['group']) {
$sql .= ' GROUP BY ' . implode(',', array_map(function ($str) use($db) {
return preg_replace_callback('/\\b(\\w+)\\h*(HAVING.+|$)/i', function ($parts) use($db) {
return $db->quotekey($parts[1]) . (isset($parts[2]) ? ' ' . $parts[2] : '');
}, $str);
}, explode(',', $options['group'])));
}
if ($options['order']) {
$sql .= ' ORDER BY ' . implode(',', array_map(function ($str) use($db) {
return preg_match('/^(\\w+)(?:\\h+(ASC|DESC))?\\h*(?:,|$)/i', $str, $parts) ? $db->quotekey($parts[1]) . (isset($parts[2]) ? ' ' . $parts[2] : '') : $str;
}, explode(',', $options['order'])));
}
if (preg_match('/mssql|sqlsrv|odbc/', $this->engine) && ($options['limit'] || $options['offset'])) {
$pkeys = [];
foreach ($this->fields as $key => $field) {
if ($field['pkey']) {
$pkeys[] = $key;
}
}
$ofs = $options['offset'] ? (int) $options['offset'] : 0;
$lmt = $options['limit'] ? (int) $options['limit'] : 0;
if (strncmp($db->version(), '11', 2) >= 0) {
// SQL Server 2012
if (!$options['order']) {
$sql .= ' ORDER BY ' . $db->quotekey($pkeys[0]);
}
$sql .= ' OFFSET ' . $ofs . ' ROWS';
if ($lmt) {
$sql .= ' FETCH NEXT ' . $lmt . ' ROWS ONLY';
}
} else {
// SQL Server 2008
$sql = str_replace('SELECT', 'SELECT ' . ($lmt > 0 ? 'TOP ' . ($ofs + $lmt) : '') . ' ROW_NUMBER() ' . 'OVER (ORDER BY ' . $db->quotekey($pkeys[0]) . ') AS rnum,', $sql);
$sql = 'SELECT * FROM (' . $sql . ') x WHERE rnum > ' . $ofs;
}
} else {
if ($options['limit']) {
$sql .= ' LIMIT ' . (int) $options['limit'];
}
if ($options['offset']) {
$sql .= ' OFFSET ' . (int) $options['offset'];
}
}
$result = $this->db->exec($sql, $args, $ttl);
$out = [];
foreach ($result as &$row) {
foreach ($row as $field => &$val) {
if (array_key_exists($field, $this->fields)) {
if (!is_null($val) || !$this->fields[$field]['nullable']) {
$val = $this->db->value($this->fields[$field]['pdo_type'], $val);
}
} elseif (array_key_exists($field, $this->adhoc)) {
$this->adhoc[$field]['value'] = $val;
}
unset($val);
}
$out[] = $this->factory($row);
unset($row);
}
return $out;
}