Create your Gitee Account
Explore and code with more than 5 million developers,Free private repositories !:)
Sign up
Clone or download
sdb_item.cc 37.30 KB
Copy Edit Web IDE Raw Blame History
DavidLi authored 2019-03-27 13:38 . Fix compiling warnings.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309
/* Copyright (c) 2018, SequoiaDB and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef MYSQL_SERVER
#define MYSQL_SERVER
#endif
#include <sql_time.h>
#include <my_dbug.h>
#include "sdb_item.h"
#include "sdb_errcode.h"
#include "sdb_util.h"
#include "sdb_def.h"
#include <json_dom.h>
#include <item_json_func.h>
#define BSON_APPEND(field_name, value, obj, arr_builder) \
do { \
if (NULL == (arr_builder)) { \
(obj) = BSON((field_name) << (value)); \
} else { \
(arr_builder)->append(value); \
} \
} while (0)
static const uint MAX_TIME_DEC = 6;
static const uint POWER_10[7] = {1, 10, 100, 1000, 10000, 100000, 1000000};
// This function is similar to Item::get_timeval() but return true if value is
// out of the supported range.
static bool get_timeval(Item *item, struct timeval *tm) {
MYSQL_TIME ltime;
int warnings = 0;
if (item->get_date(&ltime, TIME_FUZZY_DATE)) {
goto error; /* Could not extract date from the value */
}
if (datetime_to_timeval(current_thd, &ltime, tm, &warnings)) {
goto error; /* Value is out of the supported range */
}
return false; /* Value is a good Unix timestamp */
error:
tm->tv_sec = tm->tv_usec = 0;
return true;
}
int Sdb_logic_item::push_sdb_item(Sdb_item *cond_item) {
int rc = 0;
bson::BSONObj obj_tmp;
if (is_finished) {
// there must be something wrong,
// skip all condition
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
is_ok = FALSE;
goto error;
}
rc = cond_item->to_bson(obj_tmp);
if (rc != 0) {
// skip the error and go on to parse the condition-item
// the error will return in to_bson() ;
rc = SDB_ERR_COND_PART_UNSUPPORTED;
is_ok = FALSE;
goto error;
}
delete cond_item;
children.append(obj_tmp);
done:
return rc;
error:
goto done;
}
int Sdb_logic_item::push_item(Item *cond_item) {
if (NULL != cond_item) {
return SDB_ERR_COND_UNEXPECTED_ITEM;
}
is_finished = TRUE;
return SDB_ERR_OK;
}
int Sdb_logic_item::to_bson(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
if (is_ok) {
obj = BSON(this->name() << children.arr());
} else {
rc = SDB_ERR_COND_INCOMPLETED;
}
return rc;
}
int Sdb_and_item::to_bson(bson::BSONObj &obj) {
obj = BSON(this->name() << children.arr());
return SDB_ERR_OK;
}
Sdb_func_item::Sdb_func_item() : para_num_cur(0), para_num_max(1) {
l_child = NULL;
r_child = NULL;
}
Sdb_func_item::~Sdb_func_item() {
para_list.pop();
if (l_child != NULL) {
delete l_child;
l_child = NULL;
}
if (r_child != NULL) {
delete r_child;
r_child = NULL;
}
}
void Sdb_func_item::update_stat() {
if (++para_num_cur >= para_num_max) {
is_finished = TRUE;
}
}
int Sdb_func_item::push_sdb_item(Sdb_item *cond_item) {
int rc = SDB_ERR_OK;
if (cond_item->type() != Item_func::UNKNOWN_FUNC) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (((Sdb_func_unkown *)cond_item)->get_func_item()->const_item()) {
rc = push_item(((Sdb_func_unkown *)cond_item)->get_func_item());
if (rc != SDB_ERR_OK) {
goto error;
}
delete cond_item;
} else {
if (l_child != NULL || r_child != NULL) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (para_num_cur != 0) {
r_child = cond_item;
} else {
l_child = cond_item;
}
update_stat();
}
done:
return rc;
error:
goto done;
}
int Sdb_func_item::push_item(Item *cond_item) {
int rc = SDB_ERR_OK;
if (is_finished) {
goto error;
}
para_list.push_back(cond_item);
update_stat();
done:
return rc;
error:
rc = SDB_ERR_COND_UNSUPPORTED;
goto done;
}
int Sdb_func_item::pop_item(Item *&para_item) {
if (para_list.is_empty()) {
return SDB_ERR_EOF;
}
para_item = para_list.pop();
return SDB_ERR_OK;
}
int Sdb_func_item::get_item_val(const char *field_name, Item *item_val,
Field *field, bson::BSONObj &obj,
bson::BSONArrayBuilder *arr_builder) {
int rc = SDB_ERR_OK;
THD *thd = current_thd;
// When type casting is needed, some mysql functions may raise warning,
// so we use `Dummy_error_handler` to ignore all error and warning states.
Dummy_error_handler error_handler;
my_bool has_err_handler = false;
if (can_ignore_warning(item_val->type())) {
thd->push_internal_handler(&error_handler);
has_err_handler = true;
}
if (NULL == item_val || !item_val->const_item() ||
(Item::FUNC_ITEM == item_val->type() &&
(((Item_func *)item_val)->functype() == Item_func::FUNC_SP ||
((Item_func *)item_val)->functype() == Item_func::TRIG_COND_FUNC))) {
// don't push down the triggered conditions or the func will be
// triggered in push down one more time
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (Item::NULL_ITEM == item_val->type()) {
// "$exists" appear in array is not support now
if (NULL == arr_builder) {
if (type() == Item_func::EQ_FUNC) {
obj = BSON("$exists" << 0);
goto done;
} else if (type() == Item_func::NE_FUNC) {
obj = BSON("$exists" << 1);
goto done;
} else if (type() == Item_func::EQUAL_FUNC) {
obj = BSON("$isnull" << 1);
goto done;
}
}
rc = SDB_ERR_OVF;
goto error;
}
switch (field->type()) {
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL: {
switch (item_val->result_type()) {
case INT_RESULT: {
longlong val_tmp = item_val->val_int();
if (val_tmp < 0 && item_val->unsigned_flag) {
bson::bsonDecimal decimal;
my_decimal dec_tmp;
char buff[MAX_FIELD_WIDTH] = {0};
String str(buff, sizeof(buff), item_val->charset_for_protocol());
item_val->val_decimal(&dec_tmp);
my_decimal2string(E_DEC_FATAL_ERROR, &dec_tmp, 0, 0, 0, &str);
rc = decimal.fromString(str.c_ptr());
if (0 != rc) {
rc = SDB_ERR_INVALID_ARG;
goto error;
}
BSON_APPEND(field_name, decimal, obj, arr_builder);
} else {
BSON_APPEND(field_name, val_tmp, obj, arr_builder);
}
break;
}
case REAL_RESULT: {
BSON_APPEND(field_name, item_val->val_real(), obj, arr_builder);
break;
}
case STRING_RESULT: {
if (NULL != arr_builder) {
// SEQUOIADBMAINSTREAM-3365
// the string value is not support for "in"
rc = SDB_ERR_TYPE_UNSUPPORTED;
goto error;
}
// pass through
}
case DECIMAL_RESULT: {
if (MYSQL_TYPE_FLOAT == field->type()) {
float value = (float)item_val->val_real();
BSON_APPEND(field_name, value, obj, arr_builder);
} else if (MYSQL_TYPE_DOUBLE == field->type()) {
double value = item_val->val_real();
BSON_APPEND(field_name, value, obj, arr_builder);
} else {
bson::bsonDecimal decimal;
char buff[MAX_FIELD_WIDTH] = {0};
String str(buff, sizeof(buff), item_val->charset_for_protocol());
String conv_str;
String *pStr;
pStr = item_val->val_str(&str);
if (NULL == pStr) {
rc = SDB_ERR_INVALID_ARG;
goto error;
}
if (!my_charset_same(pStr->charset(), &SDB_CHARSET)) {
rc = sdb_convert_charset(*pStr, conv_str, &SDB_CHARSET);
if (rc) {
goto error;
}
pStr = &conv_str;
}
rc = decimal.fromString(pStr->c_ptr());
if (0 != rc) {
rc = SDB_ERR_INVALID_ARG;
goto error;
}
BSON_APPEND(field_name, decimal, obj, arr_builder);
}
break;
}
default: {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
}
break;
}
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_BLOB: {
if (item_val->result_type() == STRING_RESULT && !field->binary()) {
String *pStr = NULL;
String conv_str;
char buff[MAX_FIELD_WIDTH] = {0};
Json_wrapper wr;
String buf;
String str(buff, sizeof(buff), item_val->charset_for_protocol());
if (Item::FUNC_ITEM == item_val->type()) {
const char *func_name = ((Item_func *)item_val)->func_name();
if (0 == strcmp("cast_as_date", func_name) ||
0 == strcmp("cast_as_datetime", func_name)) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
} else if (0 == strcmp("cast_as_json", func_name)) {
Item_json_typecast *item_json = NULL;
item_json = dynamic_cast<Item_json_typecast *>(item_val);
if (!item_json || item_json->val_json(&wr)) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
buf.length(0);
if (wr.to_string(&buf, false, func_name)) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
pStr = &buf;
}
}
if (Item::CACHE_ITEM == item_val->type() &&
(MYSQL_TYPE_DATE == item_val->field_type() ||
MYSQL_TYPE_DATETIME == item_val->field_type())) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (!pStr) {
pStr = item_val->val_str(&str);
if (NULL == pStr) {
rc = SDB_ERR_INVALID_ARG;
break;
}
}
if (!my_charset_same(pStr->charset(), &my_charset_bin)) {
if (!my_charset_same(pStr->charset(), &SDB_CHARSET)) {
rc = sdb_convert_charset(*pStr, conv_str, &SDB_CHARSET);
if (rc) {
break;
}
pStr = &conv_str;
}
if (MYSQL_TYPE_STRING == field->type() ||
MYSQL_TYPE_VAR_STRING == field->type()) {
// Trailing space of CHAR/ENUM/SET condition should be stripped.
pStr->strip_sp();
}
}
if (NULL == arr_builder) {
bson::BSONObjBuilder obj_builder;
obj_builder.appendStrWithNoTerminating(field_name, pStr->ptr(),
pStr->length());
obj = obj_builder.obj();
} else {
arr_builder->append(pStr->c_ptr());
}
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
break;
}
case MYSQL_TYPE_DATE: {
MYSQL_TIME ltime;
my_time_flags_t flags = TIME_FUZZY_DATE;
if (Item::FUNC_ITEM == item_val->type() &&
strcmp("cast_as_time", ((Item_func *)item_val)->func_name())) {
flags |= TIME_DATETIME_ONLY;
}
if (STRING_RESULT == item_val->result_type() &&
!item_val->get_date(&ltime, flags)) {
struct tm tm_val;
tm_val.tm_sec = ltime.second;
tm_val.tm_min = ltime.minute;
tm_val.tm_hour = ltime.hour;
tm_val.tm_mday = ltime.day;
tm_val.tm_mon = ltime.month - 1;
tm_val.tm_year = ltime.year - 1900;
tm_val.tm_wday = 0;
tm_val.tm_yday = 0;
tm_val.tm_isdst = 0;
time_t time_tmp = mktime(&tm_val);
bson::Date_t dt((longlong)(time_tmp * 1000));
BSON_APPEND(field_name, dt, obj, arr_builder);
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
break;
}
case MYSQL_TYPE_TIMESTAMP: {
struct timeval tm;
if (item_val->result_type() != STRING_RESULT ||
get_timeval(item_val, &tm)) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
} else {
uint dec = field->decimals();
if (dec < 6) {
uint power = POWER_10[MAX_TIME_DEC - dec];
tm.tv_usec = (tm.tv_usec / power) * power;
}
bson::OpTime t(tm.tv_sec, tm.tv_usec);
long long time_val = t.asDate();
if (NULL == arr_builder) {
bson::BSONObjBuilder obj_builder;
obj_builder.appendTimestamp(field_name, time_val);
obj = obj_builder.obj();
} else {
arr_builder->appendTimestamp(time_val);
}
}
break;
}
case MYSQL_TYPE_DATETIME: {
MYSQL_TIME ltime;
my_time_flags_t flags = TIME_FUZZY_DATE;
if (Item::FUNC_ITEM == item_val->type() &&
strcmp("cast_as_time", ((Item_func *)item_val)->func_name())) {
flags |= TIME_DATETIME_ONLY;
}
if (item_val->result_type() != STRING_RESULT ||
item_val->get_date(&ltime, flags) || ltime.year > 9999 ||
ltime.year < 1000) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
} else {
uint dec = field->decimals();
char buff[MAX_FIELD_WIDTH];
int len = sprintf(buff, "%04u-%02u-%02u %s%02u:%02u:%02u", ltime.year,
ltime.month, ltime.day, (ltime.neg ? "-" : ""),
ltime.hour, ltime.minute, ltime.second);
if (dec) {
len += sprintf(buff + len, ".%0*lu", (int)dec, ltime.second_part);
}
BSON_APPEND(field_name, buff, obj, arr_builder);
}
break;
}
case MYSQL_TYPE_TIME: {
MYSQL_TIME ltime;
if (STRING_RESULT == item_val->result_type() &&
!item_val->get_time(&ltime)) {
uint dec = field->decimals();
double time = ltime.hour;
time = time * 100 + ltime.minute;
time = time * 100 + ltime.second;
if (ltime.second_part && dec > 0) {
ulong second_part = ltime.second_part;
if (dec < 6) {
uint power = POWER_10[MAX_TIME_DEC - dec];
second_part = (second_part / power) * power;
}
double ms = second_part / (double)1000000;
time += ms;
}
if (ltime.neg) {
time = -time;
}
BSON_APPEND(field_name, time, obj, arr_builder);
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
break;
}
case MYSQL_TYPE_YEAR: {
if (INT_RESULT == item_val->result_type()) {
longlong value = item_val->val_int();
if (value > 0) {
if (value < YY_PART_YEAR) {
value += 2000; // 2000 - 2069
} else if (value < 100) {
value += 1900; // 1970 - 2000
}
}
BSON_APPEND(field_name, value, obj, arr_builder);
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
break;
}
case MYSQL_TYPE_BIT: {
if (INT_RESULT == item_val->result_type()) {
longlong value = item_val->val_int();
BSON_APPEND(field_name, value, obj, arr_builder);
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
break;
}
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_JSON:
case MYSQL_TYPE_GEOMETRY:
default: {
rc = SDB_ERR_TYPE_UNSUPPORTED;
goto error;
}
}
// If the item fails to get the value(by val_int, val_date_temporal...),
// null_value will be set as true. It may happen when doing cast, math,
// subselect...
if (item_val->null_value) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
done:
if (has_err_handler) {
thd->pop_internal_handler();
}
return rc;
error:
// clear the cache to prevent important errors/warnings from being
// ignored.
if (has_err_handler && item_val->null_value) {
if (Item::CACHE_ITEM == item_val->type()) {
((Item_cache *)item_val)->clear();
}
}
goto done;
}
Sdb_func_unkown::Sdb_func_unkown(Item_func *item) {
func_item = item;
para_num_max = item->argument_count();
if (0 == para_num_max) {
is_finished = TRUE;
}
}
Sdb_func_unkown::~Sdb_func_unkown() {}
Sdb_func_unary_op::Sdb_func_unary_op() {
para_num_max = 1;
}
Sdb_func_unary_op::~Sdb_func_unary_op() {}
Sdb_func_isnull::Sdb_func_isnull() {}
Sdb_func_isnull::~Sdb_func_isnull() {}
int Sdb_func_isnull::to_bson(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
Item *item_tmp = NULL;
if (!is_finished || para_list.elements != para_num_max) {
rc = SDB_ERR_COND_INCOMPLETED;
goto error;
}
if (l_child != NULL || r_child != NULL) {
rc = SDB_ERR_COND_UNKOWN_ITEM;
goto error;
}
item_tmp = para_list.pop();
if (Item::FIELD_ITEM != item_tmp->type()) {
rc = SDB_ERR_COND_UNKOWN_ITEM;
goto error;
}
obj = BSON(((Item_field *)item_tmp)->field_name << BSON(this->name() << 1));
done:
return rc;
error:
goto done;
}
Sdb_func_isnotnull::Sdb_func_isnotnull() {}
Sdb_func_isnotnull::~Sdb_func_isnotnull() {}
int Sdb_func_isnotnull::to_bson(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
Item *item_tmp = NULL;
if (!is_finished || para_list.elements != para_num_max) {
rc = SDB_ERR_COND_INCOMPLETED;
goto error;
}
item_tmp = para_list.pop();
if (Item::FIELD_ITEM != item_tmp->type()) {
rc = SDB_ERR_COND_UNKOWN_ITEM;
goto error;
}
obj = BSON(((Item_field *)item_tmp)->field_name << BSON(this->name() << 0));
done:
return rc;
error:
goto done;
}
Sdb_func_bin_op::Sdb_func_bin_op() {
para_num_max = 2;
}
Sdb_func_bin_op::~Sdb_func_bin_op() {}
Sdb_func_cmp::Sdb_func_cmp() {}
Sdb_func_cmp::~Sdb_func_cmp() {}
int Sdb_func_cmp::to_bson_with_child(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
Sdb_item *child = NULL;
Item *field1 = NULL, *field2 = NULL, *field3 = NULL, *item_tmp;
Item_func *func = NULL;
Sdb_func_unkown *sdb_func = NULL;
bool cmp_inverse = FALSE;
bson::BSONObj obj_tmp;
bson::BSONObjBuilder builder_tmp;
if (r_child != NULL) {
child = r_child;
cmp_inverse = TRUE;
} else {
child = l_child;
}
if (child->type() != Item_func::UNKNOWN_FUNC || !child->finished() ||
((Sdb_func_item *)child)->get_para_num() != 2 ||
this->get_para_num() != 2) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
sdb_func = (Sdb_func_unkown *)child;
item_tmp = sdb_func->get_func_item();
if (item_tmp->type() != Item::FUNC_ITEM) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
func = (Item_func *)item_tmp;
if (func->functype() != Item_func::UNKNOWN_FUNC) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (sdb_func->pop_item(field1) || sdb_func->pop_item(field2)) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
field3 = para_list.pop();
if (Item::FIELD_ITEM == field1->type()) {
if (Item::FIELD_ITEM == field2->type()) {
if (!(field3->const_item()) || (0 != strcmp(func->func_name(), "-") &&
0 != strcmp(func->func_name(), "/"))) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (0 == strcmp(func->func_name(), "-")) {
// field1 - field2 < num
rc = get_item_val("$add", field3, ((Item_field *)field2)->field,
obj_tmp);
} else {
// field1 / field2 < num
rc = get_item_val("$multiply", field3, ((Item_field *)field2)->field,
obj_tmp);
}
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
obj_tmp =
BSON((cmp_inverse ? this->name() : this->inverse_name())
<< BSON("$field" << ((Item_field *)field1)->field->field_name));
builder_tmp.appendElements(obj_tmp);
obj_tmp = builder_tmp.obj();
obj = BSON(((Item_field *)field2)->field_name << obj_tmp);
} else {
if (!field2->const_item()) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (0 == strcmp(func->func_name(), "+")) {
rc = get_item_val("$add", field2, ((Item_field *)field1)->field,
obj_tmp);
} else if (0 == strcmp(func->func_name(), "-")) {
rc = get_item_val("$subtract", field2, ((Item_field *)field1)->field,
obj_tmp);
} else if (0 == strcmp(func->func_name(), "*")) {
rc = get_item_val("$multiply", field2, ((Item_field *)field1)->field,
obj_tmp);
} else if (0 == strcmp(func->func_name(), "/")) {
rc = get_item_val("$divide", field2, ((Item_field *)field1)->field,
obj_tmp);
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
}
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
if (Item::FIELD_ITEM == field3->type()) {
// field1 - num < field3
obj_tmp = BSON(
(cmp_inverse ? this->inverse_name() : this->name())
<< BSON("$field" << ((Item_field *)field3)->field->field_name));
} else {
// field1 - num1 < num3
rc = get_item_val((cmp_inverse ? this->inverse_name() : this->name()),
field3, ((Item_field *)field1)->field, obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
}
builder_tmp.appendElements(obj_tmp);
obj_tmp = builder_tmp.obj();
obj = BSON(((Item_field *)field1)->field->field_name << obj_tmp);
}
} else {
if (!field1->const_item()) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (Item::FIELD_ITEM == field2->type()) {
if (Item::FIELD_ITEM == field3->type()) {
// num + field2 < field3
if (0 == strcmp(func->func_name(), "+")) {
rc = get_item_val("$add", field1, ((Item_field *)field2)->field,
obj_tmp);
} else if (0 == strcmp(func->func_name(), "*")) {
rc = get_item_val("$multiply", field1, ((Item_field *)field2)->field,
obj_tmp);
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
}
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
obj_tmp = BSON(
(cmp_inverse ? this->inverse_name() : this->name())
<< BSON("$field" << ((Item_field *)field3)->field->field_name));
builder_tmp.appendElements(obj_tmp);
obj = BSON(((Item_field *)field2)->field->field_name
<< builder_tmp.obj());
} else {
if (!field3->const_item()) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
if (0 == strcmp(func->func_name(), "+")) {
// num1 + field2 < num3
rc = get_item_val("$add", field1, ((Item_field *)field2)->field,
obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
rc = get_item_val((cmp_inverse ? this->inverse_name() : this->name()),
field3, ((Item_field *)field2)->field, obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
obj = BSON(((Item_field *)field2)->field->field_name
<< builder_tmp.obj());
} else if (0 == strcmp(func->func_name(), "-")) {
// num1 - field2 < num3 => num1 < num3 + field2
rc = get_item_val("$add", field3, ((Item_field *)field2)->field,
obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
rc = get_item_val((cmp_inverse ? this->name() : this->inverse_name()),
field1, ((Item_field *)field2)->field, obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
obj = BSON(((Item_field *)field2)->field->field_name
<< builder_tmp.obj());
} else if (0 == strcmp(func->func_name(), "*")) {
// num1 * field2 < num3
rc = get_item_val("$multiply", field1, ((Item_field *)field2)->field,
obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
rc = get_item_val((cmp_inverse ? this->inverse_name() : this->name()),
field3, ((Item_field *)field2)->field, obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
obj = BSON(((Item_field *)field2)->field->field_name
<< builder_tmp.obj());
} else if (0 == strcmp(func->func_name(), "/")) {
// num1 / field2 < num3 => num1 < num3 + field2
rc = get_item_val("$multiply", field3, ((Item_field *)field2)->field,
obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
rc = get_item_val((cmp_inverse ? this->name() : this->inverse_name()),
field1, ((Item_field *)field2)->field, obj_tmp);
if (rc != SDB_ERR_OK) {
goto error;
}
builder_tmp.appendElements(obj_tmp);
obj = BSON(((Item_field *)field2)->field->field_name
<< builder_tmp.obj());
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
}
} else {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
}
done:
return rc;
error:
goto done;
}
int Sdb_func_cmp::to_bson(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
bool inverse = FALSE;
bool cmp_with_field = FALSE;
Item *item_tmp = NULL, *item_val = NULL;
Item_field *item_field = NULL;
const char *name_tmp = NULL;
bson::BSONObj obj_tmp;
if (!is_finished || para_list.elements != para_num_max) {
rc = SDB_ERR_COND_INCOMPLETED;
goto error;
}
if (l_child != NULL || r_child != NULL) {
rc = to_bson_with_child(obj);
if (rc != SDB_ERR_OK) {
goto error;
}
goto done;
}
while (!para_list.is_empty()) {
item_tmp = para_list.pop();
if (Item::FIELD_ITEM != item_tmp->type() || item_tmp->const_item()) {
if (NULL == item_field) {
inverse = TRUE;
}
if (item_val != NULL) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
item_val = item_tmp;
} else {
if (item_field != NULL) {
if (item_val != NULL) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
goto error;
}
if (NULL == item_field->db_name ||
NULL == ((Item_field *)item_tmp)->db_name ||
NULL == item_field->table_name ||
NULL == ((Item_field *)item_tmp)->table_name ||
0 != strcmp(item_field->db_name,
((Item_field *)item_tmp)->db_name) ||
0 != strcmp(item_field->table_name,
((Item_field *)item_tmp)->table_name)) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
goto error;
}
item_val = item_tmp;
cmp_with_field = TRUE;
} else {
item_field = (Item_field *)item_tmp;
}
}
}
if (inverse) {
name_tmp = this->inverse_name();
} else {
name_tmp = this->name();
}
if (cmp_with_field) {
enum_field_types l_type = item_field->field->type();
enum_field_types r_type = ((Item_field *)item_val)->field->type();
if (MYSQL_TYPE_JSON == l_type || MYSQL_TYPE_JSON == r_type) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
goto error;
}
if (l_type != r_type) {
// floating-point values in different types can't compare
if (sdb_field_is_floating(l_type) && sdb_field_is_floating(r_type)) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
goto error;
}
// date and time types can't compare
if (sdb_field_is_date_time(l_type) || sdb_field_is_date_time(r_type)) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
goto error;
}
}
obj = BSON(item_field->field_name
<< BSON(name_tmp << BSON(
"$field" << ((Item_field *)item_val)->field_name)));
goto done;
}
rc = get_item_val(name_tmp, item_val, item_field->field, obj_tmp);
if (rc) {
goto error;
}
obj = BSON(item_field->field_name << obj_tmp);
done:
return rc;
error:
if (SDB_ERR_OVF == rc) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
}
goto done;
}
Sdb_func_between::Sdb_func_between(bool has_not) : Sdb_func_neg(has_not) {
para_num_max = 3;
}
Sdb_func_between::~Sdb_func_between() {}
int Sdb_func_between::to_bson(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
Item_field *item_field = NULL;
Item *item_start = NULL, *item_end = NULL, *item_tmp = NULL;
bson::BSONObj obj_start, obj_end, obj_tmp;
bson::BSONArrayBuilder arr_builder;
if (!is_finished || para_list.elements != para_num_max) {
rc = SDB_ERR_COND_INCOMPLETED;
goto error;
}
if (l_child != NULL || r_child != NULL) {
rc = SDB_ERR_COND_UNKOWN_ITEM;
goto error;
}
item_tmp = para_list.pop();
if (Item::FIELD_ITEM != item_tmp->type()) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
item_field = (Item_field *)item_tmp;
item_start = para_list.pop();
item_end = para_list.pop();
if (negated) {
rc = get_item_val("$lt", item_start, item_field->field, obj_tmp);
if (rc) {
goto error;
}
obj_start = BSON(item_field->field_name << obj_tmp);
rc = get_item_val("$gt", item_end, item_field->field, obj_tmp);
if (rc) {
goto error;
}
obj_end = BSON(item_field->field_name << obj_tmp);
arr_builder.append(obj_start);
arr_builder.append(obj_end);
obj = BSON("$or" << arr_builder.arr());
} else {
rc = get_item_val("$gte", item_start, item_field->field, obj_tmp);
if (rc) {
goto error;
}
obj_start = BSON(item_field->field_name << obj_tmp);
rc = get_item_val("$lte", item_end, item_field->field, obj_tmp);
if (rc) {
goto error;
}
obj_end = BSON(item_field->field_name << obj_tmp);
arr_builder.append(obj_start);
arr_builder.append(obj_end);
obj = BSON("$and" << arr_builder.arr());
}
done:
return rc;
error:
if (SDB_ERR_OVF == rc) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
}
goto done;
}
Sdb_func_in::Sdb_func_in(bool has_not, uint args_num) : Sdb_func_neg(has_not) {
para_num_max = args_num;
}
Sdb_func_in::~Sdb_func_in() {}
int Sdb_func_in::to_bson(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
Item_field *item_field = NULL;
Item *item_tmp = NULL;
bson::BSONArrayBuilder arr_builder;
bson::BSONObj obj_tmp;
if (!is_finished || para_list.elements != para_num_max) {
rc = SDB_ERR_COND_INCOMPLETED;
goto error;
}
if (l_child != NULL || r_child != NULL) {
rc = SDB_ERR_COND_UNKOWN_ITEM;
goto error;
}
item_tmp = para_list.pop();
if (Item::FIELD_ITEM != item_tmp->type()) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
item_field = (Item_field *)item_tmp;
while (!para_list.is_empty()) {
item_tmp = para_list.pop();
rc = get_item_val("", item_tmp, item_field->field, obj_tmp, &arr_builder);
if (rc) {
goto error;
}
}
if (negated) {
obj = BSON(item_field->field_name << BSON("$nin" << arr_builder.arr()));
} else {
obj = BSON(item_field->field_name << BSON("$in" << arr_builder.arr()));
}
done:
return rc;
error:
if (SDB_ERR_OVF == rc) {
rc = SDB_ERR_COND_PART_UNSUPPORTED;
}
goto done;
}
Sdb_func_like::Sdb_func_like(Item_func_like *item) : like_item(item) {}
Sdb_func_like::~Sdb_func_like() {}
int Sdb_func_like::to_bson(bson::BSONObj &obj) {
int rc = SDB_ERR_OK;
Item_field *item_field = NULL;
Item *item_tmp = NULL;
Item_string *item_val = NULL;
String *str_val_org;
String str_val_conv;
std::string regex_val;
bson::BSONObjBuilder regex_builder;
if (!is_finished || para_list.elements != para_num_max) {
rc = SDB_ERR_COND_INCOMPLETED;
goto error;
}
if (!like_item->escape_is_evaluated() || !my_isascii(like_item->escape)) {
rc = SDB_ERR_COND_UNSUPPORTED;
goto error;
}
if (l_child != NULL || r_child != NULL) {
rc = SDB_ERR_COND_UNKOWN_ITEM;
goto error;
}
while (!para_list.is_empty()) {
item_tmp = para_list.pop();
if (Item::FIELD_ITEM != item_tmp->type()) {
if (item_tmp->type() != Item::STRING_ITEM // only support string
|| item_val != NULL) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
item_val = (Item_string *)item_tmp;
} else {
if (item_field != NULL) {
// not support: field1 like field2
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
item_field = (Item_field *)item_tmp;
// only support the string-field
if ((item_field->field_type() != MYSQL_TYPE_VARCHAR &&
item_field->field_type() != MYSQL_TYPE_VAR_STRING &&
item_field->field_type() != MYSQL_TYPE_STRING &&
item_field->field_type() != MYSQL_TYPE_TINY_BLOB &&
item_field->field_type() != MYSQL_TYPE_MEDIUM_BLOB &&
item_field->field_type() != MYSQL_TYPE_LONG_BLOB &&
item_field->field_type() != MYSQL_TYPE_BLOB) ||
item_field->field->binary()) {
rc = SDB_ERR_COND_UNEXPECTED_ITEM;
goto error;
}
}
}
str_val_org = item_val->val_str(NULL);
rc = sdb_convert_charset(*str_val_org, str_val_conv, &SDB_CHARSET);
if (rc) {
goto error;
}
rc = get_regex_str(str_val_conv.ptr(), str_val_conv.length(), regex_val);
if (rc) {
goto error;
}
if (regex_val.empty()) {
// select * from t1 where a like "";
// => {a:""}
obj = BSON(item_field->field_name << regex_val);
} else {
regex_builder.appendRegex(item_field->field_name, regex_val, "s");
obj = regex_builder.obj();
}
done:
return rc;
error:
goto done;
}
int Sdb_func_like::get_regex_str(const char *like_str, size_t len,
std::string &regex_str) {
int rc = SDB_ERR_OK;
const char *p_prev, *p_cur, *p_begin, *p_end, *p_last;
char str_buf[SDB_MATCH_FIELD_SIZE_MAX + 2] = {0}; // reserve one byte for '\'
int buf_pos = 0;
regex_str = "";
int escape_char = like_item->escape;
if (0 == len) {
// select * from t1 where field like "" ;
// => {field: ""}
goto done;
}
p_begin = like_str;
p_end = p_begin + len - 1;
p_prev = NULL;
p_cur = p_begin;
p_last = p_begin;
while (p_cur <= p_end) {
if (buf_pos >= SDB_MATCH_FIELD_SIZE_MAX) {
// reserve 2 byte for character and '\'
rc = SDB_ERR_SIZE_OVF;
}
if ('%' == *p_cur || '_' == *p_cur) {
// '%' and '_' are treated as normal character
if (p_prev != NULL && escape_char == *p_prev) {
// skip the escape
str_buf[buf_pos - 1] = *p_cur;
p_prev = NULL;
} else {
// begin with the string:
// select * from t1 where field like "abc%"
// => (^abc.*)
if (p_begin == p_last) {
regex_str = "^";
}
if (buf_pos > 0) {
regex_str.append(str_buf, buf_pos);
buf_pos = 0;
}
if ('%' == *p_cur) {
regex_str.append(".*");
} else {
regex_str.append(".");
}
p_last = p_cur + 1;
++p_cur;
continue;
}
} else {
if (p_prev != NULL && escape_char == *p_prev) {
if (buf_pos > 0) {
// skip the escape.
--buf_pos;
}
if ('(' == *p_cur || ')' == *p_cur || '[' == *p_cur || ']' == *p_cur ||
'{' == *p_cur || '}' == *p_cur || '\\' == *p_cur || '^' == *p_cur ||
'$' == *p_cur || '.' == *p_cur || '|' == *p_cur || '*' == *p_cur ||
'+' == *p_cur || '?' == *p_cur || '-' == *p_cur) {
/* process perl regexp special characters: {}[]()^$.|*+?-\ */
/* add '\' before the special character */
str_buf[buf_pos++] = '\\';
}
str_buf[buf_pos++] = *p_cur;
p_prev = NULL;
} else {
if (('(' == *p_cur || ')' == *p_cur || '[' == *p_cur || ']' == *p_cur ||
'{' == *p_cur || '}' == *p_cur || '^' == *p_cur || '$' == *p_cur ||
'.' == *p_cur || '|' == *p_cur || '*' == *p_cur || '+' == *p_cur ||
'?' == *p_cur || '-' == *p_cur || '\\' == *p_cur) &&
(escape_char != *p_cur)) {
/* process perl regexp special characters: {}[]()^$.|*+?-\ */
/* add '\' before the special character */
str_buf[buf_pos++] = '\\';
str_buf[buf_pos++] = *p_cur;
} else {
str_buf[buf_pos++] = *p_cur;
}
p_prev = p_cur;
}
}
++p_cur;
}
if (p_last == p_begin) {
regex_str = "^";
}
if (buf_pos > 0) {
regex_str.append(str_buf, buf_pos);
buf_pos = 0;
}
regex_str.append("$");
done:
return rc;
}

Comment ( 0 )

Sign in for post a comment