Navigation Menu

Skip to content

Commit

Permalink
Add query rewrite system
Browse files Browse the repository at this point in the history
TODO:

  * Support customizing rewriter registration table
  * Support ordering rewriters
  • Loading branch information
kou committed Oct 7, 2015
1 parent 746cb6f commit 66e87a9
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 29 deletions.
3 changes: 2 additions & 1 deletion include/groonga/expr.h
@@ -1,5 +1,5 @@
/*
Copyright(C) 2009-2014 Brazil
Copyright(C) 2009-2015 Brazil
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -55,6 +55,7 @@ GRN_API grn_rc grn_expr_syntax_escape_query(grn_ctx *ctx,
grn_obj *escaped_query);

GRN_API grn_rc grn_expr_compile(grn_ctx *ctx, grn_obj *expr);
GRN_API grn_obj *grn_expr_rewrite(grn_ctx *ctx, grn_obj *expr);
GRN_API grn_rc grn_expr_dump_plan(grn_ctx *ctx, grn_obj *expr, grn_obj *buffer);
GRN_API grn_obj *grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs);

Expand Down
18 changes: 17 additions & 1 deletion lib/expr.c
Expand Up @@ -1224,6 +1224,22 @@ grn_expr_compile(grn_ctx *ctx, grn_obj *expr)
return ctx->rc;
}

grn_obj *
grn_expr_rewrite(grn_ctx *ctx, grn_obj *expr)
{
grn_obj *rewritten = NULL;

GRN_API_ENTER;

#ifdef GRN_WITH_MRUBY
if (ctx->impl->mrb.state) {
rewritten = grn_mrb_expr_rewrite(ctx, expr);
}
#endif

GRN_API_RETURN(rewritten);
}

#define WITH_SPSAVE(block) do {\
ctx->impl->stack_curr = sp - ctx->impl->stack;\
e->values_curr = vp - e->values;\
Expand Down Expand Up @@ -5471,7 +5487,7 @@ grn_table_select(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
scanner = grn_scanner_open(ctx, expr, op, res_size > 0);
if (scanner) {
grn_obj res_stack;
grn_expr *e = (grn_expr *)expr;
grn_expr *e = (grn_expr *)scanner->expr;
grn_expr_code *codes = e->codes;
uint32_t codes_curr = e->codes_curr;
GRN_PTR_INIT(&res_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
Expand Down
2 changes: 1 addition & 1 deletion lib/grn_scanner.h
Expand Up @@ -27,7 +27,7 @@ extern "C" {

typedef struct _grn_scaner {
grn_obj *expr;
grn_obj *rewritten_expr;
grn_obj *source_expr;
scan_info **sis;
unsigned int n_sis;
} grn_scanner;
Expand Down
32 changes: 32 additions & 0 deletions lib/mrb/mrb_expr.c
Expand Up @@ -809,6 +809,38 @@ grn_mrb_expr_init(grn_ctx *ctx)
mrb_grn_expression_append_operator, MRB_ARGS_REQ(2));
}

grn_obj *
grn_mrb_expr_rewrite(grn_ctx *ctx, grn_obj *expr)
{
grn_mrb_data *data = &(ctx->impl->mrb);
mrb_state *mrb = data->state;
mrb_value mrb_expression;
mrb_value mrb_rewritten_expression;
grn_obj *rewritten_expression = NULL;
int arena_index;

arena_index = mrb_gc_arena_save(mrb);

mrb_expression = grn_mrb_value_from_grn_obj(mrb, expr);
mrb_rewritten_expression = mrb_funcall(mrb, mrb_expression, "rewrite", 0);
if (mrb_nil_p(mrb_rewritten_expression)) {
goto exit;
}

if (mrb_type(mrb_rewritten_expression) == MRB_TT_EXCEPTION) {
mrb->exc = mrb_obj_ptr(mrb_rewritten_expression);
mrb_print_error(mrb);
goto exit;
}

rewritten_expression = DATA_PTR(mrb_rewritten_expression);

exit:
mrb_gc_arena_restore(mrb, arena_index);

return rewritten_expression;
}

scan_info **
grn_mrb_scan_info_build(grn_ctx *ctx,
grn_obj *expr,
Expand Down
2 changes: 2 additions & 0 deletions lib/mrb/mrb_expr.h
Expand Up @@ -27,6 +27,8 @@ extern "C" {
#endif

void grn_mrb_expr_init(grn_ctx *ctx);

grn_obj *grn_mrb_expr_rewrite(grn_ctx *ctx, grn_obj *expr);
scan_info **grn_mrb_scan_info_build(grn_ctx *ctx,
grn_obj *expr,
int *n,
Expand Down
28 changes: 28 additions & 0 deletions lib/mrb/scripts/expression.rb
@@ -1,10 +1,38 @@
require "expression_rewriter"
require "expression_rewriters"

require "scan_info"
require "scan_info_builder"

require "expression_size_estimator"

module Groonga
class Expression
def rewrite
rewritten = nil
begin
source = self
ExpressionRewriters.classes.each do |rewriter_class|
rewriter = rewriter_class.new(source)
new_rewritten = rewriter.rewrite
if new_rewritten
rewritten.close if rewritten
rewritten = new_rewritten
source = rewritten
end
end
rescue GroongaError => groonga_error
context.set_groonga_error(groonga_error)
rewritten.close if rewritten
rewritten = nil
rescue => error
context.record_error(:invalid_argument, error)
rewritten.close if rewritten
rewritten = nil
end
rewritten
end

def build_scan_info(op, record_exist)
begin
builder = ScanInfoBuilder.new(self, op, record_exist)
Expand Down
22 changes: 22 additions & 0 deletions lib/mrb/scripts/expression_rewriter.rb
@@ -0,0 +1,22 @@
module Groonga
class ExpressionRewriter
class << self
def register(name)
ExpressionRewriters.register(name, self)
end
end

def initialize(expression)
@expression = expression
end

def rewrite
nil
end

private
def context
@context ||= Context.instance
end
end
end
29 changes: 29 additions & 0 deletions lib/mrb/scripts/expression_rewriters.rb
@@ -0,0 +1,29 @@
module Groonga
module ExpressionRewriters
@@rewriters = {}

class << self
def register(name, rewriter_class)
@@rewriters[name] = rewriter_class
end

def classes
rewriters_table = Context.instance["rewriters"]
return [] if rewriters_table.nil?

rewriters_table.collect do |id|
record = Record.new(rewriters_table, id)
name = record.key
rewriter = @@rewriters[name]
if rewriter.nil?
plugin_name = record.plugin_name.value
require plugin_name
rewriter = @@rewriters[name]
raise "unknown rewriter: <#{name}>:<#{plugin_name}>" if rewriter.nil?
end
rewriter
end
end
end
end
end
49 changes: 23 additions & 26 deletions lib/scanner.c
Expand Up @@ -18,41 +18,34 @@

#include "grn_scanner.h"

static void
sis_free(grn_ctx *ctx, scan_info **sis, unsigned int n_sis)
{
int i;
for (i = 0; i < n_sis; i++) {
grn_scan_info_close(ctx, sis[i]);
}
GRN_FREE(sis);
}

grn_scanner *
grn_scanner_open(grn_ctx *ctx,
grn_obj *expr,
grn_operator op,
grn_bool record_exist)
{
grn_scanner *scanner;
scan_info **sis;
unsigned int n_sis;

sis = grn_scan_info_build(ctx, expr, &n_sis, op, record_exist);
if (!sis) {
return NULL;
}

scanner = GRN_MALLOC(sizeof(grn_scanner));
if (!scanner) {
sis_free(ctx, sis, n_sis);
return NULL;
}

scanner->expr = expr;
scanner->rewritten_expr = NULL;
scanner->sis = sis;
scanner->n_sis = n_sis;
scanner->source_expr = expr;
scanner->expr = grn_expr_rewrite(ctx, expr);
if (!scanner->expr) {
scanner->expr = expr;
}

scanner->sis = grn_scan_info_build(ctx,
scanner->expr,
&(scanner->n_sis),
op,
record_exist);
if (!scanner->sis) {
grn_scanner_close(ctx, scanner);
return NULL;
}

return scanner;
}
Expand All @@ -64,12 +57,16 @@ grn_scanner_close(grn_ctx *ctx, grn_scanner *scanner)
return;
}

if (scanner->rewritten_expr) {
grn_obj_close(ctx, scanner->rewritten_expr);
if (scanner->sis) {
int i;
for (i = 0; i < scanner->n_sis; i++) {
grn_scan_info_close(ctx, scanner->sis[i]);
}
GRN_FREE(scanner->sis);
}

if (scanner->sis) {
sis_free(ctx, scanner->sis, scanner->n_sis);
if (scanner->expr != scanner->source_expr) {
grn_obj_close(ctx, scanner->expr);
}

GRN_FREE(scanner);
Expand Down

0 comments on commit 66e87a9

Please sign in to comment.