/* -*- c-basic-offset: 2 -*- */
/*
Copyright ( C ) 2009 - 2017 Brazil
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License version 2 . 1 as published by the Free Software Foundation .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1335 USA
*/
#include "grn_proc.h"
#include "grn_ctx.h"
#include "grn_ii.h"
#include "grn_db.h"
#include "grn_util.h"
#include "grn_output.h"
#include "grn_pat.h"
#include "grn_geo.h"
#include "grn_expr.h"
#include "grn_cache.h"
#include "grn_load.h"
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef WIN32
# include <io.h>
# include <share.h>
#endif /* WIN32 */
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 0
#endif
/**** globals for procs ****/
const char *grn_document_root = NULL;
#define VAR GRN_PROC_GET_VAR_BY_OFFSET
static double grn_between_too_many_index_match_ratio = 0 .01 ;
static double grn_in_values_too_many_index_match_ratio = 0 .01 ;
void
grn_proc_init_from_env(void )
{
{
char grn_between_too_many_index_match_ratio_env[GRN_ENV_BUFFER_SIZE];
grn_getenv("GRN_BETWEEN_TOO_MANY_INDEX_MATCH_RATIO" ,
grn_between_too_many_index_match_ratio_env,
GRN_ENV_BUFFER_SIZE);
if (grn_between_too_many_index_match_ratio_env[0 ]) {
grn_between_too_many_index_match_ratio =
atof(grn_between_too_many_index_match_ratio_env);
}
}
{
char grn_in_values_too_many_index_match_ratio_env[GRN_ENV_BUFFER_SIZE];
grn_getenv("GRN_IN_VALUES_TOO_MANY_INDEX_MATCH_RATIO" ,
grn_in_values_too_many_index_match_ratio_env,
GRN_ENV_BUFFER_SIZE);
if (grn_in_values_too_many_index_match_ratio_env[0 ]) {
grn_in_values_too_many_index_match_ratio =
atof(grn_in_values_too_many_index_match_ratio_env);
}
}
}
/* bulk must be initialized grn_bulk or grn_msg */
static int
grn_bulk_put_from_file(grn_ctx *ctx, grn_obj *bulk, const char *path)
{
/* FIXME: implement more smartly with grn_bulk */
int fd, ret = 0 ;
struct stat stat;
grn_open(fd, path, O_RDONLY|O_NOFOLLOW|GRN_OPEN_FLAG_BINARY);
if (fd == -1 ) {
switch (errno) {
case EACCES :
ERR(GRN_OPERATION_NOT_PERMITTED, "request is not allowed: <%s>" , path);
break ;
case ENOENT :
ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY, "no such file: <%s>" , path);
break ;
#ifndef WIN32
case ELOOP :
ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY,
"symbolic link is not allowed: <%s>" , path);
break ;
#endif /* WIN32 */
default :
ERRNO_ERR("failed to open file: <%s>" , path);
break ;
}
return 0 ;
}
if (fstat(fd, &stat) != -1 ) {
char *buf, *bp;
off_t rest = stat.st_size;
if ((buf = GRN_MALLOC(rest))) {
ssize_t ss;
for (bp = buf; rest; rest -= ss, bp += ss) {
if ((ss = grn_read(fd, bp, rest)) == -1 ) { goto exit ; }
}
GRN_TEXT_PUT(ctx, bulk, buf, stat.st_size);
ret = 1 ;
}
GRN_FREE(buf);
} else {
ERR(GRN_INVALID_ARGUMENT, "cannot stat file: <%s>" , path);
}
exit :
grn_close(fd);
return ret;
}
#ifdef stat
# undef stat
#endif /* stat */
/**** procs ****/
static grn_obj *
proc_load(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_load_input input;
input.type = grn_plugin_proc_get_var_content_type(ctx,
user_data,
"input_type" ,
-1 ,
GRN_CONTENT_JSON);
#define INIT_STRING_ARGUMENT(member_name, arg_name) \
input.member_name.value = \
grn_plugin_proc_get_var_string(ctx, \
user_data, \
arg_name, \
-1 , \
&(input.member_name.length))
INIT_STRING_ARGUMENT(table, "table" );
INIT_STRING_ARGUMENT(columns, "columns" );
INIT_STRING_ARGUMENT(values, "values" );
INIT_STRING_ARGUMENT(if_exists, "ifexists" );
INIT_STRING_ARGUMENT(each, "each" );
#undef INIT_STRING_ARGUMENT
input.output_ids = grn_plugin_proc_get_var_bool(ctx,
user_data,
"output_ids" , -1 ,
GRN_FALSE);
input.output_errors = grn_plugin_proc_get_var_bool(ctx,
user_data,
"output_errors" , -1 ,
GRN_FALSE);
input.emit_level = 1 ;
grn_load_internal(ctx, &input);
if (ctx->rc == GRN_CANCEL) {
ctx->impl->loader.stat = GRN_LOADER_END;
ctx->impl->loader.rc = GRN_SUCCESS;
}
if (ctx->impl->loader.stat != GRN_LOADER_END &&
!(ctx->impl->command.flags & GRN_CTX_TAIL)) {
grn_obj *command = grn_proc_get_info(ctx, user_data, NULL, NULL, NULL);
grn_ctx_set_keep_command(ctx, command);
} else {
if (ctx->impl->loader.rc != GRN_SUCCESS) {
ctx->rc = ctx->impl->loader.rc;
grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, ctx->impl->loader.errbuf);
}
if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
int n_elements = 1 ;
if (ctx->impl->loader.output_ids) {
n_elements++;
}
if (ctx->impl->loader.output_errors) {
n_elements++;
}
GRN_OUTPUT_MAP_OPEN("result" , n_elements);
GRN_OUTPUT_CSTR("n_loaded_records" );
GRN_OUTPUT_INT64(ctx->impl->loader.nrecords);
if (ctx->impl->loader.output_ids) {
grn_obj *ids = &(ctx->impl->loader.ids);
int i, n_ids;
GRN_OUTPUT_CSTR("loaded_ids" );
n_ids = GRN_BULK_VSIZE(ids) / sizeof (uint32_t);
GRN_OUTPUT_ARRAY_OPEN("loaded_ids" , n_ids);
for (i = 0 ; i < n_ids; i++) {
GRN_OUTPUT_UINT64(GRN_UINT32_VALUE_AT(ids, i));
}
GRN_OUTPUT_ARRAY_CLOSE();
}
if (ctx->impl->loader.output_errors) {
grn_obj *return_codes = &(ctx->impl->loader.return_codes);
grn_obj *error_messages = &(ctx->impl->loader.error_messages);
int i, n;
GRN_OUTPUT_CSTR("errors" );
n = GRN_BULK_VSIZE(return_codes) / sizeof (int32_t);
GRN_OUTPUT_ARRAY_OPEN("errors" , n);
for (i = 0 ; i < n; i++) {
const char *message;
unsigned int message_size;
message_size = grn_vector_get_element(ctx,
error_messages,
i,
&message,
NULL,
NULL);
GRN_OUTPUT_MAP_OPEN("error" , 2 );
GRN_OUTPUT_CSTR("return_code" );
GRN_OUTPUT_INT64(GRN_INT32_VALUE_AT(return_codes, i));
GRN_OUTPUT_CSTR("message" );
if (message_size == 0 ) {
GRN_OUTPUT_NULL();
} else {
GRN_OUTPUT_STR(message, message_size);
}
GRN_OUTPUT_MAP_CLOSE();
}
GRN_OUTPUT_ARRAY_CLOSE();
}
GRN_OUTPUT_MAP_CLOSE();
} else {
GRN_OUTPUT_INT64(ctx->impl->loader.nrecords);
}
if (ctx->impl->loader.table) {
grn_db_touch(ctx, DB_OBJ(ctx->impl->loader.table)->db);
}
grn_ctx_loader_clear(ctx);
}
return NULL;
}
static grn_obj *
proc_status(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_timeval now;
grn_cache *cache;
grn_cache_statistics statistics;
grn_timeval_now(ctx, &now);
cache = grn_cache_current_get(ctx);
grn_cache_get_statistics(ctx, cache, &statistics);
GRN_OUTPUT_MAP_OPEN("RESULT" , 10 );
GRN_OUTPUT_CSTR("alloc_count" );
GRN_OUTPUT_INT32(grn_alloc_count());
GRN_OUTPUT_CSTR("starttime" );
GRN_OUTPUT_INT32(grn_starttime.tv_sec);
GRN_OUTPUT_CSTR("start_time" );
GRN_OUTPUT_INT32(grn_starttime.tv_sec);
GRN_OUTPUT_CSTR("uptime" );
GRN_OUTPUT_INT32(now.tv_sec - grn_starttime.tv_sec);
GRN_OUTPUT_CSTR("version" );
GRN_OUTPUT_CSTR(grn_get_version());
GRN_OUTPUT_CSTR("n_queries" );
GRN_OUTPUT_INT64(statistics.nfetches);
GRN_OUTPUT_CSTR("cache_hit_rate" );
if (statistics.nfetches == 0 ) {
GRN_OUTPUT_FLOAT(0 .0 );
} else {
double cache_hit_rate;
cache_hit_rate = (double )statistics.nhits / (double )statistics.nfetches;
GRN_OUTPUT_FLOAT(cache_hit_rate * 100 .0 );
}
GRN_OUTPUT_CSTR("command_version" );
GRN_OUTPUT_INT32(grn_ctx_get_command_version(ctx));
GRN_OUTPUT_CSTR("default_command_version" );
GRN_OUTPUT_INT32(grn_get_default_command_version());
GRN_OUTPUT_CSTR("max_command_version" );
GRN_OUTPUT_INT32(GRN_COMMAND_VERSION_MAX);
GRN_OUTPUT_MAP_CLOSE();
#ifdef USE_MEMORY_DEBUG
grn_alloc_info_dump(&grn_gctx);
#endif /* USE_MEMORY_DEBUG */
return NULL;
}
#define GRN_STRLEN(s) ((s) ? strlen(s) : 0 )
void
grn_proc_output_object_name(grn_ctx *ctx, grn_obj *obj)
{
grn_obj bulk;
int name_len;
char name[GRN_TABLE_MAX_KEY_SIZE];
if (obj) {
GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY);
name_len = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
GRN_TEXT_SET(ctx, &bulk, name, name_len);
} else {
GRN_VOID_INIT(&bulk);
}
GRN_OUTPUT_OBJ(&bulk, NULL);
GRN_OBJ_FIN(ctx, &bulk);
}
void
grn_proc_output_object_id_name(grn_ctx *ctx, grn_id id)
{
grn_obj *obj = NULL;
if (id != GRN_ID_NIL) {
obj = grn_ctx_at(ctx, id);
}
grn_proc_output_object_name(ctx, obj);
}
static grn_obj *
proc_missing(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
uint32_t plen;
grn_obj *outbuf = ctx->impl->output.buf;
static int grn_document_root_len = -1 ;
if (!grn_document_root) { return NULL; }
if (grn_document_root_len < 0 ) {
size_t l;
if ((l = strlen(grn_document_root)) > PATH_MAX) {
return NULL;
}
grn_document_root_len = (int )l;
if (l > 0 && grn_document_root[l - 1 ] == '/' ) { grn_document_root_len--; }
}
if ((plen = GRN_TEXT_LEN(VAR(0 ))) + grn_document_root_len < PATH_MAX) {
char path[PATH_MAX];
grn_memcpy(path, grn_document_root, grn_document_root_len);
path[grn_document_root_len] = '/' ;
grn_str_url_path_normalize(ctx,
GRN_TEXT_VALUE(VAR(0 )),
GRN_TEXT_LEN(VAR(0 )),
path + grn_document_root_len + 1 ,
PATH_MAX - grn_document_root_len - 1 );
grn_bulk_put_from_file(ctx, outbuf, path);
} else {
uint32_t abbrlen = 32 ;
ERR(GRN_INVALID_ARGUMENT,
"too long path name: <%s/%.*s...> %u(%u)" ,
grn_document_root,
abbrlen < plen ? abbrlen : plen, GRN_TEXT_VALUE(VAR(0 )),
plen + grn_document_root_len, PATH_MAX);
}
return NULL;
}
static grn_obj *
proc_quit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
ctx->stat = GRN_CTX_QUITTING;
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_obj *
proc_shutdown(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
const char *mode;
size_t mode_size;
mode = grn_plugin_proc_get_var_string(ctx, user_data, "mode" , -1 , &mode_size);
#define MODE_EQUAL(name) \
(mode_size == strlen(name) && memcmp(mode, name, mode_size) == 0 )
if (mode_size == 0 || MODE_EQUAL("graceful" )) {
/* Do nothing. This is the default. */
} else if (MODE_EQUAL("immediate" )) {
grn_request_canceler_cancel_all();
if (ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) {
ctx->rc = GRN_SUCCESS;
}
} else {
ERR(GRN_INVALID_ARGUMENT,
"[shutdown] mode must be <graceful> or <immediate>: <%.*s>" ,
(int )mode_size, mode);
}
#undef MODE_EQUAL
if (ctx->rc == GRN_SUCCESS) {
grn_gctx.stat = GRN_CTX_QUIT;
ctx->stat = GRN_CTX_QUITTING;
}
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_obj *
proc_defrag(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj;
int olen, threshold;
olen = GRN_TEXT_LEN(VAR(0 ));
if (olen) {
obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0 )), olen);
} else {
obj = ctx->impl->db;
}
threshold = GRN_TEXT_LEN(VAR(1 ))
? grn_atoi(GRN_TEXT_VALUE(VAR(1 )), GRN_BULK_CURR(VAR(1 )), NULL)
: 0 ;
if (obj) {
grn_obj_defrag(ctx, obj, threshold);
} else {
ERR(GRN_INVALID_ARGUMENT, "defrag object not found" );
}
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_obj *
proc_log_level(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *level_name = VAR(0 );
if (GRN_TEXT_LEN(level_name) > 0 ) {
grn_log_level max_level;
GRN_TEXT_PUTC(ctx, level_name, '\0' );
if (grn_log_level_parse(GRN_TEXT_VALUE(level_name), &max_level)) {
grn_logger_set_max_level(ctx, max_level);
} else {
ERR(GRN_INVALID_ARGUMENT,
"invalid log level: <%s>" , GRN_TEXT_VALUE(level_name));
}
} else {
ERR(GRN_INVALID_ARGUMENT, "log level is missing" );
}
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_obj *
proc_log_put(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *level_name = VAR(0 );
grn_obj *message = VAR(1 );
if (GRN_TEXT_LEN(level_name) > 0 ) {
grn_log_level level;
GRN_TEXT_PUTC(ctx, level_name, '\0' );
if (grn_log_level_parse(GRN_TEXT_VALUE(level_name), &level)) {
GRN_LOG(ctx, level, "%.*s" ,
(int )GRN_TEXT_LEN(message),
GRN_TEXT_VALUE(message));
} else {
ERR(GRN_INVALID_ARGUMENT,
"invalid log level: <%s>" , GRN_TEXT_VALUE(level_name));
}
} else {
ERR(GRN_INVALID_ARGUMENT, "log level is missing" );
}
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_obj *
proc_log_reopen(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_log_reopen(ctx);
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_rc
proc_delete_validate_selector(grn_ctx *ctx, grn_obj *table, grn_obj *table_name,
grn_obj *key, grn_obj *id, grn_obj *filter)
{
grn_rc rc = GRN_SUCCESS;
if (!table) {
rc = GRN_INVALID_ARGUMENT;
ERR(rc,
"[table][record][delete] table doesn't exist: <%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
return rc;
}
if (GRN_TEXT_LEN(key) == 0 &&
GRN_TEXT_LEN(id) == 0 &&
GRN_TEXT_LEN(filter) == 0 ) {
rc = GRN_INVALID_ARGUMENT;
ERR(rc,
"[table][record][delete] either key, id or filter must be specified: "
"table: <%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
return rc;
}
if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
rc = GRN_INVALID_ARGUMENT;
ERR(rc,
"[table][record][delete] "
"record selector must be one of key, id and filter: "
"table: <%.*s>, key: <%.*s>, id: <%.*s>, filter: <%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
(int )GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
(int )GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
(int )GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
return rc;
}
if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter) == 0 ) {
rc = GRN_INVALID_ARGUMENT;
ERR(rc,
"[table][record][delete] "
"can't use both key and id: table: <%.*s>, key: <%.*s>, id: <%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
(int )GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
(int )GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id));
return rc;
}
if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) == 0 && GRN_TEXT_LEN(filter)) {
rc = GRN_INVALID_ARGUMENT;
ERR(rc,
"[table][record][delete] "
"can't use both key and filter: "
"table: <%.*s>, key: <%.*s>, filter: <%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
(int )GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
(int )GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
return rc;
}
if (GRN_TEXT_LEN(key) == 0 && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
rc = GRN_INVALID_ARGUMENT;
ERR(rc,
"[table][record][delete] "
"can't use both id and filter: "
"table: <%.*s>, id: <%.*s>, filter: <%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
(int )GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
(int )GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
return rc;
}
return rc;
}
static grn_obj *
proc_delete(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_rc rc = GRN_INVALID_ARGUMENT;
grn_obj *table_name = VAR(0 );
grn_obj *key = VAR(1 );
grn_obj *id = VAR(2 );
grn_obj *filter = VAR(3 );
grn_obj *table = NULL;
if (GRN_TEXT_LEN(table_name) == 0 ) {
rc = GRN_INVALID_ARGUMENT;
ERR(rc, "[table][record][delete] table name isn't specified" );
goto exit ;
}
table = grn_ctx_get(ctx,
GRN_TEXT_VALUE(table_name),
GRN_TEXT_LEN(table_name));
rc = proc_delete_validate_selector(ctx, table, table_name, key, id, filter);
if (rc != GRN_SUCCESS) { goto exit ; }
if (GRN_TEXT_LEN(key)) {
grn_obj casted_key;
if (key->header.domain != table->header.domain) {
GRN_OBJ_INIT(&casted_key, GRN_BULK, 0 , table->header.domain);
grn_obj_cast(ctx, key, &casted_key, GRN_FALSE);
key = &casted_key;
}
if (ctx->rc) {
rc = ctx->rc;
} else {
rc = grn_table_delete(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key));
if (key == &casted_key) {
GRN_OBJ_FIN(ctx, &casted_key);
}
}
} else if (GRN_TEXT_LEN(id)) {
const char *end;
grn_id parsed_id = grn_atoui(GRN_TEXT_VALUE(id), GRN_BULK_CURR(id), &end);
if (end == GRN_BULK_CURR(id)) {
rc = grn_table_delete_by_id(ctx, table, parsed_id);
} else {
rc = GRN_INVALID_ARGUMENT;
ERR(rc,
"[table][record][delete] id should be number: "
"table: <%.*s>, id: <%.*s>, detail: <%.*s|%c|%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
(int )GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
(int )(end - GRN_TEXT_VALUE(id)), GRN_TEXT_VALUE(id),
end[0 ],
(int )(GRN_TEXT_VALUE(id) - end - 1 ), end + 1 );
}
} else if (GRN_TEXT_LEN(filter)) {
grn_obj *cond, *v;
GRN_EXPR_CREATE_FOR_QUERY(ctx, table, cond, v);
grn_expr_parse(ctx, cond,
GRN_TEXT_VALUE(filter),
GRN_TEXT_LEN(filter),
NULL, GRN_OP_MATCH, GRN_OP_AND,
GRN_EXPR_SYNTAX_SCRIPT);
if (ctx->rc) {
rc = ctx->rc;
ERR(rc,
"[table][record][delete] failed to parse filter: "
"table: <%.*s>, filter: <%.*s>, detail: <%s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
(int )GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter),
ctx->errbuf);
} else {
grn_obj *records;
records = grn_table_select(ctx, table, cond, NULL, GRN_OP_OR);
if (records) {
GRN_TABLE_EACH_BEGIN(ctx, records, cursor, result_id) {
void *key;
grn_id id;
grn_rc sub_rc;
if (grn_table_cursor_get_key(ctx, cursor, &key) == 0 ) {
continue ;
}
id = *(grn_id *)key;
sub_rc = grn_table_delete_by_id(ctx, table, id);
if (rc == GRN_SUCCESS) {
rc = sub_rc;
}
if (ctx->rc == GRN_CANCEL) {
break ;
}
if (ctx->rc != GRN_SUCCESS) {
ERRCLR(ctx);
}
} GRN_TABLE_EACH_END(ctx, cursor);
grn_obj_unlink(ctx, records);
}
}
grn_obj_unlink(ctx, cond);
}
exit :
if (table) {
grn_obj_unlink(ctx, table);
}
GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
return NULL;
}
grn_bool
grn_proc_option_value_bool(grn_ctx *ctx,
grn_obj *option,
grn_bool default_value)
{
const char *value;
size_t value_length;
if (!option) {
return default_value;
}
value = GRN_TEXT_VALUE(option);
value_length = GRN_TEXT_LEN(option);
if (value_length == 0 ) {
return default_value;
}
if (value_length == strlen("yes" ) &&
strncmp(value, "yes" , value_length) == 0 ) {
return GRN_TRUE;
} else if (value_length == strlen("no" ) &&
strncmp(value, "no" , value_length) == 0 ) {
return GRN_FALSE;
} else {
return default_value;
}
}
int32_t
grn_proc_option_value_int32(grn_ctx *ctx,
grn_obj *option,
int32_t default_value)
{
const char *value;
size_t value_length;
int32_t int32_value;
const char *rest;
if (!option) {
return default_value;
}
value = GRN_TEXT_VALUE(option);
value_length = GRN_TEXT_LEN(option);
if (value_length == 0 ) {
return default_value;
}
int32_value = grn_atoi(value, value + value_length, &rest);
if (rest == value + value_length) {
return int32_value;
} else {
return default_value;
}
}
const char *
grn_proc_option_value_string(grn_ctx *ctx,
grn_obj *option,
size_t *size)
{
const char *value;
size_t value_length;
if (!option) {
if (size) {
*size = 0 ;
}
return NULL;
}
value = GRN_TEXT_VALUE(option);
value_length = GRN_TEXT_LEN(option);
if (size) {
*size = value_length;
}
if (value_length == 0 ) {
return NULL;
} else {
return value;
}
}
grn_content_type
grn_proc_option_value_content_type(grn_ctx *ctx,
grn_obj *option,
grn_content_type default_value)
{
if (!option) {
return default_value;
}
return grn_content_type_parse(ctx, option, default_value);
}
static grn_obj *
proc_cache_limit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_cache *cache;
unsigned int current_max_n_entries;
cache = grn_cache_current_get(ctx);
current_max_n_entries = grn_cache_get_max_n_entries(ctx, cache);
if (GRN_TEXT_LEN(VAR(0 ))) {
const char *rest;
uint32_t max = grn_atoui(GRN_TEXT_VALUE(VAR(0 )),
GRN_BULK_CURR(VAR(0 )), &rest);
if (GRN_BULK_CURR(VAR(0 )) == rest) {
grn_cache_set_max_n_entries(ctx, cache, max);
} else {
ERR(GRN_INVALID_ARGUMENT,
"max value is invalid unsigned integer format: <%.*s>" ,
(int )GRN_TEXT_LEN(VAR(0 )), GRN_TEXT_VALUE(VAR(0 )));
}
}
if (ctx->rc == GRN_SUCCESS) {
GRN_OUTPUT_INT64(current_max_n_entries);
}
return NULL;
}
static grn_obj *
proc_register(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
if (GRN_TEXT_LEN(VAR(0 ))) {
const char *name;
GRN_TEXT_PUTC(ctx, VAR(0 ), '\0' );
name = GRN_TEXT_VALUE(VAR(0 ));
grn_plugin_register(ctx, name);
} else {
ERR(GRN_INVALID_ARGUMENT, "path is required" );
}
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
void grn_ii_buffer_check(grn_ctx *ctx, grn_ii *ii, uint32_t seg);
static grn_obj *
proc_check(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0 )), GRN_TEXT_LEN(VAR(0 )));
if (!obj) {
ERR(GRN_INVALID_ARGUMENT,
"no such object: <%.*s>" , (int )GRN_TEXT_LEN(VAR(0 )), GRN_TEXT_VALUE(VAR(0 )));
GRN_OUTPUT_BOOL(!ctx->rc);
} else {
switch (obj->header.type) {
case GRN_DB :
GRN_OUTPUT_BOOL(!ctx->rc);
break ;
case GRN_TABLE_PAT_KEY :
grn_pat_check(ctx, (grn_pat *)obj);
break ;
case GRN_TABLE_HASH_KEY :
grn_hash_check(ctx, (grn_hash *)obj);
break ;
case GRN_TABLE_DAT_KEY :
case GRN_TABLE_NO_KEY :
case GRN_COLUMN_FIX_SIZE :
GRN_OUTPUT_BOOL(!ctx->rc);
break ;
case GRN_COLUMN_VAR_SIZE :
grn_ja_check(ctx, (grn_ja *)obj);
break ;
case GRN_COLUMN_INDEX :
{
grn_ii *ii = (grn_ii *)obj;
struct grn_ii_header *h = ii->header;
char buf[8 ];
GRN_OUTPUT_ARRAY_OPEN("RESULT" , 8 );
{
uint32_t i, j, g =0 , a = 0 , b = 0 ;
uint32_t max = 0 ;
for (i = h->bgqtail; i != h->bgqhead; i = ((i + 1 ) & (GRN_II_BGQSIZE - 1 ))) {
j = h->bgqbody[i];
g++;
if (j > max) { max = j; }
}
for (i = 0 ; i < GRN_II_MAX_LSEG; i++) {
j = h->binfo[i];
if (j != GRN_II_PSEG_NOT_ASSIGNED) {
if (j > max) { max = j; }
b++;
}
}
for (i = 0 ; i < GRN_II_MAX_LSEG; i++) {
j = h->ainfo[i];
if (j != GRN_II_PSEG_NOT_ASSIGNED) {
if (j > max) { max = j; }
a++;
}
}
GRN_OUTPUT_MAP_OPEN("SUMMARY" , 12 );
GRN_OUTPUT_CSTR("flags" );
grn_itoh(h->flags, buf, 8 );
GRN_OUTPUT_STR(buf, 8 );
GRN_OUTPUT_CSTR("max sid" );
GRN_OUTPUT_INT64(h->smax);
GRN_OUTPUT_CSTR("number of garbage segments" );
GRN_OUTPUT_INT64(g);
GRN_OUTPUT_CSTR("number of array segments" );
GRN_OUTPUT_INT64(a);
GRN_OUTPUT_CSTR("max id of array segment" );
GRN_OUTPUT_INT64(h->amax);
GRN_OUTPUT_CSTR("number of buffer segments" );
GRN_OUTPUT_INT64(b);
GRN_OUTPUT_CSTR("max id of buffer segment" );
GRN_OUTPUT_INT64(h->bmax);
GRN_OUTPUT_CSTR("max id of physical segment in use" );
GRN_OUTPUT_INT64(max);
GRN_OUTPUT_CSTR("number of unmanaged segments" );
GRN_OUTPUT_INT64(h->pnext - a - b - g);
GRN_OUTPUT_CSTR("total chunk size" );
GRN_OUTPUT_INT64(h->total_chunk_size);
for (max = 0 , i = 0 ; i < (GRN_II_MAX_CHUNK >> 3 ); i++) {
if ((j = h->chunks[i])) {
int k;
for (k = 0 ; k < 8 ; k++) {
if ((j & (1 << k))) { max = (i << 3 ) + j; }
}
}
}
GRN_OUTPUT_CSTR("max id of chunk segments in use" );
GRN_OUTPUT_INT64(max);
GRN_OUTPUT_CSTR("number of garbage chunk" );
GRN_OUTPUT_ARRAY_OPEN("NGARBAGES" , GRN_II_N_CHUNK_VARIATION);
for (i = 0 ; i <= GRN_II_N_CHUNK_VARIATION; i++) {
GRN_OUTPUT_INT64(h->ngarbages[i]);
}
GRN_OUTPUT_ARRAY_CLOSE();
GRN_OUTPUT_MAP_CLOSE();
for (i = 0 ; i < GRN_II_MAX_LSEG; i++) {
if (h->binfo[i] < 0 x20000) { grn_ii_buffer_check(ctx, ii, i); }
}
}
GRN_OUTPUT_ARRAY_CLOSE();
}
break ;
}
}
return NULL;
}
static grn_obj *
proc_truncate(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
const char *target_name;
int target_name_len;
target_name_len = GRN_TEXT_LEN(VAR(0 ));
if (target_name_len > 0 ) {
target_name = GRN_TEXT_VALUE(VAR(0 ));
} else {
target_name_len = GRN_TEXT_LEN(VAR(1 ));
if (target_name_len == 0 ) {
ERR(GRN_INVALID_ARGUMENT, "[truncate] table name is missing" );
goto exit ;
}
target_name = GRN_TEXT_VALUE(VAR(1 ));
}
{
grn_obj *target = grn_ctx_get(ctx, target_name, target_name_len);
if (!target) {
ERR(GRN_INVALID_ARGUMENT,
"[truncate] no such target: <%.*s>" , target_name_len, target_name);
goto exit ;
}
switch (target->header.type) {
case GRN_TABLE_HASH_KEY :
case GRN_TABLE_PAT_KEY :
case GRN_TABLE_DAT_KEY :
case GRN_TABLE_NO_KEY :
grn_table_truncate(ctx, target);
break ;
case GRN_COLUMN_FIX_SIZE :
case GRN_COLUMN_VAR_SIZE :
case GRN_COLUMN_INDEX :
grn_column_truncate(ctx, target);
break ;
default :
{
grn_obj buffer;
GRN_TEXT_INIT(&buffer, 0 );
grn_inspect(ctx, &buffer, target);
ERR(GRN_INVALID_ARGUMENT,
"[truncate] not a table nor column object: <%.*s>" ,
(int )GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
GRN_OBJ_FIN(ctx, &buffer);
}
break ;
}
}
exit :
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static int
parse_normalize_flags(grn_ctx *ctx, grn_obj *flag_names)
{
int flags = 0 ;
const char *names, *names_end;
int length;
names = GRN_TEXT_VALUE(flag_names);
length = GRN_TEXT_LEN(flag_names);
names_end = names + length;
while (names < names_end) {
if (*names == '|' || *names == ' ' ) {
names += 1 ;
continue ;
}
#define CHECK_FLAG(name)\
if (((unsigned long ) (names_end - names) >= (unsigned long ) (sizeof (#name ) - 1 )) && \
(!memcmp(names, #name , sizeof (#name ) - 1 ))) {\
flags |= GRN_STRING_ ## name;\
names += sizeof (#name ) - 1 ;\
continue ;\
}
CHECK_FLAG(REMOVE_BLANK);
CHECK_FLAG(WITH_TYPES);
CHECK_FLAG(WITH_CHECKS);
CHECK_FLAG(REMOVE_TOKENIZED_DELIMITER);
#define GRN_STRING_NONE 0
CHECK_FLAG(NONE);
#undef GRN_STRING_NONE
ERR(GRN_INVALID_ARGUMENT, "[normalize] invalid flag: <%.*s>" ,
(int )(names_end - names), names);
return 0 ;
#undef CHECK_FLAG
}
return flags;
}
static grn_bool
is_normalizer(grn_ctx *ctx, grn_obj *object)
{
if (object->header.type != GRN_PROC) {
return GRN_FALSE;
}
if (grn_proc_get_type(ctx, object) != GRN_PROC_NORMALIZER) {
return GRN_FALSE;
}
return GRN_TRUE;
}
static const char *
char_type_name(grn_char_type type)
{
const char *name = "unknown" ;
#define CHAR_TYPE_NAME_WITH_BLANK(type_name) do { \
if (GRN_CHAR_IS_BLANK(type)) { \
name = type_name "|blank" ; \
} else { \
name = type_name; \
} \
} while (GRN_FALSE)
switch (GRN_CHAR_TYPE(type)) {
case GRN_CHAR_NULL :
CHAR_TYPE_NAME_WITH_BLANK("null" );
break ;
case GRN_CHAR_ALPHA :
CHAR_TYPE_NAME_WITH_BLANK("alpha" );
break ;
case GRN_CHAR_DIGIT :
CHAR_TYPE_NAME_WITH_BLANK("digit" );
break ;
case GRN_CHAR_SYMBOL :
CHAR_TYPE_NAME_WITH_BLANK("symbol" );
break ;
case GRN_CHAR_HIRAGANA :
CHAR_TYPE_NAME_WITH_BLANK("hiragana" );
break ;
case GRN_CHAR_KATAKANA :
CHAR_TYPE_NAME_WITH_BLANK("katakana" );
break ;
case GRN_CHAR_KANJI :
CHAR_TYPE_NAME_WITH_BLANK("kanji" );
break ;
case GRN_CHAR_OTHERS :
CHAR_TYPE_NAME_WITH_BLANK("others" );
break ;
default :
CHAR_TYPE_NAME_WITH_BLANK("unknown" );
break ;
}
#undef CHAR_TYPE_NAME_WITH_BLANK
return name;
}
static grn_obj *
proc_normalize(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *normalizer_name;
grn_obj *string;
grn_obj *flag_names;
normalizer_name = VAR(0 );
string = VAR(1 );
flag_names = VAR(2 );
if (GRN_TEXT_LEN(normalizer_name) == 0 ) {
ERR(GRN_INVALID_ARGUMENT, "normalizer name is missing" );
return NULL;
}
{
grn_obj *normalizer;
grn_obj *grn_string;
int flags;
unsigned int normalized_length_in_bytes;
unsigned int normalized_n_characters;
flags = parse_normalize_flags(ctx, flag_names);
normalizer = grn_ctx_get(ctx,
GRN_TEXT_VALUE(normalizer_name),
GRN_TEXT_LEN(normalizer_name));
if (!normalizer) {
ERR(GRN_INVALID_ARGUMENT,
"[normalize] nonexistent normalizer: <%.*s>" ,
(int )GRN_TEXT_LEN(normalizer_name),
GRN_TEXT_VALUE(normalizer_name));
return NULL;
}
if (!is_normalizer(ctx, normalizer)) {
grn_obj inspected;
GRN_TEXT_INIT(&inspected, 0 );
grn_inspect(ctx, &inspected, normalizer);
ERR(GRN_INVALID_ARGUMENT,
"[normalize] not normalizer: %.*s" ,
(int )GRN_TEXT_LEN(&inspected),
GRN_TEXT_VALUE(&inspected));
GRN_OBJ_FIN(ctx, &inspected);
grn_obj_unlink(ctx, normalizer);
return NULL;
}
grn_string = grn_string_open(ctx,
GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
normalizer, flags);
grn_obj_unlink(ctx, normalizer);
GRN_OUTPUT_MAP_OPEN("RESULT" , 3 );
{
const char *normalized;
grn_string_get_normalized(ctx, grn_string,
&normalized,
&normalized_length_in_bytes,
&normalized_n_characters);
GRN_OUTPUT_CSTR("normalized" );
GRN_OUTPUT_STR(normalized, normalized_length_in_bytes);
}
{
const unsigned char *types;
types = grn_string_get_types(ctx, grn_string);
GRN_OUTPUT_CSTR("types" );
if (types) {
unsigned int i;
GRN_OUTPUT_ARRAY_OPEN("types" , normalized_n_characters);
for (i = 0 ; i < normalized_n_characters; i++) {
GRN_OUTPUT_CSTR(char_type_name(types[i]));
}
GRN_OUTPUT_ARRAY_CLOSE();
} else {
GRN_OUTPUT_ARRAY_OPEN("types" , 0 );
GRN_OUTPUT_ARRAY_CLOSE();
}
}
{
const short *checks;
checks = grn_string_get_checks(ctx, grn_string);
GRN_OUTPUT_CSTR("checks" );
if (checks) {
unsigned int i;
GRN_OUTPUT_ARRAY_OPEN("checks" , normalized_length_in_bytes);
for (i = 0 ; i < normalized_length_in_bytes; i++) {
GRN_OUTPUT_INT32(checks[i]);
}
GRN_OUTPUT_ARRAY_CLOSE();
} else {
GRN_OUTPUT_ARRAY_OPEN("checks" , 0 );
GRN_OUTPUT_ARRAY_CLOSE();
}
}
GRN_OUTPUT_MAP_CLOSE();
grn_obj_unlink(ctx, grn_string);
}
return NULL;
}
static void
list_proc(grn_ctx *ctx, grn_proc_type target_proc_type,
const char *name, const char *plural_name)
{
grn_obj *db;
grn_table_cursor *cursor;
grn_obj target_procs;
db = grn_ctx_db(ctx);
cursor = grn_table_cursor_open(ctx, db, NULL, 0 , NULL, 0 , 0 , -1 ,
GRN_CURSOR_BY_ID);
if (!cursor) {
return ;
}
GRN_PTR_INIT(&target_procs, GRN_OBJ_VECTOR, GRN_ID_NIL);
{
grn_id id;
while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
grn_obj *obj;
grn_proc_type proc_type;
obj = grn_ctx_at(ctx, id);
if (!obj) {
continue ;
}
if (obj->header.type != GRN_PROC) {
grn_obj_unlink(ctx, obj);
continue ;
}
proc_type = grn_proc_get_type(ctx, obj);
if (proc_type != target_proc_type) {
grn_obj_unlink(ctx, obj);
continue ;
}
GRN_PTR_PUT(ctx, &target_procs, obj);
}
grn_table_cursor_close(ctx, cursor);
{
int i, n_procs;
n_procs = GRN_BULK_VSIZE(&target_procs) / sizeof (grn_obj *);
GRN_OUTPUT_ARRAY_OPEN(plural_name, n_procs);
for (i = 0 ; i < n_procs; i++) {
grn_obj *proc;
char name[GRN_TABLE_MAX_KEY_SIZE];
int name_size;
proc = GRN_PTR_VALUE_AT(&target_procs, i);
name_size = grn_obj_name(ctx, proc, name, GRN_TABLE_MAX_KEY_SIZE);
GRN_OUTPUT_MAP_OPEN(name, 1 );
GRN_OUTPUT_CSTR("name" );
GRN_OUTPUT_STR(name, name_size);
GRN_OUTPUT_MAP_CLOSE();
grn_obj_unlink(ctx, proc);
}
GRN_OUTPUT_ARRAY_CLOSE();
}
grn_obj_unlink(ctx, &target_procs);
}
}
static grn_obj *
proc_tokenizer_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
list_proc(ctx, GRN_PROC_TOKENIZER, "tokenizer" , "tokenizers" );
return NULL;
}
static grn_obj *
proc_normalizer_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
list_proc(ctx, GRN_PROC_NORMALIZER, "normalizer" , "normalizers" );
return NULL;
}
static grn_obj *
func_rand(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
int val;
grn_obj *obj;
if (nargs > 0 ) {
int max = GRN_INT32_VALUE(args[0 ]);
val = (int ) (1 .0 * max * rand() / (RAND_MAX + 1 .0 ));
} else {
val = rand();
}
if ((obj = GRN_PROC_ALLOC(GRN_DB_INT32, 0 ))) {
GRN_INT32_SET(ctx, obj, val);
}
return obj;
}
static grn_obj *
func_now(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj;
if ((obj = GRN_PROC_ALLOC(GRN_DB_TIME, 0 ))) {
GRN_TIME_NOW(ctx, obj);
}
return obj;
}
static inline grn_bool
is_comparable_number_type(grn_id type)
{
return GRN_DB_INT8 <= type && type <= GRN_DB_TIME;
}
static inline grn_id
larger_number_type(grn_id type1, grn_id type2)
{
if (type1 == type2) {
return type1;
}
switch (type1) {
case GRN_DB_FLOAT :
return type1;
case GRN_DB_TIME :
if (type2 == GRN_DB_FLOAT) {
return type2;
} else {
return type1;
}
default :
if (type2 > type1) {
return type2;
} else {
return type1;
}
}
}
static inline grn_id
smaller_number_type(grn_id type1, grn_id type2)
{
if (type1 == type2) {
return type1;
}
switch (type1) {
case GRN_DB_FLOAT :
return type1;
case GRN_DB_TIME :
if (type2 == GRN_DB_FLOAT) {
return type2;
} else {
return type1;
}
default :
{
grn_id smaller_number_type;
if (type2 > type1) {
smaller_number_type = type2;
} else {
smaller_number_type = type1;
}
switch (smaller_number_type) {
case GRN_DB_UINT8 :
return GRN_DB_INT8;
case GRN_DB_UINT16 :
return GRN_DB_INT16;
case GRN_DB_UINT32 :
return GRN_DB_INT32;
case GRN_DB_UINT64 :
return GRN_DB_INT64;
default :
return smaller_number_type;
}
}
}
}
static inline grn_bool
is_negative_value(grn_obj *number)
{
switch (number->header.domain) {
case GRN_DB_INT8 :
return GRN_INT8_VALUE(number) < 0 ;
case GRN_DB_INT16 :
return GRN_INT16_VALUE(number) < 0 ;
case GRN_DB_INT32 :
return GRN_INT32_VALUE(number) < 0 ;
case GRN_DB_INT64 :
return GRN_INT64_VALUE(number) < 0 ;
case GRN_DB_TIME :
return GRN_TIME_VALUE(number) < 0 ;
case GRN_DB_FLOAT :
return GRN_FLOAT_VALUE(number) < 0 ;
default :
return GRN_FALSE;
}
}
static inline grn_bool
number_safe_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, grn_id type)
{
grn_obj_reinit(ctx, dest, type, 0 );
if (src->header.domain == type) {
GRN_TEXT_SET(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
return GRN_TRUE;
}
switch (type) {
case GRN_DB_UINT8 :
if (is_negative_value(src)) {
GRN_UINT8_SET(ctx, dest, 0 );
return GRN_TRUE;
}
break ;
case GRN_DB_UINT16 :
if (is_negative_value(src)) {
GRN_UINT16_SET(ctx, dest, 0 );
return GRN_TRUE;
}
break ;
case GRN_DB_UINT32 :
if (is_negative_value(src)) {
GRN_UINT32_SET(ctx, dest, 0 );
return GRN_TRUE;
}
break ;
case GRN_DB_UINT64 :
if (is_negative_value(src)) {
GRN_UINT64_SET(ctx, dest, 0 );
return GRN_TRUE;
}
break ;
}
return grn_obj_cast(ctx, src, dest, GRN_FALSE) == GRN_SUCCESS;
}
static inline int
compare_number(grn_ctx *ctx, grn_obj *number1, grn_obj *number2, grn_id type)
{
#define COMPARE_AND_RETURN(type, value1, value2)\
{\
type computed_value1 = value1;\
type computed_value2 = value2;\
if (computed_value1 > computed_value2) {\
return 1 ;\
} else if (computed_value1 < computed_value2) {\
return -1 ;\
} else {\
return 0 ;\
}\
}
switch (type) {
case GRN_DB_INT8 :
COMPARE_AND_RETURN(int8_t,
GRN_INT8_VALUE(number1),
GRN_INT8_VALUE(number2));
case GRN_DB_UINT8 :
COMPARE_AND_RETURN(uint8_t,
GRN_UINT8_VALUE(number1),
GRN_UINT8_VALUE(number2));
case GRN_DB_INT16 :
COMPARE_AND_RETURN(int16_t,
GRN_INT16_VALUE(number1),
GRN_INT16_VALUE(number2));
case GRN_DB_UINT16 :
COMPARE_AND_RETURN(uint16_t,
GRN_UINT16_VALUE(number1),
GRN_UINT16_VALUE(number2));
case GRN_DB_INT32 :
COMPARE_AND_RETURN(int32_t,
GRN_INT32_VALUE(number1),
GRN_INT32_VALUE(number2));
case GRN_DB_UINT32 :
COMPARE_AND_RETURN(uint32_t,
GRN_UINT32_VALUE(number1),
GRN_UINT32_VALUE(number2));
case GRN_DB_INT64 :
COMPARE_AND_RETURN(int64_t,
GRN_INT64_VALUE(number1),
GRN_INT64_VALUE(number2));
case GRN_DB_UINT64 :
COMPARE_AND_RETURN(uint64_t,
GRN_UINT64_VALUE(number1),
GRN_UINT64_VALUE(number2));
case GRN_DB_FLOAT :
COMPARE_AND_RETURN(double ,
GRN_FLOAT_VALUE(number1),
GRN_FLOAT_VALUE(number2));
case GRN_DB_TIME :
COMPARE_AND_RETURN(int64_t,
GRN_TIME_VALUE(number1),
GRN_TIME_VALUE(number2));
default :
return 0 ;
}
#undef COMPARE_AND_RETURN
}
inline static void
get_number_in_grn_uvector(grn_ctx *ctx, grn_obj *uvector, unsigned int offset,
grn_obj *buf)
{
#define GET_UVECTOR_ELEMENT_AS(type) do { \
GRN_ ## type ## _SET(ctx, \
buf, \
GRN_ ## type ## _VALUE_AT(uvector, offset)); \
} while (GRN_FALSE)
switch (uvector->header.domain) {
case GRN_DB_BOOL :
GET_UVECTOR_ELEMENT_AS(BOOL );
break ;
case GRN_DB_INT8 :
GET_UVECTOR_ELEMENT_AS(INT8);
break ;
case GRN_DB_UINT8 :
GET_UVECTOR_ELEMENT_AS(UINT8);
break ;
case GRN_DB_INT16 :
GET_UVECTOR_ELEMENT_AS(INT16);
break ;
case GRN_DB_UINT16 :
GET_UVECTOR_ELEMENT_AS(UINT16);
break ;
case GRN_DB_INT32 :
GET_UVECTOR_ELEMENT_AS(INT32);
break ;
case GRN_DB_UINT32 :
GET_UVECTOR_ELEMENT_AS(UINT32);
break ;
case GRN_DB_INT64 :
GET_UVECTOR_ELEMENT_AS(INT64);
break ;
case GRN_DB_UINT64 :
GET_UVECTOR_ELEMENT_AS(UINT64);
break ;
case GRN_DB_FLOAT :
GET_UVECTOR_ELEMENT_AS(FLOAT );
break ;
case GRN_DB_TIME :
GET_UVECTOR_ELEMENT_AS(TIME);
break ;
default :
GET_UVECTOR_ELEMENT_AS(RECORD);
break ;
}
#undef GET_UVECTOR_ELEMENT_AS
}
inline static void
apply_max(grn_ctx *ctx, grn_obj *number, grn_obj *max,
grn_obj *casted_number, grn_obj *casted_max, grn_id cast_type)
{
grn_id domain = number->header.domain;
if (!is_comparable_number_type(domain)) {
return ;
}
cast_type = larger_number_type(cast_type, domain);
if (!number_safe_cast(ctx, number, casted_number, cast_type)) {
return ;
}
if (max->header.domain == GRN_DB_VOID) {
grn_obj_reinit(ctx, max, cast_type, 0 );
GRN_TEXT_SET(ctx, max,
GRN_TEXT_VALUE(casted_number),
GRN_TEXT_LEN(casted_number));
return ;
}
if (max->header.domain != cast_type) {
if (!number_safe_cast(ctx, max, casted_max, cast_type)) {
return ;
}
grn_obj_reinit(ctx, max, cast_type, 0 );
GRN_TEXT_SET(ctx, max,
GRN_TEXT_VALUE(casted_max),
GRN_TEXT_LEN(casted_max));
}
if (compare_number(ctx, casted_number, max, cast_type) > 0 ) {
grn_obj_reinit(ctx, max, cast_type, 0 );
GRN_TEXT_SET(ctx, max,
GRN_TEXT_VALUE(casted_number),
GRN_TEXT_LEN(casted_number));
}
}
static grn_obj *
func_max(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *max;
grn_id cast_type = GRN_DB_INT8;
grn_obj casted_max, casted_number;
int i;
max = GRN_PROC_ALLOC(GRN_DB_VOID, 0 );
if (!max) {
return max;
}
GRN_VOID_INIT(&casted_max);
GRN_VOID_INIT(&casted_number);
for (i = 0 ; i < nargs; i++) {
switch (args[i]->header.type) {
case GRN_BULK :
apply_max(ctx, args[i], max, &casted_number, &casted_max, cast_type);
break ;
case GRN_UVECTOR :
{
unsigned int j;
unsigned int n_elements;
grn_obj number_in_uvector;
grn_obj *domain;
domain = grn_ctx_at(ctx, args[i]->header.domain);
GRN_OBJ_INIT(&number_in_uvector, GRN_BULK, 0 , args[i]->header.domain);
n_elements = grn_uvector_size(ctx, args[i]);
for (j = 0 ; j < n_elements; j++) {
get_number_in_grn_uvector(ctx, args[i], j, &number_in_uvector);
if (grn_obj_is_table(ctx, domain)) {
grn_obj_reinit(ctx, &number_in_uvector, domain->header.domain, 0 );
grn_table_get_key2(ctx, domain,
GRN_RECORD_VALUE(&number_in_uvector),
&number_in_uvector);
}
apply_max(ctx, &number_in_uvector, max, &casted_number, &casted_max, cast_type);
}
GRN_OBJ_FIN(ctx, &number_in_uvector);
}
break ;
default :
continue ;
}
}
GRN_OBJ_FIN(ctx, &casted_max);
GRN_OBJ_FIN(ctx, &casted_number);
return max;
}
static void
apply_min(grn_ctx *ctx, grn_obj *number, grn_obj *min,
grn_obj *casted_number, grn_obj *casted_min, grn_id cast_type)
{
grn_id domain = number->header.domain;
if (!is_comparable_number_type(domain)) {
return ;
}
cast_type = smaller_number_type(cast_type, domain);
if (!number_safe_cast(ctx, number, casted_number, cast_type)) {
return ;
}
if (min->header.domain == GRN_DB_VOID) {
grn_obj_reinit(ctx, min, cast_type, 0 );
GRN_TEXT_SET(ctx, min,
GRN_TEXT_VALUE(casted_number),
GRN_TEXT_LEN(casted_number));
return ;
}
if (min->header.domain != cast_type) {
if (!number_safe_cast(ctx, min, casted_min, cast_type)) {
return ;
}
grn_obj_reinit(ctx, min, cast_type, 0 );
GRN_TEXT_SET(ctx, min,
GRN_TEXT_VALUE(casted_min),
GRN_TEXT_LEN(casted_min));
}
if (compare_number(ctx, casted_number, min, cast_type) < 0 ) {
grn_obj_reinit(ctx, min, cast_type, 0 );
GRN_TEXT_SET(ctx, min,
GRN_TEXT_VALUE(casted_number),
GRN_TEXT_LEN(casted_number));
}
}
static grn_obj *
func_min(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *min;
grn_id cast_type = GRN_DB_INT8;
grn_obj casted_min, casted_number;
int i;
min = GRN_PROC_ALLOC(GRN_DB_VOID, 0 );
if (!min) {
return min;
}
GRN_VOID_INIT(&casted_min);
GRN_VOID_INIT(&casted_number);
for (i = 0 ; i < nargs; i++) {
switch (args[i]->header.type) {
case GRN_BULK :
apply_min(ctx, args[i], min, &casted_number, &casted_min, cast_type);
break ;
case GRN_UVECTOR :
{
unsigned int j;
unsigned int n_elements;
grn_obj number_in_uvector;
grn_obj *domain;
domain = grn_ctx_at(ctx, args[i]->header.domain);
GRN_OBJ_INIT(&number_in_uvector, GRN_BULK, 0 , args[i]->header.domain);
n_elements = grn_uvector_size(ctx, args[i]);
for (j = 0 ; j < n_elements; j++) {
get_number_in_grn_uvector(ctx, args[i], j, &number_in_uvector);
if (grn_obj_is_table(ctx, domain)) {
grn_obj_reinit(ctx, &number_in_uvector, domain->header.domain, 0 );
grn_table_get_key2(ctx, domain,
GRN_RECORD_VALUE(&number_in_uvector),
&number_in_uvector);
}
apply_min(ctx, &number_in_uvector, min, &casted_number, &casted_min, cast_type);
}
GRN_OBJ_FIN(ctx, &number_in_uvector);
}
break ;
default :
continue ;
}
}
GRN_OBJ_FIN(ctx, &casted_min);
GRN_OBJ_FIN(ctx, &casted_number);
return min;
}
static grn_obj *
func_geo_in_circle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj;
grn_bool r = GRN_FALSE;
grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
switch (nargs) {
case 4 :
if (grn_geo_resolve_approximate_type(ctx, args[3 ], &type) != GRN_SUCCESS) {
break ;
}
/* fallthru */
case 3 :
r = grn_geo_in_circle(ctx, args[0 ], args[1 ], args[2 ], type);
break ;
default :
break ;
}
if ((obj = GRN_PROC_ALLOC(GRN_DB_BOOL, 0 ))) {
GRN_BOOL_SET(ctx, obj, r);
}
return obj;
}
static grn_obj *
func_geo_in_rectangle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj;
grn_bool r = GRN_FALSE;
if (nargs == 3 ) {
r = grn_geo_in_rectangle(ctx, args[0 ], args[1 ], args[2 ]);
}
if ((obj = GRN_PROC_ALLOC(GRN_DB_BOOL, 0 ))) {
GRN_BOOL_SET(ctx, obj, r);
}
return obj;
}
static grn_obj *
func_geo_distance(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj;
double d = 0 .0 ;
grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
switch (nargs) {
case 3 :
if (grn_geo_resolve_approximate_type(ctx, args[2 ], &type) != GRN_SUCCESS) {
break ;
}
/* fallthru */
case 2 :
d = grn_geo_distance(ctx, args[0 ], args[1 ], type);
break ;
default :
break ;
}
if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0 ))) {
GRN_FLOAT_SET(ctx, obj, d);
}
return obj;
}
/* deprecated. */
static grn_obj *
func_geo_distance2(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj;
double d = 0 ;
if (nargs == 2 ) {
d = grn_geo_distance_sphere(ctx, args[0 ], args[1 ]);
}
if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0 ))) {
GRN_FLOAT_SET(ctx, obj, d);
}
return obj;
}
/* deprecated. */
static grn_obj *
func_geo_distance3(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *obj;
double d = 0 ;
if (nargs == 2 ) {
d = grn_geo_distance_ellipsoid(ctx, args[0 ], args[1 ]);
}
if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0 ))) {
GRN_FLOAT_SET(ctx, obj, d);
}
return obj;
}
static grn_obj *
func_all_records(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
grn_obj *true_value;
if ((true_value = GRN_PROC_ALLOC(GRN_DB_BOOL, 0 ))) {
GRN_BOOL_SET(ctx, true_value, GRN_TRUE);
}
return true_value;
}
static grn_rc
selector_all_records(grn_ctx *ctx, grn_obj *table, grn_obj *index,
int nargs, grn_obj **args,
grn_obj *res, grn_operator op)
{
grn_posting posting;
memset(&posting, 0 , sizeof (grn_posting));
GRN_TABLE_EACH(ctx, table, 0 , 0 , id, NULL, NULL, NULL, {
posting.rid = id;
grn_ii_posting_add(ctx, &posting, (grn_hash *)res, GRN_OP_OR);
});
return ctx->rc;
}
typedef struct {
grn_obj *found;
grn_obj *table;
grn_obj *records;
} selector_to_function_data;
static grn_bool
selector_to_function_data_init(grn_ctx *ctx,
selector_to_function_data *data,
grn_user_data *user_data)
{
grn_obj *condition = NULL;
grn_obj *variable;
data->table = NULL;
data->records = NULL;
data->found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0 );
if (!data->found) {
return GRN_FALSE;
}
GRN_BOOL_SET(ctx, data->found, GRN_FALSE);
grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
if (!condition) {
return GRN_FALSE;
}
variable = grn_expr_get_var_by_offset(ctx, condition, 0 );
if (!variable) {
return GRN_FALSE;
}
data->table = grn_ctx_at(ctx, variable->header.domain);
if (!data->table) {
return GRN_FALSE;
}
data->records = grn_table_create(ctx, NULL, 0 , NULL,
GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
data->table, NULL);
if (!data->records) {
return GRN_FALSE;
}
{
grn_rset_posinfo pi;
unsigned int key_size;
memset(&pi, 0 , sizeof (grn_rset_posinfo));
pi.rid = GRN_RECORD_VALUE(variable);
key_size = ((grn_hash *)(data->records))->key_size;
if (grn_table_add(ctx, data->records, &pi, key_size, NULL) == GRN_ID_NIL) {
return GRN_FALSE;
}
}
return GRN_TRUE;
}
static void
selector_to_function_data_selected(grn_ctx *ctx,
selector_to_function_data *data)
{
GRN_BOOL_SET(ctx, data->found, grn_table_size(ctx, data->records) > 0 );
}
static void
selector_to_function_data_fin(grn_ctx *ctx,
selector_to_function_data *data)
{
if (data->records) {
grn_obj_unlink(ctx, data->records);
}
}
grn_operator
grn_proc_option_value_mode(grn_ctx *ctx,
grn_obj *option,
grn_operator default_mode,
const char *context)
{
if (option->header.domain != GRN_DB_TEXT) {
grn_obj inspected;
GRN_TEXT_INIT(&inspected, 0 );
grn_inspect(ctx, &inspected, option);
GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
"%s: mode must be text: <%.*s>" ,
context,
(int )GRN_TEXT_LEN(&inspected),
GRN_TEXT_VALUE(&inspected));
GRN_OBJ_FIN(ctx, &inspected);
return GRN_OP_NOP;
}
if (GRN_TEXT_LEN(option) == 0 ) {
return default_mode;
}
#define EQUAL_MODE(name) \
(GRN_TEXT_LEN(option) == strlen(name) && \
memcmp(GRN_TEXT_VALUE(option), name, strlen(name)) == 0 )
if (EQUAL_MODE("==" ) || EQUAL_MODE("EQUAL" )) {
return GRN_OP_EQUAL;
} else if (EQUAL_MODE("!=" ) || EQUAL_MODE("NOT_EQUAL" )) {
return GRN_OP_NOT_EQUAL;
} else if (EQUAL_MODE("<" ) || EQUAL_MODE("LESS" )) {
return GRN_OP_LESS;
} else if (EQUAL_MODE(">" ) || EQUAL_MODE("GREATER" )) {
return GRN_OP_GREATER;
} else if (EQUAL_MODE("<=" ) || EQUAL_MODE("LESS_EQUAL" )) {
return GRN_OP_LESS_EQUAL;
} else if (EQUAL_MODE(">=" ) || EQUAL_MODE("GREATER_EQUAL" )) {
return GRN_OP_GREATER_EQUAL;
} else if (EQUAL_MODE("@" ) || EQUAL_MODE("MATCH" )) {
return GRN_OP_MATCH;
} else if (EQUAL_MODE("*N" ) || EQUAL_MODE("NEAR" )) {
return GRN_OP_NEAR;
} else if (EQUAL_MODE("*S" ) || EQUAL_MODE("SIMILAR" )) {
return GRN_OP_SIMILAR;
} else if (EQUAL_MODE("^" ) || EQUAL_MODE("@^" ) || EQUAL_MODE("PREFIX" )) {
return GRN_OP_PREFIX;
} else if (EQUAL_MODE("$" ) || EQUAL_MODE("@$" ) || EQUAL_MODE("SUFFIX" )) {
return GRN_OP_SUFFIX;
} else if (EQUAL_MODE("~" ) || EQUAL_MODE("@~" ) || EQUAL_MODE("REGEXP" )) {
return GRN_OP_REGEXP;
} else {
GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
"%s: mode must be one of them: "
"["
"\" ==\", \" EQUAL\", "
"\" !=\", \" NOT_EQUAL\", "
"\" <\", \" LESS\", "
"\" >\", \" GREATER\", "
"\" <=\", \" LESS_EQUAL\", "
"\" >=\", \" GREATER_EQUAL\", "
"\" @\", \" MATCH\", "
"\" *N\", \" NEAR\", "
"\" *S\", \" SIMILAR\", "
"\" ^\", \" @^\", \" PREFIX\", "
"\" $\", \" @$\", \" SUFFIX\", "
"\" ~\", \" @~\", \" REGEXP\""
"]: <%.*s>" ,
context,
(int )GRN_TEXT_LEN(option),
GRN_TEXT_VALUE(option));
return GRN_OP_NOP;
}
#undef EQUAL_MODE
}
static grn_rc
run_query(grn_ctx *ctx, grn_obj *table,
int nargs, grn_obj **args,
grn_obj *res, grn_operator op)
{
grn_rc rc = GRN_SUCCESS;
grn_obj *match_columns_string;
grn_obj *query;
grn_obj *query_expander_name = NULL;
grn_operator default_mode = GRN_OP_MATCH;
grn_expr_flags flags = GRN_EXPR_SYNTAX_QUERY;
grn_bool flags_specified = GRN_FALSE;
grn_obj *match_columns = NULL;
grn_obj *condition = NULL;
grn_obj *dummy_variable;
if (!(2 <= nargs && nargs <= 3 )) {
ERR(GRN_INVALID_ARGUMENT,
"query(): wrong number of arguments (%d for 2..3)" , nargs);
rc = ctx->rc;
goto exit ;
}
match_columns_string = args[0 ];
query = args[1 ];
if (nargs > 2 ) {
grn_obj *options = args[2 ];
switch (options->header.type) {
case GRN_BULK :
query_expander_name = options;
break ;
case GRN_TABLE_HASH_KEY :
{
grn_hash_cursor *cursor;
void *key;
grn_obj *value;
int key_size;
cursor = grn_hash_cursor_open(ctx, (grn_hash *)options,
NULL, 0 , NULL, 0 ,
0 , -1 , 0 );
if (!cursor) {
GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
"query(): failed to open cursor for options" );
rc = ctx->rc;
goto exit ;
}
while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
grn_hash_cursor_get_key_value(ctx, cursor, &key, &key_size,
(void **)&value);
#define KEY_EQUAL(name) \
(key_size == strlen(name) && memcmp(key, name, strlen(name)) == 0 )
if (KEY_EQUAL("expander" )) {
query_expander_name = value;
} else if (KEY_EQUAL("default_mode" )) {
default_mode = grn_proc_option_value_mode(ctx,
value,
GRN_OP_MATCH,
"query()" );
if (ctx->rc != GRN_SUCCESS) {
grn_hash_cursor_close(ctx, cursor);
rc = ctx->rc;
goto exit ;
}
} else if (KEY_EQUAL("flags" )) {
flags_specified = GRN_TRUE;
flags |= grn_proc_expr_query_flags_parse(ctx,
GRN_TEXT_VALUE(value),
GRN_TEXT_LEN(value),
"query()" );
if (ctx->rc != GRN_SUCCESS) {
grn_hash_cursor_close(ctx, cursor);
rc = ctx->rc;
goto exit ;
}
} else {
GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
"query(): unknown option name: <%.*s>" ,
key_size, (char *)key);
grn_hash_cursor_close(ctx, cursor);
rc = ctx->rc;
goto exit ;
}
#undef KEY_EQUAL
}
grn_hash_cursor_close(ctx, cursor);
}
break ;
default :
{
grn_obj inspected;
GRN_TEXT_INIT(&inspected, 0 );
grn_inspect(ctx, &inspected, options);
GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
"query(): "
"3rd argument must be string or object literal: <%.*s>" ,
(int )GRN_TEXT_LEN(&inspected),
GRN_TEXT_VALUE(&inspected));
GRN_OBJ_FIN(ctx, &inspected);
}
rc = ctx->rc;
goto exit ;
}
}
if (!flags_specified) {
flags |= GRN_EXPR_ALLOW_PRAGMA | GRN_EXPR_ALLOW_COLUMN;
}
if (match_columns_string->header.domain == GRN_DB_TEXT &&
GRN_TEXT_LEN(match_columns_string) > 0 ) {
GRN_EXPR_CREATE_FOR_QUERY(ctx, table, match_columns, dummy_variable);
if (!match_columns) {
rc = ctx->rc;
goto exit ;
}
grn_expr_parse(ctx, match_columns,
GRN_TEXT_VALUE(match_columns_string),
GRN_TEXT_LEN(match_columns_string),
NULL, GRN_OP_MATCH, GRN_OP_AND,
GRN_EXPR_SYNTAX_SCRIPT);
if (ctx->rc != GRN_SUCCESS) {
rc = ctx->rc;
goto exit ;
}
}
if (query->header.domain == GRN_DB_TEXT && GRN_TEXT_LEN(query) > 0 ) {
const char *query_string;
unsigned int query_string_len;
grn_obj expanded_query;
GRN_EXPR_CREATE_FOR_QUERY(ctx, table, condition, dummy_variable);
if (!condition) {
rc = ctx->rc;
goto exit ;
}
query_string = GRN_TEXT_VALUE(query);
query_string_len = GRN_TEXT_LEN(query);
GRN_TEXT_INIT(&expanded_query, 0 );
if (query_expander_name &&
query_expander_name->header.domain == GRN_DB_TEXT &&
GRN_TEXT_LEN(query_expander_name) > 0 ) {
rc = grn_proc_syntax_expand_query(ctx,
query_string, query_string_len,
flags,
GRN_TEXT_VALUE(query_expander_name),
GRN_TEXT_LEN(query_expander_name),
NULL, 0 ,
NULL, 0 ,
&expanded_query,
"[query]" );
if (rc != GRN_SUCCESS) {
GRN_OBJ_FIN(ctx, &expanded_query);
goto exit ;
}
query_string = GRN_TEXT_VALUE(&expanded_query);
query_string_len = GRN_TEXT_LEN(&expanded_query);
}
grn_expr_parse(ctx, condition,
query_string,
query_string_len,
match_columns, default_mode, GRN_OP_AND, flags);
rc = ctx->rc;
GRN_OBJ_FIN(ctx, &expanded_query);
if (rc != GRN_SUCCESS) {
goto exit ;
}
grn_table_select(ctx, table, condition, res, op);
rc = ctx->rc;
}
exit :
if (match_columns) {
grn_obj_unlink(ctx, match_columns);
}
if (condition) {
grn_obj_unlink(ctx, condition);
}
return rc;
}
static grn_obj *
func_query(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
selector_to_function_data data;
if (selector_to_function_data_init(ctx, &data, user_data)) {
grn_rc rc;
rc = run_query(ctx, data.table, nargs, args, data.records, GRN_OP_AND);
if (rc == GRN_SUCCESS) {
selector_to_function_data_selected(ctx, &data);
}
}
selector_to_function_data_fin(ctx, &data);
return data.found;
}
static grn_rc
selector_query(grn_ctx *ctx, grn_obj *table, grn_obj *index,
int nargs, grn_obj **args,
grn_obj *res, grn_operator op)
{
return run_query(ctx, table, nargs - 1 , args + 1 , res, op);
}
static grn_rc
run_sub_filter(grn_ctx *ctx, grn_obj *table,
int nargs, grn_obj **args,
grn_obj *res, grn_operator op)
{
grn_rc rc = GRN_SUCCESS;
grn_obj *scope;
grn_obj *sub_filter_string;
grn_obj *scope_domain = NULL;
grn_obj *sub_filter = NULL;
grn_obj *dummy_variable = NULL;
if (nargs != 2 ) {
ERR(GRN_INVALID_ARGUMENT,
"sub_filter(): wrong number of arguments (%d for 2)" , nargs);
rc = ctx->rc;
goto exit ;
}
scope = args[0 ];
sub_filter_string = args[1 ];
switch (scope->header.type) {
case GRN_ACCESSOR :
case GRN_COLUMN_FIX_SIZE :
case GRN_COLUMN_VAR_SIZE :
case GRN_COLUMN_INDEX :
break ;
default :
/* TODO: put inspected the 1st argument to message */
ERR(GRN_INVALID_ARGUMENT,
"sub_filter(): the 1st argument must be column or accessor" );
rc = ctx->rc;
goto exit ;
break ;
}
scope_domain = grn_ctx_at(ctx, grn_obj_get_range(ctx, scope));
if (sub_filter_string->header.domain != GRN_DB_TEXT) {
/* TODO: put inspected the 2nd argument to message */
ERR(GRN_INVALID_ARGUMENT,
"sub_filter(): the 2nd argument must be String" );
rc = ctx->rc;
goto exit ;
}
if (GRN_TEXT_LEN(sub_filter_string) == 0 ) {
ERR(GRN_INVALID_ARGUMENT,
"sub_filter(): the 2nd argument must not be empty String" );
rc = ctx->rc;
goto exit ;
}
GRN_EXPR_CREATE_FOR_QUERY(ctx, scope_domain, sub_filter, dummy_variable);
if (!sub_filter) {
rc = ctx->rc;
goto exit ;
}
grn_expr_parse(ctx, sub_filter,
GRN_TEXT_VALUE(sub_filter_string),
GRN_TEXT_LEN(sub_filter_string),
NULL, GRN_OP_MATCH, GRN_OP_AND,
GRN_EXPR_SYNTAX_SCRIPT);
if (ctx->rc != GRN_SUCCESS) {
rc = ctx->rc;
goto exit ;
}
{
grn_obj *base_res = NULL;
base_res = grn_table_create(ctx, NULL, 0 , NULL,
GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
scope_domain, NULL);
grn_table_select(ctx, scope_domain, sub_filter, base_res, GRN_OP_OR);
if (scope->header.type == GRN_ACCESSOR) {
rc = grn_accessor_resolve(ctx, scope, -1 , base_res, res, op);
} else {
grn_accessor accessor;
accessor.header.type = GRN_ACCESSOR;
accessor.obj = scope;
accessor.action = GRN_ACCESSOR_GET_COLUMN_VALUE;
accessor.next = NULL;
rc = grn_accessor_resolve(ctx, (grn_obj *)&accessor, -1 , base_res,
res, op);
}
grn_obj_unlink(ctx, base_res);
}
exit :
if (scope_domain) {
grn_obj_unlink(ctx, scope_domain);
}
if (sub_filter) {
grn_obj_unlink(ctx, sub_filter);
}
return rc;
}
static grn_rc
selector_sub_filter(grn_ctx *ctx, grn_obj *table, grn_obj *index,
int nargs, grn_obj **args,
grn_obj *res, grn_operator op)
{
return run_sub_filter(ctx, table, nargs - 1 , args + 1 , res, op);
}
static grn_obj *
func_html_untag(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
grn_obj *html_arg;
int html_arg_domain;
grn_obj html;
grn_obj *text;
const char *html_raw;
int i, length;
grn_bool in_tag = GRN_FALSE;
if (nargs != 1 ) {
ERR(GRN_INVALID_ARGUMENT, "HTML is missing" );
return NULL;
}
html_arg = args[0 ];
html_arg_domain = html_arg->header.domain;
switch (html_arg_domain) {
case GRN_DB_SHORT_TEXT :
case GRN_DB_TEXT :
case GRN_DB_LONG_TEXT :
GRN_VALUE_VAR_SIZE_INIT(&html, GRN_OBJ_DO_SHALLOW_COPY, html_arg_domain);
GRN_TEXT_SET(ctx, &html, GRN_TEXT_VALUE(html_arg), GRN_TEXT_LEN(html_arg));
break ;
default :
GRN_TEXT_INIT(&html, 0 );
if (grn_obj_cast(ctx, html_arg, &html, GRN_FALSE)) {
grn_obj inspected;
GRN_TEXT_INIT(&inspected, 0 );
grn_inspect(ctx, &inspected, html_arg);
ERR(GRN_INVALID_ARGUMENT, "failed to cast to text: <%.*s>" ,
(int )GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
GRN_OBJ_FIN(ctx, &inspected);
GRN_OBJ_FIN(ctx, &html);
return NULL;
}
break ;
}
text = GRN_PROC_ALLOC(html.header.domain, 0 );
if (!text) {
GRN_OBJ_FIN(ctx, &html);
return NULL;
}
html_raw = GRN_TEXT_VALUE(&html);
length = GRN_TEXT_LEN(&html);
for (i = 0 ; i < length; i++) {
switch (html_raw[i]) {
case '<' :
in_tag = GRN_TRUE;
break ;
case '>' :
if (in_tag) {
in_tag = GRN_FALSE;
} else {
GRN_TEXT_PUTC(ctx, text, html_raw[i]);
}
break ;
default :
if (!in_tag) {
GRN_TEXT_PUTC(ctx, text, html_raw[i]);
}
break ;
}
}
GRN_OBJ_FIN(ctx, &html);
return text;
}
static grn_bool
grn_text_equal_cstr(grn_ctx *ctx, grn_obj *text, const char *cstr)
{
int cstr_len;
cstr_len = strlen(cstr);
return (GRN_TEXT_LEN(text) == cstr_len &&
strncmp(GRN_TEXT_VALUE(text), cstr, cstr_len) == 0 );
}
typedef enum {
BETWEEN_BORDER_INVALID,
BETWEEN_BORDER_INCLUDE,
BETWEEN_BORDER_EXCLUDE
} between_border_type;
typedef struct {
grn_obj *value;
grn_obj *min;
grn_obj casted_min;
between_border_type min_border_type;
grn_obj *max;
grn_obj casted_max;
between_border_type max_border_type;
} between_data;
static void
between_data_init(grn_ctx *ctx, between_data *data)
{
GRN_VOID_INIT(&(data->casted_min));
GRN_VOID_INIT(&(data->casted_max));
}
static void
between_data_fin(grn_ctx *ctx, between_data *data)
{
GRN_OBJ_FIN(ctx, &(data->casted_min));
GRN_OBJ_FIN(ctx, &(data->casted_max));
}
static between_border_type
between_parse_border(grn_ctx *ctx, grn_obj *border,
const char *argument_description)
{
grn_obj inspected;
/* TODO: support other text types */
if (border->header.domain == GRN_DB_TEXT) {
if (grn_text_equal_cstr(ctx, border, "include" )) {
return BETWEEN_BORDER_INCLUDE;
} else if (grn_text_equal_cstr(ctx, border, "exclude" )) {
return BETWEEN_BORDER_EXCLUDE;
}
}
GRN_TEXT_INIT(&inspected, 0 );
grn_inspect(ctx, &inspected, border);
ERR(GRN_INVALID_ARGUMENT,
"between(): %s must be \" include\" or \" exclude\": <%.*s>" ,
argument_description,
(int )GRN_TEXT_LEN(&inspected),
GRN_TEXT_VALUE(&inspected));
grn_obj_unlink(ctx, &inspected);
return BETWEEN_BORDER_INVALID;
}
static grn_rc
between_cast(grn_ctx *ctx, grn_obj *source, grn_obj *destination, grn_id domain,
const char *target_argument_name)
{
grn_rc rc;
GRN_OBJ_INIT(destination, GRN_BULK, 0 , domain);
rc = grn_obj_cast(ctx, source, destination, GRN_FALSE);
if (rc != GRN_SUCCESS) {
grn_obj inspected_source;
grn_obj *domain_object;
char domain_name[GRN_TABLE_MAX_KEY_SIZE];
int domain_name_length;
GRN_TEXT_INIT(&inspected_source, 0 );
grn_inspect(ctx, &inspected_source, source);
domain_object = grn_ctx_at(ctx, domain);
domain_name_length =
grn_obj_name(ctx, domain_object, domain_name, GRN_TABLE_MAX_KEY_SIZE);
ERR(rc, "between(): failed to cast %s: <%.*s> -> <%.*s>" ,
target_argument_name,
(int )GRN_TEXT_LEN(&inspected_source),
GRN_TEXT_VALUE(&inspected_source),
domain_name_length,
domain_name);
grn_obj_unlink(ctx, &inspected_source);
grn_obj_unlink(ctx, domain_object);
}
return rc;
}
static grn_rc
between_parse_args(grn_ctx *ctx, int nargs, grn_obj **args, between_data *data)
{
grn_rc rc = GRN_SUCCESS;
grn_obj *min_border;
grn_obj *max_border;
if (nargs != 5 ) {
ERR(GRN_INVALID_ARGUMENT,
"between(): wrong number of arguments (%d for 5)" , nargs);
rc = ctx->rc;
goto exit ;
}
data->value = args[0 ];
data->min = args[1 ];
min_border = args[2 ];
data->max = args[3 ];
max_border = args[4 ];
data->min_border_type =
between_parse_border(ctx, min_border, "the 3rd argument (min_border)" );
if (data->min_border_type == BETWEEN_BORDER_INVALID) {
rc = ctx->rc;
goto exit ;
}
data->max_border_type =
between_parse_border(ctx, max_border, "the 5th argument (max_border)" );
if (data->max_border_type == BETWEEN_BORDER_INVALID) {
rc = ctx->rc;
goto exit ;
}
{
grn_id value_type;
switch (data->value->header.type) {
case GRN_BULK :
value_type = data->value->header.domain;
break ;
case GRN_COLUMN_INDEX :
{
grn_obj *domain_object;
domain_object = grn_ctx_at(ctx, data->value->header.domain);
value_type = domain_object->header.domain;
}
break ;
default :
value_type = grn_obj_get_range(ctx, data->value);
break ;
}
if (value_type != data->min->header.domain) {
rc = between_cast(ctx, data->min, &data->casted_min, value_type, "min" );
if (rc != GRN_SUCCESS) {
goto exit ;
}
data->min = &(data->casted_min);
}
if (value_type != data->max->header.domain) {
rc = between_cast(ctx, data->max, &data->casted_max, value_type, "max" );
if (rc != GRN_SUCCESS) {
goto exit ;
}
data->max = &(data->casted_max);
}
}
exit :
return rc;
}
static grn_bool
between_create_expr(grn_ctx *ctx, grn_obj *table, between_data *data,
grn_obj **expr, grn_obj **variable)
{
GRN_EXPR_CREATE_FOR_QUERY(ctx, table, *expr, *variable);
if (!*expr) {
return GRN_FALSE;
}
if (data->value->header.type == GRN_BULK) {
grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_PUSH, 1 );
} else {
grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_GET_VALUE, 1 );
}
grn_expr_append_obj(ctx, *expr, data->min, GRN_OP_PUSH, 1 );
if (data->min_border_type == BETWEEN_BORDER_INCLUDE) {
grn_expr_append_op(ctx, *expr, GRN_OP_GREATER_EQUAL, 2 );
} else {
grn_expr_append_op(ctx, *expr, GRN_OP_GREATER, 2 );
}
if (data->value->header.type == GRN_BULK) {
grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_PUSH, 1 );
} else {
grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_GET_VALUE, 1 );
}
grn_expr_append_obj(ctx, *expr, data->max, GRN_OP_PUSH, 1 );
if (data->max_border_type == BETWEEN_BORDER_INCLUDE) {
grn_expr_append_op(ctx, *expr, GRN_OP_LESS_EQUAL, 2 );
} else {
grn_expr_append_op(ctx, *expr, GRN_OP_LESS, 2 );
}
grn_expr_append_op(ctx, *expr, GRN_OP_AND, 2 );
return GRN_TRUE;
}
static grn_obj *
func_between(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_rc rc = GRN_SUCCESS;
grn_obj *found;
between_data data;
grn_obj *condition = NULL;
grn_obj *variable;
grn_obj *table = NULL;
grn_obj *between_expr;
grn_obj *between_variable;
grn_obj *result;
found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0 );
if (!found) {
return NULL;
}
GRN_BOOL_SET(ctx, found, GRN_FALSE);
grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
if (!condition) {
return found;
}
variable = grn_expr_get_var_by_offset(ctx, condition, 0 );
if (!variable) {
return found;
}
between_data_init(ctx, &data);
rc = between_parse_args(ctx, nargs, args, &data);
if (rc != GRN_SUCCESS) {
goto exit ;
}
table = grn_ctx_at(ctx, variable->header.domain);
if (!table) {
goto exit ;
}
if (!between_create_expr(ctx, table, &data, &between_expr, &between_variable)) {
goto exit ;
}
GRN_RECORD_SET(ctx, between_variable, GRN_RECORD_VALUE(variable));
result = grn_expr_exec(ctx, between_expr, 0 );
if (grn_obj_is_true(ctx, result)) {
GRN_BOOL_SET(ctx, found, GRN_TRUE);
}
grn_obj_unlink(ctx, between_expr);
grn_obj_unlink(ctx, table);
exit :
between_data_fin(ctx, &data);
if (table) {
grn_obj_unlink(ctx, table);
}
return found;
}
static grn_bool
selector_between_sequential_search_should_use(grn_ctx *ctx,
grn_obj *table,
grn_obj *index,
grn_obj *index_table,
between_data *data,
grn_obj *res,
grn_operator op,
double too_many_index_match_ratio)
{
int n_index_keys;
if (too_many_index_match_ratio < 0 .0 ) {
return GRN_FALSE;
}
if (op != GRN_OP_AND) {
return GRN_FALSE;
}
if (!index) {
return GRN_FALSE;
}
if (index->header.flags & GRN_OBJ_WITH_WEIGHT) {
return GRN_FALSE;
}
if (data->value->header.type == GRN_COLUMN_INDEX) {
return GRN_FALSE;
}
n_index_keys = grn_table_size(ctx, index_table);
if (n_index_keys == 0 ) {
return GRN_FALSE;
}
switch (index_table->header.domain) {
/* TODO: */
/* case GRN_DB_INT8 : */
/* case GRN_DB_UINT8 : */
/* case GRN_DB_INT16 : */
/* case GRN_DB_UINT16 : */
/* case GRN_DB_INT32 : */
/* case GRN_DB_UINT32 : */
/* case GRN_DB_INT64 : */
/* case GRN_DB_UINT64 : */
/* case GRN_DB_FLOAT : */
case GRN_DB_TIME :
break ;
default :
return GRN_FALSE;
}
{
grn_table_cursor *cursor;
long long int all_min;
long long int all_max;
cursor = grn_table_cursor_open(ctx, index_table,
NULL, -1 ,
NULL, -1 ,
0 , 1 ,
GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING);
if (!cursor) {
return GRN_FALSE;
}
if (grn_table_cursor_next(ctx, cursor) == GRN_ID_NIL) {
grn_table_cursor_close(ctx, cursor);
return GRN_FALSE;
}
{
long long int *key;
grn_table_cursor_get_key(ctx, cursor, (void **)&key);
all_min = *key;
}
grn_table_cursor_close(ctx, cursor);
cursor = grn_table_cursor_open(ctx, index_table,
NULL, 0 , NULL, 0 ,
0 , 1 ,
GRN_CURSOR_BY_KEY | GRN_CURSOR_DESCENDING);
if (!cursor) {
return GRN_FALSE;
}
if (grn_table_cursor_next(ctx, cursor) == GRN_ID_NIL) {
grn_table_cursor_close(ctx, cursor);
return GRN_FALSE;
}
{
long long int *key;
grn_table_cursor_get_key(ctx, cursor, (void **)&key);
all_max = *key;
}
grn_table_cursor_close(ctx, cursor);
/*
* We assume the following :
* * homogeneous index key distribution .
* * each index key matches only 1 record .
* TODO : Improve me .
*/
{
int n_existing_records;
int n_indexed_records;
long long int all_difference;
long long int argument_difference;
n_existing_records = grn_table_size(ctx, res);
all_difference = all_max - all_min;
if (all_difference <= 0 ) {
return GRN_FALSE;
}
argument_difference =
GRN_TIME_VALUE(data->max) - GRN_TIME_VALUE(data->min);
if (argument_difference <= 0 ) {
return GRN_FALSE;
}
n_indexed_records =
n_index_keys * ((double )argument_difference / (double )all_difference);
/*
* Same as :
* ( ( n_existing_record / n_indexed_records ) > too_many_index_match_ratio )
*/
if (n_existing_records > (n_indexed_records * too_many_index_match_ratio)) {
return GRN_FALSE;
}
}
}
return GRN_TRUE;
}
static grn_rc
selector_between_sequential_search(grn_ctx *ctx,
grn_obj *table,
between_data *data,
grn_obj *res,
grn_operator op)
{
{
int offset = 0 ;
int limit = -1 ;
int flags = 0 ;
grn_obj *target_table;
grn_obj *target_column;
grn_operator_exec_func *greater;
grn_operator_exec_func *less;
grn_table_cursor *cursor;
grn_id id;
grn_obj value;
if (op == GRN_OP_AND) {
target_table = res;
} else {
target_table = table;
}
cursor = grn_table_cursor_open(ctx, target_table,
NULL, 0 ,
NULL, 0 ,
offset, limit, flags);
if (!cursor) {
return ctx->rc;
}
if (data->value->header.type == GRN_BULK) {
target_column = grn_obj_column(ctx,
table,
GRN_TEXT_VALUE(data->value),
GRN_TEXT_LEN(data->value));
} else {
target_column = data->value;
}
if (data->min_border_type == BETWEEN_BORDER_INCLUDE) {
greater = grn_operator_exec_greater_equal;
} else {
greater = grn_operator_exec_greater;
}
if (data->max_border_type == BETWEEN_BORDER_INCLUDE) {
less = grn_operator_exec_less_equal;
} else {
less = grn_operator_exec_less;
}
GRN_VOID_INIT(&value);
while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
grn_id record_id;
if (target_table == res) {
grn_id *key;
grn_table_cursor_get_key(ctx, cursor, (void **)&key);
record_id = *key;
} else {
record_id = id;
}
GRN_BULK_REWIND(&value);
grn_obj_get_value(ctx, target_column, record_id, &value);
if (greater(ctx, &value, data->min) && less(ctx, &value, data->max)) {
grn_posting posting;
posting.rid = record_id;
posting.sid = 1 ;
posting.pos = 0 ;
posting.weight = 0 ;
grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
}
}
GRN_OBJ_FIN(ctx, &value);
if (target_column != data->value &&
target_column->header.type == GRN_ACCESSOR) {
grn_obj_unlink(ctx, target_column);
}
grn_table_cursor_close(ctx, cursor);
grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
}
return GRN_SUCCESS;
}
static grn_rc
selector_between(grn_ctx *ctx,
grn_obj *table,
grn_obj *index,
int nargs,
grn_obj **args,
grn_obj *res,
grn_operator op)
{
grn_rc rc = GRN_SUCCESS;
int offset = 0 ;
int limit = -1 ;
int flags = GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_KEY;
between_data data;
grn_bool use_sequential_search;
grn_obj *index_table = NULL;
grn_table_cursor *cursor;
grn_id id;
between_data_init(ctx, &data);
rc = between_parse_args(ctx, nargs - 1 , args + 1 , &data);
if (rc != GRN_SUCCESS) {
goto exit ;
}
if (data.min_border_type == BETWEEN_BORDER_EXCLUDE) {
flags |= GRN_CURSOR_GT;
}
if (data.max_border_type == BETWEEN_BORDER_EXCLUDE) {
flags |= GRN_CURSOR_LT;
}
if (data.value->header.type == GRN_COLUMN_INDEX) {
index = data.value;
}
if (index) {
switch (index->header.type) {
case GRN_TABLE_NO_KEY :
case GRN_TABLE_HASH_KEY :
break ;
case GRN_TABLE_PAT_KEY :
case GRN_TABLE_DAT_KEY :
index_table = index;
index = NULL;
break ;
default :
index_table = grn_ctx_at(ctx, index->header.domain);
break ;
}
}
if (index_table) {
double ratio = grn_between_too_many_index_match_ratio;
use_sequential_search =
selector_between_sequential_search_should_use(ctx,
table,
index,
index_table,
&data,
res,
op,
ratio);
} else {
use_sequential_search = GRN_TRUE;
}
if (use_sequential_search) {
rc = selector_between_sequential_search(ctx, table, &data, res, op);
goto exit ;
}
cursor = grn_table_cursor_open(ctx, index_table,
GRN_BULK_HEAD(data.min),
GRN_BULK_VSIZE(data.min),
GRN_BULK_HEAD(data.max),
GRN_BULK_VSIZE(data.max),
offset, limit, flags);
if (!cursor) {
rc = ctx->rc;
goto exit ;
}
if (index) {
while ((id = grn_table_cursor_next(ctx, cursor))) {
grn_ii_at(ctx, (grn_ii *)index, id, (grn_hash *)res, op);
}
} else {
grn_posting posting;
memset(&posting, 0 , sizeof (grn_posting));
posting.sid = 1 ;
posting.pos = 0 ;
while ((id = grn_table_cursor_next(ctx, cursor))) {
posting.rid = id;
grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
}
}
grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
grn_table_cursor_close(ctx, cursor);
exit :
between_data_fin(ctx, &data);
return rc;
}
static grn_obj *
func_in_values(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *found;
grn_obj *target_value;
int i;
found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0 );
if (!found) {
return NULL;
}
GRN_BOOL_SET(ctx, found, GRN_FALSE);
if (nargs < 1 ) {
ERR(GRN_INVALID_ARGUMENT,
"in_values(): wrong number of arguments (%d for 1..)" , nargs);
return found;
}
target_value = args[0 ];
for (i = 1 ; i < nargs; i++) {
grn_obj *value = args[i];
grn_bool result;
result = grn_operator_exec_equal(ctx, target_value, value);
if (ctx->rc) {
break ;
}
if (result) {
GRN_BOOL_SET(ctx, found, GRN_TRUE);
break ;
}
}
return found;
}
static grn_bool
is_reference_type_column(grn_ctx *ctx, grn_obj *column)
{
grn_bool is_reference_type;
grn_obj *range;
range = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
switch (range->header.type) {
case GRN_TABLE_HASH_KEY :
case GRN_TABLE_PAT_KEY :
case GRN_TABLE_DAT_KEY :
is_reference_type = GRN_TRUE;
break ;
default :
is_reference_type = GRN_FALSE;
break ;
}
grn_obj_unlink(ctx, range);
return is_reference_type;
}
static grn_obj *
selector_in_values_find_source(grn_ctx *ctx, grn_obj *index, grn_obj *res)
{
grn_id source_id = GRN_ID_NIL;
grn_obj source_ids;
unsigned int n_source_ids;
GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
n_source_ids = GRN_BULK_VSIZE(&source_ids) / sizeof (grn_id);
if (n_source_ids == 1 ) {
source_id = GRN_UINT32_VALUE_AT(&source_ids, 0 );
}
GRN_OBJ_FIN(ctx, &source_ids);
if (source_id == GRN_ID_NIL) {
return NULL;
} else {
return grn_ctx_at(ctx, source_id);
}
}
static grn_bool
selector_in_values_sequential_search(grn_ctx *ctx,
grn_obj *table,
grn_obj *index,
int n_values,
grn_obj **values,
grn_obj *res,
grn_operator op)
{
grn_obj *source;
int n_existing_records;
if (grn_in_values_too_many_index_match_ratio < 0 .0 ) {
return GRN_FALSE;
}
if (op != GRN_OP_AND) {
return GRN_FALSE;
}
if (index->header.flags & GRN_OBJ_WITH_WEIGHT) {
return GRN_FALSE;
}
n_existing_records = grn_table_size(ctx, res);
if (n_existing_records == 0 ) {
return GRN_TRUE;
}
source = selector_in_values_find_source(ctx, index, res);
if (!source) {
return GRN_FALSE;
}
if (!is_reference_type_column(ctx, source)) {
grn_obj_unlink(ctx, source);
return GRN_FALSE;
}
{
grn_obj value_ids;
int i, n_value_ids;
int n_indexed_records = 0 ;
{
grn_id range_id;
grn_obj *range;
range_id = grn_obj_get_range(ctx, source);
range = grn_ctx_at(ctx, range_id);
if (!range) {
grn_obj_unlink(ctx, source);
return GRN_FALSE;
}
GRN_RECORD_INIT(&value_ids, GRN_OBJ_VECTOR, range_id);
for (i = 0 ; i < n_values; i++) {
grn_obj *value = values[i];
grn_id value_id;
value_id = grn_table_get(ctx, range,
GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
if (value_id == GRN_ID_NIL) {
continue ;
}
GRN_RECORD_PUT(ctx, &value_ids, value_id);
}
grn_obj_unlink(ctx, range);
}
n_value_ids = GRN_BULK_VSIZE(&value_ids) / sizeof (grn_id);
for (i = 0 ; i < n_value_ids; i++) {
grn_id value_id = GRN_RECORD_VALUE_AT(&value_ids, i);
n_indexed_records += grn_ii_estimate_size(ctx, (grn_ii *)index, value_id);
}
/*
* Same as :
* ( ( n_existing_record / n_indexed_records ) >
* grn_in_values_too_many_index_match_ratio )
*/
if (n_existing_records >
(n_indexed_records * grn_in_values_too_many_index_match_ratio)) {
grn_obj_unlink(ctx, &value_ids);
grn_obj_unlink(ctx, source);
return GRN_FALSE;
}
{
grn_obj *accessor;
char local_source_name[GRN_TABLE_MAX_KEY_SIZE];
int local_source_name_length;
local_source_name_length = grn_column_name(ctx, source,
local_source_name,
GRN_TABLE_MAX_KEY_SIZE);
grn_obj_unlink(ctx, source);
accessor = grn_obj_column(ctx, res,
local_source_name,
local_source_name_length);
{
grn_table_cursor *cursor;
grn_id id;
grn_obj record_value;
GRN_VOID_INIT(&record_value);
cursor = grn_table_cursor_open(ctx, res,
NULL, 0 , NULL, 0 ,
0 , -1 , GRN_CURSOR_ASCENDING);
while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
grn_id *record_id;
grn_table_cursor_get_key(ctx, cursor, (void **)&record_id);
GRN_BULK_REWIND(&record_value);
grn_obj_get_value(ctx, accessor, id, &record_value);
for (i = 0 ; i < n_value_ids; i++) {
grn_id value_id = GRN_RECORD_VALUE_AT(&value_ids, i);
switch (record_value.header.type) {
case GRN_BULK :
if (value_id == GRN_RECORD_VALUE(&record_value)) {
grn_posting posting;
posting.rid = *record_id;
posting.sid = 1 ;
posting.pos = 0 ;
posting.weight = 0 ;
grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
}
break ;
case GRN_UVECTOR :
{
int j, n_elements;
n_elements = GRN_BULK_VSIZE(&record_value) / sizeof (grn_id);
for (j = 0 ; j < n_elements; j++) {
if (value_id == GRN_RECORD_VALUE_AT(&record_value, j)) {
grn_posting posting;
posting.rid = *record_id;
posting.sid = 1 ;
posting.pos = 0 ;
posting.weight = 0 ;
grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
}
}
}
break ;
default :
break ;
}
}
}
grn_table_cursor_close(ctx, cursor);
grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
GRN_OBJ_FIN(ctx, &record_value);
}
grn_obj_unlink(ctx, accessor);
}
grn_obj_unlink(ctx, &value_ids);
}
grn_obj_unlink(ctx, source);
return GRN_TRUE;
}
static grn_rc
selector_in_values(grn_ctx *ctx, grn_obj *table, grn_obj *index,
int nargs, grn_obj **args,
grn_obj *res, grn_operator op)
{
grn_rc rc = GRN_SUCCESS;
int i, n_values;
grn_obj **values;
if (!index) {
return GRN_INVALID_ARGUMENT;
}
if (nargs < 2 ) {
ERR(GRN_INVALID_ARGUMENT,
"in_values(): wrong number of arguments (%d for 1..)" , nargs);
return ctx->rc;
}
n_values = nargs - 2 ;
values = args + 2 ;
if (n_values == 0 ) {
return rc;
}
if (selector_in_values_sequential_search(ctx, table, index,
n_values, values,
res, op)) {
return ctx->rc;
}
ctx->flags |= GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
for (i = 0 ; i < n_values; i++) {
grn_obj *value = values[i];
grn_search_optarg search_options;
memset(&search_options, 0 , sizeof (grn_search_optarg));
search_options.mode = GRN_OP_EXACT;
search_options.similarity_threshold = 0 ;
search_options.max_interval = 0 ;
search_options.weight_vector = NULL;
search_options.vector_size = 0 ;
search_options.proc = NULL;
search_options.max_size = 0 ;
search_options.scorer = NULL;
if (i == n_values - 1 ) {
ctx->flags &= ~GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
}
rc = grn_obj_search(ctx, index, value, res, op, &search_options);
if (rc != GRN_SUCCESS) {
break ;
}
}
return rc;
}
static grn_obj *
proc_range_filter(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
grn_obj *table_name = VAR(0 );
grn_obj *column_name = VAR(1 );
grn_obj *min = VAR(2 );
grn_obj *min_border = VAR(3 );
grn_obj *max = VAR(4 );
grn_obj *max_border = VAR(5 );
grn_obj *offset = VAR(6 );
grn_obj *limit = VAR(7 );
grn_obj *filter = VAR(8 );
grn_obj *output_columns = VAR(9 );
grn_obj *table;
grn_obj *res = NULL;
grn_obj *filter_expr = NULL;
grn_obj *filter_variable = NULL;
int real_offset;
int real_limit;
table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_name), GRN_TEXT_LEN(table_name));
if (!table) {
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] nonexistent table <%.*s>" ,
(int )GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
return NULL;
}
if (GRN_TEXT_LEN(filter) > 0 ) {
GRN_EXPR_CREATE_FOR_QUERY(ctx, table, filter_expr, filter_variable);
if (!filter_expr) {
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] failed to create expression" );
goto exit ;
}
grn_expr_parse(ctx, filter_expr,
GRN_TEXT_VALUE(filter), GRN_TEXT_LEN(filter),
NULL, GRN_OP_MATCH, GRN_OP_AND, GRN_EXPR_SYNTAX_SCRIPT);
if (ctx->rc != GRN_SUCCESS) {
goto exit ;
}
}
res = grn_table_create(ctx, NULL, 0 , NULL,
GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
table, NULL);
if (!res) {
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] failed to result table" );
goto exit ;
}
{
grn_obj int32_value;
GRN_INT32_INIT(&int32_value, 0 );
if (GRN_TEXT_LEN(offset) > 0 ) {
if (grn_obj_cast(ctx, offset, &int32_value, GRN_FALSE) != GRN_SUCCESS) {
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] invalid offset format: <%.*s>" ,
(int )GRN_TEXT_LEN(offset), GRN_TEXT_VALUE(offset));
GRN_OBJ_FIN(ctx, &int32_value);
goto exit ;
}
real_offset = GRN_INT32_VALUE(&int32_value);
} else {
real_offset = 0 ;
}
GRN_BULK_REWIND(&int32_value);
if (GRN_TEXT_LEN(limit) > 0 ) {
if (grn_obj_cast(ctx, limit, &int32_value, GRN_FALSE) != GRN_SUCCESS) {
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] invalid limit format: <%.*s>" ,
(int )GRN_TEXT_LEN(limit), GRN_TEXT_VALUE(limit));
GRN_OBJ_FIN(ctx, &int32_value);
goto exit ;
}
real_limit = GRN_INT32_VALUE(&int32_value);
} else {
real_limit = GRN_SELECT_DEFAULT_LIMIT;
}
GRN_OBJ_FIN(ctx, &int32_value);
}
{
grn_rc rc;
int original_offset = real_offset;
int original_limit = real_limit;
rc = grn_normalize_offset_and_limit(ctx, grn_table_size(ctx, table),
&real_offset, &real_limit);
switch (rc) {
case GRN_TOO_SMALL_OFFSET :
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] too small offset: <%d>" , original_offset);
goto exit ;
case GRN_TOO_LARGE_OFFSET :
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] too large offset: <%d>" , original_offset);
goto exit ;
case GRN_TOO_SMALL_LIMIT :
ERR(GRN_INVALID_ARGUMENT,
"[range_filter] too small limit: <%d>" , original_limit);
goto exit ;
default :
break ;
}
}
if (real_limit != 0 ) {
grn_table_sort_key *sort_keys;
unsigned int n_sort_keys;
sort_keys = grn_table_sort_key_from_str(ctx,
GRN_TEXT_VALUE(column_name),
GRN_TEXT_LEN(column_name),
table,
&n_sort_keys);
if (n_sort_keys == 1 ) {
grn_table_sort_key *sort_key;
grn_obj *index;
int n_indexes;
grn_operator op = GRN_OP_OR;
sort_key = &(sort_keys[0 ]);
n_indexes = grn_column_index(ctx, sort_key->key, GRN_OP_LESS,
&index, 1 , NULL);
if (n_indexes > 0 ) {
grn_obj *lexicon;
grn_table_cursor *table_cursor;
int table_cursor_flags = 0 ;
between_border_type min_border_type;
between_border_type max_border_type;
grn_obj real_min;
grn_obj real_max;
int n_records = 0 ;
grn_obj *index_cursor;
int index_cursor_flags = 0 ;
grn_posting *posting;
lexicon = grn_ctx_at(ctx, index->header.domain);
if (sort_key->flags & GRN_TABLE_SORT_DESC) {
table_cursor_flags |= GRN_CURSOR_DESCENDING;
} else {
table_cursor_flags |= GRN_CURSOR_ASCENDING;
}
if (GRN_TEXT_LEN(min_border) > 0 ) {
min_border_type = between_parse_border(ctx, min_border, "min_border" );
} else {
min_border_type = BETWEEN_BORDER_INCLUDE;
}
if (GRN_TEXT_LEN(max_border) > 0 ) {
max_border_type = between_parse_border(ctx, max_border, "max_border" );
} else {
max_border_type = BETWEEN_BORDER_INCLUDE;
}
if (min_border_type == BETWEEN_BORDER_EXCLUDE) {
table_cursor_flags |= GRN_CURSOR_GT;
}
if (max_border_type == BETWEEN_BORDER_EXCLUDE) {
table_cursor_flags |= GRN_CURSOR_LT;
}
GRN_OBJ_INIT(&real_min, GRN_BULK, 0 , lexicon->header.domain);
GRN_OBJ_INIT(&real_max, GRN_BULK, 0 , lexicon->header.domain);
if (GRN_TEXT_LEN(min) > 0 ) {
grn_obj_cast(ctx, min, &real_min, GRN_FALSE);
}
if (GRN_TEXT_LEN(max) > 0 ) {
grn_obj_cast(ctx, max, &real_max, GRN_FALSE);
}
table_cursor = grn_table_cursor_open(ctx, lexicon,
GRN_BULK_HEAD(&real_min),
GRN_BULK_VSIZE(&real_min),
GRN_BULK_HEAD(&real_max),
GRN_BULK_VSIZE(&real_max),
0 , -1 , table_cursor_flags);
index_cursor = grn_index_cursor_open(ctx, table_cursor,
index, GRN_ID_NIL, GRN_ID_NIL,
index_cursor_flags);
while ((posting = grn_index_cursor_next(ctx, index_cursor, NULL))) {
grn_bool result_boolean = GRN_FALSE;
if (filter_expr) {
grn_obj *result;
GRN_RECORD_SET(ctx, filter_variable, posting->rid);
result = grn_expr_exec(ctx, filter_expr, 0 );
if (ctx->rc) {
break ;
}
result_boolean = grn_obj_is_true(ctx, result);
} else {
result_boolean = GRN_TRUE;
}
if (result_boolean) {
if (n_records >= real_offset) {
grn_ii_posting_add(ctx, posting, (grn_hash *)res, op);
}
n_records++;
if (n_records == real_limit) {
break ;
}
}
}
grn_obj_unlink(ctx, index_cursor);
grn_table_cursor_close(ctx, table_cursor);
GRN_OBJ_FIN(ctx, &real_min);
GRN_OBJ_FIN(ctx, &real_max);
}
grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
}
grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
}
if (ctx->rc == GRN_SUCCESS) {
const char *raw_output_columns;
int raw_output_columns_len;
raw_output_columns = GRN_TEXT_VALUE(output_columns);
raw_output_columns_len = GRN_TEXT_LEN(output_columns);
if (raw_output_columns_len == 0 ) {
raw_output_columns = GRN_SELECT_DEFAULT_OUTPUT_COLUMNS;
raw_output_columns_len = strlen(raw_output_columns);
}
grn_proc_select_output_columns(ctx, res, -1 , real_offset, real_limit,
raw_output_columns,
raw_output_columns_len,
filter_expr);
}
exit :
if (filter_expr) {
grn_obj_unlink(ctx, filter_expr);
}
if (res) {
grn_obj_unlink(ctx, res);
}
return NULL;
}
static grn_obj *
proc_request_cancel(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
grn_obj *id = VAR(0 );
grn_bool canceled;
if (GRN_TEXT_LEN(id) == 0 ) {
ERR(GRN_INVALID_ARGUMENT, "[request_cancel] ID is missing" );
return NULL;
}
canceled = grn_request_canceler_cancel(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id));
GRN_OUTPUT_MAP_OPEN("result" , 2 );
GRN_OUTPUT_CSTR("id" );
GRN_OUTPUT_STR(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id));
GRN_OUTPUT_CSTR("canceled" );
GRN_OUTPUT_BOOL(canceled);
GRN_OUTPUT_MAP_CLOSE();
return NULL;
}
static grn_obj *
proc_plugin_register(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
if (GRN_TEXT_LEN(VAR(0 ))) {
const char *name;
GRN_TEXT_PUTC(ctx, VAR(0 ), '\0' );
name = GRN_TEXT_VALUE(VAR(0 ));
grn_plugin_register(ctx, name);
} else {
ERR(GRN_INVALID_ARGUMENT, "[plugin_register] name is missing" );
}
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_obj *
proc_plugin_unregister(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
if (GRN_TEXT_LEN(VAR(0 ))) {
const char *name;
GRN_TEXT_PUTC(ctx, VAR(0 ), '\0' );
name = GRN_TEXT_VALUE(VAR(0 ));
grn_plugin_unregister(ctx, name);
} else {
ERR(GRN_INVALID_ARGUMENT, "[plugin_unregister] name is missing" );
}
GRN_OUTPUT_BOOL(!ctx->rc);
return NULL;
}
static grn_obj *
proc_io_flush(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *target_name;
grn_obj *recursive;
grn_obj *only_opened;
grn_obj *target;
grn_bool is_recursive;
grn_bool is_only_opened;
target_name = VAR(0 );
recursive = VAR(1 );
only_opened = VAR(2 );
if (GRN_TEXT_LEN(target_name) > 0 ) {
target = grn_ctx_get(ctx,
GRN_TEXT_VALUE(target_name),
GRN_TEXT_LEN(target_name));
if (!target) {
ERR(GRN_INVALID_ARGUMENT, "[io_flush] unknown target: <%.*s>" ,
(int )GRN_TEXT_LEN(target_name),
GRN_TEXT_VALUE(target_name));
GRN_OUTPUT_BOOL(GRN_FALSE);
return NULL;
}
} else {
target = grn_ctx_db(ctx);
}
is_recursive = grn_proc_option_value_bool(ctx, recursive, GRN_TRUE);
is_only_opened = grn_proc_option_value_bool(ctx, only_opened, GRN_FALSE);
{
grn_rc rc;
if (target->header.type == GRN_DB && is_only_opened) {
rc = grn_obj_flush(ctx, target);
if (rc == GRN_SUCCESS) {
GRN_TABLE_EACH_BEGIN_FLAGS(ctx, target, cursor, id, GRN_CURSOR_BY_ID) {
grn_obj *sub_target;
if (id < GRN_N_RESERVED_TYPES) {
continue ;
}
if (!grn_ctx_is_opened(ctx, id)) {
continue ;
}
sub_target = grn_ctx_at(ctx, id);
rc = grn_obj_flush(ctx, sub_target);
if (rc != GRN_SUCCESS) {
break ;
}
} GRN_TABLE_EACH_END(ctx, cursor);
}
} else {
if (is_recursive) {
rc = grn_obj_flush_recursive(ctx, target);
} else {
rc = grn_obj_flush(ctx, target);
}
}
GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
}
return NULL;
}
static grn_obj *
proc_thread_limit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
{
grn_obj *max_bulk;
uint32_t current_limit;
current_limit = grn_thread_get_limit();
GRN_OUTPUT_INT64(current_limit);
max_bulk = VAR(0 );
if (GRN_TEXT_LEN(max_bulk) > 0 ) {
uint32_t max;
const char *max_text = GRN_TEXT_VALUE(max_bulk);
const char *max_text_end;
const char *max_text_rest;
max_text_end = max_text + GRN_TEXT_LEN(max_bulk);
max = grn_atoui(max_text, max_text_end, &max_text_rest);
if (max_text_rest != max_text_end) {
ERR(GRN_INVALID_ARGUMENT,
"[thread_limit] max must be unsigned integer value: <%.*s>" ,
(int )GRN_TEXT_LEN(max_bulk),
max_text);
return NULL;
}
if (max == 0 ) {
ERR(GRN_INVALID_ARGUMENT,
"[thread_limit] max must be 1 or larger: <%.*s>" ,
(int )GRN_TEXT_LEN(max_bulk),
max_text);
return NULL;
}
grn_thread_set_limit(max);
}
return NULL;
}
static grn_obj *
proc_database_unmap(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
grn_rc rc;
uint32_t current_limit;
current_limit = grn_thread_get_limit();
if (current_limit != 1 ) {
ERR(GRN_OPERATION_NOT_PERMITTED,
"[database_unmap] the max number of threads must be 1: <%u>" ,
current_limit);
GRN_OUTPUT_BOOL(GRN_FALSE);
return NULL;
}
rc = grn_db_unmap(ctx, grn_ctx_db(ctx));
GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
return NULL;
}
static grn_obj *
proc_reindex(grn_ctx *ctx, int nargs, grn_obj **args,
grn_user_data *user_data)
{
grn_obj *target_name;
grn_obj *target;
target_name = VAR(0 );
if (GRN_TEXT_LEN(target_name) == 0 ) {
target = grn_ctx_db(ctx);
} else {
target = grn_ctx_get(ctx,
GRN_TEXT_VALUE(target_name),
GRN_TEXT_LEN(target_name));
if (!target) {
ERR(GRN_INVALID_ARGUMENT,
"[reindex] nonexistent target: <%.*s>" ,
(int )GRN_TEXT_LEN(target_name),
GRN_TEXT_VALUE(target_name));
GRN_OUTPUT_BOOL(GRN_FALSE);
return NULL;
}
}
grn_obj_reindex(ctx, target);
GRN_OUTPUT_BOOL(ctx->rc == GRN_SUCCESS);
return NULL;
}
static grn_rc
selector_prefix_rk_search_key(grn_ctx *ctx,
grn_obj *table,
grn_obj *column,
grn_obj *query,
grn_obj *res,
grn_operator op)
{
grn_rc rc = GRN_SUCCESS;
if (!grn_obj_is_key_accessor(ctx, column)) {
grn_obj inspected_column;
GRN_TEXT_INIT(&inspected_column, 0 );
grn_inspect(ctx, &inspected_column, column);
ERR(GRN_INVALID_ARGUMENT,
"prefix_rk_serach(): column must be _key: %.*s" ,
(int )GRN_TEXT_LEN(&inspected_column),
GRN_TEXT_VALUE(&inspected_column));
rc = ctx->rc;
GRN_OBJ_FIN(ctx, &inspected_column);
goto exit ;
}
if (table->header.type != GRN_TABLE_PAT_KEY) {
grn_obj inspected_table;
GRN_TEXT_INIT(&inspected_table, 0 );
grn_inspect(ctx, &inspected_table, table);
ERR(GRN_INVALID_ARGUMENT,
"prefix_rk_serach(): table of _key must TABLE_PAT_KEY: %.*s" ,
(int )GRN_TEXT_LEN(&inspected_table),
GRN_TEXT_VALUE(&inspected_table));
rc = ctx->rc;
GRN_OBJ_FIN(ctx, &inspected_table);
goto exit ;
}
GRN_TABLE_EACH_BEGIN_MIN(ctx,
table,
cursor,
id,
GRN_TEXT_VALUE(query),
GRN_TEXT_LEN(query),
GRN_CURSOR_PREFIX | GRN_CURSOR_RK) {
grn_posting posting;
posting.rid = id;
posting.sid = 1 ;
posting.pos = 0 ;
posting.weight = 0 ;
grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
} GRN_TABLE_EACH_END(ctx, cursor);
grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
exit :
return rc;
}
static grn_rc
selector_prefix_rk_search_index(grn_ctx *ctx,
grn_obj *index,
grn_obj *query,
grn_obj *res,
grn_operator op)
{
grn_rc rc = GRN_SUCCESS;
grn_obj *table;
table = grn_column_table(ctx, index);
GRN_TABLE_EACH_BEGIN_MIN(ctx,
table,
cursor,
id,
GRN_TEXT_VALUE(query),
GRN_TEXT_LEN(query),
GRN_CURSOR_PREFIX | GRN_CURSOR_RK) {
grn_ii_at(ctx, (grn_ii *)index, id, (grn_hash *)res, op);
} GRN_TABLE_EACH_END(ctx, cursor);
grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
return rc;
}
static grn_rc
selector_prefix_rk_search(grn_ctx *ctx,
grn_obj *table,
grn_obj *index,
int nargs,
grn_obj **args,
grn_obj *res,
grn_operator op)
{
grn_rc rc = GRN_SUCCESS;
grn_obj *column;
grn_obj *query;
if ((nargs - 1 ) != 2 ) {
ERR(GRN_INVALID_ARGUMENT,
"prefix_rk_serach(): wrong number of arguments (%d for 2)" , nargs - 1 );
return ctx->rc;
}
column = args[1 ];
query = args[2 ];
if (index) {
rc = selector_prefix_rk_search_index(ctx, index, query, res, op);
} else if (grn_obj_is_accessor(ctx, column) &&
((grn_accessor *)column)->next) {
grn_obj *accessor = column;
unsigned int accessor_deep = 0 ;
grn_obj *base_table = NULL;
grn_obj *base_column = NULL;
grn_obj *base_index = NULL;
grn_obj *base_res = NULL;
grn_accessor *a;
for (a = (grn_accessor *)accessor; a; a = a->next) {
if (a->next) {
accessor_deep++;
} else {
if (grn_obj_is_data_column(ctx, a->obj)) {
grn_operator selector_op;
grn_index_datum index_data;
unsigned int n_index_datum;
selector_op = grn_proc_get_selector_operator(ctx, args[0 ]);
base_column = a->obj;
base_table = grn_column_table(ctx, a->obj);
n_index_datum = grn_column_find_index_data(ctx,
base_column,
selector_op,
&index_data,
1 );
if (n_index_datum > 0 ) {
base_index = index_data.index;
}
} else {
base_column = (grn_obj *)a;
base_table = a->obj;
}
base_res = grn_table_create(ctx, NULL, 0 , NULL,
GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
base_table, NULL);
}
}
if (base_index) {
rc = selector_prefix_rk_search_index(ctx,
base_index,
query,
base_res,
GRN_OP_OR);
} else {
rc = selector_prefix_rk_search_key(ctx,
base_table,
base_column,
query,
base_res,
GRN_OP_OR);
}
if (rc == GRN_SUCCESS) {
grn_accessor_resolve(ctx,
accessor,
accessor_deep,
base_res,
res,
op);
}
grn_obj_close(ctx, base_res);
} else {
rc = selector_prefix_rk_search_key(ctx,
table,
column,
query,
res,
op);
}
return rc;
}
#define DEF_VAR(v,name_str) do {\
(v).name = (name_str);\
(v).name_size = GRN_STRLEN(name_str);\
GRN_TEXT_INIT(&(v).value, 0 );\
} while (0 )
#define DEF_COMMAND(name, func, nvars, vars)\
(grn_proc_create(ctx, (name), (sizeof (name) - 1 ),\
GRN_PROC_COMMAND, (func), NULL, NULL, (nvars), (vars)))
void
grn_db_init_builtin_commands(grn_ctx *ctx)
{
grn_expr_var vars[10 ];
grn_proc_init_define_selector(ctx);
grn_proc_init_select(ctx);
DEF_VAR(vars[0 ], "values" );
DEF_VAR(vars[1 ], "table" );
DEF_VAR(vars[2 ], "columns" );
DEF_VAR(vars[3 ], "ifexists" );
DEF_VAR(vars[4 ], "input_type" );
DEF_VAR(vars[5 ], "each" );
DEF_VAR(vars[6 ], "output_ids" );
DEF_VAR(vars[7 ], "output_errors" );
DEF_COMMAND("load" , proc_load, 8 , vars);
DEF_COMMAND("status" , proc_status, 0 , vars);
grn_proc_init_table_list(ctx);
grn_proc_init_column_list(ctx);
grn_proc_init_table_create(ctx);
grn_proc_init_table_remove(ctx);
grn_proc_init_table_rename(ctx);
grn_proc_init_column_create(ctx);
grn_proc_init_column_remove(ctx);
grn_proc_init_column_rename(ctx);
DEF_VAR(vars[0 ], "path" );
DEF_COMMAND(GRN_EXPR_MISSING_NAME, proc_missing, 1 , vars);
DEF_COMMAND("quit" , proc_quit, 0 , vars);
DEF_VAR(vars[0 ], "mode" );
DEF_COMMAND("shutdown" , proc_shutdown, 1 , vars);
grn_proc_init_clearlock(ctx);
grn_proc_init_lock_clear(ctx);
DEF_VAR(vars[0 ], "target_name" );
DEF_VAR(vars[1 ], "threshold" );
DEF_COMMAND("defrag" , proc_defrag, 2 , vars);
DEF_VAR(vars[0 ], "level" );
DEF_COMMAND("log_level" , proc_log_level, 1 , vars);
DEF_VAR(vars[0 ], "level" );
DEF_VAR(vars[1 ], "message" );
DEF_COMMAND("log_put" , proc_log_put, 2 , vars);
DEF_COMMAND("log_reopen" , proc_log_reopen, 0 , vars);
DEF_VAR(vars[0 ], "table" );
DEF_VAR(vars[1 ], "key" );
DEF_VAR(vars[2 ], "id" );
DEF_VAR(vars[3 ], "filter" );
DEF_COMMAND("delete" , proc_delete, 4 , vars);
DEF_VAR(vars[0 ], "max" );
DEF_COMMAND("cache_limit" , proc_cache_limit, 1 , vars);
grn_proc_init_dump(ctx);
/* Deprecated. Use "plugin_register" instead. */
DEF_VAR(vars[0 ], "path" );
DEF_COMMAND("register" , proc_register, 1 , vars);
DEF_VAR(vars[0 ], "obj" );
DEF_COMMAND("check" , proc_check, 1 , vars);
DEF_VAR(vars[0 ], "target_name" );
DEF_VAR(vars[1 ], "table" );
DEF_COMMAND("truncate" , proc_truncate, 2 , vars);
DEF_VAR(vars[0 ], "normalizer" );
DEF_VAR(vars[1 ], "string" );
DEF_VAR(vars[2 ], "flags" );
DEF_COMMAND("normalize" , proc_normalize, 3 , vars);
grn_proc_init_tokenize(ctx);
grn_proc_init_table_tokenize(ctx);
DEF_COMMAND("tokenizer_list" , proc_tokenizer_list, 0 , vars);
DEF_COMMAND("normalizer_list" , proc_normalizer_list, 0 , vars);
{
grn_obj *proc;
proc = grn_proc_create(ctx, "rand" , -1 , GRN_PROC_FUNCTION, func_rand,
NULL, NULL, 0 , NULL);
grn_proc_set_is_stable(ctx, proc, GRN_FALSE);
}
{
grn_obj *proc;
proc = grn_proc_create(ctx, "now" , -1 , GRN_PROC_FUNCTION, func_now,
NULL, NULL, 0 , NULL);
grn_proc_set_is_stable(ctx, proc, GRN_FALSE);
}
grn_proc_create(ctx, "max" , -1 , GRN_PROC_FUNCTION, func_max,
NULL, NULL, 0 , NULL);
grn_proc_create(ctx, "min" , -1 , GRN_PROC_FUNCTION, func_min,
NULL, NULL, 0 , NULL);
{
grn_obj *selector_proc;
selector_proc = grn_proc_create(ctx, "geo_in_circle" , -1 , GRN_PROC_FUNCTION,
func_geo_in_circle, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, grn_selector_geo_in_circle);
/* We may need GRN_OP_GEO_IN_CIRCLE. */
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_MATCH);
selector_proc = grn_proc_create(ctx, "geo_in_rectangle" , -1 ,
GRN_PROC_FUNCTION,
func_geo_in_rectangle, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, grn_selector_geo_in_rectangle);
/* We may need GRN_OP_GEO_IN_RECTANGLE. */
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_MATCH);
}
grn_proc_create(ctx, "geo_distance" , -1 , GRN_PROC_FUNCTION,
func_geo_distance, NULL, NULL, 0 , NULL);
/* deprecated. */
grn_proc_create(ctx, "geo_distance2" , -1 , GRN_PROC_FUNCTION,
func_geo_distance2, NULL, NULL, 0 , NULL);
/* deprecated. */
grn_proc_create(ctx, "geo_distance3" , -1 , GRN_PROC_FUNCTION,
func_geo_distance3, NULL, NULL, 0 , NULL);
grn_proc_init_edit_distance(ctx);
{
grn_obj *selector_proc;
selector_proc = grn_proc_create(ctx, "all_records" , -1 , GRN_PROC_FUNCTION,
func_all_records, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, selector_all_records);
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
}
/* experimental */
grn_proc_init_snippet_html(ctx);
{
grn_obj *selector_proc;
selector_proc = grn_proc_create(ctx, "query" , -1 , GRN_PROC_FUNCTION,
func_query, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, selector_query);
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
}
{
grn_obj *selector_proc;
selector_proc = grn_proc_create(ctx, "sub_filter" , -1 , GRN_PROC_FUNCTION,
NULL, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, selector_sub_filter);
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
}
grn_proc_create(ctx, "html_untag" , -1 , GRN_PROC_FUNCTION,
func_html_untag, NULL, NULL, 0 , NULL);
{
grn_obj *selector_proc;
selector_proc = grn_proc_create(ctx, "between" , -1 , GRN_PROC_FUNCTION,
func_between, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, selector_between);
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_LESS);
}
grn_proc_init_highlight_html(ctx);
grn_proc_init_highlight_full(ctx);
{
grn_obj *selector_proc;
selector_proc = grn_proc_create(ctx, "in_values" , -1 , GRN_PROC_FUNCTION,
func_in_values, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, selector_in_values);
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_EQUAL);
}
DEF_VAR(vars[0 ], "table" );
DEF_VAR(vars[1 ], "column" );
DEF_VAR(vars[2 ], "min" );
DEF_VAR(vars[3 ], "min_border" );
DEF_VAR(vars[4 ], "max" );
DEF_VAR(vars[5 ], "max_border" );
DEF_VAR(vars[6 ], "offset" );
DEF_VAR(vars[7 ], "limit" );
DEF_VAR(vars[8 ], "filter" );
DEF_VAR(vars[9 ], "output_columns" );
DEF_COMMAND("range_filter" , proc_range_filter, 10 , vars);
DEF_VAR(vars[0 ], "id" );
DEF_COMMAND("request_cancel" , proc_request_cancel, 1 , vars);
DEF_VAR(vars[0 ], "name" );
DEF_COMMAND("plugin_register" , proc_plugin_register, 1 , vars);
DEF_VAR(vars[0 ], "name" );
DEF_COMMAND("plugin_unregister" , proc_plugin_unregister, 1 , vars);
DEF_VAR(vars[0 ], "target_name" );
DEF_VAR(vars[1 ], "recursive" );
DEF_VAR(vars[2 ], "only_opened" );
DEF_COMMAND("io_flush" , proc_io_flush, 3 , vars);
grn_proc_init_object_exist(ctx);
DEF_VAR(vars[0 ], "max" );
DEF_COMMAND("thread_limit" , proc_thread_limit, 1 , vars);
DEF_COMMAND("database_unmap" , proc_database_unmap, 0 , vars);
grn_proc_init_column_copy(ctx);
grn_proc_init_schema(ctx);
DEF_VAR(vars[0 ], "target_name" );
DEF_COMMAND("reindex" , proc_reindex, 1 , vars);
{
grn_obj *selector_proc;
selector_proc = grn_proc_create(ctx, "prefix_rk_search" , -1 ,
GRN_PROC_FUNCTION,
NULL, NULL, NULL, 0 , NULL);
grn_proc_set_selector(ctx, selector_proc, selector_prefix_rk_search);
grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_PREFIX);
}
grn_proc_init_config_get(ctx);
grn_proc_init_config_set(ctx);
grn_proc_init_config_delete(ctx);
grn_proc_init_lock_acquire(ctx);
grn_proc_init_lock_release(ctx);
grn_proc_init_object_inspect(ctx);
grn_proc_init_fuzzy_search(ctx);
grn_proc_init_object_remove(ctx);
grn_proc_init_snippet(ctx);
grn_proc_init_highlight(ctx);
grn_proc_init_query_expand(ctx);
grn_proc_init_object_list(ctx);
grn_proc_init_table_copy(ctx);
grn_proc_init_in_records(ctx);
grn_proc_init_query_log_flags_get(ctx);
grn_proc_init_query_log_flags_set(ctx);
grn_proc_init_query_log_flags_add(ctx);
grn_proc_init_query_log_flags_remove(ctx);
}
Messung V0.5 in Prozent C=100 H=89 G=94
¤ Dauer der Verarbeitung: 0.127 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland