"?string", "schema" => "?array", "cols" => "?array", "col_prefix" => "?string", "from" => "?string", "where" => "?array", "order by" => "?array", "group by" => "?array", "having" => "?array", "suffix" => "?string", ]; static function isa(string $sql): bool { return preg_match("/^select\b/i", $sql); } private static function add_prefix(string $col, ?string $prefix): string { if ($prefix === null) return $col; if (strpos($col, ".") !== false) return $col; return "$prefix$col"; } /** * parser une chaine de la forme * "select [COLS] [from TABLE] [where CONDS] [order by ORDERS] [group by GROUPS] [having CONDS]" */ static function parse(array $query, ?array &$bindings=null): string { # fusionner d'abord toutes les parties séquentielles $usersql = $tmpsql = self::merge_seq($query); ### vérifier la présence des parties nécessaires $sql = []; ## préfixe if (($prefix = $query["prefix"] ?? null) !== null) $sql[] = $prefix; ## select self::consume('(select(?:\s*distinct)?)\s*', $tmpsql, $ms); $sql[] = $ms[1]; ## cols $usercols = []; if (self::consume('(.*?)\s*(?=$|\bfrom\b)', $tmpsql, $ms)) { if ($ms[1]) $usercols[] = $ms[1]; } $colPrefix = $query["col_prefix"] ?? null; if ($colPrefix !== null) str::add_suffix($colPrefix, "."); $tmpcols = cl::withn($query["cols"] ?? null); $schema = $query["schema"] ?? null; if ($tmpcols !== null) { $cols = []; $index = 0; foreach ($tmpcols as $key => $col) { if ($key === $index) { $index++; $cols[] = $col; $usercols[] = self::add_prefix($col, $colPrefix); } else { $cols[] = $key; $usercols[] = self::add_prefix($col, $colPrefix)." as $key"; } } } else { $cols = null; if ($schema && is_array($schema) && !in_array("*", $usercols)) { $cols = array_keys($schema); foreach ($cols as $col) { $usercols[] = self::add_prefix($col, $colPrefix); } } } if (!$usercols && !$cols) $usercols = [self::add_prefix("*", $colPrefix)]; $sql[] = implode(", ", $usercols); ## from $from = $query["from"] ?? null; if (self::consume('from\s+([a-z_][a-z0-9_.]*)\s*(?=;?\s*$|\bwhere\b)', $tmpsql, $ms)) { if ($from === null) $from = $ms[1]; $sql[] = "from"; $sql[] = $from; } elseif ($from !== null) { $sql[] = "from"; $sql[] = $from; } else { throw new ValueException("expected table name: $usersql"); } ## where $userwhere = []; if (self::consume('where\b\s*(.*?)(?=;?\s*$|\border\s+by\b)', $tmpsql, $ms)) { if ($ms[1]) $userwhere[] = $ms[1]; } $where = cl::withn($query["where"] ?? null); if ($where !== null) self::parse_conds($where, $userwhere, $bindings); if ($userwhere) { $sql[] = "where"; $sql[] = implode(" and ", $userwhere); } ## order by $userorderby = []; if (self::consume('order\s+by\b\s*(.*?)(?=;?\s*$|\bgroup\s+by\b)', $tmpsql, $ms)) { if ($ms[1]) $userorderby[] = $ms[1]; } $orderby = cl::withn($query["order by"] ?? null); if ($orderby !== null) { $index = 0; foreach ($orderby as $key => $value) { if ($key === $index) { $userorderby[] = $value; $index++; } else { if ($value === null) $value = false; if (!is_bool($value)) { $userorderby[] = "$key $value"; } elseif ($value) { $userorderby[] = $key; } } } } if ($userorderby) { $sql[] = "order by"; $sql[] = implode(", ", $userorderby); } ## group by $usergroupby = []; if (self::consume('group\s+by\b\s*(.*?)(?=;?\s*$|\bhaving\b)', $tmpsql, $ms)) { if ($ms[1]) $usergroupby[] = $ms[1]; } $groupby = cl::withn($query["group by"] ?? null); if ($groupby !== null) { $index = 0; foreach ($groupby as $key => $value) { if ($key === $index) { $usergroupby[] = $value; $index++; } else { if ($value === null) $value = false; if (!is_bool($value)) { $usergroupby[] = "$key $value"; } elseif ($value) { $usergroupby[] = $key; } } } } if ($usergroupby) { $sql[] = "group by"; $sql[] = implode(", ", $usergroupby); } ## having $userhaving = []; if (self::consume('having\b\s*(.*?)(?=;?\s*$)', $tmpsql, $ms)) { if ($ms[1]) $userhaving[] = $ms[1]; } $having = cl::withn($query["having"] ?? null); if ($having !== null) self::parse_conds($having, $userhaving, $bindings); if ($userhaving) { $sql[] = "having"; $sql[] = implode(" and ", $userhaving); } ## suffixe if (($suffix = $query["suffix"] ?? null) !== null) $sql[] = $suffix; ## fin de la requête self::check_eof($tmpsql, $usersql); return implode(" ", $sql); } }