mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:52:45 +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
	
	 Guilherme Gonçalves
						Guilherme Gonçalves