grn_rc grn_ts_obj_cursor_open(grn_ctx *ctx, grn_obj *obj, grn_ts_cursor **cursor) { grn_ts_obj_cursor *new_cursor; if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!obj || !cursor) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } switch (obj->header.type) { case GRN_CURSOR_TABLE_HASH_KEY: case GRN_CURSOR_TABLE_PAT_KEY: case GRN_CURSOR_TABLE_DAT_KEY: case GRN_CURSOR_TABLE_NO_KEY: { break; } default: { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } } new_cursor = GRN_MALLOCN(grn_ts_obj_cursor, 1); if (!new_cursor) { GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", sizeof(grn_ts_obj_cursor)); } new_cursor->type = GRN_TS_OBJ_CURSOR; new_cursor->obj = obj; *cursor = (grn_ts_cursor *)new_cursor; return GRN_SUCCESS; }
grn_rc grn_ts_expr_parse(grn_ctx *ctx, grn_obj *table, grn_ts_str str, grn_ts_expr **expr) { grn_rc rc; grn_ts_expr *new_expr; grn_ts_expr_parser *parser; if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!table || !grn_ts_obj_is_table(ctx, table) || (!str.ptr && str.size) || !expr) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } rc = grn_ts_expr_parser_open(ctx, table, &parser); if (rc != GRN_SUCCESS) { return rc; } rc = grn_ts_expr_parser_parse(ctx, parser, str, &new_expr); grn_ts_expr_parser_close(ctx, parser); if (rc != GRN_SUCCESS) { return rc; } *expr = new_expr; return GRN_SUCCESS; }
/* * grn_ts_writer_output_body() evaluates expressions and outputs the results. */ static grn_rc grn_ts_writer_output_body(grn_ctx *ctx, grn_ts_writer *writer, const grn_ts_record *in, size_t n_in) { size_t i, j, count = 0; writer->bufs = GRN_MALLOCN(grn_ts_buf, writer->n_exprs); if (!writer->bufs) { GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE, sizeof(grn_ts_buf), writer->n_exprs); } for (i = 0; i < writer->n_exprs; i++) { grn_ts_buf_init(ctx, &writer->bufs[i]); } while (count < n_in) { size_t batch_size = GRN_TS_BATCH_SIZE; if (batch_size > (n_in - count)) { batch_size = n_in - count; } for (i = 0; i < writer->n_exprs; ++i) { grn_rc rc = grn_ts_expr_evaluate_to_buf(ctx, writer->exprs[i], in + count, batch_size, &writer->bufs[i]); if (rc != GRN_SUCCESS) { return rc; } } for (i = 0; i < batch_size; ++i) { GRN_OUTPUT_ARRAY_OPEN("HIT", writer->n_exprs); for (j = 0; j < writer->n_exprs; ++j) { if (j) { GRN_TEXT_PUTC(ctx, ctx->impl->output.buf, ','); } switch (writer->exprs[j]->data_kind) { GRN_TS_WRITER_OUTPUT_BODY_CASE(BOOL, bool); GRN_TS_WRITER_OUTPUT_BODY_CASE(INT, int); GRN_TS_WRITER_OUTPUT_BODY_CASE(FLOAT, float); GRN_TS_WRITER_OUTPUT_BODY_CASE(TIME, time); GRN_TS_WRITER_OUTPUT_BODY_CASE(TEXT, text); GRN_TS_WRITER_OUTPUT_BODY_CASE(GEO, geo); GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(BOOL, bool); GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(INT, int); GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(FLOAT, float); GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TIME, time); GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TEXT, text); GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(GEO, geo); default: { break; } } } GRN_OUTPUT_ARRAY_CLOSE(); /* HITS. */ } count += batch_size; } return GRN_SUCCESS; }
grn_rc grn_ts_cursor_close(grn_ctx *ctx, grn_ts_cursor *cursor) { if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!cursor) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } switch (cursor->type) { case GRN_TS_OBJ_CURSOR: { return grn_ts_obj_cursor_close(ctx, (grn_ts_obj_cursor *)cursor); } default: { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid cursor type: %d", cursor->type); } } }
grn_rc grn_ts_cursor_read(grn_ctx *ctx, grn_ts_cursor *cursor, grn_ts_record *out, size_t max_n_out, size_t *n_out) { if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!cursor || (!out && max_n_out) || !n_out) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } switch (cursor->type) { case GRN_TS_OBJ_CURSOR: { return grn_ts_obj_cursor_read(ctx, (grn_ts_obj_cursor *)cursor, out, max_n_out, n_out); } default: { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid cursor type: %d", cursor->type); } } }
grn_rc grn_ts_expr_close(grn_ctx *ctx, grn_ts_expr *expr) { if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!expr) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } grn_ts_expr_fin(ctx, expr); GRN_FREE(expr); return GRN_SUCCESS; }
/* grn_ts_writer_build() builds output expresions. */ static grn_rc grn_ts_writer_build(grn_ctx *ctx, grn_ts_writer *writer, grn_obj *table) { size_t i, n_names = grn_vector_size(ctx, &writer->name_buf); if (!n_names) { return GRN_SUCCESS; } writer->names = GRN_MALLOCN(grn_ts_str, n_names); if (!writer->names) { GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE, sizeof(grn_ts_str), n_names); } writer->exprs = GRN_MALLOCN(grn_ts_expr *, n_names); if (!writer->exprs) { GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE, sizeof(grn_ts_expr *), n_names); } for (i = 0; i < n_names; i++) { grn_rc rc; grn_ts_expr *new_expr; const char *name_ptr; size_t name_size = grn_vector_get_element(ctx, &writer->name_buf, i, &name_ptr, NULL, NULL); rc = grn_ts_expr_parser_parse(ctx, writer->parser, (grn_ts_str){ name_ptr, name_size }, &new_expr); if (rc != GRN_SUCCESS) { return rc; } writer->names[i].ptr = name_ptr; writer->names[i].size = name_size; writer->exprs[i] = new_expr; writer->n_exprs++; } return GRN_SUCCESS; }
grn_rc grn_ts_expr_adjust(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_record *io, size_t n_io) { if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!expr || (!io && n_io)) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } if (!n_io) { return GRN_SUCCESS; } return grn_ts_expr_node_adjust(ctx, expr->root, io, n_io); }
grn_rc grn_ts_expr_evaluate(grn_ctx *ctx, grn_ts_expr *expr, const grn_ts_record *in, size_t n_in, void *out) { if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!expr || (!in && n_in) || (n_in && !out)) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } if (!n_in) { return GRN_SUCCESS; } return grn_ts_expr_node_evaluate(ctx, expr->root, in, n_in, out); }
grn_rc grn_ts_expr_filter(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_record *in, size_t n_in, grn_ts_record *out, size_t *n_out) { if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!expr || (!in && n_in) || !out || !n_out) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } if (!n_in) { *n_out = 0; return GRN_SUCCESS; } return grn_ts_expr_node_filter(ctx, expr->root, in, n_in, out, n_out); }
grn_rc grn_ts_select(grn_ctx *ctx, grn_obj *table, const char *filter_ptr, size_t filter_len, const char *scorer_ptr, size_t scorer_len, const char *sortby_ptr, size_t sortby_len, const char *output_columns_ptr, size_t output_columns_len, size_t offset, size_t limit) { grn_rc rc; grn_ts_str filter = { filter_ptr, filter_len }; grn_ts_str scorer = { scorer_ptr, scorer_len }; grn_ts_str sortby = { sortby_ptr, sortby_len }; grn_ts_str output_columns = { output_columns_ptr, output_columns_len }; if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!table || !grn_ts_obj_is_table(ctx, table) || (!filter_ptr && filter_len) || (!scorer_ptr && scorer_len) || (!sortby_ptr && sortby_len) || (!output_columns_ptr && output_columns_len)) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } if (sortby_len) { rc = grn_ts_select_with_sortby(ctx, table, filter, scorer, sortby, output_columns, offset, limit); } else { rc = grn_ts_select_without_sortby(ctx, table, filter, scorer, output_columns, offset, limit); } if (rc != GRN_SUCCESS) { GRN_BULK_REWIND(ctx->impl->output.buf); if ((ctx->rc == GRN_SUCCESS) || !ctx->errbuf[0]) { ERR(rc, "error message is missing"); } else if (ctx->errlvl < GRN_LOG_ERROR) { ctx->errlvl = GRN_LOG_ERROR; } } return rc; }
/* grn_ts_obj_cursor_read() reads records from a wrapper cursor. */ static grn_rc grn_ts_obj_cursor_read(grn_ctx *ctx, grn_ts_obj_cursor *cursor, grn_ts_record *recs, size_t max_n_recs, size_t *n_recs) { switch (cursor->obj->header.type) { case GRN_CURSOR_TABLE_HASH_KEY: { GRN_TS_OBJ_CURSOR_READ(hash) } case GRN_CURSOR_TABLE_PAT_KEY: { GRN_TS_OBJ_CURSOR_READ(pat) } case GRN_CURSOR_TABLE_DAT_KEY: { GRN_TS_OBJ_CURSOR_READ(dat) } case GRN_CURSOR_TABLE_NO_KEY: { GRN_TS_OBJ_CURSOR_READ(array) } default: { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } } return GRN_SUCCESS; }
/* grn_ts_writer_open() creates a writer. */ static grn_rc grn_ts_writer_open(grn_ctx *ctx, grn_obj *table, grn_ts_str str, grn_ts_writer **writer) { grn_rc rc; grn_ts_writer *new_writer = GRN_MALLOCN(grn_ts_writer, 1); if (!new_writer) { GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", sizeof(grn_ts_writer)); } grn_ts_writer_init(ctx, new_writer); rc = grn_ts_writer_parse(ctx, new_writer, table, str); if (rc == GRN_SUCCESS) { rc = grn_ts_writer_build(ctx, new_writer, table); } if (rc != GRN_SUCCESS) { grn_ts_writer_fin(ctx, new_writer); GRN_FREE(new_writer); return rc; } *writer = new_writer; return GRN_SUCCESS; }
grn_rc grn_ts_expr_open(grn_ctx *ctx, grn_obj *table, grn_ts_expr_node *root, grn_ts_expr **expr) { grn_rc rc; grn_ts_expr *new_expr; grn_ts_expr_type type; if (!ctx) { return GRN_INVALID_ARGUMENT; } if (!table || !grn_ts_obj_is_table(ctx, table) || !root || !expr) { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } switch (root->type) { case GRN_TS_EXPR_ID_NODE: { type = GRN_TS_EXPR_ID; break; } case GRN_TS_EXPR_SCORE_NODE: { type = GRN_TS_EXPR_SCORE; break; } case GRN_TS_EXPR_KEY_NODE: case GRN_TS_EXPR_VALUE_NODE: { type = GRN_TS_EXPR_VARIABLE; break; } case GRN_TS_EXPR_CONST_NODE: { type = GRN_TS_EXPR_CONST; break; } case GRN_TS_EXPR_COLUMN_NODE: case GRN_TS_EXPR_OP_NODE: case GRN_TS_EXPR_BRIDGE_NODE: { type = GRN_TS_EXPR_VARIABLE; break; } default: { GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); } } new_expr = GRN_MALLOCN(grn_ts_expr, 1); if (!new_expr) { GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %" GRN_FMT_SIZE, sizeof(grn_ts_expr)); } rc = grn_ts_obj_increment_ref_count(ctx, table); if (rc != GRN_SUCCESS) { GRN_FREE(new_expr); return rc; } grn_ts_expr_init(ctx, new_expr); new_expr->table = table; new_expr->type = type; new_expr->data_kind = root->data_kind; new_expr->data_type = root->data_type; new_expr->root = root; *expr = new_expr; return GRN_SUCCESS; }
/* grn_ts_select_with_sortby() executes a select command with --sortby. */ static grn_rc grn_ts_select_with_sortby(grn_ctx *ctx, grn_obj *table, grn_ts_str filter, grn_ts_str scorer, grn_ts_str sortby, grn_ts_str output_columns, size_t offset, size_t limit) { grn_rc rc; grn_ts_record *recs = NULL; size_t n_recs = 0, max_n_recs = 0, n_hits = 0; grn_table_cursor *cursor_obj; grn_ts_cursor *cursor = NULL; grn_ts_expr *filter_expr = NULL; grn_ts_expr *scorer_expr = NULL; grn_ts_sorter *sorter = NULL; cursor_obj = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_ID); if (!cursor_obj) { GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_table_cursor_open failed"); } rc = grn_ts_obj_cursor_open(ctx, cursor_obj, &cursor); if (rc != GRN_SUCCESS) { grn_obj_close(ctx, cursor_obj); return rc; } rc = grn_ts_expr_parse(ctx, table, filter, &filter_expr); if (rc == GRN_SUCCESS) { scorer = grn_ts_str_trim_score_assignment(scorer); if (scorer.size) { rc = grn_ts_expr_parse(ctx, table, scorer, &scorer_expr); } if (rc == GRN_SUCCESS) { rc = grn_ts_sorter_parse(ctx, table, sortby, offset, limit, &sorter); } } if (rc == GRN_SUCCESS) { for ( ; ; ) { size_t batch_size; grn_ts_record *batch; /* Extend a buffer for records. */ if (max_n_recs < (n_recs + GRN_TS_BATCH_SIZE)) { size_t n_bytes, new_max_n_recs = max_n_recs * 2; grn_ts_record *new_recs; if (!new_max_n_recs) { new_max_n_recs = GRN_TS_BATCH_SIZE; } n_bytes = sizeof(grn_ts_record) * new_max_n_recs; new_recs = (grn_ts_record *)GRN_REALLOC(recs, n_bytes); if (!new_recs) { GRN_TS_ERR(GRN_NO_MEMORY_AVAILABLE, "GRN_REALLOC failed: %" GRN_FMT_SIZE, n_bytes); rc = ctx->rc; break; } recs = new_recs; max_n_recs = new_max_n_recs; } /* Read records from a cursor. */ batch = recs + n_recs; rc = grn_ts_cursor_read(ctx, cursor, batch, GRN_TS_BATCH_SIZE, &batch_size); if (rc != GRN_SUCCESS) { break; } else if (!batch_size) { /* Complete sorting. */ rc = grn_ts_sorter_complete(ctx, sorter, recs, n_recs, &n_recs); break; } /* Apply a filter and a scorer. */ rc = grn_ts_expr_filter(ctx, filter_expr, batch, batch_size, batch, &batch_size); if (rc != GRN_SUCCESS) { break; } if (scorer_expr) { rc = grn_ts_expr_adjust(ctx, scorer_expr, batch, batch_size); if (rc != GRN_SUCCESS) { break; } } n_hits += batch_size; n_recs += batch_size; /* Progress sorting. */ rc = grn_ts_sorter_progress(ctx, sorter, recs, n_recs, &n_recs); if (rc != GRN_SUCCESS) { break; } } } if (rc == GRN_SUCCESS) { rc = grn_ts_select_output(ctx, table, output_columns, recs, n_recs, n_hits); } if (cursor) { grn_ts_cursor_close(ctx, cursor); } if (recs) { GRN_FREE(recs); } if (sorter) { grn_ts_sorter_close(ctx, sorter); } if (scorer_expr) { grn_ts_expr_close(ctx, scorer_expr); } if (filter_expr) { grn_ts_expr_close(ctx, filter_expr); } return rc; }
/* grn_ts_writer_output_header() outputs names and data types. */ static grn_rc grn_ts_writer_output_header(grn_ctx *ctx, grn_ts_writer *writer) { grn_rc rc; GRN_OUTPUT_ARRAY_OPEN("COLUMNS", writer->n_exprs); for (size_t i = 0; i < writer->n_exprs; ++i) { GRN_OUTPUT_ARRAY_OPEN("COLUMN", 2); rc = grn_text_esc(ctx, ctx->impl->output.buf, writer->names[i].ptr, writer->names[i].size); if (rc != GRN_SUCCESS) { return rc; } GRN_TEXT_PUT(ctx, ctx->impl->output.buf, ",\"", 2); switch (writer->exprs[i]->data_type) { case GRN_DB_VOID: { if (writer->exprs[i]->data_kind == GRN_TS_GEO) { GRN_TEXT_PUTS(ctx, ctx->impl->output.buf, "GeoPoint"); } else { GRN_TEXT_PUTS(ctx, ctx->impl->output.buf, "Void"); } break; } GRN_TS_WRITER_OUTPUT_HEADER_CASE(BOOL, "Bool") GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT8, "Int8") GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT16, "Int16") GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT32, "Int32") GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT64, "Int64") GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT8, "UInt8") GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT16, "UInt16") GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT32, "UInt32") GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT64, "UInt64") GRN_TS_WRITER_OUTPUT_HEADER_CASE(FLOAT, "Float") GRN_TS_WRITER_OUTPUT_HEADER_CASE(TIME, "Time") GRN_TS_WRITER_OUTPUT_HEADER_CASE(SHORT_TEXT, "ShortText") GRN_TS_WRITER_OUTPUT_HEADER_CASE(TEXT, "Text") GRN_TS_WRITER_OUTPUT_HEADER_CASE(LONG_TEXT, "LongText") GRN_TS_WRITER_OUTPUT_HEADER_CASE(TOKYO_GEO_POINT, "TokyoGeoPoint") GRN_TS_WRITER_OUTPUT_HEADER_CASE(WGS84_GEO_POINT, "WGS84GeoPoint") default: { char name_buf[GRN_TABLE_MAX_KEY_SIZE]; size_t name_size; grn_obj *obj = grn_ctx_at(ctx, writer->exprs[i]->data_type); if (!obj) { GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d", writer->exprs[i]->data_type); } if (!grn_ts_obj_is_table(ctx, obj)) { grn_obj_unlink(ctx, obj); GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d", writer->exprs[i]->data_type); } name_size = grn_obj_name(ctx, obj, name_buf, sizeof(name_buf)); GRN_TEXT_PUT(ctx, ctx->impl->output.buf, name_buf, name_size); grn_obj_unlink(ctx, obj); break; } } GRN_TEXT_PUTC(ctx, ctx->impl->output.buf, '"'); GRN_OUTPUT_ARRAY_CLOSE(); } GRN_OUTPUT_ARRAY_CLOSE(); /* COLUMNS. */ return GRN_SUCCESS; }