mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:48:11 +00:00
LibSQL: Implement LIKE SQL expressions
This commit is contained in:
parent
e957c078d5
commit
f91d471843
5 changed files with 133 additions and 1 deletions
|
@ -4,11 +4,14 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibRegex/Regex.h>
|
||||
#include <LibSQL/AST/AST.h>
|
||||
#include <LibSQL/Database.h>
|
||||
|
||||
namespace SQL::AST {
|
||||
|
||||
static const String s_posix_basic_metacharacters = ".^$*[]+\\";
|
||||
|
||||
Value Expression::evaluate(ExecutionContext&) const
|
||||
{
|
||||
return Value::null();
|
||||
|
@ -194,4 +197,58 @@ Value ColumnNameExpression::evaluate(ExecutionContext& context) const
|
|||
return Value::null();
|
||||
}
|
||||
|
||||
Value MatchExpression::evaluate(ExecutionContext& context) const
|
||||
{
|
||||
if (context.result->has_error())
|
||||
return Value::null();
|
||||
switch (type()) {
|
||||
case MatchOperator::Like: {
|
||||
Value lhs_value = lhs()->evaluate(context);
|
||||
Value rhs_value = rhs()->evaluate(context);
|
||||
char escape_char = '\0';
|
||||
if (escape()) {
|
||||
auto escape_str = escape()->evaluate(context).to_string();
|
||||
if (escape_str.length() != 1) {
|
||||
context.result->set_error(SQLErrorCode::SyntaxError, "ESCAPE should be a single character");
|
||||
return Value::null();
|
||||
}
|
||||
escape_char = escape_str[0];
|
||||
}
|
||||
|
||||
// Compile the pattern into a simple regex.
|
||||
// https://sqlite.org/lang_expr.html#the_like_glob_regexp_and_match_operators
|
||||
bool escaped = false;
|
||||
AK::StringBuilder builder;
|
||||
builder.append('^');
|
||||
for (auto c : rhs_value.to_string()) {
|
||||
if (escape() && c == escape_char && !escaped) {
|
||||
escaped = true;
|
||||
} else if (s_posix_basic_metacharacters.contains(c)) {
|
||||
escaped = false;
|
||||
builder.append('\\');
|
||||
builder.append(c);
|
||||
} else if (c == '_' && !escaped) {
|
||||
builder.append('.');
|
||||
} else if (c == '%' && !escaped) {
|
||||
builder.append(".*");
|
||||
} else {
|
||||
escaped = false;
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
builder.append('$');
|
||||
// FIXME: We should probably cache this regex.
|
||||
auto regex = Regex<PosixBasic>(builder.build());
|
||||
auto result = regex.match(lhs_value.to_string(), PosixFlags::Insensitive | PosixFlags::Unicode);
|
||||
return Value(invert_expression() ? !result.success : result.success);
|
||||
}
|
||||
case MatchOperator::Glob:
|
||||
case MatchOperator::Match:
|
||||
case MatchOperator::Regexp:
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
return Value::null();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue