From bf59cac108c7cd9861d06029c9958ec0c19f41a6 Mon Sep 17 00:00:00 2001 From: adam Date: Wed, 14 Nov 2012 00:00:23 +0700 Subject: [PATCH] #3 --- tcejdb/configure | 189 ++++++++++++++++++++++++++------------------------- tcejdb/ejdb.c | 102 +++++++++++++++++---------- tcejdb/tcutil.c | 9 ++- tcejdb/tcutil.h | 2 +- tcejdb/testejdb/t2.c | 23 ++++++- 5 files changed, 193 insertions(+), 132 deletions(-) diff --git a/tcejdb/configure b/tcejdb/configure index 0949dbf..bb84c27 100755 --- a/tcejdb/configure +++ b/tcejdb/configure @@ -1,11 +1,9 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for tcejdb 1.0.0. +# Generated by GNU Autoconf 2.69 for tcejdb 1.0.0. # # -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -# Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -134,6 +132,31 @@ export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh @@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi -test x\$exitcode = x0 || exit 1" +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && @@ -212,21 +236,25 @@ IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : - # We cannot yet assume a decent shell, so we have to provide a - # neutralization value for shells without unset; and this also - # works around shells that cannot unset nonexistent variables. - # Preserve -v and -x to the replacement shell. - BASH_ENV=/dev/null - ENV=/dev/null - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV - export CONFIG_SHELL - case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; - esac - exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi if test x$as_have_required = xno; then : @@ -328,6 +356,14 @@ $as_echo X"$as_dir" | } # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take @@ -449,6 +485,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). @@ -483,16 +523,16 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -504,28 +544,8 @@ else as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -1152,8 +1172,6 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1407,9 +1425,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF tcejdb configure 1.0.0 -generated by GNU Autoconf 2.68 +generated by GNU Autoconf 2.69 -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1595,7 +1613,7 @@ $as_echo "$ac_try_echo"; } >&5 test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext + test -x conftest$ac_exeext }; then : ac_retval=0 else @@ -1705,7 +1723,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by tcejdb $as_me 1.0.0, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2357,7 +2375,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2397,7 +2415,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2450,7 +2468,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2491,7 +2509,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue @@ -2549,7 +2567,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2593,7 +2611,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3039,8 +3057,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); @@ -3290,7 +3307,7 @@ do for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in @@ -3356,7 +3373,7 @@ do for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in @@ -4753,16 +4770,16 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -4822,28 +4839,16 @@ else as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -4865,7 +4870,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by tcejdb $as_me 1.0.0, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -4918,10 +4923,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ tcejdb config.status 1.0.0 -configured by $0, generated by GNU Autoconf 2.68, +configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -4998,7 +5003,7 @@ fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' diff --git a/tcejdb/ejdb.c b/tcejdb/ejdb.c index 5ced64c..9967f83 100644 --- a/tcejdb/ejdb.c +++ b/tcejdb/ejdb.c @@ -31,14 +31,18 @@ return JB_ret; \ } +/* string processing/conversion flags */ +typedef enum { + JBICASE = 1 +} txtflags_t; + /* ejdb number */ typedef union { int64_t inum; double dnum; } _EJDBNUM; - -/* opaque data for `_bsonipathrowldr()`function */ +/* opaque data for `_bsonipathrowldr()` and `_bsonfpathrowldr()` functions */ typedef struct { EJCOLL *jcoll; //current collection bool icase; //ignore case normalization @@ -53,7 +57,7 @@ static bool _ejdbcolsetmutex(EJCOLL *coll); static bool _ejcollockmethod(EJCOLL *coll, bool wr); static bool _ejcollunlockmethod(EJCOLL *coll); static bool _bsonoidkey(bson *bs, bson_oid_t *oid); -static char* _bsonitstrval(bson_iterator *it, int *vsz, TCLIST *tokens); +static char* _bsonitstrval(EJDB *jb, bson_iterator *it, int *vsz, TCLIST *tokens, txtflags_t flags); static char* _bsonipathrowldr(TCLIST *tokens, const char *pkbuf, int pksz, const char *rowdata, int rowdatasz, const char *ipath, int ipathsz, void *op, int *vsz); static char* _bsonfpathrowldr(TCLIST *tokens, const char *rowdata, int rowdatasz, @@ -486,7 +490,7 @@ EJDB_EXPORT bool ejdbsetindex(EJCOLL *jcoll, const char *fpath, int flags) { memmove(ikey + 1, fpath, fpathlen + 1); ikey[0] = 'i'; memmove(ipath + 1, fpath, fpathlen + 1); - ipath[0] = 's'; //string index type + ipath[0] = 's'; //defaulting to string index type JBENSUREOPENLOCK(jcoll->jb, true, false); imeta = _imetaidx(jcoll, fpath); @@ -544,8 +548,8 @@ EJDB_EXPORT bool ejdbsetindex(EJCOLL *jcoll, const char *fpath, int flags) { goto finish; } _BSONIPATHROWLDR op; - op.icase = false; - op.jcoll = jcoll; + op.icase = false; + op.jcoll = jcoll; if (tcitype) { if (flags & JBIDXSTR) { @@ -554,6 +558,7 @@ EJDB_EXPORT bool ejdbsetindex(EJCOLL *jcoll, const char *fpath, int flags) { } if (flags & JBIDXISTR) { ipath[0] = 'i'; + op.icase = true; rv = tctdbsetindexrldr(jcoll->tdb, ipath, tcitype, _bsonipathrowldr, &op); } if (rv && (flags & JBIDXNUM)) { @@ -584,6 +589,7 @@ EJDB_EXPORT bool ejdbsetindex(EJCOLL *jcoll, const char *fpath, int flags) { } if ((flags & JBIDXISTR) && (ibld || !(oldiflags & JBIDXISTR))) { ipath[0] = 'i'; + op.icase = true; rv = tctdbsetindexrldr(jcoll->tdb, ipath, TDBITLEXICAL, _bsonipathrowldr, &op); } if (rv && (flags & JBIDXNUM) && (ibld || !(oldiflags & JBIDXNUM))) { @@ -2618,7 +2624,8 @@ finish: * Resulting value size stored into 'vsz'. * If returned value is not NULL it must be freed by TCFREE. */ -static char* _bsonitstrval(bson_iterator *it, int *vsz, TCLIST *tokens) { +static char* _bsonitstrval(EJDB *jb, bson_iterator *it, int *vsz, TCLIST *tokens, txtflags_t flags) { + int retlen = 0; char *ret = NULL; bson_type btype = bson_iterator_type(it); if (btype == BSON_STRING) { @@ -2632,30 +2639,40 @@ static char* _bsonitstrval(bson_iterator *it, int *vsz, TCLIST *tokens) { while (*ep > ' ' && *ep != ',') { ep++; } - if (ep > sp) TCLISTPUSH(tokens, sp, ep - sp); + if (ep > sp) { + if (flags & JBICASE) { //ignore case mode + char *isp; + int len = tcicaseformat((const char*) sp, ep - sp, &isp); + if (len >= 0) { //success + TCLISTPUSH(tokens, isp, len); + TCFREE(isp); + } else { + _ejdbsetecode(jb, len, __FILE__, __LINE__, __func__); + } + } else { + TCLISTPUSH(tokens, sp, ep - sp); + } + } sp = ep; } - *vsz = 0; - ret = NULL; } else { - *vsz = bson_iterator_string_len(it) - 1; - ret = (*vsz > 0) ? tcmemdup(bson_iterator_string(it), *vsz) : NULL; + retlen = bson_iterator_string_len(it) - 1; + ret = (retlen > 0) ? tcmemdup(bson_iterator_string(it), retlen) : NULL; } } else if (BSON_IS_NUM_TYPE(btype)) { char nbuff[TCNUMBUFSIZ]; if (btype == BSON_INT || btype == BSON_LONG) { - *vsz = bson_numstrn(nbuff, TCNUMBUFSIZ, bson_iterator_long(it)); - if (*vsz >= TCNUMBUFSIZ) { - *vsz = TCNUMBUFSIZ - 1; - nbuff[TCNUMBUFSIZ - 1] = '\0'; + retlen = bson_numstrn(nbuff, TCNUMBUFSIZ, bson_iterator_long(it)); + if (retlen >= TCNUMBUFSIZ) { + retlen = TCNUMBUFSIZ - 1; } - ret = tcmemdup(nbuff, *vsz); + ret = tcmemdup(nbuff, retlen); } else if (btype == BSON_DOUBLE) { - *vsz = tcftoa(bson_iterator_double(it), nbuff, TCNUMBUFSIZ, 6); - if (*vsz >= TCNUMBUFSIZ) { - *vsz = TCNUMBUFSIZ - 1; + retlen = tcftoa(bson_iterator_double(it), nbuff, TCNUMBUFSIZ, 6); + if (retlen >= TCNUMBUFSIZ) { + retlen = TCNUMBUFSIZ - 1; } - ret = tcmemdup(nbuff, *vsz); + ret = tcmemdup(nbuff, retlen); } } else if (btype == BSON_ARRAY) { bson_type eltype; //last element bson type @@ -2664,22 +2681,31 @@ static char* _bsonitstrval(bson_iterator *it, int *vsz, TCLIST *tokens) { if (tokens) { while ((eltype = bson_iterator_next(&sit)) != BSON_EOO) { int vz = 0; - char *v = _bsonitstrval(&sit, &vz, NULL); + char *v = _bsonitstrval(jb, &sit, &vz, NULL, flags); if (v) { TCLISTPUSH(tokens, v, vz); TCFREE(v); } } - ret = NULL; - *vsz = 0; } else { //Array elements are joined with ',' delimeter. ret = _fetch_bson_str_array2(&sit, &eltype); - *vsz = strlen(ret); + retlen = strlen(ret); } - } else { - *vsz = 0; } + if ((flags & JBICASE) && ret) { + char *isp; + retlen = tcicaseformat((const char*) ret, retlen, &isp); + TCFREE(ret); + if (retlen >= 0) { //success + ret = isp; + } else { + _ejdbsetecode(jb, retlen, __FILE__, __LINE__, __func__); + ret = NULL; + retlen = 0; + } + } + *vsz = retlen; return ret; } @@ -2713,7 +2739,7 @@ static char* _bsonipathrowldr( return res; } } - if (!ipath || ipathsz < 2 || *(ipath + 1) == '\0' || (*ipath != 's' && *ipath != 'n' && *ipath != 'a')) { + if (!ipath || ipathsz < 2 || *(ipath + 1) == '\0' || strchr("snai", *ipath) == NULL) { return NULL; } //skip index type prefix char with (fpath + 1) @@ -2722,6 +2748,8 @@ static char* _bsonipathrowldr( static char* _bsonfpathrowldr(TCLIST *tokens, const char *rowdata, int rowdatasz, const char *fpath, int fpathsz, void *op, int *vsz) { + _BSONIPATHROWLDR *odata = (_BSONIPATHROWLDR*) op; + assert(odata && odata->jcoll); char *ret = NULL; int bsize; bson_iterator it; @@ -2732,7 +2760,7 @@ static char* _bsonfpathrowldr(TCLIST *tokens, const char *rowdata, int rowdatasz } bson_iterator_from_buffer(&it, bsdata); bson_find_fieldpath_value2(fpath, fpathsz, &it); - ret = _bsonitstrval(&it, vsz, tokens); + ret = _bsonitstrval(odata->jcoll->jb, &it, vsz, tokens, (odata->icase ? JBICASE : 0)); TCFREE(bsdata); return ret; } @@ -2774,12 +2802,13 @@ static bool _updatebsonidx(EJCOLL *jcoll, const bson_oid_t *oid, const bson *bs, char *fvalue = NULL; int ofvaluesz = 0; char *ofvalue = NULL; + txtflags_t textflags = (iflags & JBIDXISTR) ? JBICASE : 0; if (obsdata && obsdatasz > 0) { bson_iterator_from_buffer(&oit, obsdata); oft = bson_find_fieldpath_value2(mkey + 1, mkeysz - 1, &oit); TCLIST *tokens = (oft == BSON_ARRAY) ? tclistnew() : NULL; - ofvalue = BSON_IS_IDXSUPPORTED_TYPE(oft) ? _bsonitstrval(&oit, &ofvaluesz, tokens) : NULL; + ofvalue = BSON_IS_IDXSUPPORTED_TYPE(oft) ? _bsonitstrval(jcoll->jb, &oit, &ofvaluesz, tokens, textflags) : NULL; if (tokens) { ofvalue = tclistdump(tokens, &ofvaluesz); tclistdel(tokens); @@ -2789,7 +2818,7 @@ static bool _updatebsonidx(EJCOLL *jcoll, const bson_oid_t *oid, const bson *bs, bson_iterator_init(&fit, bs); ft = bson_find_fieldpath_value2(mkey + 1, mkeysz - 1, &fit); TCLIST *tokens = (ft == BSON_ARRAY) ? tclistnew() : NULL; - fvalue = BSON_IS_IDXSUPPORTED_TYPE(ft) ? _bsonitstrval(&fit, &fvaluesz, tokens) : NULL; + fvalue = BSON_IS_IDXSUPPORTED_TYPE(ft) ? _bsonitstrval(jcoll->jb, &fit, &fvaluesz, tokens, textflags) : NULL; if (tokens) { fvalue = tclistdump(tokens, &fvaluesz); tclistdel(tokens); @@ -2802,13 +2831,16 @@ static bool _updatebsonidx(EJCOLL *jcoll, const bson_oid_t *oid, const bson *bs, imap = tcmapnew2(16); rimap = tcmapnew2(16); } - for (int i = 4; i <= 6; ++i) { /* JBIDXNUM, JBIDXSTR, JBIDXARR */ + for (int i = 4; i <= 7; ++i) { /* JBIDXNUM, JBIDXSTR, JBIDXARR, JBIDXISTR */ bool rm = false; - if ((1 << i) == JBIDXNUM && (JBIDXNUM & iflags)) { + int itype = (1 << i); + if (itype == JBIDXNUM && (JBIDXNUM & iflags)) { ikey[0] = 'n'; - } else if ((1 << i) == JBIDXSTR && (JBIDXSTR & iflags)) { + } else if (itype == JBIDXSTR && (JBIDXSTR & iflags)) { ikey[0] = 's'; - } else if ((1 << i) == JBIDXARR && (JBIDXARR & iflags)) { + } else if (itype == JBIDXISTR && (JBIDXISTR & iflags)) { + ikey[0] = 'i'; + } else if (itype == JBIDXARR && (JBIDXARR & iflags)) { ikey[0] = 'a'; if (ofvalue && oft == BSON_ARRAY && (!fvalue || ft != oft || fvaluesz != ofvaluesz || memcmp(fvalue, ofvalue, fvaluesz))) { diff --git a/tcejdb/tcutil.c b/tcejdb/tcutil.c index c3361f5..7d06cf2 100644 --- a/tcejdb/tcutil.c +++ b/tcejdb/tcutil.c @@ -10659,14 +10659,17 @@ static int tcgammadecode(const char *ptr, int size, char *obuf){ #include "utf8proc.h" -ssize_t tcicaseformat(const char *str, int strlen, char **dstptr) { - ssize_t res = utf8proc_map((uint8_t*)str, strlen, (uint8_t**)dstptr, +int tcicaseformat(const char *str, int strlen, char **dstptr) { + if (strlen == 0 || *str == '\0') { + *dstptr = strdup(""); + return 0; + } + return utf8proc_map((uint8_t*)str, strlen, (uint8_t**)dstptr, UTF8PROC_COMPOSE | UTF8PROC_IGNORE | UTF8PROC_LUMP | UTF8PROC_CASEFOLD | UTF8PROC_STRIPMARK); - return res; } diff --git a/tcejdb/tcutil.h b/tcejdb/tcutil.h index 5f687ae..697638c 100644 --- a/tcejdb/tcutil.h +++ b/tcejdb/tcutil.h @@ -3901,7 +3901,7 @@ uint64_t tcpagealign(uint64_t off); * @return In case of success the length of the resulting UTF-8 string is * returned, otherwise a negative value. */ -ssize_t tcicaseformat(const char *str, int strlen, char **dstptr); +int tcicaseformat(const char *str, int strlen, char **dstptr); /* Print debug information with a formatted string as with `printf'. */ diff --git a/tcejdb/testejdb/t2.c b/tcejdb/testejdb/t2.c index a3b697f..19ba658 100644 --- a/tcejdb/testejdb/t2.c +++ b/tcejdb/testejdb/t2.c @@ -2467,6 +2467,26 @@ void testOIDSMatching() { //OID matching ejdbquerydel(q1); } +void testICaseIndex() { //OID matching + EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(coll); + CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXDROPALL)); + + bson a1; + bson_oid_t oid; + bson_init(&a1); + bson_append_string(&a1, "name", "ПрИвЕт МйР"); + bson_append_int(&a1, "age", 1); + CU_ASSERT_FALSE_FATAL(a1.err); + bson_finish(&a1); + CU_ASSERT_TRUE(ejdbsavebson(coll, &a1, &oid)); + bson_destroy(&a1); + CU_ASSERT_EQUAL(ejdbecode(coll->jb), 0); + + CU_ASSERT_TRUE(ejdbsetindex(coll, "name", JBIDXISTR)); //Ignore case string index + CU_ASSERT_EQUAL(ejdbecode(coll->jb), 0); +} + int main() { setlocale(LC_ALL, "en_US.UTF-8"); CU_pSuite pSuite = NULL; @@ -2512,7 +2532,8 @@ int main() { (NULL == CU_add_test(pSuite, "testQuery25", testQuery25)) || (NULL == CU_add_test(pSuite, "testQuery26", testQuery26)) || (NULL == CU_add_test(pSuite, "testQuery27", testQuery27)) || - (NULL == CU_add_test(pSuite, "testOIDSMatching", testOIDSMatching)) + (NULL == CU_add_test(pSuite, "testOIDSMatching", testOIDSMatching)) || + (NULL == CU_add_test(pSuite, "testICaseIndex", testICaseIndex)) ) { CU_cleanup_registry(); return CU_get_error(); -- 2.7.4