File query_opfunc.c¶
File List > cubrid > src > query > query_opfunc.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* query_opfunc.c - The manipulation of data stored in the XASL nodes
*/
#ident "$Id$"
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <float.h>
#include <math.h>
#include <assert.h>
#include "query_opfunc.h"
#include "system_parameter.h"
#include "error_manager.h"
#include "fetch.h"
#include "list_file.h"
#include "object_domain.h"
#include "object_primitive.h"
#include "object_representation.h"
#include "set_object.h"
#include "query_executor.h"
#include "databases_file.h"
#include "tz_support.h"
#include "memory_hash.h"
#include "numeric_opfunc.h"
#include "tz_support.h"
#include "db_date.h"
#include "dbtype.h"
#include "query_dump.h"
#include "query_list.h"
#include "db_json.hpp"
#include "arithmetic.h"
#include "xasl.h"
#include "xasl_aggregate.hpp"
#include "xasl_analytic.hpp"
#include "dbtype.h"
#include <chrono>
#include <regex>
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
#define NOT_NULL_VALUE(a, b) ((a) ? (a) : (b))
#define INITIAL_OID_STACK_SIZE 1
#define SYS_CONNECT_BY_PATH_MEM_STEP 256
static bool qdata_is_zero_value_date (DB_VALUE * dbval_p);
static int qdata_add_short (short s, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_int (int i1, int i2, DB_VALUE * result_p);
static int qdata_add_bigint (DB_BIGINT i1, DB_BIGINT i2, DB_VALUE * result_p);
static int qdata_add_float (float f1, float f2, DB_VALUE * result_p);
static int qdata_add_double (double d1, double d2, DB_VALUE * result_p);
static double qdata_coerce_numeric_to_double (DB_VALUE * numeric_val_p);
static void qdata_coerce_dbval_to_numeric (DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_numeric (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_numeric_to_monetary (DB_VALUE * numeric_val_p, DB_VALUE * monetary_val_p, DB_VALUE * result_p);
static int qdata_add_monetary (double d1, double d2, DB_CURRENCY type, DB_VALUE * result_p);
static int qdata_add_bigint_to_time (DB_VALUE * time_val_p, DB_BIGINT add_time, DB_VALUE * result_p);
static int qdata_add_short_to_utime_asymmetry (DB_VALUE * utime_val_p, short s, unsigned int *utime,
DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_int_to_utime_asymmetry (DB_VALUE * utime_val_p, int i, unsigned int *utime, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_short_to_utime (DB_VALUE * utime_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_int_to_utime (DB_VALUE * utime_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_bigint_to_utime (DB_VALUE * utime_val_p, DB_BIGINT bi, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_short_to_timestamptz (DB_VALUE * ts_tz_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_int_to_timestamptz (DB_VALUE * ts_tz_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_bigint_to_timestamptz (DB_VALUE * ts_tz_val_p, DB_BIGINT bi, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_short_to_datetime (DB_VALUE * datetime_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_int_to_datetime (DB_VALUE * datetime_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_bigint_to_datetime (DB_VALUE * datetime_val_p, DB_BIGINT bi, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_short_to_date (DB_VALUE * date_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_int_to_date (DB_VALUE * date_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_bigint_to_date (DB_VALUE * date_val_p, DB_BIGINT i, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_add_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_chars_to_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p);
static int qdata_add_sequence_to_dbval (DB_VALUE * seq_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_time_to_dbval (DB_VALUE * time_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_utime_to_dbval (DB_VALUE * utime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_timestamptz_to_dbval (DB_VALUE * ts_tz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_datetime_to_dbval (DB_VALUE * datetime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_add_datetimetz_to_dbval (DB_VALUE * datetimetz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_add_date_to_dbval (DB_VALUE * date_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_coerce_result_to_domain (DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_cast_to_domain (DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_subtract_short (short s1, short s2, DB_VALUE * result_p);
static int qdata_subtract_int (int i1, int i2, DB_VALUE * result_p);
static int qdata_subtract_bigint (DB_BIGINT i1, DB_BIGINT i2, DB_VALUE * result_p);
static int qdata_subtract_float (float f1, float f2, DB_VALUE * result_p);
static int qdata_subtract_double (double d1, double d2, DB_VALUE * result_p);
static int qdata_subtract_monetary (double d1, double d2, DB_CURRENCY currency, DB_VALUE * result_p);
static int qdata_subtract_time (DB_TIME u1, DB_TIME u2, DB_VALUE * result_p);
static int qdata_subtract_utime (DB_UTIME u1, DB_UTIME u2, DB_VALUE * result_p);
static int qdata_subtract_utime_to_short_asymmetry (DB_VALUE * utime_val_p, short s, unsigned int *utime,
DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_subtract_utime_to_int_asymmetry (DB_VALUE * utime_val_p, int i, unsigned int *utime,
DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_subtract_datetime_to_int (DB_DATETIME * dt1, DB_BIGINT i2, DB_VALUE * result_p);
static int qdata_subtract_datetime (DB_DATETIME * dt1, DB_DATETIME * dt2, DB_VALUE * result_p);
static int qdata_subtract_datetime_to_int_asymmetry (DB_VALUE * datetime_val_p, DB_BIGINT i, DB_DATETIME * datetime,
DB_VALUE * result_p, TP_DOMAIN * domain_p);
static int qdata_subtract_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_sequence_to_dbval (DB_VALUE * seq_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_subtract_time_to_dbval (DB_VALUE * time_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_subtract_utime_to_dbval (DB_VALUE * utime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_subtract_timestampltz_to_dbval (DB_VALUE * ts_ltz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_subtract_timestamptz_to_dbval (DB_VALUE * utime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_subtract_datetime_to_dbval (DB_VALUE * datetime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_subtract_datetimetz_to_dbval (DB_VALUE * dt_tz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_subtract_date_to_dbval (DB_VALUE * date_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static int qdata_multiply_short (DB_VALUE * short_val_p, short s2, DB_VALUE * result_p);
static int qdata_multiply_int (DB_VALUE * int_val_p, int i2, DB_VALUE * result_p);
static int qdata_multiply_bigint (DB_VALUE * bigint_val_p, DB_BIGINT bi2, DB_VALUE * result_p);
static int qdata_multiply_float (DB_VALUE * float_val_p, float f2, DB_VALUE * result_p);
static int qdata_multiply_double (double d1, double d2, DB_VALUE * result_p);
static int qdata_multiply_numeric (DB_VALUE * numeric_val_p, DB_VALUE * dbval, DB_VALUE * result_p);
static int qdata_multiply_monetary (DB_VALUE * monetary_val_p, double d, DB_VALUE * result_p);
static int qdata_multiply_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_multiply_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_multiply_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_multiply_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_multiply_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_multiply_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_multiply_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_multiply_sequence_to_dbval (DB_VALUE * seq_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p);
static bool qdata_is_divided_zero (DB_VALUE * dbval_p);
static int qdata_divide_short (short s1, short s2, DB_VALUE * result_p);
static int qdata_divide_int (int i1, int i2, DB_VALUE * result_p);
static int qdata_divide_bigint (DB_BIGINT bi1, DB_BIGINT bi2, DB_VALUE * result_p);
static int qdata_divide_float (float f1, float f2, DB_VALUE * result_p);
static int qdata_divide_double (double d1, double d2, DB_VALUE * result_p, bool is_check_overflow);
static int qdata_divide_monetary (double d1, double d2, DB_CURRENCY currency, DB_VALUE * result_p,
bool is_check_overflow);
static int qdata_divide_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_divide_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_divide_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_divide_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_divide_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_divide_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static int qdata_divide_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p);
static DB_VALUE *qdata_get_dbval_from_constant_regu_variable (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var,
VAL_DESCR * val_desc_p);
static int qdata_convert_dbvals_to_set (THREAD_ENTRY * thread_p, DB_TYPE stype, REGU_VARIABLE * func,
VAL_DESCR * val_desc_p, OID * obj_oid_p, QFILE_TUPLE tuple);
static int qdata_evaluate_generic_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple);
static int qdata_get_class_of_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple);
static int qdata_convert_table_to_set (THREAD_ENTRY * thread_p, DB_TYPE stype, REGU_VARIABLE * func,
VAL_DESCR * val_desc_p);
static int qdata_insert_substring_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple);
static int qdata_elt (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p, OID * obj_oid_p,
QFILE_TUPLE tuple);
static int qdata_benchmark (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple);
static int qdata_regexp_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple);
static int qdata_convert_operands_to_value_and_call (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p,
VAL_DESCR * val_desc_p, OID * obj_oid_p, QFILE_TUPLE tuple,
int (*function_to_call) (DB_VALUE *, DB_VALUE * const *,
int const));
static bool
qdata_is_zero_value_date (DB_VALUE * dbval_p)
{
DB_TYPE type;
DB_UTIME *utime;
DB_DATE *date;
DB_DATETIME *datetime;
DB_TIMESTAMPTZ *ts_tz;
DB_DATETIMETZ *dt_tz;
if (DB_IS_NULL (dbval_p)) /* NULL is not zero value */
{
return false;
}
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
if (TP_IS_DATE_TYPE (type))
{
switch (type)
{
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
utime = db_get_timestamp (dbval_p);
return (*utime == 0);
case DB_TYPE_TIMESTAMPTZ:
ts_tz = db_get_timestamptz (dbval_p);
return (ts_tz->timestamp == 0);
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
datetime = db_get_datetime (dbval_p);
return (datetime->date == 0 && datetime->time == 0);
case DB_TYPE_DATETIMETZ:
dt_tz = db_get_datetimetz (dbval_p);
return (dt_tz->datetime.date == 0 && dt_tz->datetime.time == 0);
case DB_TYPE_DATE:
date = db_get_date (dbval_p);
return (*date == 0);
default:
break;
}
}
return false;
}
/*
* qdata_set_value_list_to_null () -
* return:
* val_list(in) : Value List
*
* Note: Set all db_values on the value list to null.
*/
void
qdata_set_value_list_to_null (val_list_node * val_list_p)
{
QPROC_DB_VALUE_LIST db_val_list;
if (val_list_p == NULL)
{
return;
}
db_val_list = val_list_p->valp;
while (db_val_list)
{
pr_clear_value (db_val_list->val);
db_val_list = db_val_list->next;
}
}
/*
* COPY ROUTINES
*/
/*
* qdata_copy_db_value () -
* return: int (true on success, false on failure)
* dbval1(in) : Destination db_value node
* dbval2(in) : Source db_value node
*
* Note: Copy source value to destination value.
*/
bool
qdata_copy_db_value (DB_VALUE * dest_p, const DB_VALUE * src_p)
{
const PR_TYPE *pr_type_p;
DB_TYPE src_type;
/* check if there is nothing to do, so we don't clobber a db_value if we happen to try to copy it to itself */
if (dest_p == src_p)
{
return true;
}
/* clear any value from a previous iteration */
(void) pr_clear_value (dest_p);
src_type = DB_VALUE_DOMAIN_TYPE (src_p);
pr_type_p = pr_type_from_id (src_type);
if (pr_type_p == NULL)
{
return false;
}
if (pr_type_p->setval (dest_p, src_p, true) == NO_ERROR)
{
return true;
}
else
{
return false;
}
}
/*
* qdata_copy_db_value_to_tuple_value () -
* return: int (true on success, false on failure)
* dbval(in) : Source dbval node
* tvalp(in) : Tuple value
* tval_size(out) : Set to the tuple value size
*
* Note: Copy an db_value to an tuple value.
* THIS ROUTINE ASSUMES THAT THE VALUE WILL FIT IN THE TPL!!!!
*/
int
qdata_copy_db_value_to_tuple_value (DB_VALUE * dbval_p, char *tuple_val_p, int *tuple_val_size)
{
char *val_p;
int val_size, align, rc;
OR_BUF buf;
const PR_TYPE *pr_type;
DB_TYPE dbval_type;
if (DB_IS_NULL (dbval_p))
{
QFILE_PUT_TUPLE_VALUE_FLAG (tuple_val_p, V_UNBOUND);
QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_val_p, 0);
*tuple_val_size = QFILE_TUPLE_VALUE_HEADER_SIZE;
}
else
{
QFILE_PUT_TUPLE_VALUE_FLAG (tuple_val_p, V_BOUND);
val_p = (char *) tuple_val_p + QFILE_TUPLE_VALUE_HEADER_SIZE;
dbval_type = DB_VALUE_DOMAIN_TYPE (dbval_p);
pr_type = pr_type_from_id (dbval_type);
if (pr_type == NULL)
{
return ER_FAILED;
}
val_size = pr_data_writeval_disk_size (dbval_p);
or_init (&buf, val_p, val_size);
rc = pr_type->data_writeval (&buf, dbval_p);
if (buf.ptr > buf.endptr || rc != NO_ERROR)
{
/* This should not happen */
assert_release (false);
return ER_FAILED;
}
/* I don't know if the following is still true. */
/* since each tuple data value field is already aligned with MAX_ALIGNMENT, val_size by itself can be used to
* find the maximum alignment for the following field which is next val_header */
align = DB_ALIGN (val_size, MAX_ALIGNMENT); /* to align for the next field */
*tuple_val_size = QFILE_TUPLE_VALUE_HEADER_SIZE + align;
QFILE_PUT_TUPLE_VALUE_LENGTH (tuple_val_p, align);
#if !defined(NDEBUG)
/* suppress valgrind UMW error */
memset (tuple_val_p + QFILE_TUPLE_VALUE_HEADER_SIZE + val_size, 0, align - val_size);
#endif
}
return NO_ERROR;
}
/*
* qdata_copy_valptr_list_to_tuple () -
* return: NO_ERROR, or ER_code
* valptr_list(in) : Value pointer list
* vd(in) : Value descriptor
* tplrec(in) : Tuple descriptor
*
* Note: Copy valptr_list values to tuple descriptor. Regu variables
* that are hidden columns are not copied to the list file tuple
*/
int
qdata_copy_valptr_list_to_tuple (THREAD_ENTRY * thread_p, valptr_list_node * valptr_list_p, val_descr * val_desc_p,
qfile_tuple_record * tuple_record_p)
{
REGU_VARIABLE_LIST reg_var_p;
REGU_VARIABLE *regu_var_p;
DB_VALUE *dbval_p;
char *tuple_p;
int k, tval_size, tlen, tpl_size;
int n_size, toffset;
int flags;
tpl_size = 0;
tlen = QFILE_TUPLE_LENGTH_SIZE;
toffset = 0; /* tuple offset position */
/* skip the length of the tuple, we'll fill it in after we know what it is */
tuple_p = (char *) (tuple_record_p->tpl) + tlen;
toffset += tlen;
/* copy each value into the tuple */
reg_var_p = valptr_list_p->valptrp;
for (k = 0; k < valptr_list_p->valptr_cnt; k++, reg_var_p = reg_var_p->next)
{
regu_var_p = ®_var_p->value;
flags = regu_var_p->flags;
if (unlikely (flags & REGU_VARIABLE_HIDDEN_COLUMN))
{
continue;
}
dbval_p = qdata_get_dbval_from_constant_regu_variable (thread_p, regu_var_p, val_desc_p);
if (dbval_p == NULL)
{
return ER_FAILED;
}
n_size = qdata_get_tuple_value_size_from_dbval (dbval_p);
if (n_size == ER_FAILED)
{
return ER_FAILED;
}
if ((tuple_record_p->size - toffset) < n_size)
{
/* no space left in tuple to put next item, increase the tuple size by the max of n_size and DB_PAGE_SIZE
* since we can't compute the actual tuple size without re-evaluating the expressions. This guarantees
* that we can at least get the next value into the tuple. */
tpl_size = MAX (tuple_record_p->size, QFILE_TUPLE_LENGTH_SIZE);
tpl_size += MAX (n_size, DB_PAGESIZE);
if (tuple_record_p->size == 0)
{
tuple_record_p->tpl = (char *) db_private_alloc (thread_p, tpl_size);
if (tuple_record_p->tpl == NULL)
{
return ER_FAILED;
}
}
else
{
tuple_record_p->tpl = (char *) db_private_realloc (thread_p, tuple_record_p->tpl, tpl_size);
if (tuple_record_p->tpl == NULL)
{
return ER_FAILED;
}
}
tuple_record_p->size = tpl_size;
tuple_p = (char *) (tuple_record_p->tpl) + toffset;
}
if (qdata_copy_db_value_to_tuple_value (dbval_p, tuple_p, &tval_size) != NO_ERROR)
{
return ER_FAILED;
}
tlen += tval_size;
tuple_p += tval_size;
toffset += tval_size;
}
/* now that we know the tuple size, set it. */
QFILE_PUT_TUPLE_LENGTH (tuple_record_p->tpl, tlen);
return NO_ERROR;
}
int
qdata_copy_val_list_to_tuple (THREAD_ENTRY * thread_p, VAL_LIST * val_list, qfile_tuple_record * tuple_record_p)
{
QPROC_DB_VALUE_LIST val_list_iterator;
int val_list_index;
DB_VALUE *dbval_p;
char *tuple_p;
int tval_size, tlen, tpl_size;
int n_size, toffset;
int flags;
tpl_size = 0;
tlen = QFILE_TUPLE_LENGTH_SIZE;
toffset = 0;
tuple_p = (char *) (tuple_record_p->tpl) + tlen;
toffset += tlen;
val_list_iterator = val_list->valp;
for (val_list_index = 0; val_list_iterator; val_list_iterator = val_list_iterator->next, val_list_index++)
{
dbval_p = val_list_iterator->val;
n_size = qdata_get_tuple_value_size_from_dbval (dbval_p);
if (n_size == ER_FAILED)
{
return ER_FAILED;
}
if (unlikely ((tuple_record_p->size - toffset) < n_size))
{
/* no space left in tuple to put next item, increase the tuple size by the max of n_size and DB_PAGE_SIZE
* since we can't compute the actual tuple size without re-evaluating the expressions. This guarantees
* that we can at least get the next value into the tuple. */
tpl_size = MAX (tuple_record_p->size, QFILE_TUPLE_LENGTH_SIZE);
tpl_size += MAX (n_size, DB_PAGESIZE);
if (tuple_record_p->size == 0)
{
tuple_record_p->tpl = (char *) db_private_alloc (thread_p, tpl_size);
if (tuple_record_p->tpl == NULL)
{
return ER_FAILED;
}
}
else
{
tuple_record_p->tpl = (char *) db_private_realloc (thread_p, tuple_record_p->tpl, tpl_size);
if (tuple_record_p->tpl == NULL)
{
return ER_FAILED;
}
}
tuple_record_p->size = tpl_size;
tuple_p = (char *) (tuple_record_p->tpl) + toffset;
}
if (qdata_copy_db_value_to_tuple_value (dbval_p, tuple_p, &tval_size) != NO_ERROR)
{
return ER_FAILED;
}
tlen += tval_size;
tuple_p += tval_size;
toffset += tval_size;
}
QFILE_PUT_TUPLE_LENGTH (tuple_record_p->tpl, tlen);
return NO_ERROR;
}
extern int
qdata_tuple_to_val_list (THREAD_ENTRY * thread_p, qfile_tuple_value_type_list * type_list, qfile_tuple_record * tplrec,
VAL_LIST * val_list)
{
QPROC_DB_VALUE_LIST val_list_iterator;
int val_list_index;
OR_BUF iterator, buf;
int err_code;
QFILE_TUPLE_VALUE_FLAG flag;
or_init (&iterator, tplrec->tpl, QFILE_GET_TUPLE_LENGTH (tplrec->tpl));
or_advance (&iterator, QFILE_TUPLE_LENGTH_SIZE);
for (val_list_iterator = val_list->valp, val_list_index = 0; val_list_iterator
&& val_list_index < val_list->val_cnt; val_list_iterator = val_list_iterator->next, val_list_index++)
{
qfile_locate_tuple_next_value (&iterator, &buf, &flag);
pr_clear_value (val_list_iterator->val);
if (flag == V_UNBOUND)
{
db_make_null (val_list_iterator->val);
continue;
}
err_code = type_list->domp[val_list_index]->type->data_readval (&buf, val_list_iterator->val,
type_list->domp[val_list_index],
-1, false /* Don't copy */ ,
NULL, 0);
if (err_code != NO_ERROR)
{
return err_code;
}
}
return NO_ERROR;
}
/*
* qdata_generate_tuple_desc_for_valptr_list () -
* return: QPROC_TPLDESCR_SUCCESS on success or
* QP_TPLDESCR_RETRY_xxx,
* QPROC_TPLDESCR_FAILURE
* valptr_list(in) : Value pointer list
* vd(in) : Value descriptor
* tdp(in) : Tuple descriptor
*
* Note: Generate tuple descriptor for given valptr_list values.
* Regu variables that are hidden columns are not copied
* to the list file tuple
*/
QPROC_TPLDESCR_STATUS
qdata_generate_tuple_desc_for_valptr_list (THREAD_ENTRY * thread_p, valptr_list_node * valptr_list_p,
val_descr * val_desc_p, qfile_tuple_descriptor * tuple_desc_p)
{
REGU_VARIABLE_LIST reg_var_p;
REGU_VARIABLE *regu_var_p;
int i;
int value_size;
int flags;
QPROC_TPLDESCR_STATUS status = QPROC_TPLDESCR_SUCCESS;
DB_TYPE dbval_type;
tuple_desc_p->tpl_size = QFILE_TUPLE_LENGTH_SIZE; /* set tuple size as header size */
tuple_desc_p->f_cnt = 0;
/* copy each value pointer into the each tdp field */
reg_var_p = valptr_list_p->valptrp;
for (i = 0; i < valptr_list_p->valptr_cnt; i++, reg_var_p = reg_var_p->next)
{
regu_var_p = ®_var_p->value;
flags = regu_var_p->flags;
if (unlikely (flags & REGU_VARIABLE_HIDDEN_COLUMN))
{
continue;
}
tuple_desc_p->f_valp[tuple_desc_p->f_cnt] =
qdata_get_dbval_from_constant_regu_variable (thread_p, regu_var_p, val_desc_p);
if (tuple_desc_p->f_valp[tuple_desc_p->f_cnt] == NULL)
{
status = QPROC_TPLDESCR_FAILURE;
goto exit_with_status;
}
dbval_type = DB_VALUE_DOMAIN_TYPE (tuple_desc_p->f_valp[tuple_desc_p->f_cnt]);
/* SET data-type cannot use tuple descriptor */
if (unlikely (pr_is_set_type (dbval_type)))
{
status = QPROC_TPLDESCR_RETRY_SET_TYPE;
goto exit_with_status;
}
/* add aligned field size to tuple size */
value_size = qdata_get_tuple_value_size_from_dbval (tuple_desc_p->f_valp[tuple_desc_p->f_cnt]);
if (value_size == ER_FAILED)
{
status = QPROC_TPLDESCR_FAILURE;
goto exit_with_status;
}
/* The compressed string will be deallocated later, after copying db_value into tuple. */
tuple_desc_p->tpl_size += value_size;
tuple_desc_p->f_cnt += 1; /* increase field number */
}
/* BIG RECORD cannot use tuple descriptor */
if (tuple_desc_p->tpl_size >= QFILE_MAX_TUPLE_SIZE_IN_PAGE)
{
status = QPROC_TPLDESCR_RETRY_BIG_REC;
}
exit_with_status:
return status;
}
/*
* qdata_set_valptr_list_unbound () -
* return: NO_ERROR, or ER_code
* valptr_list(in) : Value pointer list
* vd(in) : Value descriptor
*
* Note: Set valptr_list values UNBOUND.
*/
int
qdata_set_valptr_list_unbound (THREAD_ENTRY * thread_p, valptr_list_node * valptr_list_p, val_descr * val_desc_p)
{
REGU_VARIABLE_LIST reg_var_p;
DB_VALUE *dbval_p;
int i;
reg_var_p = valptr_list_p->valptrp;
for (i = 0; i < valptr_list_p->valptr_cnt; i++)
{
dbval_p = qdata_get_dbval_from_constant_regu_variable (thread_p, ®_var_p->value, val_desc_p);
if (dbval_p != NULL)
{
if (!REGU_VARIABLE_IS_FLAGED (®_var_p->value, REGU_VARIABLE_CLEAR_AT_CLONE_DECACHE))
{
/* this may be shared with another regu variable that was already evaluated */
pr_clear_value (dbval_p);
if (db_value_domain_init (dbval_p, DB_VALUE_DOMAIN_TYPE (dbval_p), DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE)
!= NO_ERROR)
{
return ER_FAILED;
}
}
}
reg_var_p = reg_var_p->next;
}
return NO_ERROR;
}
/*
* ARITHMETIC EXPRESSION EVALUATION ROUTINES
*/
static int
qdata_add_short (short s, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
short result, tmp;
tmp = db_get_short (dbval_p);
result = s + tmp;
if (OR_CHECK_ADD_OVERFLOW (s, tmp, result))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_short (result_p, result);
return NO_ERROR;
}
static int
qdata_add_int (int i1, int i2, DB_VALUE * result_p)
{
int result;
result = i1 + i2;
if (OR_CHECK_ADD_OVERFLOW (i1, i2, result))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_int (result_p, result);
return NO_ERROR;
}
static int
qdata_add_bigint (DB_BIGINT bi1, DB_BIGINT bi2, DB_VALUE * result_p)
{
DB_BIGINT result;
result = bi1 + bi2;
if (OR_CHECK_ADD_OVERFLOW (bi1, bi2, result))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_bigint (result_p, result);
return NO_ERROR;
}
static int
qdata_add_float (float f1, float f2, DB_VALUE * result_p)
{
float result;
result = f1 + f2;
if (OR_CHECK_FLOAT_OVERFLOW (result))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_float (result_p, result);
return NO_ERROR;
}
static int
qdata_add_double (double d1, double d2, DB_VALUE * result_p)
{
double result;
result = d1 + d2;
if (OR_CHECK_DOUBLE_OVERFLOW (result))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_double (result_p, result);
return NO_ERROR;
}
static double
qdata_coerce_numeric_to_double (DB_VALUE * numeric_val_p)
{
DB_VALUE dbval_tmp;
DB_DATA_STATUS data_stat;
db_value_domain_init (&dbval_tmp, DB_TYPE_DOUBLE, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
(void) numeric_db_value_coerce_from_num (numeric_val_p, &dbval_tmp, &data_stat);
return db_get_double (&dbval_tmp);
}
static void
qdata_coerce_dbval_to_numeric (DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_DATA_STATUS data_stat;
db_value_domain_init (result_p, DB_TYPE_NUMERIC, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
(void) numeric_db_value_coerce_to_num (dbval_p, result_p, &data_stat);
}
static int
qdata_add_numeric (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_VALUE dbval_tmp;
qdata_coerce_dbval_to_numeric (dbval_p, &dbval_tmp);
if (numeric_db_value_add (&dbval_tmp, numeric_val_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
return NO_ERROR;
}
static int
qdata_add_numeric_to_monetary (DB_VALUE * numeric_val_p, DB_VALUE * monetary_val_p, DB_VALUE * result_p)
{
double d1, d2, dtmp;
d1 = qdata_coerce_numeric_to_double (numeric_val_p);
d2 = (db_get_monetary (monetary_val_p))->amount;
dtmp = d1 + d2;
db_make_monetary (result_p, (db_get_monetary (monetary_val_p))->type, dtmp);
return NO_ERROR;
}
static int
qdata_add_monetary (double d1, double d2, DB_CURRENCY type, DB_VALUE * result_p)
{
double result;
result = d1 + d2;
if (OR_CHECK_DOUBLE_OVERFLOW (result))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_monetary (result_p, type, result);
return NO_ERROR;
}
#if defined (ENABLE_UNUSED_FUNCTION)
static int
qdata_add_int_to_time (DB_VALUE * time_val_p, unsigned int add_time, DB_VALUE * result_p)
{
unsigned int result, utime;
DB_TIME *time;
int hour, minute, second;
time = db_get_time (time_val_p);
utime = (unsigned int) *time % SECONDS_OF_ONE_DAY;
result = (utime + add_time) % SECONDS_OF_ONE_DAY;
db_time_decode (&result, &hour, &minute, &second);
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
db_make_time (result_p, hour, minute, second);
}
else
{
DB_TYPE type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_INTEGER:
db_make_int (result_p, (hour * 100 + minute) * 100 + second);
break;
case DB_TYPE_SHORT:
db_make_short (result_p, (hour * 100 + minute) * 100 + second);
break;
default:
db_make_time (result_p, hour, minute, second);
break;
}
}
return NO_ERROR;
}
#endif
static int
qdata_add_bigint_to_time (DB_VALUE * time_val_p, DB_BIGINT add_time, DB_VALUE * result_p)
{
DB_TIME utime, result;
int hour, minute, second;
int error = NO_ERROR;
utime = *(db_get_time (time_val_p)) % SECONDS_OF_ONE_DAY;
add_time = add_time % SECONDS_OF_ONE_DAY;
if (add_time < 0)
{
return qdata_subtract_time (utime, (DB_TIME) (-add_time), result_p);
}
result = (utime + add_time) % SECONDS_OF_ONE_DAY;
db_time_decode (&result, &hour, &minute, &second);
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
error = db_make_time (result_p, hour, minute, second);
}
else
{
DB_TYPE type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
error = db_make_bigint (result_p, (hour * 100 + minute) * 100 + second);
break;
case DB_TYPE_INTEGER:
error = db_make_int (result_p, (hour * 100 + minute) * 100 + second);
break;
default:
error = db_make_time (result_p, hour, minute, second);
break;
}
}
return error;
}
static int
qdata_add_short_to_utime_asymmetry (DB_VALUE * utime_val_p, short s, unsigned int *utime, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
DB_VALUE tmp;
if (s == DB_INT16_MIN) /* check for asymmetry */
{
if (*utime <= 1)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_TIME_UNDERFLOW, 0);
return ER_QPROC_TIME_UNDERFLOW;
}
(*utime)--;
s++;
}
db_make_short (&tmp, -(s));
return (qdata_subtract_dbval (utime_val_p, &tmp, result_p, domain_p));
}
static int
qdata_add_int_to_utime_asymmetry (DB_VALUE * utime_val_p, int i, unsigned int *utime, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
DB_VALUE tmp;
if (i == DB_INT32_MIN) /* check for asymmetry */
{
if (*utime <= 1)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_TIME_UNDERFLOW, 0);
return ER_QPROC_TIME_UNDERFLOW;
}
(*utime)--;
i++;
}
db_make_int (&tmp, -i);
return (qdata_subtract_dbval (utime_val_p, &tmp, result_p, domain_p));
}
static int
qdata_add_bigint_to_utime_asymmetry (DB_VALUE * utime_val_p, DB_BIGINT bi, unsigned int *utime, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
DB_VALUE tmp;
if (bi == DB_BIGINT_MIN) /* check for asymmetry */
{
if (*utime <= 1)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_TIME_UNDERFLOW, 0);
return ER_QPROC_TIME_UNDERFLOW;
}
(*utime)--;
bi++;
}
db_make_bigint (&tmp, -bi);
return (qdata_subtract_dbval (utime_val_p, &tmp, result_p, domain_p));
}
static int
qdata_add_short_to_utime (DB_VALUE * utime_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_UTIME *utime;
DB_UTIME utmp, u1, u2;
DB_DATE date;
DB_TIME time;
DB_TYPE type;
DB_BIGINT bigint = 0;
int d, m, y, h, mi, sec;
utime = db_get_timestamp (utime_val_p);
if (s < 0)
{
return qdata_add_short_to_utime_asymmetry (utime_val_p, s, utime, result_p, domain_p);
}
u1 = s;
u2 = *utime;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || INT_MAX < utmp)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
db_make_timestamp (result_p, utmp);
}
else
{
type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
(void) db_timestamp_decode_ses (&utmp, &date, &time);
db_date_decode (&date, &m, &d, &y);
db_time_decode (&time, &h, &mi, &sec);
bigint = (y * 100 + m) * 100 + d;
bigint = ((bigint * 100 + h) * 100 + mi) * 100 + sec;
db_make_bigint (result_p, bigint);
break;
default:
db_make_timestamp (result_p, utmp);
break;
}
}
return NO_ERROR;
}
static int
qdata_add_int_to_utime (DB_VALUE * utime_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_UTIME *utime;
DB_UTIME utmp, u1, u2;
DB_DATE date;
DB_TIME time;
DB_TYPE type;
DB_BIGINT bigint;
int d, m, y, h, mi, s;
utime = db_get_timestamp (utime_val_p);
if (i < 0)
{
return qdata_add_int_to_utime_asymmetry (utime_val_p, i, utime, result_p, domain_p);
}
u1 = i;
u2 = *utime;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || INT_MAX < utmp)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
db_make_timestamp (result_p, utmp);
}
else
{
type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
(void) db_timestamp_decode_ses (&utmp, &date, &time);
db_date_decode (&date, &m, &d, &y);
db_time_decode (&time, &h, &mi, &s);
bigint = (y * 100 + m) * 100 + d;
bigint = ((bigint * 100 + h) * 100 + mi) * 100 + s;
db_make_bigint (result_p, bigint);
break;
default:
db_make_timestamp (result_p, utmp);
break;
}
}
return NO_ERROR;
}
static int
qdata_add_bigint_to_utime (DB_VALUE * utime_val_p, DB_BIGINT bi, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_UTIME *utime;
DB_BIGINT utmp, u1, u2;
DB_DATE date;
DB_TIME time;
DB_TYPE type;
DB_BIGINT bigint;
int d, m, y, h, mi, s;
utime = db_get_timestamp (utime_val_p);
if (bi < 0)
{
return qdata_add_bigint_to_utime_asymmetry (utime_val_p, bi, utime, result_p, domain_p);
}
u1 = bi;
u2 = *utime;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || INT_MAX < utmp)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
db_make_timestamp (result_p, (unsigned int) utmp); /* truncate to 4bytes time_t */
}
else
{
type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
{
DB_TIMESTAMP timestamp = (DB_TIMESTAMP) utmp;
(void) db_timestamp_decode_ses (×tamp, &date, &time);
db_date_decode (&date, &m, &d, &y);
db_time_decode (&time, &h, &mi, &s);
bigint = (y * 100 + m) * 100 + d;
bigint = ((bigint * 100 + h) * 100 + mi) * 100 + s;
db_make_bigint (result_p, bigint);
}
break;
default:
db_make_timestamp (result_p, (unsigned int) utmp);
break;
}
}
return NO_ERROR;
}
static int
qdata_add_short_to_timestamptz (DB_VALUE * ts_tz_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int err = NO_ERROR;
DB_TIMESTAMPTZ *ts_tz_p;
DB_TIMESTAMPTZ ts_tz_res, ts_tz_fixed;
DB_UTIME utime;
DB_UTIME utmp, u1, u2;
DB_DATE date;
DB_TIME time;
DB_TYPE type;
DB_BIGINT bigint = 0;
int d, m, y, h, mi, sec;
DB_VALUE tmp_utime_val, tmp_utime_val_res;
ts_tz_p = db_get_timestamptz (ts_tz_val_p);
utime = ts_tz_p->timestamp;
if (s < 0)
{
db_make_timestamp (&tmp_utime_val, utime);
err =
qdata_add_short_to_utime_asymmetry (&tmp_utime_val, s, &utime, &tmp_utime_val_res,
tp_domain_resolve_default (DB_TYPE_TIMESTAMP));
if (err != NO_ERROR)
{
goto exit;
}
assert (DB_VALUE_TYPE (&tmp_utime_val_res) == DB_TYPE_TIMESTAMP);
utmp = *db_get_timestamp (&tmp_utime_val_res);
goto return_timestamp_tz;
}
u1 = s;
u2 = utime;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || INT_MAX < utmp)
{
err = ER_QPROC_OVERFLOW_ADDITION;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto exit;
}
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
goto return_timestamp_tz;
}
else
{
type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
ts_tz_res.timestamp = utmp;
ts_tz_res.tz_id = ts_tz_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_fixed);
if (err != NO_ERROR)
{
goto exit;
}
err = db_timestamp_decode_w_tz_id (&ts_tz_fixed.timestamp, &ts_tz_fixed.tz_id, &date, &time);
if (err != NO_ERROR)
{
goto exit;
}
db_date_decode (&date, &m, &d, &y);
db_time_decode (&time, &h, &mi, &sec);
bigint = (y * 100 + m) * 100 + d;
bigint = ((bigint * 100 + h) * 100 + mi) * 100 + sec;
db_make_bigint (result_p, bigint);
break;
default:
break;
}
}
return_timestamp_tz:
ts_tz_res.timestamp = utmp;
ts_tz_res.tz_id = ts_tz_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_fixed);
if (err != NO_ERROR)
{
return err;
}
db_make_timestamptz (result_p, &ts_tz_fixed);
exit:
return err;
}
static int
qdata_add_int_to_timestamptz (DB_VALUE * ts_tz_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int err = NO_ERROR;
DB_TIMESTAMPTZ *ts_tz_p;
DB_TIMESTAMPTZ ts_tz_res, ts_tz_fixed;
DB_UTIME utime;
DB_UTIME utmp, u1, u2;
DB_DATE date;
DB_TIME time;
DB_TYPE type;
DB_BIGINT bigint = 0;
int d, m, y, h, mi, sec;
DB_VALUE tmp_utime_val, tmp_utime_val_res;
ts_tz_p = db_get_timestamptz (ts_tz_val_p);
utime = ts_tz_p->timestamp;
if (i < 0)
{
db_make_timestamp (&tmp_utime_val, utime);
err =
qdata_add_int_to_utime_asymmetry (&tmp_utime_val, i, &utime, &tmp_utime_val_res,
tp_domain_resolve_default (DB_TYPE_TIMESTAMP));
if (err != NO_ERROR)
{
goto exit;
}
assert (DB_VALUE_TYPE (&tmp_utime_val_res) == DB_TYPE_TIMESTAMP);
utmp = *db_get_timestamp (&tmp_utime_val_res);
goto return_timestamp_tz;
}
u1 = i;
u2 = utime;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || INT_MAX < utmp)
{
err = ER_QPROC_OVERFLOW_ADDITION;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto exit;
}
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
goto return_timestamp_tz;
}
else
{
type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
ts_tz_res.timestamp = utmp;
ts_tz_res.tz_id = ts_tz_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_fixed);
if (err != NO_ERROR)
{
goto exit;
}
err = db_timestamp_decode_w_tz_id (&ts_tz_fixed.timestamp, &ts_tz_fixed.tz_id, &date, &time);
if (err != NO_ERROR)
{
goto exit;
}
db_date_decode (&date, &m, &d, &y);
db_time_decode (&time, &h, &mi, &sec);
bigint = (y * 100 + m) * 100 + d;
bigint = ((bigint * 100 + h) * 100 + mi) * 100 + sec;
db_make_bigint (result_p, bigint);
break;
default:
break;
}
}
return_timestamp_tz:
ts_tz_res.timestamp = utmp;
ts_tz_res.tz_id = ts_tz_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_fixed);
if (err != NO_ERROR)
{
return err;
}
db_make_timestamptz (result_p, &ts_tz_fixed);
exit:
return err;
}
static int
qdata_add_bigint_to_timestamptz (DB_VALUE * ts_tz_val_p, DB_BIGINT bi, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int err = NO_ERROR;
DB_TIMESTAMPTZ *ts_tz_p;
DB_TIMESTAMPTZ ts_tz_res, ts_tz_fixed;
DB_UTIME utime;
DB_DATE date;
DB_TIME time;
DB_TYPE type;
DB_BIGINT u1, u2, utmp, bigint = 0;
int d, m, y, h, mi, sec;
DB_VALUE tmp_utime_val, tmp_utime_val_res;
ts_tz_p = db_get_timestamptz (ts_tz_val_p);
utime = ts_tz_p->timestamp;
if (bi < 0)
{
db_make_timestamp (&tmp_utime_val, utime);
err =
qdata_add_bigint_to_utime_asymmetry (&tmp_utime_val, bi, &utime, &tmp_utime_val_res,
tp_domain_resolve_default (DB_TYPE_TIMESTAMP));
if (err != NO_ERROR)
{
goto exit;
}
assert (DB_VALUE_TYPE (&tmp_utime_val_res) == DB_TYPE_TIMESTAMP);
utmp = *db_get_timestamp (&tmp_utime_val_res);
goto return_timestamp_tz;
}
u1 = bi;
u2 = utime;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || INT_MAX < utmp)
{
err = ER_QPROC_OVERFLOW_ADDITION;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 0);
goto exit;
}
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
goto return_timestamp_tz;
}
else
{
type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
utime = (DB_UTIME) utmp;
ts_tz_res.timestamp = utime;
ts_tz_res.tz_id = ts_tz_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_fixed);
if (err != NO_ERROR)
{
goto exit;
}
err = db_timestamp_decode_w_tz_id (&ts_tz_fixed.timestamp, &ts_tz_fixed.tz_id, &date, &time);
if (err != NO_ERROR)
{
goto exit;
}
db_date_decode (&date, &m, &d, &y);
db_time_decode (&time, &h, &mi, &sec);
bigint = (y * 100 + m) * 100 + d;
bigint = ((bigint * 100 + h) * 100 + mi) * 100 + sec;
db_make_bigint (result_p, bigint);
break;
default:
break;
}
}
return_timestamp_tz:
utime = (DB_UTIME) utmp;
ts_tz_res.timestamp = utime;
ts_tz_res.tz_id = ts_tz_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_fixed);
if (err != NO_ERROR)
{
return err;
}
db_make_timestamptz (result_p, &ts_tz_fixed);
exit:
return err;
}
static int
qdata_add_short_to_datetime (DB_VALUE * datetime_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_DATETIME *datetime;
DB_DATETIME tmp;
int error = NO_ERROR;
datetime = db_get_datetime (datetime_val_p);
error = db_add_int_to_datetime (datetime, s, &tmp);
if (error == NO_ERROR)
{
db_make_datetime (result_p, &tmp);
}
return error;
}
static int
qdata_add_int_to_datetime (DB_VALUE * datetime_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_DATETIME *datetime;
DB_DATETIME tmp;
int error = NO_ERROR;
datetime = db_get_datetime (datetime_val_p);
error = db_add_int_to_datetime (datetime, i, &tmp);
if (error == NO_ERROR)
{
db_make_datetime (result_p, &tmp);
}
return error;
}
static int
qdata_add_bigint_to_datetime (DB_VALUE * datetime_val_p, DB_BIGINT bi, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_DATETIME *datetime;
DB_DATETIME tmp;
int error = NO_ERROR;
datetime = db_get_datetime (datetime_val_p);
error = db_add_int_to_datetime (datetime, bi, &tmp);
if (error == NO_ERROR)
{
db_make_datetime (result_p, &tmp);
}
return error;
}
static int
qdata_add_short_to_date (DB_VALUE * date_val_p, short s, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_DATE *date;
unsigned int utmp, u1, u2;
int day, month, year;
date = db_get_date (date_val_p);
if (s < 0)
{
return qdata_add_short_to_utime_asymmetry (date_val_p, s, date, result_p, domain_p);
}
u1 = (unsigned int) s;
u2 = (unsigned int) *date;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || utmp > DB_DATE_MAX)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_date_decode (&utmp, &month, &day, &year);
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
db_make_date (result_p, month, day, year);
}
else
{
DB_TYPE type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_SHORT:
db_make_short (result_p, (year * 100 + month) * 100 + day);
break;
default:
db_make_date (result_p, month, day, year);
break;
}
}
return NO_ERROR;
}
static int
qdata_add_int_to_date (DB_VALUE * date_val_p, int i, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_DATE *date;
unsigned int utmp, u1, u2;
int day, month, year;
date = db_get_date (date_val_p);
if (i < 0)
{
return qdata_add_int_to_utime_asymmetry (date_val_p, i, date, result_p, domain_p);
}
u1 = (unsigned int) i;
u2 = (unsigned int) *date;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || utmp > DB_DATE_MAX)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_date_decode (&utmp, &month, &day, &year);
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) != COMPAT_MYSQL)
{
db_make_date (result_p, month, day, year);
}
else
{
DB_TYPE type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_INTEGER:
db_make_int (result_p, (year * 100 + month) * 100 + day);
break;
default:
db_make_date (result_p, month, day, year);
break;
}
}
return NO_ERROR;
}
static int
qdata_add_bigint_to_date (DB_VALUE * date_val_p, DB_BIGINT bi, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_DATE *date;
DB_BIGINT utmp, u1, u2;
DB_DATE tmp_date;
int day, month, year;
date = db_get_date (date_val_p);
if (bi < 0)
{
return qdata_add_bigint_to_utime_asymmetry (date_val_p, bi, date, result_p, domain_p);
}
u1 = bi;
u2 = *date;
utmp = u1 + u2;
if (OR_CHECK_UNS_ADD_OVERFLOW (u1, u2, utmp) || utmp > DB_DATE_MAX)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
tmp_date = (DB_DATE) utmp;
db_date_decode (&tmp_date, &month, &day, &year);
if (prm_get_integer_value (PRM_ID_COMPAT_MODE) == COMPAT_MYSQL)
{
db_make_date (result_p, month, day, year);
}
else
{
DB_TYPE type = DB_VALUE_DOMAIN_TYPE (result_p);
switch (type)
{
case DB_TYPE_BIGINT:
db_make_bigint (result_p, (year * 100 + month) * 100 + day);
break;
default:
db_make_date (result_p, month, day, year);
break;
}
}
return NO_ERROR;
}
static int
qdata_add_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int err = NO_ERROR;
DB_VALUE tmp_val;
short s;
DB_TYPE type;
s = db_get_short (short_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_short (s, dbval_p, result_p);
case DB_TYPE_INTEGER:
return qdata_add_int (s, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint (s, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_add_float (s, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_add_double (s, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_add_numeric (dbval_p, short_val_p, result_p);
case DB_TYPE_MONETARY:
return qdata_add_monetary (s, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p);
case DB_TYPE_TIME:
return qdata_add_bigint_to_time (dbval_p, (DB_BIGINT) s, result_p);
case DB_TYPE_TIMESTAMP:
return qdata_add_short_to_utime (dbval_p, s, result_p, domain_p);
case DB_TYPE_TIMESTAMPLTZ:
{
DB_TIMESTAMPTZ ts_tz;
ts_tz.timestamp = *db_get_timestamp (dbval_p);
err = tz_create_session_tzid_for_timestamp (&ts_tz.timestamp, &ts_tz.tz_id);
if (err != NO_ERROR)
{
break;
}
db_make_timestamptz (&tmp_val, &ts_tz);
err = qdata_add_short_to_timestamptz (&tmp_val, (DB_BIGINT) s, result_p, domain_p);
if (err != NO_ERROR)
{
break;
}
if (DB_VALUE_TYPE (result_p) == DB_TYPE_TIMESTAMPTZ)
{
ts_tz = *db_get_timestamptz (result_p);
db_make_timestampltz (result_p, ts_tz.timestamp);
}
break;
}
case DB_TYPE_TIMESTAMPTZ:
return qdata_add_short_to_timestamptz (dbval_p, s, result_p, domain_p);
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
err = qdata_add_short_to_datetime (dbval_p, s, &tmp_val, domain_p);
if (err == NO_ERROR && type == DB_TYPE_DATETIMELTZ)
{
db_make_datetimeltz (result_p, db_get_datetime (&tmp_val));
}
return err;
case DB_TYPE_DATETIMETZ:
db_make_short (&tmp_val, s);
return qdata_add_datetimetz_to_dbval (dbval_p, &tmp_val, result_p);
case DB_TYPE_DATE:
return qdata_add_short_to_date (dbval_p, s, result_p, domain_p);
default:
break;
}
return err;
}
static int
qdata_add_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int i;
int err = NO_ERROR;
DB_TYPE type;
DB_VALUE tmp_val;
i = db_get_int (int_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_int (i, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_add_int (i, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint (i, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_add_float ((float) i, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_add_double (i, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_add_numeric (dbval_p, int_val_p, result_p);
break;
case DB_TYPE_MONETARY:
return qdata_add_monetary (i, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p);
case DB_TYPE_TIME:
return qdata_add_bigint_to_time (dbval_p, (DB_BIGINT) i, result_p);
case DB_TYPE_TIMESTAMP:
return qdata_add_int_to_utime (dbval_p, i, result_p, domain_p);
case DB_TYPE_TIMESTAMPLTZ:
{
DB_TIMESTAMPTZ ts_tz;
ts_tz.timestamp = *db_get_timestamp (dbval_p);
err = tz_create_session_tzid_for_timestamp (&ts_tz.timestamp, &ts_tz.tz_id);
if (err != NO_ERROR)
{
break;
}
db_make_timestamptz (&tmp_val, &ts_tz);
err = qdata_add_int_to_timestamptz (&tmp_val, (DB_BIGINT) i, result_p, domain_p);
if (err != NO_ERROR)
{
break;
}
if (DB_VALUE_TYPE (result_p) == DB_TYPE_TIMESTAMPTZ)
{
ts_tz = *db_get_timestamptz (result_p);
db_make_timestampltz (result_p, ts_tz.timestamp);
}
break;
}
case DB_TYPE_TIMESTAMPTZ:
return qdata_add_int_to_timestamptz (dbval_p, i, result_p, domain_p);
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
err = qdata_add_int_to_datetime (dbval_p, i, &tmp_val, domain_p);
if (err == NO_ERROR && type == DB_TYPE_DATETIMELTZ)
{
db_make_datetimeltz (result_p, db_get_datetime (&tmp_val));
}
return err;
case DB_TYPE_DATETIMETZ:
db_make_int (&tmp_val, i);
return qdata_add_datetimetz_to_dbval (dbval_p, &tmp_val, result_p);
case DB_TYPE_DATE:
return qdata_add_int_to_date (dbval_p, i, result_p, domain_p);
default:
break;
}
return err;
}
static int
qdata_add_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int err = NO_ERROR;
DB_BIGINT bi;
DB_TYPE type;
DB_VALUE tmp_val;
bi = db_get_bigint (bigint_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_bigint (bi, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_add_bigint (bi, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint (bi, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_add_float ((float) bi, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_add_double ((double) bi, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_add_numeric (dbval_p, bigint_val_p, result_p);
break;
case DB_TYPE_MONETARY:
return qdata_add_monetary ((double) bi, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type,
result_p);
case DB_TYPE_TIME:
return qdata_add_bigint_to_time (dbval_p, bi, result_p);
case DB_TYPE_TIMESTAMP:
return qdata_add_bigint_to_utime (dbval_p, bi, result_p, domain_p);
case DB_TYPE_TIMESTAMPLTZ:
{
DB_TIMESTAMPTZ ts_tz;
ts_tz.timestamp = *db_get_timestamp (dbval_p);
err = tz_create_session_tzid_for_timestamp (&ts_tz.timestamp, &ts_tz.tz_id);
if (err != NO_ERROR)
{
break;
}
db_make_timestamptz (&tmp_val, &ts_tz);
err = qdata_add_bigint_to_timestamptz (&tmp_val, bi, result_p, domain_p);
if (err != NO_ERROR)
{
break;
}
if (DB_VALUE_TYPE (result_p) == DB_TYPE_TIMESTAMPTZ)
{
ts_tz = *db_get_timestamptz (result_p);
db_make_timestampltz (result_p, ts_tz.timestamp);
}
break;
}
case DB_TYPE_TIMESTAMPTZ:
return qdata_add_bigint_to_timestamptz (dbval_p, bi, result_p, domain_p);
case DB_TYPE_DATE:
return qdata_add_bigint_to_date (dbval_p, bi, result_p, domain_p);
case DB_TYPE_DATETIME:
return qdata_add_bigint_to_datetime (dbval_p, bi, result_p, domain_p);
case DB_TYPE_DATETIMELTZ:
err = qdata_add_bigint_to_datetime (dbval_p, bi, &tmp_val, domain_p);
if (err == NO_ERROR && type == DB_TYPE_DATETIMELTZ)
{
db_make_datetimeltz (result_p, db_get_datetime (&tmp_val));
}
return err;
case DB_TYPE_DATETIMETZ:
db_make_bigint (&tmp_val, bi);
return qdata_add_datetimetz_to_dbval (dbval_p, &tmp_val, result_p);
default:
break;
}
return err;
}
static int
qdata_add_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
float f1;
DB_TYPE type;
f1 = db_get_float (float_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_float (f1, (float) db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_add_float (f1, (float) db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_add_double (f1, (double) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_add_float (f1, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_add_double (f1, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_add_double (f1, qdata_coerce_numeric_to_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_add_monetary (f1, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
double d1;
DB_TYPE type;
d1 = db_get_double (double_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_double (d1, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_add_double (d1, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_add_double (d1, (double) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_add_double (d1, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_add_double (d1, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_add_double (d1, qdata_coerce_numeric_to_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_add_monetary (d1, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
return qdata_add_numeric (numeric_val_p, dbval_p, result_p);
case DB_TYPE_NUMERIC:
if (numeric_db_value_add (numeric_val_p, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
break;
case DB_TYPE_FLOAT:
return qdata_add_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_add_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_add_numeric_to_monetary (numeric_val_p, dbval_p, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type;
double d1;
DB_CURRENCY currency;
d1 = (db_get_monetary (monetary_val_p))->amount;
currency = (db_get_monetary (monetary_val_p))->type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_monetary (d1, db_get_short (dbval_p), currency, result_p);
case DB_TYPE_INTEGER:
return qdata_add_monetary (d1, db_get_int (dbval_p), currency, result_p);
case DB_TYPE_BIGINT:
return qdata_add_monetary (d1, (double) db_get_bigint (dbval_p), currency, result_p);
case DB_TYPE_FLOAT:
return qdata_add_monetary (d1, db_get_float (dbval_p), currency, result_p);
case DB_TYPE_DOUBLE:
return qdata_add_monetary (d1, db_get_double (dbval_p), currency, result_p);
case DB_TYPE_NUMERIC:
return qdata_add_numeric_to_monetary (dbval_p, monetary_val_p, result_p);
case DB_TYPE_MONETARY:
/* Note: we probably should return an error if the two monetaries have different monetary types. */
return qdata_add_monetary (d1, (db_get_monetary (dbval_p))->amount, currency, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_chars_to_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p)
{
DB_DATA_STATUS data_stat;
if ((db_string_concatenate (dbval1_p, dbval2_p, result_p, &data_stat) != NO_ERROR) || (data_stat != DATA_STATUS_OK))
{
return ER_FAILED;
}
return NO_ERROR;
}
static int
qdata_add_sequence_to_dbval (DB_VALUE * seq_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_SET *set_tmp;
DB_SEQ *seq_tmp, *seq_tmp1;
DB_VALUE dbval_tmp;
int i, card, card1;
#if !defined(NDEBUG)
DB_TYPE type1, type2;
#endif
#if !defined(NDEBUG)
type1 = DB_VALUE_DOMAIN_TYPE (seq_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
assert (TP_IS_SET_TYPE (type1));
assert (TP_IS_SET_TYPE (type2));
#endif
if (domain_p == NULL)
{
return ER_FAILED;
}
db_make_null (&dbval_tmp);
if (TP_DOMAIN_TYPE (domain_p) == DB_TYPE_SEQUENCE)
{
if (tp_value_coerce (seq_val_p, result_p, domain_p) != DOMAIN_COMPATIBLE)
{
return ER_FAILED;
}
seq_tmp = db_get_set (dbval_p);
card = db_seq_size (seq_tmp);
seq_tmp1 = db_get_set (result_p);
card1 = db_seq_size (seq_tmp1);
for (i = 0; i < card; i++)
{
if (db_seq_get (seq_tmp, i, &dbval_tmp) != NO_ERROR)
{
return ER_FAILED;
}
if (db_seq_put (seq_tmp1, card1 + i, &dbval_tmp) != NO_ERROR)
{
pr_clear_value (&dbval_tmp);
return ER_FAILED;
}
pr_clear_value (&dbval_tmp);
}
}
else
{
/* set or multiset */
if (set_union (db_get_set (seq_val_p), db_get_set (dbval_p), &set_tmp, domain_p) < 0)
{
return ER_FAILED;
}
pr_clear_value (result_p);
set_make_collection (result_p, set_tmp);
}
return NO_ERROR;
}
static int
qdata_add_time_to_dbval (DB_VALUE * time_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_bigint_to_time (time_val_p, (DB_BIGINT) db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_add_bigint_to_time (time_val_p, (DB_BIGINT) db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint_to_time (time_val_p, db_get_bigint (dbval_p), result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_utime_to_dbval (DB_VALUE * utime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_TYPE type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_short_to_utime (utime_val_p, db_get_short (dbval_p), result_p, domain_p);
case DB_TYPE_INTEGER:
return qdata_add_int_to_utime (utime_val_p, db_get_int (dbval_p), result_p, domain_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint_to_utime (utime_val_p, db_get_bigint (dbval_p), result_p, domain_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_timestamptz_to_dbval (DB_VALUE * ts_tz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type;
TP_DOMAIN *domain_p;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
domain_p = tp_domain_resolve_default (DB_TYPE_TIMESTAMPTZ);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_short_to_timestamptz (ts_tz_val_p, db_get_short (dbval_p), result_p, domain_p);
case DB_TYPE_INTEGER:
return qdata_add_int_to_timestamptz (ts_tz_val_p, db_get_int (dbval_p), result_p, domain_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint_to_timestamptz (ts_tz_val_p, db_get_bigint (dbval_p), result_p, domain_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_datetime_to_dbval (DB_VALUE * datetime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_TYPE type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_short_to_datetime (datetime_val_p, db_get_short (dbval_p), result_p, domain_p);
case DB_TYPE_INTEGER:
return qdata_add_int_to_datetime (datetime_val_p, db_get_int (dbval_p), result_p, domain_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint_to_datetime (datetime_val_p, db_get_bigint (dbval_p), result_p, domain_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_add_datetimetz_to_dbval (DB_VALUE * datetimetz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
int error = NO_ERROR;
DB_VALUE dt_val, dt_val_res;
DB_DATETIMETZ *dt_tz_p = db_get_datetimetz (datetimetz_val_p);
DB_DATETIMETZ dt_tz_res, dt_tz_fixed;
db_make_datetime (&dt_val, &dt_tz_p->datetime);
error = qdata_add_datetime_to_dbval (&dt_val, dbval_p, &dt_val_res, tp_domain_resolve_default (DB_TYPE_DATETIME));
if (error != NO_ERROR)
{
return error;
}
dt_tz_res.datetime = *db_get_datetime (&dt_val_res);
dt_tz_res.tz_id = dt_tz_p->tz_id;
error = tz_datetimetz_fix_zone (&dt_tz_res, &dt_tz_fixed);
if (error != NO_ERROR)
{
return error;
}
db_make_datetimetz (result_p, &dt_tz_fixed);
return NO_ERROR;
}
static int
qdata_add_date_to_dbval (DB_VALUE * date_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_TYPE type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_add_short_to_date (date_val_p, db_get_short (dbval_p), result_p, domain_p);
case DB_TYPE_INTEGER:
return qdata_add_int_to_date (date_val_p, db_get_int (dbval_p), result_p, domain_p);
case DB_TYPE_BIGINT:
return qdata_add_bigint_to_date (date_val_p, db_get_bigint (dbval_p), result_p, domain_p);
default:
if (prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS) == false)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
break;
}
return NO_ERROR;
}
static int
qdata_coerce_result_to_domain (DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int error = NO_ERROR;
TP_DOMAIN_STATUS dom_status;
if (domain_p != NULL)
{
dom_status = tp_value_coerce (result_p, result_p, domain_p);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, result_p, domain_p);
assert_release (error != NO_ERROR);
}
}
return error;
}
static int
qdata_cast_to_domain (DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
int error = NO_ERROR;
TP_DOMAIN_STATUS dom_status;
if (domain_p != NULL)
{
dom_status = tp_value_cast (dbval_p, result_p, domain_p, false);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval_p, domain_p);
assert_release (error != NO_ERROR);
}
}
return error;
}
/*
* qdata_add_dbval () -
* return: NO_ERROR, or ER_code
* dbval1(in) : First db_value node
* dbval2(in) : Second db_value node
* res(out) : Resultant db_value node
* domain(in) :
*
* Note: Add two db_values.
* Overflow checks are only done when both operand maximums have
* overlapping precision/scale. That is,
* short + integer -> overflow is checked
* float + double -> overflow is not checked. Maximum float
* value does not overlap maximum double
* precision/scale.
* MAX_FLT + MAX_DBL = MAX_DBL
*/
int
qdata_add_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type1;
DB_TYPE type2;
int error = NO_ERROR;
DB_VALUE cast_value1;
DB_VALUE cast_value2;
TP_DOMAIN *cast_dom1 = NULL;
TP_DOMAIN *cast_dom2 = NULL;
TP_DOMAIN_STATUS dom_status;
if (domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL)
{
return NO_ERROR;
}
type1 = dbval1_p ? DB_VALUE_DOMAIN_TYPE (dbval1_p) : DB_TYPE_NULL;
type2 = dbval2_p ? DB_VALUE_DOMAIN_TYPE (dbval2_p) : DB_TYPE_NULL;
/* Enumeration */
if (type1 == DB_TYPE_ENUMERATION)
{
if (TP_IS_CHAR_BIT_TYPE (type2))
{
cast_dom1 = tp_domain_resolve_default (DB_TYPE_VARCHAR);
}
else
{
cast_dom1 = tp_domain_resolve_default (DB_TYPE_SMALLINT);
}
dom_status = tp_value_auto_cast (dbval1_p, &cast_value1, cast_dom1);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval1_p, cast_dom1);
return error;
}
error = qdata_add_dbval (&cast_value1, dbval2_p, result_p, domain_p);
pr_clear_value (&cast_value1);
return error;
}
else if (type2 == DB_TYPE_ENUMERATION)
{
if (TP_IS_CHAR_BIT_TYPE (type1))
{
cast_dom2 = tp_domain_resolve_default (DB_TYPE_VARCHAR);
}
else
{
cast_dom2 = tp_domain_resolve_default (DB_TYPE_SMALLINT);
}
dom_status = tp_value_auto_cast (dbval2_p, &cast_value2, cast_dom2);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval2_p, cast_dom2);
return error;
}
error = qdata_add_dbval (dbval1_p, &cast_value2, result_p, domain_p);
pr_clear_value (&cast_value2);
return error;
}
/* plus as concat : when both operands are string or bit */
if (prm_get_bool_value (PRM_ID_PLUS_AS_CONCAT) == true)
{
if (TP_IS_CHAR_BIT_TYPE (type1) && TP_IS_CHAR_BIT_TYPE (type2))
{
return qdata_strcat_dbval (dbval1_p, dbval2_p, result_p, domain_p);
}
}
if (DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
db_make_null (&cast_value1);
db_make_null (&cast_value2);
/* not all pairs of operands types can be handled; for some of these pairs, reverse the order of operands to match
* the handled case */
/* STRING + NUMBER NUMBER + DATE STRING + DATE */
if ((TP_IS_CHAR_TYPE (type1) && TP_IS_NUMERIC_TYPE (type2))
|| (TP_IS_NUMERIC_TYPE (type1) && TP_IS_DATE_OR_TIME_TYPE (type2)) || (TP_IS_CHAR_TYPE (type1)
&& TP_IS_DATE_OR_TIME_TYPE (type2)))
{
DB_VALUE *temp = NULL;
temp = dbval1_p;
dbval1_p = dbval2_p;
dbval2_p = temp;
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
}
/* number + string : cast string to DOUBLE, add as numbers */
if (TP_IS_NUMERIC_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast string to double */
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* date + number : cast number to bigint, add as date + bigint */
/* date + string : cast string to bigint, add as date + bigint */
else if (TP_IS_DATE_OR_TIME_TYPE (type1) && (TP_IS_FLOATING_NUMBER_TYPE (type2) || TP_IS_CHAR_TYPE (type2)))
{
/* cast number to BIGINT */
cast_dom2 = tp_domain_resolve_default (DB_TYPE_BIGINT);
}
/* string + string: cast number to bigint, add as date + bigint */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast number to BIGINT */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
if (cast_dom2 != NULL)
{
dom_status = tp_value_auto_cast (dbval2_p, &cast_value2, cast_dom2);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval2_p, cast_dom2);
return error;
}
dbval2_p = &cast_value2;
}
if (cast_dom1 != NULL)
{
dom_status = tp_value_auto_cast (dbval1_p, &cast_value1, cast_dom1);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval1_p, cast_dom1);
return error;
}
dbval1_p = &cast_value1;
}
type1 = dbval1_p ? DB_VALUE_DOMAIN_TYPE (dbval1_p) : DB_TYPE_NULL;
type2 = dbval2_p ? DB_VALUE_DOMAIN_TYPE (dbval2_p) : DB_TYPE_NULL;
if (DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
if (qdata_is_zero_value_date (dbval1_p) || qdata_is_zero_value_date (dbval2_p))
{
/* add operation with zero date returns null */
db_make_null (result_p);
if (!prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ATTEMPT_TO_USE_ZERODATE, 0);
return ER_ATTEMPT_TO_USE_ZERODATE;
}
return NO_ERROR;
}
switch (type1)
{
case DB_TYPE_SHORT:
error = qdata_add_short_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_INTEGER:
error = qdata_add_int_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_BIGINT:
error = qdata_add_bigint_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_FLOAT:
error = qdata_add_float_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DOUBLE:
error = qdata_add_double_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_NUMERIC:
error = qdata_add_numeric_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_MONETARY:
error = qdata_add_monetary_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_CHAR:
case DB_TYPE_VARCHAR:
case DB_TYPE_BIT:
case DB_TYPE_VARBIT:
error = qdata_add_chars_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
if (!TP_IS_SET_TYPE (type2))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
if (domain_p == NULL)
{
if (type1 == type2)
{
/* partial resolve : set only basic domain; full domain will be resolved in 'fetch', based on the
* result's value */
domain_p = tp_domain_resolve_default (type1);
}
else
{
domain_p = tp_domain_resolve_default (DB_TYPE_MULTISET);
}
}
error = qdata_add_sequence_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_TIME:
error = qdata_add_time_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_TIMESTAMP:
error = qdata_add_utime_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_TIMESTAMPLTZ:
{
DB_TIMESTAMPTZ ts_tz, *ts_tz_p;
DB_VALUE ts_tz_val, tmp_val_res;
ts_tz.timestamp = *db_get_timestamp (dbval1_p);
error = tz_create_session_tzid_for_timestamp (&ts_tz.timestamp, &ts_tz.tz_id);
if (error != NO_ERROR)
{
break;
}
db_make_timestamptz (&ts_tz_val, &ts_tz);
error = qdata_add_timestamptz_to_dbval (&ts_tz_val, dbval2_p, &tmp_val_res);
if (error != NO_ERROR)
{
break;
}
if (DB_VALUE_TYPE (&tmp_val_res) == DB_TYPE_TIMESTAMPTZ)
{
ts_tz_p = db_get_timestamptz (&tmp_val_res);
db_make_timestampltz (result_p, ts_tz_p->timestamp);
}
else
{
assert (DB_VALUE_TYPE (&tmp_val_res) == DB_TYPE_BIGINT);
pr_clone_value (&tmp_val_res, result_p);
}
break;
}
case DB_TYPE_TIMESTAMPTZ:
error = qdata_add_timestamptz_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
/* we are adding only numbers, safe to handle DATETIMELTZ as DATETIME */
error = qdata_add_datetime_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
if (error == NO_ERROR && type1 == DB_TYPE_DATETIMELTZ)
{
db_make_datetimeltz (result_p, db_get_datetime (result_p));
}
break;
case DB_TYPE_DATETIMETZ:
error = qdata_add_datetimetz_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DATE:
error = qdata_add_date_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
if (error != NO_ERROR)
{
return error;
}
return qdata_coerce_result_to_domain (result_p, domain_p);
}
/*
* qdata_concatenate_dbval () -
* return: NO_ERROR, or ER_code
* dbval1(in) : First db_value node
* dbval2(in) : Second db_value node
* result_p(out) : Resultant db_value node
* domain_p(in) : DB domain of result
* max_allowed_size(in) : max allowed size for result
* warning_context(in) : used only to display truncation warning context
*
* Note: Concatenates a db_values to string db value.
* Value to be added is truncated in case the allowed size would be
* exceeded . Truncation is done without modifying the value (a new
* temporary value is used).
* A warning is logged the first time the allowed size is exceeded
* (when the value to add has already exceeded the size, no warning is
* logged).
*/
int
qdata_concatenate_dbval (THREAD_ENTRY * thread_p, DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p,
tp_domain * domain_p, const int max_allowed_size, const char *warning_context)
{
DB_TYPE type2, type1;
int error = NO_ERROR;
DB_VALUE arg_val, db_temp;
int res_size = 0, val_size = 0;
bool warning_size_exceeded = false;
int spare_bytes = 0;
bool save_need_clear;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
if (!QSTR_IS_ANY_CHAR_OR_BIT (type1))
{
assert (false);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
db_make_null (&arg_val);
db_make_null (&db_temp);
res_size = db_get_string_size (dbval1_p);
switch (type2)
{
case DB_TYPE_CHAR:
case DB_TYPE_VARCHAR:
case DB_TYPE_BIT:
case DB_TYPE_VARBIT:
val_size = db_get_string_size (dbval2_p);
if (res_size >= max_allowed_size)
{
assert (warning_size_exceeded == false);
break;
}
else if (res_size + val_size > max_allowed_size)
{
warning_size_exceeded = true;
error = db_string_limit_size_string (dbval2_p, &db_temp, max_allowed_size - res_size, &spare_bytes);
if (error != NO_ERROR)
{
break;
}
error = qdata_add_chars_to_dbval (dbval1_p, &db_temp, result_p);
if (spare_bytes > 0)
{
/* The adjusted 'db_temp' string was truncated to the last full multibyte character. Increase the
* 'result' with 'spare_bytes' remained from the last truncated multibyte character. This prevents
* GROUP_CONCAT to add other single-byte chars (or char with fewer bytes than 'spare_bytes' to current
* aggregate. */
save_need_clear = result_p->need_clear;
qstr_make_typed_string (DB_VALUE_DOMAIN_TYPE (result_p), result_p, DB_VALUE_PRECISION (result_p),
db_get_string (result_p), db_get_string_size (result_p) + spare_bytes,
db_get_string_codeset (dbval1_p), db_get_string_collation (dbval1_p));
result_p->need_clear = save_need_clear;
}
}
else
{
error = qdata_add_chars_to_dbval (dbval1_p, dbval2_p, result_p);
}
break;
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
case DB_TYPE_FLOAT:
case DB_TYPE_DOUBLE:
case DB_TYPE_NUMERIC:
case DB_TYPE_MONETARY:
case DB_TYPE_TIME:
case DB_TYPE_DATE:
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_DATETIMETZ:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
case DB_TYPE_ENUMERATION:
{
TP_DOMAIN_STATUS err_dom;
err_dom = tp_value_cast (dbval2_p, &arg_val, domain_p, false);
if (err_dom == DOMAIN_COMPATIBLE)
{
val_size = db_get_string_size (&arg_val);
if (res_size >= max_allowed_size)
{
assert (warning_size_exceeded == false);
break;
}
else if (res_size + val_size > max_allowed_size)
{
warning_size_exceeded = true;
error = db_string_limit_size_string (&arg_val, &db_temp, max_allowed_size - res_size, &spare_bytes);
if (error != NO_ERROR)
{
break;
}
error = qdata_add_chars_to_dbval (dbval1_p, &db_temp, result_p);
if (spare_bytes > 0)
{
save_need_clear = result_p->need_clear;
qstr_make_typed_string (DB_VALUE_DOMAIN_TYPE (result_p), result_p, DB_VALUE_PRECISION (result_p),
db_get_string (result_p), db_get_string_size (result_p) + spare_bytes,
db_get_string_codeset (dbval1_p), db_get_string_collation (dbval1_p));
result_p->need_clear = save_need_clear;
}
}
else
{
error = qdata_add_chars_to_dbval (dbval1_p, &arg_val, result_p);
}
}
else
{
error = tp_domain_status_er_set (err_dom, ARG_FILE_LINE, dbval2_p, domain_p);
}
}
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
pr_clear_value (&arg_val);
pr_clear_value (&db_temp);
if (error == NO_ERROR && warning_size_exceeded == true)
{
er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_QPROC_SIZE_STRING_TRUNCATED, 1, warning_context);
}
return error;
}
/*
* qdata_increment_dbval () -
* return: NO_ERROR, or ER_code
* dbval1(in) : db_value node
* res(in) :
* incval(in) :
*
* Note: Increment the db_value.
* If overflow happens, reset the db_value as 0.
*/
int
qdata_increment_dbval (DB_VALUE * dbval_p, DB_VALUE * result_p, int inc_val)
{
DB_TYPE type1;
short stmp, s1;
int itmp, i1;
DB_BIGINT bitmp, bi1;
type1 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type1)
{
case DB_TYPE_SHORT:
s1 = db_get_short (dbval_p);
stmp = s1 + inc_val;
if ((inc_val > 0 && OR_CHECK_ADD_OVERFLOW (s1, inc_val, stmp))
|| (inc_val < 0 && OR_CHECK_SUB_UNDERFLOW (s1, -inc_val, stmp)))
{
stmp = 0;
}
db_make_short (result_p, stmp);
break;
case DB_TYPE_INTEGER:
i1 = db_get_int (dbval_p);
itmp = i1 + inc_val;
if ((inc_val > 0 && OR_CHECK_ADD_OVERFLOW (i1, inc_val, itmp))
|| (inc_val < 0 && OR_CHECK_SUB_UNDERFLOW (i1, -inc_val, itmp)))
{
itmp = 0;
}
db_make_int (result_p, itmp);
break;
case DB_TYPE_BIGINT:
bi1 = db_get_bigint (dbval_p);
bitmp = bi1 + inc_val;
if ((inc_val > 0 && OR_CHECK_ADD_OVERFLOW (bi1, inc_val, bitmp))
|| (inc_val < 0 && OR_CHECK_SUB_UNDERFLOW (bi1, -inc_val, bitmp)))
{
bitmp = 0;
}
db_make_bigint (result_p, bitmp);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_FAILED;
}
return NO_ERROR;
}
static int
qdata_subtract_short (short s1, short s2, DB_VALUE * result_p)
{
short stmp;
stmp = s1 - s2;
if (OR_CHECK_SUB_UNDERFLOW (s1, s2, stmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
db_make_short (result_p, stmp);
return NO_ERROR;
}
static int
qdata_subtract_int (int i1, int i2, DB_VALUE * result_p)
{
int itmp;
itmp = i1 - i2;
if (OR_CHECK_SUB_UNDERFLOW (i1, i2, itmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
db_make_int (result_p, itmp);
return NO_ERROR;
}
static int
qdata_subtract_bigint (DB_BIGINT bi1, DB_BIGINT bi2, DB_VALUE * result_p)
{
DB_BIGINT bitmp;
bitmp = bi1 - bi2;
if (OR_CHECK_SUB_UNDERFLOW (bi1, bi2, bitmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
db_make_bigint (result_p, bitmp);
return NO_ERROR;
}
static int
qdata_subtract_float (float f1, float f2, DB_VALUE * result_p)
{
float ftmp;
ftmp = f1 - f2;
if (OR_CHECK_FLOAT_OVERFLOW (ftmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
db_make_float (result_p, ftmp);
return NO_ERROR;
}
static int
qdata_subtract_double (double d1, double d2, DB_VALUE * result_p)
{
double dtmp;
dtmp = d1 - d2;
if (OR_CHECK_DOUBLE_OVERFLOW (dtmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
db_make_double (result_p, dtmp);
return NO_ERROR;
}
static int
qdata_subtract_monetary (double d1, double d2, DB_CURRENCY currency, DB_VALUE * result_p)
{
double dtmp;
dtmp = d1 - d2;
if (OR_CHECK_DOUBLE_OVERFLOW (dtmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
db_make_monetary (result_p, currency, dtmp);
return NO_ERROR;
}
static int
qdata_subtract_time (DB_TIME u1, DB_TIME u2, DB_VALUE * result_p)
{
DB_TIME utmp;
int hour, minute, second;
if (u1 < u2)
{
u1 += SECONDS_OF_ONE_DAY;
}
utmp = u1 - u2;
db_time_decode (&utmp, &hour, &minute, &second);
db_make_time (result_p, hour, minute, second);
return NO_ERROR;
}
static int
qdata_subtract_utime (DB_UTIME u1, DB_UTIME u2, DB_VALUE * result_p)
{
DB_UTIME utmp;
utmp = u1 - u2;
if (OR_CHECK_UNS_SUB_UNDERFLOW (u1, u2, utmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_TIME_UNDERFLOW, 0);
return ER_FAILED;
}
db_make_timestamp (result_p, utmp);
return NO_ERROR;
}
static int
qdata_subtract_utime_to_short_asymmetry (DB_VALUE * utime_val_p, short s, unsigned int *utime, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
DB_VALUE tmp;
int error = NO_ERROR;
if (s == DB_INT16_MIN) /* check for asymmetry. */
{
if (*utime == DB_UINT32_MAX)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
(*utime)++;
s++;
}
db_make_short (&tmp, -(s));
error = qdata_add_dbval (utime_val_p, &tmp, result_p, domain_p);
return error;
}
static int
qdata_subtract_utime_to_int_asymmetry (DB_VALUE * utime_val_p, int i, unsigned int *utime, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
DB_VALUE tmp;
int error = NO_ERROR;
if (i == DB_INT32_MIN) /* check for asymmetry. */
{
if (*utime == DB_UINT32_MAX)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
(*utime)++;
i++;
}
db_make_int (&tmp, -(i));
error = qdata_add_dbval (utime_val_p, &tmp, result_p, domain_p);
return error;
}
static int
qdata_subtract_utime_to_bigint_asymmetry (DB_VALUE * utime_val_p, DB_BIGINT bi, unsigned int *utime,
DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_VALUE tmp;
int error = NO_ERROR;
if (bi == DB_BIGINT_MIN) /* check for asymmetry. */
{
if (*utime == DB_UINT32_MAX)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
(*utime)++;
bi++;
}
db_make_bigint (&tmp, -(bi));
error = qdata_add_dbval (utime_val_p, &tmp, result_p, domain_p);
return error;
}
static int
qdata_subtract_datetime_to_int (DB_DATETIME * dt1, DB_BIGINT i2, DB_VALUE * result_p)
{
DB_DATETIME datetime_tmp;
int error;
error = db_subtract_int_from_datetime (dt1, i2, &datetime_tmp);
if (error != NO_ERROR)
{
return error;
}
db_make_datetime (result_p, &datetime_tmp);
return NO_ERROR;
}
static int
qdata_subtract_datetime (DB_DATETIME * dt1, DB_DATETIME * dt2, DB_VALUE * result_p)
{
DB_BIGINT u1, u2, tmp;
u1 = ((DB_BIGINT) dt1->date) * MILLISECONDS_OF_ONE_DAY + dt1->time;
u2 = ((DB_BIGINT) dt2->date) * MILLISECONDS_OF_ONE_DAY + dt2->time;
tmp = u1 - u2;
if (OR_CHECK_SUB_UNDERFLOW (u1, u2, tmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_TIME_UNDERFLOW, 0);
return ER_FAILED;
}
db_make_bigint (result_p, tmp);
return NO_ERROR;
}
static int
qdata_subtract_datetime_to_int_asymmetry (DB_VALUE * datetime_val_p, DB_BIGINT i, DB_DATETIME * datetime,
DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_VALUE tmp;
int error = NO_ERROR;
if (i == DB_BIGINT_MIN) /* check for asymmetry. */
{
if (datetime->time == 0)
{
datetime->date--;
datetime->time = MILLISECONDS_OF_ONE_DAY;
}
datetime->time--;
i++;
}
db_make_bigint (&tmp, -(i));
error = qdata_add_dbval (datetime_val_p, &tmp, result_p, domain_p);
return error;
}
static int
qdata_subtract_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
short s;
DB_TYPE type2;
DB_VALUE dbval_tmp;
DB_TIME *timeval, timetmp;
DB_DATE *date;
unsigned int u1, u2, utmp;
int hour, minute, second;
int err = NO_ERROR;
DB_VALUE tmp_val;
s = db_get_short (short_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_subtract_short (s, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_subtract_int (s, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_subtract_bigint (s, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_subtract_float (s, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_subtract_double (s, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
qdata_coerce_dbval_to_numeric (short_val_p, &dbval_tmp);
if (numeric_db_value_sub (&dbval_tmp, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_QPROC_OVERFLOW_SUBTRACTION;
}
break;
case DB_TYPE_MONETARY:
return qdata_subtract_monetary (s, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type,
result_p);
case DB_TYPE_TIME:
if (s < 0)
{
timetmp = s + SECONDS_OF_ONE_DAY;
}
else
{
timetmp = s;
}
timeval = db_get_time (dbval_p);
err = qdata_subtract_time (timetmp, (DB_TIME) (*timeval % SECONDS_OF_ONE_DAY), result_p);
return err;
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
db_make_bigint (&tmp_val, (DB_BIGINT) s);
return qdata_subtract_bigint_to_dbval (&tmp_val, dbval_p, result_p);
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_DATETIMETZ:
db_make_int (&tmp_val, (int) s);
return qdata_subtract_int_to_dbval (&tmp_val, dbval_p, result_p);
case DB_TYPE_DATE:
date = db_get_date (dbval_p);
u1 = (unsigned int) s;
u2 = (unsigned int) *date;
utmp = u1 - u2;
if (s < 0 || OR_CHECK_UNS_SUB_UNDERFLOW (u1, u2, utmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_DATE_UNDERFLOW, 0);
return ER_FAILED;
}
db_time_decode (&utmp, &hour, &minute, &second);
db_make_time (result_p, hour, minute, second);
break;
default:
break;
}
return err;
}
static int
qdata_subtract_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
int i;
DB_TYPE type;
DB_VALUE dbval_tmp;
DB_DATE *date;
DB_DATETIME *datetime, datetime_tmp;
unsigned int u1, u2, utmp;
int day, month, year;
DB_VALUE tmp_val;
int err = NO_ERROR;
i = db_get_int (int_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_subtract_int (i, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_subtract_int (i, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_subtract_bigint (i, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_subtract_float ((float) i, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_subtract_double (i, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
qdata_coerce_dbval_to_numeric (int_val_p, &dbval_tmp);
if (numeric_db_value_sub (&dbval_tmp, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_MONETARY:
return qdata_subtract_monetary (i, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type,
result_p);
case DB_TYPE_TIME:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
db_make_bigint (&tmp_val, (DB_BIGINT) i);
return qdata_subtract_bigint_to_dbval (&tmp_val, dbval_p, result_p);
case DB_TYPE_DATETIME:
datetime = db_get_datetime (dbval_p);
datetime_tmp.date = i / MILLISECONDS_OF_ONE_DAY;
datetime_tmp.time = i % MILLISECONDS_OF_ONE_DAY;
return qdata_subtract_datetime (&datetime_tmp, datetime, result_p);
case DB_TYPE_DATETIMELTZ:
{
DB_DATETIME dt_local;
datetime = db_get_datetime (dbval_p);
err = tz_datetimeltz_to_local (datetime, &dt_local);
if (err != NO_ERROR)
{
break;
}
datetime_tmp.date = i / MILLISECONDS_OF_ONE_DAY;
datetime_tmp.time = i % MILLISECONDS_OF_ONE_DAY;
return qdata_subtract_datetime (&datetime_tmp, &dt_local, result_p);
}
case DB_TYPE_DATETIMETZ:
{
DB_DATETIMETZ dt_tz;
DB_DATETIME dt_local;
dt_tz = *db_get_datetimetz (dbval_p);
err = tz_utc_datetimetz_to_local (&dt_tz.datetime, &dt_tz.tz_id, &dt_local);
if (err != NO_ERROR)
{
break;
}
datetime_tmp.date = i / MILLISECONDS_OF_ONE_DAY;
datetime_tmp.time = i % MILLISECONDS_OF_ONE_DAY;
return qdata_subtract_datetime (&datetime_tmp, &dt_local, result_p);
}
case DB_TYPE_DATE:
date = db_get_date (dbval_p);
u1 = (unsigned int) i;
u2 = (unsigned int) *date;
utmp = u1 - u2;
if (i < 0 || OR_CHECK_UNS_SUB_UNDERFLOW (u1, u2, utmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_DATE_UNDERFLOW, 0);
return ER_FAILED;
}
db_date_decode (&utmp, &month, &day, &year);
db_make_date (result_p, month, day, year);
break;
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_BIGINT bi;
DB_TYPE type;
DB_VALUE dbval_tmp;
DB_TIME *timeval;
DB_DATE *date;
unsigned int u1, u2, utmp;
DB_UTIME *utime;
int day, month, year;
int err = NO_ERROR;
bi = db_get_bigint (bigint_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_subtract_bigint (bi, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_subtract_bigint (bi, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_subtract_bigint (bi, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_subtract_float ((float) bi, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_subtract_double ((double) bi, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
qdata_coerce_dbval_to_numeric (bigint_val_p, &dbval_tmp);
if (numeric_db_value_sub (&dbval_tmp, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_MONETARY:
return qdata_subtract_monetary ((double) bi, (db_get_monetary (dbval_p))->amount,
(db_get_monetary (dbval_p))->type, result_p);
case DB_TYPE_TIME:
if (bi < 0)
{
bi = (bi % SECONDS_OF_ONE_DAY) + SECONDS_OF_ONE_DAY;
}
else
{
bi %= SECONDS_OF_ONE_DAY;
}
timeval = db_get_time (dbval_p);
err = qdata_subtract_time ((DB_TIME) bi, (DB_TIME) (*timeval % SECONDS_OF_ONE_DAY), result_p);
return err;
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
utime = db_get_timestamp (dbval_p);
err = qdata_subtract_utime ((DB_UTIME) bi, *utime, result_p);
if (err != NO_ERROR)
{
break;
}
if (err == NO_ERROR && type == DB_TYPE_TIMESTAMPLTZ)
{
db_make_timestampltz (result_p, *db_get_timestamp (result_p));
}
return err;
case DB_TYPE_TIMESTAMPTZ:
{
DB_TIMESTAMPTZ ts_tz_res, ts_tz_fixed, *ts_tz_p;
ts_tz_p = db_get_timestamptz (dbval_p);
utime = &ts_tz_p->timestamp;
err = qdata_subtract_utime ((DB_UTIME) bi, *utime, result_p);
if (err != NO_ERROR)
{
break;
}
ts_tz_res.timestamp = *db_get_timestamp (result_p);
ts_tz_res.tz_id = ts_tz_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_fixed);
if (err != NO_ERROR)
{
break;
}
db_make_timestamptz (result_p, &ts_tz_fixed);
return err;
}
case DB_TYPE_DATE:
date = db_get_date (dbval_p);
u1 = (unsigned int) bi;
u2 = (unsigned int) *date;
utmp = u1 - u2;
if (bi < 0 || OR_CHECK_UNS_SUB_UNDERFLOW (u1, u2, utmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_DATE_UNDERFLOW, 0);
return ER_FAILED;
}
db_date_decode (&utmp, &month, &day, &year);
db_make_date (result_p, month, day, year);
break;
default:
break;
}
return err;
}
static int
qdata_subtract_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
float f;
DB_TYPE type;
f = db_get_float (float_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_subtract_float (f, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_subtract_float (f, (float) db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_subtract_float (f, (float) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_subtract_float (f, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_subtract_double (f, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_subtract_double (f, qdata_coerce_numeric_to_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_subtract_monetary (f, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type,
result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
double d;
DB_TYPE type;
d = db_get_double (double_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_subtract_double (d, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_subtract_double (d, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_subtract_double (d, (double) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_subtract_double (d, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_subtract_double (d, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_subtract_double (d, qdata_coerce_numeric_to_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_subtract_monetary (d, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type,
result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type;
DB_VALUE dbval_tmp;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
qdata_coerce_dbval_to_numeric (dbval_p, &dbval_tmp);
if (numeric_db_value_sub (numeric_val_p, &dbval_tmp, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_NUMERIC:
if (numeric_db_value_sub (numeric_val_p, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_SUBTRACTION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_FLOAT:
return qdata_subtract_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_float (dbval_p), result_p);
break;
case DB_TYPE_DOUBLE:
return qdata_subtract_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_double (dbval_p), result_p);
break;
case DB_TYPE_MONETARY:
return qdata_subtract_monetary (qdata_coerce_numeric_to_double (numeric_val_p),
(db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p);
break;
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
double d;
DB_CURRENCY currency;
DB_TYPE type;
d = (db_get_monetary (monetary_val_p))->amount;
currency = (db_get_monetary (monetary_val_p))->type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return qdata_subtract_monetary (d, db_get_short (dbval_p), currency, result_p);
case DB_TYPE_INTEGER:
return qdata_subtract_monetary (d, db_get_int (dbval_p), currency, result_p);
case DB_TYPE_BIGINT:
return qdata_subtract_monetary (d, (double) db_get_bigint (dbval_p), currency, result_p);
case DB_TYPE_FLOAT:
return qdata_subtract_monetary (d, db_get_float (dbval_p), currency, result_p);
case DB_TYPE_DOUBLE:
return qdata_subtract_monetary (d, db_get_double (dbval_p), currency, result_p);
case DB_TYPE_NUMERIC:
return qdata_subtract_monetary (d, qdata_coerce_numeric_to_double (dbval_p), currency, result_p);
case DB_TYPE_MONETARY:
/* Note: we probably should return an error if the two monetaries have different monetary types. */
return qdata_subtract_monetary (d, (db_get_monetary (dbval_p))->amount, currency, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_sequence_to_dbval (DB_VALUE * seq_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_SET *set_tmp;
#if !defined(NDEBUG)
DB_TYPE type1, type2;
#endif
#if !defined(NDEBUG)
type1 = DB_VALUE_DOMAIN_TYPE (seq_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
assert (TP_IS_SET_TYPE (type1));
assert (TP_IS_SET_TYPE (type2));
#endif
if (domain_p == NULL)
{
return ER_FAILED;
}
if (set_difference (db_get_set (seq_val_p), db_get_set (dbval_p), &set_tmp, domain_p) < 0)
{
return ER_FAILED;
}
set_make_collection (result_p, set_tmp);
return NO_ERROR;
}
static int
qdata_subtract_time_to_dbval (DB_VALUE * time_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type;
DB_TIME *timeval, *timeval1;
int subval;
int err = NO_ERROR;
timeval = db_get_time (time_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
subval = (int) db_get_short (dbval_p);
if (subval < 0)
{
return qdata_add_bigint_to_time (time_val_p, (DB_BIGINT) (-subval), result_p);
}
return qdata_subtract_time ((DB_TIME) (*timeval % SECONDS_OF_ONE_DAY), (DB_TIME) subval, result_p);
case DB_TYPE_INTEGER:
subval = (int) (db_get_int (dbval_p) % SECONDS_OF_ONE_DAY);
if (subval < 0)
{
return qdata_add_bigint_to_time (time_val_p, (DB_BIGINT) (-subval), result_p);
}
return qdata_subtract_time ((DB_TIME) (*timeval % SECONDS_OF_ONE_DAY), (DB_TIME) subval, result_p);
case DB_TYPE_BIGINT:
subval = (int) (db_get_bigint (dbval_p) % SECONDS_OF_ONE_DAY);
if (subval < 0)
{
return qdata_add_bigint_to_time (time_val_p, (DB_BIGINT) (-subval), result_p);
}
return qdata_subtract_time ((DB_TIME) (*timeval % SECONDS_OF_ONE_DAY), (DB_TIME) subval, result_p);
case DB_TYPE_TIME:
timeval1 = db_get_time (dbval_p);
db_make_int (result_p, ((int) *timeval - (int) *timeval1));
break;
default:
break;
}
return err;
}
static int
qdata_subtract_utime_to_dbval (DB_VALUE * utime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_TYPE type;
DB_UTIME *utime, *utime1;
DB_TIMESTAMPTZ *ts_tz1;
DB_DATETIME *datetime;
DB_DATETIME tmp_datetime;
DB_DATETIMETZ datetime_tz_1;
unsigned int u1;
short s2;
int i2;
DB_BIGINT bi2;
utime = db_get_timestamp (utime_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
u1 = (unsigned int) *utime;
s2 = db_get_short (dbval_p);
if (s2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_short_asymmetry (utime_val_p, s2, utime, result_p, domain_p);
}
return qdata_subtract_utime (*utime, (DB_UTIME) s2, result_p);
case DB_TYPE_INTEGER:
u1 = (unsigned int) *utime;
i2 = db_get_int (dbval_p);
if (i2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_int_asymmetry (utime_val_p, i2, utime, result_p, domain_p);
}
return qdata_subtract_utime (*utime, (DB_UTIME) i2, result_p);
case DB_TYPE_BIGINT:
u1 = (unsigned int) *utime;
bi2 = db_get_bigint (dbval_p);
if (bi2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_bigint_asymmetry (utime_val_p, bi2, utime, result_p, domain_p);
}
return qdata_subtract_utime (*utime, (DB_UTIME) bi2, result_p);
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
utime1 = db_get_timestamp (dbval_p);
db_make_int (result_p, ((int) *utime - (int) *utime1));
break;
case DB_TYPE_TIMESTAMPTZ:
ts_tz1 = db_get_timestamptz (dbval_p);
db_make_int (result_p, ((int) *utime - (int) ts_tz1->timestamp));
break;
case DB_TYPE_DATETIME:
datetime = db_get_datetime (dbval_p);
(void) db_timestamp_decode_ses (utime, &tmp_datetime.date, &tmp_datetime.time);
return qdata_subtract_datetime (&tmp_datetime, datetime, result_p);
case DB_TYPE_DATETIMELTZ:
datetime = db_get_datetime (dbval_p);
(void) db_timestamp_decode_utc (utime, &tmp_datetime.date, &tmp_datetime.time);
return qdata_subtract_datetime (&tmp_datetime, datetime, result_p);
case DB_TYPE_DATETIMETZ:
datetime_tz_1 = *db_get_datetimetz (dbval_p);
(void) db_timestamp_decode_utc (utime, &tmp_datetime.date, &tmp_datetime.time);
return qdata_subtract_datetime (&tmp_datetime, &datetime_tz_1.datetime, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_timestampltz_to_dbval (DB_VALUE * ts_ltz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
DB_TYPE type;
DB_UTIME *utime_p;
DB_VALUE utime_val, tmp_val_res;
int err = NO_ERROR;
utime_p = db_get_timestamp (ts_ltz_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_DATETIMETZ:
/* perform operation as simple UTIME */
db_make_timestamp (&utime_val, *utime_p);
err =
qdata_subtract_utime_to_dbval (&utime_val, dbval_p, &tmp_val_res,
tp_domain_resolve_default (DB_TYPE_TIMESTAMP));
if (err != NO_ERROR)
{
break;
}
if (DB_VALUE_TYPE (&tmp_val_res) == DB_TYPE_TIMESTAMP)
{
db_make_timestampltz (result_p, *db_get_timestamp (&tmp_val_res));
}
else
{
assert (tmp_val_res.need_clear == false);
pr_clone_value (&tmp_val_res, result_p);
}
break;
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_timestamptz_to_dbval (DB_VALUE * ts_tz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
int err = NO_ERROR;
DB_TYPE type;
DB_UTIME *utime1 = NULL, *utime2 = NULL;
DB_TIMESTAMPTZ *ts_tz1_p = NULL, *ts_tz2_p = NULL, ts_tz_res, ts_tz_res_fixed;
DB_DATETIME *datetime = NULL;
DB_DATETIME tmp_datetime;
DB_DATETIMETZ datetime_tz_1;
DB_DATE date;
DB_TIME time;
unsigned int u1;
short s2;
int i2;
DB_BIGINT bi2;
DB_VALUE tmp_val_res;
tmp_val_res.data.utime = 0;
ts_tz1_p = db_get_timestamptz (ts_tz_val_p);
utime1 = &ts_tz1_p->timestamp;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
u1 = (unsigned int) *utime1;
s2 = db_get_short (dbval_p);
if (s2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_short_asymmetry (ts_tz_val_p, s2, utime1, result_p, domain_p);
}
err = qdata_subtract_utime (*utime1, (DB_UTIME) s2, &tmp_val_res);
break;
case DB_TYPE_INTEGER:
u1 = (unsigned int) *utime1;
i2 = db_get_int (dbval_p);
if (i2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_int_asymmetry (ts_tz_val_p, i2, utime1, result_p, domain_p);
}
err = qdata_subtract_utime (*utime1, (DB_UTIME) i2, &tmp_val_res);
break;
case DB_TYPE_BIGINT:
u1 = (unsigned int) *utime1;
bi2 = db_get_bigint (dbval_p);
if (bi2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_bigint_asymmetry (ts_tz_val_p, bi2, utime1, result_p, domain_p);
}
err = qdata_subtract_utime (*utime1, (DB_UTIME) bi2, &tmp_val_res);
break;
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
utime2 = db_get_timestamp (dbval_p);
db_make_int (result_p, ((int) *utime1 - (int) *utime2));
return err;
case DB_TYPE_TIMESTAMPTZ:
ts_tz2_p = db_get_timestamptz (dbval_p);
db_make_int (result_p, ((int) *utime1 - (int) ts_tz2_p->timestamp));
return err;
case DB_TYPE_DATETIME:
datetime = db_get_datetime (dbval_p);
err = db_timestamp_decode_w_tz_id (utime1, &ts_tz1_p->tz_id, &date, &time);
if (err != NO_ERROR)
{
break;
}
tmp_datetime.date = date;
tmp_datetime.time = time * 1000;
return qdata_subtract_datetime (&tmp_datetime, datetime, result_p);
case DB_TYPE_DATETIMELTZ:
datetime = db_get_datetime (dbval_p);
db_timestamp_decode_utc (utime1, &date, &time);
tmp_datetime.date = date;
tmp_datetime.time = time * 1000;
return qdata_subtract_datetime (&tmp_datetime, datetime, result_p);
case DB_TYPE_DATETIMETZ:
datetime_tz_1 = *db_get_datetimetz (dbval_p);
db_timestamp_decode_utc (utime1, &date, &time);
if (err != NO_ERROR)
{
break;
}
tmp_datetime.date = date;
tmp_datetime.time = time * 1000;
return qdata_subtract_datetime (&tmp_datetime, &datetime_tz_1.datetime, result_p);
default:
break;
}
if (err == NO_ERROR)
{
assert (DB_VALUE_TYPE (&tmp_val_res) == DB_TYPE_TIMESTAMP);
/* create TIMESTAMPTZ from result UTIME by adjusting TZ_ID */
ts_tz_res.timestamp = *db_get_timestamp (&tmp_val_res);
ts_tz_res.tz_id = ts_tz1_p->tz_id;
err = tz_timestamptz_fix_zone (&ts_tz_res, &ts_tz_res_fixed);
if (err != NO_ERROR)
{
return err;
}
db_make_timestamptz (result_p, &ts_tz_res_fixed);
}
return err;
}
static int
qdata_subtract_datetime_to_dbval (DB_VALUE * datetime_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
DB_TYPE type;
DB_DATETIME *datetime1_p;
datetime1_p = db_get_datetime (datetime_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
{
short s2;
s2 = db_get_short (dbval_p);
if (s2 < 0)
{
/* We're really adding. */
return qdata_subtract_datetime_to_int_asymmetry (datetime_val_p, s2, datetime1_p, result_p, domain_p);
}
return qdata_subtract_datetime_to_int (datetime1_p, s2, result_p);
}
case DB_TYPE_INTEGER:
{
int i2;
i2 = db_get_int (dbval_p);
if (i2 < 0)
{
/* We're really adding. */
return qdata_subtract_datetime_to_int_asymmetry (datetime_val_p, i2, datetime1_p, result_p, domain_p);
}
return qdata_subtract_datetime_to_int (datetime1_p, i2, result_p);
}
case DB_TYPE_BIGINT:
{
DB_BIGINT bi2;
bi2 = db_get_bigint (dbval_p);
if (bi2 < 0)
{
/* We're really adding. */
return qdata_subtract_datetime_to_int_asymmetry (datetime_val_p, bi2, datetime1_p, result_p, domain_p);
}
return qdata_subtract_datetime_to_int (datetime1_p, bi2, result_p);
}
case DB_TYPE_TIMESTAMP:
{
DB_BIGINT u1, u2;
DB_DATETIME datetime2;
(void) db_timestamp_decode_ses (db_get_timestamp (dbval_p), &datetime2.date, &datetime2.time);
u1 = ((DB_BIGINT) datetime1_p->date) * MILLISECONDS_OF_ONE_DAY + datetime1_p->time;
u2 = ((DB_BIGINT) datetime2.date) * MILLISECONDS_OF_ONE_DAY + datetime2.time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_TIMESTAMPLTZ:
{
DB_BIGINT u1, u2;
DB_DATETIME datetime2;
(void) db_timestamp_decode_ses (db_get_timestamp (dbval_p), &datetime2.date, &datetime2.time);
u1 = ((DB_BIGINT) datetime1_p->date) * MILLISECONDS_OF_ONE_DAY + datetime1_p->time;
u2 = ((DB_BIGINT) datetime2.date) * MILLISECONDS_OF_ONE_DAY + datetime2.time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_TIMESTAMPTZ:
{
DB_BIGINT u1, u2;
DB_DATETIME datetime2;
DB_TIMESTAMPTZ ts_tz2;
ts_tz2 = *db_get_timestamptz (dbval_p);
(void) db_timestamp_decode_ses (&ts_tz2.timestamp, &datetime2.date, &datetime2.time);
u1 = ((DB_BIGINT) datetime1_p->date) * MILLISECONDS_OF_ONE_DAY + datetime1_p->time;
u2 = ((DB_BIGINT) datetime2.date) * MILLISECONDS_OF_ONE_DAY + datetime2.time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_DATETIME:
{
DB_BIGINT u1, u2;
DB_DATETIME *datetime2_p;
datetime2_p = db_get_datetime (dbval_p);
u1 = ((DB_BIGINT) datetime1_p->date) * MILLISECONDS_OF_ONE_DAY + datetime1_p->time;
u2 = ((DB_BIGINT) datetime2_p->date) * MILLISECONDS_OF_ONE_DAY + datetime2_p->time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_DATETIMELTZ:
{
DB_BIGINT u1, u2;
DB_DATETIMETZ dt_tz1;
DB_DATETIME *dt_utc2_p;
int err;
err = tz_create_datetimetz_from_ses (datetime1_p, &dt_tz1);
if (err != NO_ERROR)
{
return err;
}
dt_utc2_p = db_get_datetime (dbval_p);
u1 = ((DB_BIGINT) dt_tz1.datetime.date) * MILLISECONDS_OF_ONE_DAY + dt_tz1.datetime.time;
u2 = ((DB_BIGINT) dt_utc2_p->date) * MILLISECONDS_OF_ONE_DAY + dt_utc2_p->time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_DATETIMETZ:
{
DB_BIGINT u1, u2;
DB_DATETIMETZ *datetimetz2_p;
DB_DATETIME datetime2;
int err;
datetimetz2_p = db_get_datetimetz (dbval_p);
err = tz_utc_datetimetz_to_local (&datetimetz2_p->datetime, &datetimetz2_p->tz_id, &datetime2);
if (err != NO_ERROR)
{
return err;
}
u1 = ((DB_BIGINT) datetime1_p->date) * MILLISECONDS_OF_ONE_DAY + datetime1_p->time;
u2 = ((DB_BIGINT) datetime2.date) * MILLISECONDS_OF_ONE_DAY + datetime2.time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_DATE:
{
DB_BIGINT u1, u2;
u1 = ((DB_BIGINT) datetime1_p->date) * MILLISECONDS_OF_ONE_DAY + datetime1_p->time;
u2 = ((DB_BIGINT) * db_get_date (dbval_p)) * MILLISECONDS_OF_ONE_DAY;
return db_make_bigint (result_p, u1 - u2);
}
default:
break;
}
return NO_ERROR;
}
static int
qdata_subtract_datetimetz_to_dbval (DB_VALUE * dt_tz_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p,
TP_DOMAIN * domain_p)
{
int err = NO_ERROR;
DB_TYPE type;
DB_DATETIMETZ *dt_tz1_p;
DB_DATETIME *datetime1_p;
dt_tz1_p = db_get_datetimetz (dt_tz_val_p);
datetime1_p = &(dt_tz1_p->datetime);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
{
DB_VALUE dt_val, dt_val_res;
DB_DATETIMETZ dt_tz, dt_tz_fixed;
db_make_datetime (&dt_val, datetime1_p);
err =
qdata_subtract_datetime_to_dbval (&dt_val, dbval_p, &dt_val_res,
tp_domain_resolve_default (DB_TYPE_DATETIME));
if (err != NO_ERROR)
{
break;
}
dt_tz.datetime = *db_get_datetime (&dt_val_res);
dt_tz.tz_id = dt_tz1_p->tz_id;
err = tz_datetimetz_fix_zone (&dt_tz, &dt_tz_fixed);
if (err != NO_ERROR)
{
break;
}
db_make_datetimetz (result_p, &dt_tz_fixed);
break;
}
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
{
DB_BIGINT u1, u2;
DB_DATETIME datetime2;
DB_UTIME *utime2_p;
/* create a DATETIME in UTC reference */
if (type == DB_TYPE_TIMESTAMPTZ)
{
DB_TIMESTAMPTZ *ts_tz2_p;
ts_tz2_p = db_get_timestamptz (dbval_p);
utime2_p = &(ts_tz2_p->timestamp);
}
else
{
utime2_p = db_get_timestamp (dbval_p);
}
(void) db_timestamp_decode_utc (utime2_p, &datetime2.date, &datetime2.time);
u1 = ((DB_BIGINT) dt_tz1_p->datetime.date) * MILLISECONDS_OF_ONE_DAY + dt_tz1_p->datetime.time;
u2 = ((DB_BIGINT) datetime2.date) * MILLISECONDS_OF_ONE_DAY + datetime2.time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_DATETIME:
{
DB_BIGINT u1, u2;
DB_DATETIME *datetime2_p;
DB_DATETIME datetime1;
/* from DT with TZ to local */
datetime2_p = db_get_datetime (dbval_p);
err = tz_utc_datetimetz_to_local (&dt_tz1_p->datetime, &dt_tz1_p->tz_id, &datetime1);
if (err != NO_ERROR)
{
return err;
}
u1 = ((DB_BIGINT) datetime1.date) * MILLISECONDS_OF_ONE_DAY + datetime1.time;
u2 = ((DB_BIGINT) datetime2_p->date) * MILLISECONDS_OF_ONE_DAY + datetime2_p->time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_DATETIMETZ:
case DB_TYPE_DATETIMELTZ:
{
DB_BIGINT u1, u2;
DB_DATETIMETZ *dt_tz2_p;
DB_DATETIME *datetime2_p;
/* both datetimes are in UTC, no need to consider timezones */
if (type == DB_TYPE_DATETIMETZ)
{
dt_tz2_p = db_get_datetimetz (dbval_p);
datetime2_p = &(dt_tz2_p->datetime);
}
else
{
datetime2_p = db_get_datetime (dbval_p);
}
u1 = ((DB_BIGINT) datetime1_p->date) * MILLISECONDS_OF_ONE_DAY + datetime1_p->time;
u2 = ((DB_BIGINT) datetime2_p->date) * MILLISECONDS_OF_ONE_DAY + datetime2_p->time;
return db_make_bigint (result_p, u1 - u2);
}
case DB_TYPE_DATE:
{
DB_BIGINT u1, u2;
DB_DATETIME *datetime2_p;
DB_DATETIME datetime1;
/* from DT with TZ to local */
datetime2_p = db_get_datetime (dbval_p);
err = tz_utc_datetimetz_to_local (&dt_tz1_p->datetime, &dt_tz1_p->tz_id, &datetime1);
if (err != NO_ERROR)
{
return err;
}
u1 = ((DB_BIGINT) datetime1.date) * MILLISECONDS_OF_ONE_DAY + datetime1.time;
u2 = ((DB_BIGINT) * db_get_date (dbval_p)) * MILLISECONDS_OF_ONE_DAY;
return db_make_bigint (result_p, u1 - u2);
}
default:
break;
}
return err;
}
static int
qdata_subtract_date_to_dbval (DB_VALUE * date_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_TYPE type;
DB_DATE *date, *date1;
unsigned int u1, u2, utmp;
short s2;
int i2;
DB_BIGINT bi1, bi2, bitmp;
int day, month, year;
date = db_get_date (date_val_p);
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
u1 = (unsigned int) *date;
s2 = db_get_short (dbval_p);
if (s2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_short_asymmetry (date_val_p, s2, date, result_p, domain_p);
}
u2 = (unsigned int) s2;
utmp = u1 - u2;
if (OR_CHECK_UNS_SUB_UNDERFLOW (u1, u2, utmp) || utmp < DB_DATE_MIN)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_DATE_UNDERFLOW, 0);
return ER_QPROC_DATE_UNDERFLOW;
}
db_date_decode (&utmp, &month, &day, &year);
db_make_date (result_p, month, day, year);
break;
case DB_TYPE_BIGINT:
bi1 = (DB_BIGINT) * date;
bi2 = db_get_bigint (dbval_p);
if (bi2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_bigint_asymmetry (date_val_p, bi2, date, result_p, domain_p);
}
bitmp = bi1 - bi2;
if (OR_CHECK_SUB_UNDERFLOW (bi1, bi2, bitmp) || OR_CHECK_UINT_OVERFLOW (bitmp) || bitmp < DB_DATE_MIN)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_DATE_UNDERFLOW, 0);
return ER_FAILED;
}
utmp = (unsigned int) bitmp;
db_date_decode (&utmp, &month, &day, &year);
db_make_date (result_p, month, day, year);
break;
case DB_TYPE_INTEGER:
u1 = (unsigned int) *date;
i2 = db_get_int (dbval_p);
if (i2 < 0)
{
/* We're really adding. */
return qdata_subtract_utime_to_int_asymmetry (date_val_p, i2, date, result_p, domain_p);
}
u2 = (unsigned int) i2;
utmp = u1 - u2;
if (OR_CHECK_UNS_SUB_UNDERFLOW (u1, u2, utmp) || utmp < DB_DATE_MIN)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_DATE_UNDERFLOW, 0);
return ER_QPROC_DATE_UNDERFLOW;
}
db_date_decode (&utmp, &month, &day, &year);
db_make_date (result_p, month, day, year);
break;
case DB_TYPE_DATE:
date1 = db_get_date (dbval_p);
db_make_int (result_p, (int) *date - (int) *date1);
break;
default:
break;
}
return NO_ERROR;
}
/*
* qdata_subtract_dbval () -
* return: NO_ERROR, or ER_code
* dbval1(in) : First db_value node
* dbval2(in) : Second db_value node
* res(out) : Resultant db_value node
* domain(in) :
*
* Note: Subtract dbval2 value from dbval1 value.
* Overflow checks are only done when both operand maximums have
* overlapping precision/scale. That is,
* short - integer -> overflow is checked
* float - double -> overflow is not checked. Maximum float
* value does not overlap maximum double
* precision/scale.
* MAX_FLT - MAX_DBL = -MAX_DBL
*/
int
qdata_subtract_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type1;
DB_TYPE type2;
int error = NO_ERROR;
DB_VALUE cast_value1;
DB_VALUE cast_value2;
TP_DOMAIN *cast_dom1 = NULL;
TP_DOMAIN *cast_dom2 = NULL;
TP_DOMAIN_STATUS dom_status;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
db_make_null (&cast_value1);
db_make_null (&cast_value2);
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
if (type1 == DB_TYPE_ENUMERATION)
{
/* The enumeration will always be casted to SMALLINT */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_SMALLINT);
dom_status = tp_value_auto_cast (dbval1_p, &cast_value1, cast_dom1);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval1_p, cast_dom1);
return error;
}
return qdata_subtract_dbval (&cast_value1, dbval2_p, result_p, domain_p);
}
else if (type2 == DB_TYPE_ENUMERATION)
{
cast_dom2 = tp_domain_resolve_default (DB_TYPE_SMALLINT);
dom_status = tp_value_auto_cast (dbval2_p, &cast_value2, cast_dom2);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval2_p, cast_dom2);
return error;
}
return qdata_subtract_dbval (dbval1_p, &cast_value2, result_p, domain_p);
}
/* number - string : cast string to number, substract as numbers */
if (TP_IS_NUMERIC_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast string to double */
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* string - number: cast string to number, substract as numbers */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_NUMERIC_TYPE (type2))
{
/* cast string to double */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* string - string: cast string to number, substract as numbers */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast string to double */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* date - number : cast floating point number to bigint, date - bigint = date */
else if (TP_IS_DATE_OR_TIME_TYPE (type1) && TP_IS_FLOATING_NUMBER_TYPE (type2))
{
/* cast number to BIGINT */
cast_dom2 = tp_domain_resolve_default (DB_TYPE_BIGINT);
}
/* number - date: cast floating point number to bigint, bigint - date= date */
else if (TP_IS_FLOATING_NUMBER_TYPE (type1) && TP_IS_DATE_OR_TIME_TYPE (type2))
{
/* cast number to BIGINT */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_BIGINT);
}
/* TIME - string : cast string to TIME , date - TIME = bigint */
/* DATE - string : cast string to DATETIME, the other operand to DATETIME DATETIME - DATETIME = bigint */
else if (TP_IS_DATE_OR_TIME_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
if (type1 == DB_TYPE_TIME)
{
cast_dom2 = tp_domain_resolve_default (DB_TYPE_TIME);
}
else
{
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DATETIME);
if (type1 != DB_TYPE_DATETIME)
{
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DATETIME);
}
}
}
/* string - TIME : cast string to TIME, TIME - TIME = bigint */
/* string - DATE : cast string to DATETIME, the other operand to DATETIME DATETIME - DATETIME = bigint */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_DATE_OR_TIME_TYPE (type2))
{
if (type2 == DB_TYPE_TIME)
{
cast_dom1 = tp_domain_resolve_default (DB_TYPE_TIME);
}
else
{
/* cast string to same 'date' */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DATETIME);
if (type2 != DB_TYPE_DATETIME)
{
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DATETIME);
}
}
}
if (cast_dom1 != NULL)
{
dom_status = tp_value_auto_cast (dbval1_p, &cast_value1, cast_dom1);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval1_p, cast_dom1);
return error;
}
dbval1_p = &cast_value1;
}
if (cast_dom2 != NULL)
{
dom_status = tp_value_auto_cast (dbval2_p, &cast_value2, cast_dom2);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval2_p, cast_dom2);
return error;
}
dbval2_p = &cast_value2;
}
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
if (DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
if (qdata_is_zero_value_date (dbval1_p) || qdata_is_zero_value_date (dbval2_p))
{
/* subtract operation with zero date returns null */
db_make_null (result_p);
if (!prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ATTEMPT_TO_USE_ZERODATE, 0);
return ER_ATTEMPT_TO_USE_ZERODATE;
}
return NO_ERROR;
}
switch (type1)
{
case DB_TYPE_SHORT:
error = qdata_subtract_short_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_BIGINT:
error = qdata_subtract_bigint_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_INTEGER:
error = qdata_subtract_int_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_FLOAT:
error = qdata_subtract_float_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DOUBLE:
error = qdata_subtract_double_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_NUMERIC:
error = qdata_subtract_numeric_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_MONETARY:
error = qdata_subtract_monetary_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
if (!TP_IS_SET_TYPE (type2))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
if (domain_p == NULL)
{
if (type1 == type2 && type1 == DB_TYPE_SET)
{
/* partial resolve : set only basic domain; full domain will be resolved in 'fetch', based on the
* result's value */
domain_p = tp_domain_resolve_default (type1);
}
else
{
domain_p = tp_domain_resolve_default (DB_TYPE_MULTISET);
}
}
error = qdata_subtract_sequence_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_TIME:
error = qdata_subtract_time_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_TIMESTAMP:
error = qdata_subtract_utime_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_TIMESTAMPLTZ:
error = qdata_subtract_timestampltz_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_TIMESTAMPTZ:
error = qdata_subtract_timestamptz_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_DATETIME:
error = qdata_subtract_datetime_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_DATETIMELTZ:
{
/* create a datetime with TZ using session timezone */
DB_VALUE tmp_val;
DB_DATETIMETZ dt_tz1;
dt_tz1.datetime = *db_get_datetime (dbval1_p);
error = tz_create_session_tzid_for_datetime (&dt_tz1.datetime, true, &dt_tz1.tz_id);
if (error != NO_ERROR)
{
break;
}
db_make_datetimetz (&tmp_val, &dt_tz1);
error = qdata_subtract_datetimetz_to_dbval (&tmp_val, dbval2_p, result_p, domain_p);
}
break;
case DB_TYPE_DATETIMETZ:
error = qdata_subtract_datetimetz_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_DATE:
error = qdata_subtract_date_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_STRING:
default:
if (prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS) == false)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (error != NO_ERROR)
{
return error;
}
return qdata_coerce_result_to_domain (result_p, domain_p);
}
static int
qdata_multiply_short (DB_VALUE * short_val_p, short s2, DB_VALUE * result_p)
{
/* NOTE that we need volatile to prevent optimizer from generating division expression as multiplication */
volatile short s1, stmp;
s1 = db_get_short (short_val_p);
stmp = s1 * s2;
if (OR_CHECK_MULT_OVERFLOW (s1, s2, stmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
db_make_short (result_p, stmp);
return NO_ERROR;
}
static int
qdata_multiply_int (DB_VALUE * int_val_p, int i2, DB_VALUE * result_p)
{
/* NOTE that we need volatile to prevent optimizer from generating division expression as multiplication */
volatile int i1, itmp;
i1 = db_get_int (int_val_p);
itmp = i1 * i2;
if (OR_CHECK_MULT_OVERFLOW (i1, i2, itmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
db_make_int (result_p, itmp);
return NO_ERROR;
}
static int
qdata_multiply_bigint (DB_VALUE * bigint_val_p, DB_BIGINT bi2, DB_VALUE * result_p)
{
/* NOTE that we need volatile to prevent optimizer from generating division expression as multiplication */
volatile DB_BIGINT bi1, bitmp;
bi1 = db_get_bigint (bigint_val_p);
bitmp = bi1 * bi2;
if (OR_CHECK_MULT_OVERFLOW (bi1, bi2, bitmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
db_make_bigint (result_p, bitmp);
return NO_ERROR;
}
static int
qdata_multiply_float (DB_VALUE * float_val_p, float f2, DB_VALUE * result_p)
{
float f1, ftmp;
f1 = db_get_float (float_val_p);
ftmp = f1 * f2;
if (OR_CHECK_FLOAT_OVERFLOW (ftmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
db_make_float (result_p, ftmp);
return NO_ERROR;
}
static int
qdata_multiply_double (double d1, double d2, DB_VALUE * result_p)
{
double dtmp;
dtmp = d1 * d2;
if (OR_CHECK_DOUBLE_OVERFLOW (dtmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
db_make_double (result_p, dtmp);
return NO_ERROR;
}
static int
qdata_multiply_numeric (DB_VALUE * numeric_val_p, DB_VALUE * dbval, DB_VALUE * result_p)
{
DB_VALUE dbval_tmp;
qdata_coerce_dbval_to_numeric (dbval, &dbval_tmp);
if (numeric_db_value_mul (numeric_val_p, &dbval_tmp, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
return NO_ERROR;
}
static int
qdata_multiply_monetary (DB_VALUE * monetary_val_p, double d, DB_VALUE * result_p)
{
double dtmp;
dtmp = (db_get_monetary (monetary_val_p))->amount * d;
if (OR_CHECK_DOUBLE_OVERFLOW (dtmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
db_make_monetary (result_p, (db_get_monetary (monetary_val_p))->type, dtmp);
return NO_ERROR;
}
static int
qdata_multiply_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
short s;
DB_TYPE type2;
s = db_get_short (short_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_multiply_short (dbval_p, s, result_p);
case DB_TYPE_BIGINT:
return qdata_multiply_bigint (dbval_p, s, result_p);
case DB_TYPE_INTEGER:
return qdata_multiply_int (dbval_p, s, result_p);
case DB_TYPE_FLOAT:
return qdata_multiply_float (dbval_p, s, result_p);
case DB_TYPE_DOUBLE:
return qdata_multiply_double (db_get_double (dbval_p), s, result_p);
case DB_TYPE_NUMERIC:
return qdata_multiply_numeric (dbval_p, short_val_p, result_p);
case DB_TYPE_MONETARY:
return qdata_multiply_monetary (dbval_p, s, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_multiply_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type2;
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_multiply_int (int_val_p, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_multiply_int (int_val_p, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_multiply_bigint (dbval_p, db_get_int (int_val_p), result_p);
case DB_TYPE_FLOAT:
return qdata_multiply_float (dbval_p, (float) db_get_int (int_val_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_multiply_double (db_get_double (dbval_p), db_get_int (int_val_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_multiply_numeric (dbval_p, int_val_p, result_p);
case DB_TYPE_MONETARY:
return qdata_multiply_monetary (dbval_p, db_get_int (int_val_p), result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_multiply_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type2;
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_multiply_bigint (bigint_val_p, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_multiply_bigint (bigint_val_p, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_multiply_bigint (bigint_val_p, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_multiply_float (dbval_p, (float) db_get_bigint (bigint_val_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_multiply_double (db_get_double (dbval_p), (double) db_get_bigint (bigint_val_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_multiply_numeric (dbval_p, bigint_val_p, result_p);
case DB_TYPE_MONETARY:
return qdata_multiply_monetary (dbval_p, (double) db_get_bigint (bigint_val_p), result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_multiply_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type2;
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_multiply_float (float_val_p, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_multiply_float (float_val_p, (float) db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_multiply_float (float_val_p, (float) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_multiply_float (float_val_p, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_multiply_double (db_get_float (float_val_p), db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_multiply_double (db_get_float (float_val_p), qdata_coerce_numeric_to_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_multiply_monetary (dbval_p, db_get_float (float_val_p), result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_multiply_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
double d;
DB_TYPE type2;
d = db_get_double (double_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_multiply_double (d, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_multiply_double (d, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_multiply_double (d, (double) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_multiply_double (d, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_multiply_double (d, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_multiply_double (d, qdata_coerce_numeric_to_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_multiply_monetary (dbval_p, d, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_multiply_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type2;
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
return qdata_multiply_numeric (numeric_val_p, dbval_p, result_p);
case DB_TYPE_NUMERIC:
if (numeric_db_value_mul (numeric_val_p, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_MULTIPLICATION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_FLOAT:
return qdata_multiply_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_multiply_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
return qdata_multiply_monetary (dbval_p, qdata_coerce_numeric_to_double (numeric_val_p), result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_multiply_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type2;
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_multiply_monetary (monetary_val_p, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_multiply_monetary (monetary_val_p, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_multiply_monetary (monetary_val_p, (double) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_multiply_monetary (monetary_val_p, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_multiply_monetary (monetary_val_p, db_get_double (dbval_p), result_p);
case DB_TYPE_NUMERIC:
return qdata_multiply_monetary (monetary_val_p, qdata_coerce_numeric_to_double (dbval_p), result_p);
case DB_TYPE_MONETARY:
/* Note: we probably should return an error if the two monetaries have different montetary types. */
return qdata_multiply_monetary (monetary_val_p, (db_get_monetary (dbval_p))->amount, result_p);
default:
break;
}
return NO_ERROR;
}
static int
qdata_multiply_sequence_to_dbval (DB_VALUE * seq_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p, TP_DOMAIN * domain_p)
{
DB_SET *set_tmp = NULL;
#if !defined(NDEBUG)
DB_TYPE type1, type2;
#endif
#if !defined(NDEBUG)
type1 = DB_VALUE_DOMAIN_TYPE (seq_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
assert (TP_IS_SET_TYPE (type1));
assert (TP_IS_SET_TYPE (type2));
#endif
if (set_intersection (db_get_set (seq_val_p), db_get_set (dbval_p), &set_tmp, domain_p) < 0)
{
return ER_FAILED;
}
set_make_collection (result_p, set_tmp);
return NO_ERROR;
}
/*
* qdata_multiply_dbval () -
* return: NO_ERROR, or ER_code
* dbval1(in) : First db_value node
* dbval2(in) : Second db_value node
* res(out) : Resultant db_value node
* domain(in) :
*
* Note: Multiply two db_values.
*/
int
qdata_multiply_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type1;
DB_TYPE type2;
int error = NO_ERROR;
DB_VALUE cast_value1;
DB_VALUE cast_value2;
TP_DOMAIN *cast_dom1 = NULL;
TP_DOMAIN *cast_dom2 = NULL;
TP_DOMAIN_STATUS dom_status;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
db_make_null (&cast_value1);
db_make_null (&cast_value2);
/* number * string : cast string to DOUBLE, multiply as number * DOUBLE */
if (TP_IS_NUMERIC_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast arg2 to double */
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* string * number: cast string to DOUBLE, multiply as DOUBLE * number */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_NUMERIC_TYPE (type2))
{
/* cast arg1 to double */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* string * string: cast both to DOUBLE, multiply as DOUBLE * DOUBLE */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast number to DOUBLE */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
if (cast_dom2 != NULL)
{
dom_status = tp_value_auto_cast (dbval2_p, &cast_value2, cast_dom2);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval2_p, cast_dom2);
return error;
}
dbval2_p = &cast_value2;
}
if (cast_dom1 != NULL)
{
dom_status = tp_value_auto_cast (dbval1_p, &cast_value1, cast_dom1);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval1_p, cast_dom1);
return error;
}
dbval1_p = &cast_value1;
}
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
if (DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
switch (type1)
{
case DB_TYPE_SHORT:
error = qdata_multiply_short_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_INTEGER:
error = qdata_multiply_int_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_BIGINT:
error = qdata_multiply_bigint_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_FLOAT:
error = qdata_multiply_float_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DOUBLE:
error = qdata_multiply_double_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_NUMERIC:
error = qdata_multiply_numeric_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_MONETARY:
error = qdata_multiply_monetary_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
if (!TP_IS_SET_TYPE (type2))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
if (domain_p == NULL)
{
if (type1 == type2 && type1 == DB_TYPE_SET)
{
/* partial resolve : set only basic domain; full domain will be resolved in 'fetch', based on the
* result's value */
domain_p = tp_domain_resolve_default (type1);
}
else
{
domain_p = tp_domain_resolve_default (DB_TYPE_MULTISET);
}
}
error = qdata_multiply_sequence_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_TIME:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
case DB_TYPE_DATE:
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_DATETIMETZ:
case DB_TYPE_STRING:
default:
if (prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS) == false)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (error != NO_ERROR)
{
return error;
}
return qdata_coerce_result_to_domain (result_p, domain_p);
}
static bool
qdata_is_divided_zero (DB_VALUE * dbval_p)
{
DB_TYPE type;
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_SHORT:
return db_get_short (dbval_p) == 0;
case DB_TYPE_INTEGER:
return db_get_int (dbval_p) == 0;
case DB_TYPE_BIGINT:
return db_get_bigint (dbval_p) == 0;
case DB_TYPE_FLOAT:
return fabs ((double) db_get_float (dbval_p)) <= DBL_EPSILON;
case DB_TYPE_DOUBLE:
return fabs (db_get_double (dbval_p)) <= DBL_EPSILON;
case DB_TYPE_MONETARY:
return db_get_monetary (dbval_p)->amount <= DBL_EPSILON;
case DB_TYPE_NUMERIC:
return numeric_db_value_is_zero (dbval_p);
default:
break;
}
return false;
}
static int
qdata_divide_short (short s1, short s2, DB_VALUE * result_p)
{
short stmp;
stmp = s1 / s2;
db_make_short (result_p, stmp);
return NO_ERROR;
}
static int
qdata_divide_int (int i1, int i2, DB_VALUE * result_p)
{
int itmp;
itmp = i1 / i2;
db_make_int (result_p, itmp);
return NO_ERROR;
}
static int
qdata_divide_bigint (DB_BIGINT bi1, DB_BIGINT bi2, DB_VALUE * result_p)
{
DB_BIGINT bitmp;
bitmp = bi1 / bi2;
db_make_bigint (result_p, bitmp);
return NO_ERROR;
}
static int
qdata_divide_float (float f1, float f2, DB_VALUE * result_p)
{
float ftmp;
ftmp = f1 / f2;
if (OR_CHECK_FLOAT_OVERFLOW (ftmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
db_make_float (result_p, ftmp);
return NO_ERROR;
}
static int
qdata_divide_double (double d1, double d2, DB_VALUE * result_p, bool is_check_overflow)
{
double dtmp;
dtmp = d1 / d2;
if (is_check_overflow && OR_CHECK_DOUBLE_OVERFLOW (dtmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
db_make_double (result_p, dtmp);
return NO_ERROR;
}
static int
qdata_divide_monetary (double d1, double d2, DB_CURRENCY currency, DB_VALUE * result_p, bool is_check_overflow)
{
double dtmp;
dtmp = d1 / d2;
if (is_check_overflow && OR_CHECK_DOUBLE_OVERFLOW (dtmp))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
db_make_monetary (result_p, currency, dtmp);
return NO_ERROR;
}
static int
qdata_divide_short_to_dbval (DB_VALUE * short_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
short s;
DB_TYPE type2;
DB_VALUE dbval_tmp;
s = db_get_short (short_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_divide_short (s, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_divide_int (s, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_divide_bigint (s, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_divide_float (s, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_divide_double (s, db_get_double (dbval_p), result_p, true);
case DB_TYPE_NUMERIC:
qdata_coerce_dbval_to_numeric (short_val_p, &dbval_tmp);
if (numeric_db_value_div (&dbval_tmp, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_MONETARY:
return qdata_divide_monetary (s, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p,
true);
default:
break;
}
return NO_ERROR;
}
static int
qdata_divide_int_to_dbval (DB_VALUE * int_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
int i;
DB_TYPE type2;
DB_VALUE dbval_tmp;
i = db_get_int (int_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_divide_int (i, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_divide_int (i, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_divide_bigint (i, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_divide_float ((float) i, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_divide_double (i, db_get_double (dbval_p), result_p, true);
case DB_TYPE_NUMERIC:
qdata_coerce_dbval_to_numeric (int_val_p, &dbval_tmp);
if (numeric_db_value_div (&dbval_tmp, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_MONETARY:
return qdata_divide_monetary (i, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p,
true);
default:
break;
}
return NO_ERROR;
}
static int
qdata_divide_bigint_to_dbval (DB_VALUE * bigint_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_BIGINT bi;
DB_TYPE type2;
DB_VALUE dbval_tmp;
bi = db_get_bigint (bigint_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_divide_bigint (bi, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_divide_bigint (bi, db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_divide_bigint (bi, db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_divide_float ((float) bi, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_divide_double ((double) bi, db_get_double (dbval_p), result_p, true);
case DB_TYPE_NUMERIC:
qdata_coerce_dbval_to_numeric (bigint_val_p, &dbval_tmp);
if (numeric_db_value_div (&dbval_tmp, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_MONETARY:
return qdata_divide_monetary ((double) bi, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type,
result_p, true);
default:
break;
}
return NO_ERROR;
}
static int
qdata_divide_float_to_dbval (DB_VALUE * float_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
float f;
DB_TYPE type2;
f = db_get_float (float_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_divide_float (f, db_get_short (dbval_p), result_p);
case DB_TYPE_INTEGER:
return qdata_divide_float (f, (float) db_get_int (dbval_p), result_p);
case DB_TYPE_BIGINT:
return qdata_divide_float (f, (float) db_get_bigint (dbval_p), result_p);
case DB_TYPE_FLOAT:
return qdata_divide_float (f, db_get_float (dbval_p), result_p);
case DB_TYPE_DOUBLE:
return qdata_divide_double (f, db_get_double (dbval_p), result_p, true);
case DB_TYPE_NUMERIC:
return qdata_divide_double (f, qdata_coerce_numeric_to_double (dbval_p), result_p, false);
case DB_TYPE_MONETARY:
return qdata_divide_monetary (f, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p,
true);
default:
break;
}
return NO_ERROR;
}
static int
qdata_divide_double_to_dbval (DB_VALUE * double_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
double d;
DB_TYPE type2;
d = db_get_double (double_val_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_divide_double (d, db_get_short (dbval_p), result_p, false);
case DB_TYPE_INTEGER:
return qdata_divide_double (d, db_get_int (dbval_p), result_p, false);
case DB_TYPE_BIGINT:
return qdata_divide_double (d, (double) db_get_bigint (dbval_p), result_p, false);
case DB_TYPE_FLOAT:
return qdata_divide_double (d, db_get_float (dbval_p), result_p, true);
case DB_TYPE_DOUBLE:
return qdata_divide_double (d, db_get_double (dbval_p), result_p, true);
case DB_TYPE_NUMERIC:
return qdata_divide_double (d, qdata_coerce_numeric_to_double (dbval_p), result_p, false);
case DB_TYPE_MONETARY:
return qdata_divide_monetary (d, (db_get_monetary (dbval_p))->amount, (db_get_monetary (dbval_p))->type, result_p,
true);
default:
break;
}
return NO_ERROR;
}
static int
qdata_divide_numeric_to_dbval (DB_VALUE * numeric_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
DB_TYPE type2;
DB_VALUE dbval_tmp;
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
qdata_coerce_dbval_to_numeric (dbval_p, &dbval_tmp);
if (numeric_db_value_div (numeric_val_p, &dbval_tmp, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_NUMERIC:
if (numeric_db_value_div (numeric_val_p, dbval_p, result_p) != NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_DIVISION, 0);
return ER_FAILED;
}
break;
case DB_TYPE_FLOAT:
return qdata_divide_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_float (dbval_p), result_p,
false);
case DB_TYPE_DOUBLE:
return qdata_divide_double (qdata_coerce_numeric_to_double (numeric_val_p), db_get_double (dbval_p), result_p,
true);
case DB_TYPE_MONETARY:
return qdata_divide_monetary (qdata_coerce_numeric_to_double (numeric_val_p), (db_get_monetary (dbval_p))->amount,
(db_get_monetary (dbval_p))->type, result_p, true);
default:
break;
}
return NO_ERROR;
}
static int
qdata_divide_monetary_to_dbval (DB_VALUE * monetary_val_p, DB_VALUE * dbval_p, DB_VALUE * result_p)
{
double d;
DB_CURRENCY currency;
DB_TYPE type2;
d = (db_get_monetary (monetary_val_p))->amount;
currency = (db_get_monetary (monetary_val_p))->type;
type2 = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type2)
{
case DB_TYPE_SHORT:
return qdata_divide_monetary (d, db_get_short (dbval_p), currency, result_p, false);
case DB_TYPE_INTEGER:
return qdata_divide_monetary (d, db_get_int (dbval_p), currency, result_p, false);
case DB_TYPE_BIGINT:
return qdata_divide_monetary (d, (double) db_get_bigint (dbval_p), currency, result_p, false);
case DB_TYPE_FLOAT:
return qdata_divide_monetary (d, db_get_float (dbval_p), currency, result_p, true);
case DB_TYPE_DOUBLE:
return qdata_divide_monetary (d, db_get_double (dbval_p), currency, result_p, true);
case DB_TYPE_NUMERIC:
return qdata_divide_monetary (d, qdata_coerce_numeric_to_double (dbval_p), currency, result_p, true);
case DB_TYPE_MONETARY:
/* Note: we probably should return an error if the two monetaries have different montetary types. */
return qdata_divide_monetary (d, (db_get_monetary (dbval_p))->amount, currency, result_p, true);
default:
break;
}
return NO_ERROR;
}
/*
* qdata_divide_dbval () -
* return: NO_ERROR, or ER_code
* dbval1(in) : First db_value node
* dbval2(in) : Second db_value node
* res(out) : Resultant db_value node
* domain(in) :
*
* Note: Divide dbval1 by dbval2
* Overflow checks are only done when the right operand may be
* smaller than one. That is,
* short / integer -> overflow is not checked. Result will
* always be smaller than the numerand.
* float / short -> overflow is not checked. Minimum float
* representation (e-38) overflows to zero
* which we want.
* Because of zero divide checks, most of the others will not
* overflow but is still being checked in case we are on a
* platform where DBL_EPSILON approaches the value of FLT_MIN.
*/
int
qdata_divide_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type1;
DB_TYPE type2;
int error = NO_ERROR;
DB_VALUE cast_value1;
DB_VALUE cast_value2;
TP_DOMAIN *cast_dom1 = NULL;
TP_DOMAIN *cast_dom2 = NULL;
TP_DOMAIN_STATUS dom_status;
/* it should not be static because the parameter could be changed without broker restart */
bool oracle_compat_number = prm_get_bool_value (PRM_ID_ORACLE_COMPAT_NUMBER_BEHAVIOR);
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
db_make_null (&cast_value1);
db_make_null (&cast_value2);
/* number / string : cast string to DOUBLE, divide as number / DOUBLE */
if (TP_IS_NUMERIC_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast arg2 to double */
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* string / number: cast string to DOUBLE, divide as DOUBLE / number */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_NUMERIC_TYPE (type2))
{
/* cast arg1 to double */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
/* string / string: cast both to DOUBLE, divide as DOUBLE / DOUBLE */
else if (TP_IS_CHAR_TYPE (type1) && TP_IS_CHAR_TYPE (type2))
{
/* cast number to DOUBLE */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
cast_dom2 = tp_domain_resolve_default (DB_TYPE_DOUBLE);
}
else if (oracle_compat_number)
{
if (TP_IS_DISCRETE_NUMBER_TYPE (type1) && TP_IS_DISCRETE_NUMBER_TYPE (type2))
{
/* cast number to NUMERIC */
cast_dom1 = tp_domain_resolve_default (DB_TYPE_NUMERIC);
cast_dom2 = tp_domain_resolve_default (DB_TYPE_NUMERIC);
}
}
if (cast_dom2 != NULL)
{
dom_status = tp_value_auto_cast (dbval2_p, &cast_value2, cast_dom2);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval2_p, cast_dom2);
return error;
}
dbval2_p = &cast_value2;
}
if (cast_dom1 != NULL)
{
dom_status = tp_value_auto_cast (dbval1_p, &cast_value1, cast_dom1);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval1_p, cast_dom1);
return error;
}
dbval1_p = &cast_value1;
}
type1 = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type2 = DB_VALUE_DOMAIN_TYPE (dbval2_p);
if (DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
if (qdata_is_divided_zero (dbval2_p))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_ZERO_DIVIDE, 0);
return ER_FAILED;
}
switch (type1)
{
case DB_TYPE_SHORT:
error = qdata_divide_short_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_INTEGER:
error = qdata_divide_int_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_BIGINT:
error = qdata_divide_bigint_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_FLOAT:
error = qdata_divide_float_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DOUBLE:
error = qdata_divide_double_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_NUMERIC:
error = qdata_divide_numeric_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_MONETARY:
error = qdata_divide_monetary_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
case DB_TYPE_TIME:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_DATETIMETZ:
case DB_TYPE_DATE:
case DB_TYPE_STRING:
default:
if (prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS) == false)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (error != NO_ERROR)
{
return error;
}
return qdata_coerce_result_to_domain (result_p, domain_p);
}
/*
* qdata_unary_minus_dbval () -
* return: NO_ERROR, or ER_code
* res(out) : Resultant db_value node
* dbval1(in) : First db_value node
*
* Note: Take unary minus of db_value.
*/
int
qdata_unary_minus_dbval (DB_VALUE * result_p, DB_VALUE * dbval_p)
{
DB_TYPE res_type;
short stmp;
int itmp;
DB_BIGINT bitmp;
double dtmp;
DB_VALUE cast_value;
int er_status = NO_ERROR;
res_type = DB_VALUE_DOMAIN_TYPE (dbval_p);
if (res_type == DB_TYPE_NULL || DB_IS_NULL (dbval_p))
{
return NO_ERROR;
}
switch (res_type)
{
case DB_TYPE_INTEGER:
itmp = db_get_int (dbval_p);
if (itmp == INT_MIN)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_UMINUS, 0);
return ER_QPROC_OVERFLOW_UMINUS;
}
db_make_int (result_p, (-1) * itmp);
break;
case DB_TYPE_BIGINT:
bitmp = db_get_bigint (dbval_p);
if (bitmp == DB_BIGINT_MIN)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_UMINUS, 0);
return ER_QPROC_OVERFLOW_UMINUS;
}
db_make_bigint (result_p, (-1) * bitmp);
break;
case DB_TYPE_FLOAT:
db_make_float (result_p, (-1) * db_get_float (dbval_p));
break;
case DB_TYPE_CHAR:
case DB_TYPE_VARCHAR:
er_status = tp_value_str_auto_cast_to_number (dbval_p, &cast_value, &res_type);
if (er_status != NO_ERROR
|| (prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS) == true && res_type != DB_TYPE_DOUBLE))
{
return er_status;
}
assert (res_type == DB_TYPE_DOUBLE);
dbval_p = &cast_value;
[[fallthrough]];
case DB_TYPE_DOUBLE:
db_make_double (result_p, (-1) * db_get_double (dbval_p));
break;
case DB_TYPE_NUMERIC:
db_make_numeric (result_p, db_get_numeric (dbval_p), DB_VALUE_PRECISION (dbval_p), DB_VALUE_SCALE (dbval_p));
if (numeric_db_value_negate (result_p) != NO_ERROR)
{
return ER_FAILED;
}
break;
case DB_TYPE_MONETARY:
dtmp = (-1) * (db_get_monetary (dbval_p))->amount;
db_make_monetary (result_p, (db_get_monetary (dbval_p))->type, dtmp);
break;
case DB_TYPE_SHORT:
stmp = db_get_short (dbval_p);
if (stmp == SHRT_MIN)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_UMINUS, 0);
return ER_QPROC_OVERFLOW_UMINUS;
}
db_make_short (result_p, (-1) * stmp);
break;
default:
if (prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS) == false)
{
er_status = ER_QPROC_INVALID_DATATYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, er_status, 0);
}
break;
}
return er_status;
}
/*
* qdata_extract_dbval () -
* return: NO_ERROR, or ER_code
* extr_operand(in) : Specifies datetime field to be extracted
* dbval(in) : Extract source db_value node
* res(out) : Resultant db_value node
* domain(in) :
*
* Note: Extract a datetime field from db_value.
*/
int
qdata_extract_dbval (const MISC_OPERAND extr_operand, DB_VALUE * dbval_p, DB_VALUE * result_p, tp_domain * domain_p)
{
if (db_string_extract_dbval (extr_operand, dbval_p, result_p, domain_p) != NO_ERROR)
{
return ER_FAILED;
}
return NO_ERROR;
}
/*
* qdata_strcat_dbval () -
* return:
* dbval1(in) :
* dbval2(in) :
* res(in) :
* domain(in) :
*/
int
qdata_strcat_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type1, type2;
int error = NO_ERROR;
DB_VALUE cast_value1;
DB_VALUE cast_value2;
TP_DOMAIN *cast_dom1 = NULL;
TP_DOMAIN *cast_dom2 = NULL;
TP_DOMAIN_STATUS dom_status;
if (domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL)
{
return NO_ERROR;
}
type1 = dbval1_p ? DB_VALUE_DOMAIN_TYPE (dbval1_p) : DB_TYPE_NULL;
type2 = dbval2_p ? DB_VALUE_DOMAIN_TYPE (dbval2_p) : DB_TYPE_NULL;
/* string STRCAT date: cast date to string, concat as strings */
/* string STRCAT number: cast number to string, concat as strings */
if (TP_IS_CHAR_TYPE (type1) && (TP_IS_DATE_OR_TIME_TYPE (type2) || TP_IS_NUMERIC_TYPE (type2)))
{
cast_dom2 = tp_domain_resolve_value (dbval1_p, NULL);
}
else if ((TP_IS_DATE_OR_TIME_TYPE (type1) || TP_IS_NUMERIC_TYPE (type1)) && TP_IS_CHAR_TYPE (type2))
{
cast_dom1 = tp_domain_resolve_value (dbval2_p, NULL);
}
db_make_null (&cast_value1);
db_make_null (&cast_value2);
if (cast_dom1 != NULL)
{
dom_status = tp_value_auto_cast (dbval1_p, &cast_value1, cast_dom1);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval1_p, cast_dom1);
pr_clear_value (&cast_value1);
pr_clear_value (&cast_value2);
return error;
}
dbval1_p = &cast_value1;
}
if (cast_dom2 != NULL)
{
dom_status = tp_value_auto_cast (dbval2_p, &cast_value2, cast_dom2);
if (dom_status != DOMAIN_COMPATIBLE)
{
error = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, dbval2_p, cast_dom2);
pr_clear_value (&cast_value1);
pr_clear_value (&cast_value2);
return error;
}
dbval2_p = &cast_value2;
}
type1 = dbval1_p ? DB_VALUE_DOMAIN_TYPE (dbval1_p) : DB_TYPE_NULL;
type2 = dbval2_p ? DB_VALUE_DOMAIN_TYPE (dbval2_p) : DB_TYPE_NULL;
if (DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
/* ORACLE7 ServerSQL Language Reference Manual 3-4; Although ORACLE treats zero-length character strings as
* nulls, concatenating a zero-length character string with another operand always results in the other operand,
* rather than a null. However, this may not continue to be true in future versions of ORACLE. To concatenate an
* expression that might be null, use the NVL function to explicitly convert the expression to a zero-length
* string. */
if (!prm_get_bool_value (PRM_ID_ORACLE_STYLE_EMPTY_STRING))
{
return NO_ERROR;
}
if ((DB_IS_NULL (dbval1_p) && QSTR_IS_ANY_CHAR_OR_BIT (type2))
|| (DB_IS_NULL (dbval2_p) && QSTR_IS_ANY_CHAR_OR_BIT (type1)))
{
; /* go ahead */
}
else
{
return NO_ERROR;
}
}
switch (type1)
{
case DB_TYPE_SHORT:
error = qdata_add_short_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_INTEGER:
error = qdata_add_int_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_BIGINT:
error = qdata_add_bigint_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_FLOAT:
error = qdata_add_float_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DOUBLE:
error = qdata_add_double_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_NUMERIC:
error = qdata_add_numeric_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_MONETARY:
error = qdata_add_monetary_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_NULL:
case DB_TYPE_CHAR:
case DB_TYPE_VARCHAR:
case DB_TYPE_BIT:
case DB_TYPE_VARBIT:
if (dbval1_p != NULL && dbval2_p != NULL)
{
error = qdata_add_chars_to_dbval (dbval1_p, dbval2_p, result_p);
}
break;
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
if (!TP_IS_SET_TYPE (type2))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
error = qdata_add_sequence_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
case DB_TYPE_TIME:
error = qdata_add_time_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
error = qdata_add_utime_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
if (error == NO_ERROR && type1 == DB_TYPE_TIMESTAMPLTZ)
{
db_make_timestampltz (result_p, *db_get_timestamp (result_p));
}
break;
case DB_TYPE_TIMESTAMPTZ:
error = qdata_add_timestamptz_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
error = qdata_add_datetime_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
if (error != NO_ERROR && type1 == DB_TYPE_DATETIMELTZ)
{
db_make_datetimeltz (result_p, db_get_datetime (result_p));
}
break;
case DB_TYPE_DATETIMETZ:
error = qdata_add_datetimetz_to_dbval (dbval1_p, dbval2_p, result_p);
break;
case DB_TYPE_DATE:
error = qdata_add_date_to_dbval (dbval1_p, dbval2_p, result_p, domain_p);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
error = ER_FAILED;
break;
}
if (error != NO_ERROR)
{
return error;
}
if (cast_dom1)
{
pr_clear_value (&cast_value1);
}
if (cast_dom2)
{
pr_clear_value (&cast_value2);
}
return qdata_coerce_result_to_domain (result_p, domain_p);
}
/*
* MISCELLANEOUS
*/
/*
* qdata_get_tuple_value_size_from_dbval () - Return the tuple value size
* for the db_value
* return: tuple_value_size or ER_FAILED
* dbval(in) : db_value node
*/
int
qdata_get_tuple_value_size_from_dbval (DB_VALUE * dbval_p)
{
int val_size, align;
int tuple_value_size = 0;
const PR_TYPE *type_p;
DB_TYPE dbval_type;
if (DB_IS_NULL (dbval_p))
{
tuple_value_size = QFILE_TUPLE_VALUE_HEADER_SIZE;
}
else
{
dbval_type = DB_VALUE_DOMAIN_TYPE (dbval_p);
type_p = pr_type_from_id (dbval_type);
if (type_p)
{
val_size = type_p->get_disk_size_of_value (dbval_p);
#if !defined(NDEBUG)
if (type_p->is_size_computed ())
{
if (pr_is_string_type (dbval_type))
{
int precision = DB_VALUE_PRECISION (dbval_p);
int string_length = db_get_string_length (dbval_p);
if (precision == TP_FLOATING_PRECISION_VALUE)
{
precision = DB_MAX_STRING_LENGTH;
}
assert (string_length <= precision);
if (val_size < 0)
{
return ER_FAILED;
}
else if (string_length > precision)
{
/* The size of db_value is greater than it's precision. This case is abnormal (assertion
* failure). Code below is remained for backward compatibility. */
if (db_string_truncate (dbval_p, precision) != NO_ERROR)
{
return ER_FAILED;
}
er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_DATA_IS_TRUNCATED_TO_PRECISION, 2, precision,
string_length);
val_size = type_p->get_disk_size_of_value (dbval_p);
}
}
}
#endif
align = DB_ALIGN (val_size, MAX_ALIGNMENT); /* to align for the next field */
tuple_value_size = QFILE_TUPLE_VALUE_HEADER_SIZE + align;
}
}
return tuple_value_size;
}
/*
* qdata_get_single_tuple_from_list_id () -
* return: NO_ERROR or error code
* list_id(in) : List file identifier
* single_tuple(in) : VAL_LIST
*/
int
qdata_get_single_tuple_from_list_id (THREAD_ENTRY * thread_p, qfile_list_id * list_id_p, val_list_node * single_tuple_p)
{
QFILE_TUPLE_RECORD tuple_record = { NULL, 0 };
QFILE_LIST_SCAN_ID scan_id;
OR_BUF buf;
const PR_TYPE *pr_type_p;
QFILE_TUPLE_VALUE_FLAG flag;
int length;
TP_DOMAIN *domain_p;
char *ptr;
INT64 tuple_count;
int value_count, i;
QPROC_DB_VALUE_LIST value_list;
int error_code;
tuple_count = list_id_p->tuple_cnt;
value_count = list_id_p->type_list.type_cnt;
/* value_count can be greater than single_tuple_p->val_cnt when the subquery has a hidden column. Under normal
* situation, those are same. */
if (tuple_count > 1 || value_count < single_tuple_p->val_cnt)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_QRY_SINGLE_TUPLE, 0);
return ER_QPROC_INVALID_QRY_SINGLE_TUPLE;
}
if (tuple_count == 1)
{
error_code = qfile_open_list_scan (list_id_p, &scan_id);
if (error_code != NO_ERROR)
{
return error_code;
}
if (qfile_scan_list_next (thread_p, &scan_id, &tuple_record, PEEK) != S_SUCCESS)
{
qfile_close_scan (thread_p, &scan_id);
return ER_FAILED;
}
for (i = 0, value_list = single_tuple_p->valp; i < single_tuple_p->val_cnt; i++, value_list = value_list->next)
{
domain_p = list_id_p->type_list.domp[i];
if (domain_p == NULL || domain_p->type == NULL)
{
qfile_close_scan (thread_p, &scan_id);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_QRY_SINGLE_TUPLE, 0);
return ER_QPROC_INVALID_QRY_SINGLE_TUPLE;
}
if (db_value_domain_init (value_list->val, TP_DOMAIN_TYPE (domain_p), domain_p->precision, domain_p->scale) !=
NO_ERROR)
{
qfile_close_scan (thread_p, &scan_id);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_QRY_SINGLE_TUPLE, 0);
return ER_QPROC_INVALID_QRY_SINGLE_TUPLE;
}
pr_type_p = domain_p->type;
if (pr_type_p == NULL)
{
qfile_close_scan (thread_p, &scan_id);
return ER_FAILED;
}
flag = (QFILE_TUPLE_VALUE_FLAG) qfile_locate_tuple_value (tuple_record.tpl, i, &ptr, &length);
or_init (&buf, ptr, length);
if (flag == V_BOUND)
{
if (pr_type_p->data_readval (&buf, value_list->val, domain_p, -1, true, NULL, 0) != NO_ERROR)
{
qfile_close_scan (thread_p, &scan_id);
return ER_FAILED;
}
}
else
{
/* If value is NULL, properly initialize the result */
db_value_domain_init (value_list->val, pr_type_p->id, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
}
}
qfile_close_scan (thread_p, &scan_id);
}
return NO_ERROR;
}
/*
* qdata_get_valptr_type_list () -
* return: NO_ERROR, or ER_code
* valptr_list(in) : Value pointer list
* type_list(out) : Set to the result type list
*
* Note: Find the result type list of value pointer list and set to
* type list. Regu variables that are hidden columns are not
* entered as part of the type list because they are not entered
* in the list file.
*/
int
qdata_get_valptr_type_list (THREAD_ENTRY * thread_p, valptr_list_node * valptr_list_p,
qfile_tuple_value_type_list * type_list_p)
{
REGU_VARIABLE_LIST reg_var_p;
int i, count;
if (type_list_p == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 1);
return ER_FAILED;
}
reg_var_p = valptr_list_p->valptrp;
count = 0;
for (i = 0; i < valptr_list_p->valptr_cnt; i++)
{
if (!REGU_VARIABLE_IS_FLAGED (®_var_p->value, REGU_VARIABLE_HIDDEN_COLUMN))
{
count++;
}
reg_var_p = reg_var_p->next;
}
type_list_p->type_cnt = count;
type_list_p->domp = NULL;
if (type_list_p->type_cnt != 0)
{
type_list_p->domp = (TP_DOMAIN **) db_private_alloc (thread_p, sizeof (TP_DOMAIN *) * type_list_p->type_cnt);
if (type_list_p->domp == NULL)
{
return ER_FAILED;
}
}
reg_var_p = valptr_list_p->valptrp;
for (i = 0; i < type_list_p->type_cnt;)
{
if (!REGU_VARIABLE_IS_FLAGED (®_var_p->value, REGU_VARIABLE_HIDDEN_COLUMN))
{
type_list_p->domp[i++] = reg_var_p->value.domain;
}
reg_var_p = reg_var_p->next;
}
return NO_ERROR;
}
int
qdata_get_val_list_type_list (THREAD_ENTRY * thread_p, VAL_LIST * val_list, qfile_tuple_value_type_list * type_list_p)
{
QPROC_DB_VALUE_LIST val_list_iterator;
int val_list_index;
if (type_list_p == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 1);
assert (false);
return ER_FAILED;
}
type_list_p->type_cnt = val_list->val_cnt;
if (type_list_p->type_cnt == 0)
{
type_list_p->domp = NULL;
return NO_ERROR;
}
type_list_p->domp = (TP_DOMAIN **) malloc (sizeof (TP_DOMAIN *) * type_list_p->type_cnt);
if (type_list_p->domp == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
sizeof (TP_DOMAIN *) * type_list_p->type_cnt);
return ER_FAILED;
}
for (val_list_iterator = val_list->valp, val_list_index = 0; val_list_iterator != NULL;
val_list_iterator = val_list_iterator->next, val_list_index++)
{
type_list_p->domp[val_list_index] = val_list_iterator->dom;
}
return NO_ERROR;
}
/*
* qdata_get_dbval_from_constant_regu_variable () -
* return: DB_VALUE *, or NULL
* regu_var(in): Regulator Variable
* vd(in) : Value descriptor
*
* Note: Find the db_value represented by regu_var node and
* return a pointer to it.
*
* Note: Regulator variable should point to only constant values.
*/
static DB_VALUE *
qdata_get_dbval_from_constant_regu_variable (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var_p,
VAL_DESCR * val_desc_p)
{
DB_VALUE *peek_value_p;
DB_TYPE dom_type, val_type;
TP_DOMAIN_STATUS dom_status;
int result;
HL_HEAPID save_heapid = 0;
assert (regu_var_p != NULL);
assert (regu_var_p->domain != NULL);
if (REGU_VARIABLE_IS_FLAGED (regu_var_p, REGU_VARIABLE_UPD_INS_LIST))
{
REGU_VARIABLE_SET_FLAG (regu_var_p, REGU_VARIABLE_STRICT_TYPE_CAST);
}
result = fetch_peek_dbval (thread_p, regu_var_p, val_desc_p, NULL, NULL, NULL, &peek_value_p);
if (result != NO_ERROR)
{
return NULL;
}
if (!DB_IS_NULL (peek_value_p))
{
val_type = DB_VALUE_TYPE (peek_value_p);
assert (val_type != DB_TYPE_NULL);
dom_type = TP_DOMAIN_TYPE (regu_var_p->domain);
if (dom_type != DB_TYPE_NULL)
{
assert (dom_type != DB_TYPE_NULL);
if (val_type == DB_TYPE_OID)
{
assert ((dom_type == DB_TYPE_OID) || (dom_type == DB_TYPE_VOBJ));
}
else if (val_type != dom_type
|| (val_type == DB_TYPE_NUMERIC
&& (peek_value_p->domain.numeric_info.precision != regu_var_p->domain->precision
|| peek_value_p->domain.numeric_info.scale != regu_var_p->domain->scale)))
{
if (REGU_VARIABLE_IS_FLAGED (regu_var_p, REGU_VARIABLE_ANALYTIC_WINDOW))
{
/* do not cast at here, is handled at analytic function evaluation later */
;
}
else
{
if (REGU_VARIABLE_IS_FLAGED (regu_var_p, REGU_VARIABLE_CLEAR_AT_CLONE_DECACHE))
{
save_heapid = db_change_private_heap (thread_p, 0);
}
dom_status = tp_value_auto_cast (peek_value_p, peek_value_p, regu_var_p->domain);
if (save_heapid != 0)
{
(void) db_change_private_heap (thread_p, save_heapid);
save_heapid = 0;
}
if (dom_status != DOMAIN_COMPATIBLE)
{
result = tp_domain_status_er_set (dom_status, ARG_FILE_LINE, peek_value_p, regu_var_p->domain);
return NULL;
}
assert (dom_type == DB_VALUE_TYPE (peek_value_p)
|| (prm_get_bool_value (PRM_ID_RETURN_NULL_ON_FUNCTION_ERRORS) && DB_IS_NULL (peek_value_p)));
}
}
}
}
return peek_value_p;
}
/*
* qdata_convert_dbvals_to_set () -
* return: NO_ERROR, or ER_code
* stype(in) : set type
* func(in) : regu variable (guaranteed TYPE_FUNC)
* vd(in) : Value descriptor
* obj_oid(in): object identifier
* tpl(in) : list file tuple
*
* Note: Convert a list of vars into a sequence and return a pointer to it.
*/
static int
qdata_convert_dbvals_to_set (THREAD_ENTRY * thread_p, DB_TYPE stype, REGU_VARIABLE * regu_func_p,
VAL_DESCR * val_desc_p, OID * obj_oid_p, QFILE_TUPLE tuple)
{
DB_VALUE dbval, *result_p = NULL;
DB_COLLECTION *collection_p = NULL;
SETOBJ *setobj_p = NULL;
int n, size;
REGU_VARIABLE_LIST regu_var_p = NULL, operand = NULL;
int error_code = NO_ERROR;
TP_DOMAIN *domain_p = NULL;
result_p = regu_func_p->value.funcp->value;
operand = regu_func_p->value.funcp->operand;
domain_p = regu_func_p->domain;
db_make_null (&dbval);
if (stype == DB_TYPE_SET)
{
collection_p = db_set_create_basic (NULL, NULL);
}
else if (stype == DB_TYPE_MULTISET)
{
collection_p = db_set_create_multi (NULL, NULL);
}
else if (stype == DB_TYPE_SEQUENCE || stype == DB_TYPE_VOBJ)
{
size = 0;
for (regu_var_p = operand; regu_var_p; regu_var_p = regu_var_p->next)
{
size++;
}
collection_p = db_seq_create (NULL, NULL, size);
}
else
{
return ER_FAILED;
}
error_code = set_get_setobj (collection_p, &setobj_p, 1);
if (error_code != NO_ERROR || !setobj_p)
{
goto error;
}
/*
* DON'T set the "set"'s domain if it's really a vobj; they don't
* play by quite the same rules. The domain coming in here is some
* flavor of vobj domain, which is definitely *not* what the
* components of the sequence will be. Putting the domain in here
* evidently causes the vobj's to get packed up in list files in some
* way that readers can't cope with.
*/
if (stype != DB_TYPE_VOBJ)
{
setobj_put_domain (setobj_p, domain_p);
}
n = 0;
while (operand)
{
if (fetch_copy_dbval (thread_p, &operand->value, val_desc_p, NULL, obj_oid_p, tuple, &dbval) != NO_ERROR)
{
goto error;
}
if ((stype == DB_TYPE_VOBJ) && (n == 2))
{
if (DB_IS_NULL (&dbval))
{
set_free (collection_p);
return NO_ERROR;
}
}
/* using setobj_put_value transfers "ownership" of the db_value memory to the set. This avoids a redundant
* clone/free. */
error_code = setobj_put_value (setobj_p, n, &dbval);
/*
* if we attempt to add a duplicate value to a set,
* clear the value, but do not set an error code
*/
if (error_code == SET_DUPLICATE_VALUE)
{
pr_clear_value (&dbval);
error_code = NO_ERROR;
}
if (error_code != NO_ERROR)
{
goto error;
}
operand = operand->next;
n++;
}
set_make_collection (result_p, collection_p);
if (stype == DB_TYPE_VOBJ)
{
db_value_alter_type (result_p, DB_TYPE_VOBJ);
}
return NO_ERROR;
error:
pr_clear_value (&dbval);
if (collection_p != NULL)
{
set_free (collection_p);
}
return ((error_code == NO_ERROR) ? ER_FAILED : error_code);
}
/*
* qdata_evaluate_generic_function () - Evaluates a generic function.
* return: NO_ERROR, or ER_code
* funcp(in) :
* vd(in) :
* obj_oid(in) :
* tpl(in) :
*/
static int
qdata_evaluate_generic_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_GENERIC_FUNCTION_FAILURE, 0);
return ER_FAILED;
}
/*
* qdata_get_class_of_function () -
* return: NO_ERROR, or ER_code
* funcp(in) :
* vd(in) :
* obj_oid(in) :
* tpl(in) :
*
* Note: This routine returns the class of its argument.
*/
static int
qdata_get_class_of_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple)
{
OID class_oid;
OID *instance_oid_p;
DB_VALUE *val_p, element;
DB_TYPE type;
int err;
if (fetch_peek_dbval (thread_p, &function_p->operand->value, val_desc_p, NULL, obj_oid_p, tuple, &val_p) != NO_ERROR)
{
return ER_FAILED;
}
if (DB_IS_NULL (val_p))
{
db_make_null (function_p->value);
return NO_ERROR;
}
type = DB_VALUE_DOMAIN_TYPE (val_p);
if (type == DB_TYPE_VOBJ)
{
/* grab the real oid */
if (db_seq_get (db_get_set (val_p), 2, &element) != NO_ERROR)
{
return ER_FAILED;
}
val_p = &element;
type = DB_VALUE_DOMAIN_TYPE (val_p);
}
if (type != DB_TYPE_OID)
{
return ER_FAILED;
}
instance_oid_p = db_get_oid (val_p);
err = heap_get_class_oid (thread_p, instance_oid_p, &class_oid);
if (err != S_SUCCESS)
{
ASSERT_ERROR_AND_SET (err);
return err;
}
db_make_oid (function_p->value, &class_oid);
return NO_ERROR;
}
/*
* qdata_evaluate_function () -
* return: NO_ERROR, or ER_code
* func(in) :
* vd(in) :
* obj_oid(in) :
* tpl(in) :
*
* Note: Evaluate given function.
*/
int
qdata_evaluate_function (THREAD_ENTRY * thread_p, regu_variable_node * function_p, val_descr * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple)
{
FUNCTION_TYPE *funcp;
/* should sync with fetch_peek_dbval () */
funcp = function_p->value.funcp;
/* clear any value from a previous iteration */
pr_clear_value (funcp->value);
switch (funcp->ftype)
{
case F_SET:
return qdata_convert_dbvals_to_set (thread_p, DB_TYPE_SET, function_p, val_desc_p, obj_oid_p, tuple);
case F_MULTISET:
return qdata_convert_dbvals_to_set (thread_p, DB_TYPE_MULTISET, function_p, val_desc_p, obj_oid_p, tuple);
case F_SEQUENCE:
return qdata_convert_dbvals_to_set (thread_p, DB_TYPE_SEQUENCE, function_p, val_desc_p, obj_oid_p, tuple);
case F_VID:
return qdata_convert_dbvals_to_set (thread_p, DB_TYPE_VOBJ, function_p, val_desc_p, obj_oid_p, tuple);
case F_TABLE_SET:
return qdata_convert_table_to_set (thread_p, DB_TYPE_SET, function_p, val_desc_p);
case F_TABLE_MULTISET:
return qdata_convert_table_to_set (thread_p, DB_TYPE_MULTISET, function_p, val_desc_p);
case F_TABLE_SEQUENCE:
return qdata_convert_table_to_set (thread_p, DB_TYPE_SEQUENCE, function_p, val_desc_p);
case F_GENERIC:
return qdata_evaluate_generic_function (thread_p, funcp, val_desc_p, obj_oid_p, tuple);
case F_CLASS_OF:
return qdata_get_class_of_function (thread_p, funcp, val_desc_p, obj_oid_p, tuple);
case F_INSERT_SUBSTRING:
return qdata_insert_substring_function (thread_p, funcp, val_desc_p, obj_oid_p, tuple);
case F_ELT:
return qdata_elt (thread_p, funcp, val_desc_p, obj_oid_p, tuple);
case F_BENCHMARK:
return qdata_benchmark (thread_p, funcp, val_desc_p, obj_oid_p, tuple);
case F_JSON_ARRAY:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_array);
case F_JSON_ARRAY_APPEND:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_array_append);
case F_JSON_ARRAY_INSERT:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_array_insert);
case F_JSON_CONTAINS:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_contains);
case F_JSON_CONTAINS_PATH:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_contains_path);
case F_JSON_DEPTH:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_depth);
case F_JSON_EXTRACT:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_extract);
case F_JSON_GET_ALL_PATHS:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_get_all_paths);
case F_JSON_INSERT:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_insert);
case F_JSON_KEYS:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_keys);
case F_JSON_LENGTH:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_length);
case F_JSON_MERGE:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_merge_preserve);
case F_JSON_MERGE_PATCH:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_merge_patch);
case F_JSON_OBJECT:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_object);
case F_JSON_PRETTY:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_pretty);
case F_JSON_QUOTE:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_quote);
case F_JSON_REMOVE:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_remove);
case F_JSON_REPLACE:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_replace);
case F_JSON_SEARCH:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_search);
case F_JSON_SET:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_set);
case F_JSON_TYPE:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_type_dbval);
case F_JSON_UNQUOTE:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_unquote);
case F_JSON_VALID:
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_valid);
case F_REGEXP_COUNT:
case F_REGEXP_INSTR:
case F_REGEXP_LIKE:
case F_REGEXP_REPLACE:
case F_REGEXP_SUBSTR:
return qdata_regexp_function (thread_p, funcp, val_desc_p, obj_oid_p, tuple);
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_XASLNODE, 0);
return ER_FAILED;
}
}
/*
* qdata_convert_table_to_set () -
* return: NO_ERROR, or ER_code
* stype(in) : set type
* func(in) : regu variable (guaranteed TYPE_FUNC)
* vd(in) : Value descriptor
*
* Note: Convert a list file into a set/sequence and return a pointer to it.
*/
static int
qdata_convert_table_to_set (THREAD_ENTRY * thread_p, DB_TYPE stype, REGU_VARIABLE * function_p, VAL_DESCR * val_desc_p)
{
QFILE_LIST_SCAN_ID scan_id;
QFILE_TUPLE_RECORD tuple_record = {
NULL, 0
};
SCAN_CODE scan_code;
QFILE_LIST_ID *list_id_p;
int i, seq_pos;
int val_size;
OR_BUF buf;
DB_VALUE dbval, *result_p;
DB_COLLECTION *collection_p = NULL;
SETOBJ *setobj_p;
DB_TYPE type;
const PR_TYPE *pr_type_p;
int error;
REGU_VARIABLE_LIST operand;
TP_DOMAIN *domain_p;
char *ptr;
result_p = function_p->value.funcp->value;
operand = function_p->value.funcp->operand;
/* execute linked query */
EXECUTE_REGU_VARIABLE_XASL (thread_p, &(operand->value), val_desc_p);
if (CHECK_REGU_VARIABLE_XASL_STATUS (&(operand->value)) != XASL_SUCCESS)
{
return ER_FAILED;
}
domain_p = function_p->domain;
list_id_p = operand->value.value.srlist_id->list_id;
db_make_null (&dbval);
if (stype == DB_TYPE_SET)
{
collection_p = db_set_create_basic (NULL, NULL);
}
else if (stype == DB_TYPE_MULTISET)
{
collection_p = db_set_create_multi (NULL, NULL);
}
else if (stype == DB_TYPE_SEQUENCE || stype == DB_TYPE_VOBJ)
{
collection_p = db_seq_create (NULL, NULL, (list_id_p->tuple_cnt * list_id_p->type_list.type_cnt));
}
else
{
return ER_FAILED;
}
error = set_get_setobj (collection_p, &setobj_p, 1);
if (error != NO_ERROR || !setobj_p)
{
set_free (collection_p);
return ER_FAILED;
}
/*
* Don't need to worry about the vobj case here; this function can't
* be called in a context where it's expected to produce a vobj. See
* xd_dbvals_to_set for the contrasting case.
*/
setobj_put_domain (setobj_p, domain_p);
if (qfile_open_list_scan (list_id_p, &scan_id) != NO_ERROR)
{
return ER_FAILED;
}
seq_pos = 0;
while (true)
{
scan_code = qfile_scan_list_next (thread_p, &scan_id, &tuple_record, PEEK);
if (scan_code != S_SUCCESS)
{
break;
}
for (i = 0; i < list_id_p->type_list.type_cnt; i++)
{
/* grab column i and add it to the col */
type = TP_DOMAIN_TYPE (list_id_p->type_list.domp[i]);
pr_type_p = pr_type_from_id (type);
if (pr_type_p == NULL)
{
qfile_close_scan (thread_p, &scan_id);
return ER_FAILED;
}
if (qfile_locate_tuple_value (tuple_record.tpl, i, &ptr, &val_size) == V_BOUND)
{
or_init (&buf, ptr, val_size);
if (pr_type_p->data_readval (&buf, &dbval, list_id_p->type_list.domp[i], -1, true, NULL, 0) != NO_ERROR)
{
qfile_close_scan (thread_p, &scan_id);
return ER_FAILED;
}
}
/*
* using setobj_put_value transfers "ownership" of the
* db_value memory to the set. This avoids a redundant clone/free.
*/
error = setobj_put_value (setobj_p, seq_pos++, &dbval);
/*
* if we attempt to add a duplicate value to a set,
* clear the value, but do not set an error
*/
if (error == SET_DUPLICATE_VALUE)
{
pr_clear_value (&dbval);
error = NO_ERROR;
}
if (error != NO_ERROR)
{
set_free (collection_p);
pr_clear_value (&dbval);
qfile_close_scan (thread_p, &scan_id);
return ER_FAILED;
}
}
}
qfile_close_scan (thread_p, &scan_id);
set_make_collection (result_p, collection_p);
return NO_ERROR;
}
/*
* qdata_evaluate_connect_by_root () - CONNECT_BY_ROOT operator evaluation func
* return:
* xasl_p(in):
* regu_p(in):
* result_val_p(in/out):
* vd(in):
*/
bool
qdata_evaluate_connect_by_root (THREAD_ENTRY * thread_p, void *xasl_p, regu_variable_node * regu_p,
DB_VALUE * result_val_p, val_descr * vd)
{
QFILE_TUPLE tpl;
QFILE_LIST_ID *list_id_p;
QFILE_LIST_SCAN_ID s_id;
QFILE_TUPLE_RECORD tuple_rec = { (QFILE_TUPLE) NULL, 0 };
const QFILE_TUPLE_POSITION *bitval = NULL;
QFILE_TUPLE_POSITION p_pos;
QPROC_DB_VALUE_LIST valp;
DB_VALUE p_pos_dbval;
XASL_NODE *xasl, *xptr;
int length, i;
/* sanity checks */
if (regu_p->type != TYPE_CONSTANT)
{
return false;
}
xasl = (XASL_NODE *) xasl_p;
if (!xasl)
{
return false;
}
if (!XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
{
return false;
}
xptr = xasl->connect_by_ptr;
if (!xptr)
{
return false;
}
tpl = xptr->proc.connect_by.curr_tuple;
/* walk the parents up to root */
list_id_p = xptr->list_id;
if (qfile_open_list_scan (list_id_p, &s_id) != NO_ERROR)
{
return false;
}
/* we start with tpl itself */
tuple_rec.tpl = tpl;
do
{
/* get the parent node */
if (qexec_get_tuple_column_value (tuple_rec.tpl, xptr->outptr_list->valptr_cnt - PCOL_PARENTPOS_TUPLE_OFFSET,
&p_pos_dbval, &tp_Bit_domain) != NO_ERROR)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
bitval = REINTERPRET_CAST (const QFILE_TUPLE_POSITION *, db_get_bit (&p_pos_dbval, &length));
if (bitval)
{
p_pos.status = s_id.status;
p_pos.position = S_ON;
p_pos.vpid = bitval->vpid;
p_pos.offset = bitval->offset;
p_pos.tpl = NULL;
p_pos.tplno = bitval->tplno;
if (qfile_jump_scan_tuple_position (thread_p, &s_id, &p_pos, &tuple_rec, PEEK) != S_SUCCESS)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
}
}
while (bitval); /* the parent tuple pos is null for the root node */
/* here tuple_rec.tpl is the root tuple; get the required column */
for (i = 0, valp = xptr->val_list->valp; valp; i++, valp = valp->next)
{
if (valp->val == regu_p->value.dbvalptr)
{
break;
}
}
if (i < xptr->val_list->val_cnt)
{
if (qexec_get_tuple_column_value (tuple_rec.tpl, i, result_val_p, regu_p->domain) != NO_ERROR)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
}
else
{
/* TYPE_CONSTANT but not in val_list, check if it is inst_num() (orderby_num() is not allowed) */
if (regu_p->value.dbvalptr == xasl->instnum_val)
{
if (pr_clone_value (xasl->instnum_val, result_val_p) != NO_ERROR)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
}
else
{
qfile_close_scan (thread_p, &s_id);
return false;
}
}
qfile_close_scan (thread_p, &s_id);
return true;
}
/*
* qdata_evaluate_qprior () - PRIOR in SELECT list evaluation func
* return:
* xasl_p(in):
* regu_p(in):
* result_val_p(in/out):
* vd(in):
*/
bool
qdata_evaluate_qprior (THREAD_ENTRY * thread_p, void *xasl_p, regu_variable_node * regu_p, DB_VALUE * result_val_p,
val_descr * vd)
{
QFILE_TUPLE tpl;
QFILE_LIST_ID *list_id_p;
QFILE_LIST_SCAN_ID s_id;
QFILE_TUPLE_RECORD tuple_rec = { (QFILE_TUPLE) NULL, 0 };
const QFILE_TUPLE_POSITION *bitval = NULL;
QFILE_TUPLE_POSITION p_pos;
DB_VALUE p_pos_dbval;
XASL_NODE *xasl, *xptr;
int length;
xasl = (XASL_NODE *) xasl_p;
/* sanity checks */
if (!xasl)
{
return false;
}
if (!XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
{
return false;
}
xptr = xasl->connect_by_ptr;
if (!xptr)
{
return false;
}
tpl = xptr->proc.connect_by.curr_tuple;
list_id_p = xptr->list_id;
if (qfile_open_list_scan (list_id_p, &s_id) != NO_ERROR)
{
return false;
}
tuple_rec.tpl = tpl;
/* get the parent node */
if (qexec_get_tuple_column_value (tuple_rec.tpl, xptr->outptr_list->valptr_cnt - PCOL_PARENTPOS_TUPLE_OFFSET,
&p_pos_dbval, &tp_Bit_domain) != NO_ERROR)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
bitval = REINTERPRET_CAST (const QFILE_TUPLE_POSITION *, db_get_bit (&p_pos_dbval, &length));
if (bitval)
{
p_pos.status = s_id.status;
p_pos.position = S_ON;
p_pos.vpid = bitval->vpid;
p_pos.offset = bitval->offset;
p_pos.tpl = NULL;
p_pos.tplno = bitval->tplno;
if (qfile_jump_scan_tuple_position (thread_p, &s_id, &p_pos, &tuple_rec, PEEK) != S_SUCCESS)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
}
else
{
/* the parent tuple pos is null for the root node */
tuple_rec.tpl = NULL;
}
if (tuple_rec.tpl != NULL)
{
/* fetch val list from the parent tuple */
if (fetch_val_list (thread_p, xptr->proc.connect_by.prior_regu_list_pred, vd, NULL, NULL, tuple_rec.tpl, PEEK) !=
NO_ERROR)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
if (fetch_val_list (thread_p, xptr->proc.connect_by.prior_regu_list_rest, vd, NULL, NULL, tuple_rec.tpl, PEEK) !=
NO_ERROR)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
/* replace values in T_QPRIOR argument with values from parent tuple */
qexec_replace_prior_regu_vars_prior_expr (thread_p, regu_p, xptr, xptr);
/* evaluate the modified regu_p */
if (fetch_copy_dbval (thread_p, regu_p, vd, NULL, NULL, tuple_rec.tpl, result_val_p) != NO_ERROR)
{
qfile_close_scan (thread_p, &s_id);
return false;
}
}
else
{
db_make_null (result_val_p);
}
qfile_close_scan (thread_p, &s_id);
return true;
}
/*
* qdata_evaluate_sys_connect_by_path () - SYS_CONNECT_BY_PATH function
* evaluation func
* return:
* select_xasl(in):
* regu_p1(in): column
* regu_p2(in): character
* result_val_p(in/out):
*/
bool
qdata_evaluate_sys_connect_by_path (THREAD_ENTRY * thread_p, void *xasl_p, regu_variable_node * regu_p,
DB_VALUE * value_char, DB_VALUE * result_p, val_descr * vd)
{
QFILE_TUPLE tpl;
QFILE_LIST_ID *list_id_p;
QFILE_LIST_SCAN_ID s_id;
QFILE_TUPLE_RECORD tuple_rec = { (QFILE_TUPLE) NULL, 0 };
const QFILE_TUPLE_POSITION *bitval = NULL;
QFILE_TUPLE_POSITION p_pos;
QPROC_DB_VALUE_LIST valp;
DB_VALUE p_pos_dbval, cast_value, arg_dbval;
XASL_NODE *xasl, *xptr;
int length, i;
char *result_path = NULL, *path_tmp = NULL;
int len_result_path;
size_t len_tmp = 0, len;
char *sep = NULL;
DB_VALUE *arg_dbval_p = NULL;
DB_VALUE **save_values = NULL;
bool use_extended = false; /* flag for using extended form, accepting an expression as the first argument of
* SYS_CONNECT_BY_PATH() */
bool need_clear_arg_dbval = false;
assert (DB_IS_NULL (result_p));
/* sanity checks */
xasl = (XASL_NODE *) xasl_p;
if (!xasl)
{
return false;
}
if (!XASL_IS_FLAGED (xasl, XASL_HAS_CONNECT_BY))
{
return false;
}
xptr = xasl->connect_by_ptr;
if (!xptr)
{
return false;
}
tpl = xptr->proc.connect_by.curr_tuple;
/* column */
if (regu_p->type != TYPE_CONSTANT)
{
/* NOTE: if the column is non-string, a cast will be made (see T_CAST). This is specific to sys_connect_by_path
* because the result is always varchar (by comparison to connect_by_root which has the result of the root
* specifiec column). The cast is propagated from the parser tree into the regu variabile, which has the
* TYPE_INARITH type with arithptr with type T_CAST and right argument the real column, which will be further
* used for column retrieving in the xasl->val_list->valp. */
if (regu_p->type == TYPE_INARITH)
{
if (regu_p->value.arithptr && regu_p->value.arithptr->opcode == T_CAST)
{
/* correct column */
regu_p = regu_p->value.arithptr->rightptr;
}
}
}
/* set the flag for using extended form, but keep the single-column argument code too for being faster for its
* particular case */
if (regu_p->type != TYPE_CONSTANT)
{
use_extended = true;
}
else
{
arg_dbval_p = &arg_dbval;
db_make_null (arg_dbval_p);
}
/* character */
i = (int) strlen (DB_GET_STRING_SAFE (value_char));
sep = (char *) db_private_alloc (thread_p, sizeof (char) * (i + 1));
if (sep == NULL)
{
return false;
}
sep[0] = 0;
if (i > 0)
{
strcpy (sep, DB_GET_STRING_SAFE (value_char));
}
/* walk the parents up to root */
list_id_p = xptr->list_id;
if (qfile_open_list_scan (list_id_p, &s_id) != NO_ERROR)
{
goto error2;
}
if (!use_extended)
{
/* column index */
for (i = 0, valp = xptr->val_list->valp; valp; i++, valp = valp->next)
{
if (valp->val == regu_p->value.dbvalptr)
{
break;
}
}
if (i >= xptr->val_list->val_cnt)
{
/* TYPE_CONSTANT but not in val_list, check if it is inst_num() (orderby_num() is not allowed) */
if (regu_p->value.dbvalptr == xasl->instnum_val)
{
arg_dbval_p = xasl->instnum_val;
}
else
{
goto error;
}
}
}
else
{
/* save val_list */
if (xptr->val_list->val_cnt > 0)
{
save_values = (DB_VALUE **) db_private_alloc (thread_p, sizeof (DB_VALUE *) * xptr->val_list->val_cnt);
if (save_values == NULL)
{
goto error;
}
memset (save_values, 0, sizeof (DB_VALUE *) * xptr->val_list->val_cnt);
for (i = 0, valp = xptr->val_list->valp; valp && i < xptr->val_list->val_cnt; i++, valp = valp->next)
{
save_values[i] = db_value_copy (valp->val);
}
}
}
/* we start with tpl itself */
tuple_rec.tpl = tpl;
len_result_path = SYS_CONNECT_BY_PATH_MEM_STEP;
result_path = (char *) db_private_alloc (thread_p, sizeof (char) * len_result_path);
if (result_path == NULL)
{
goto error;
}
strcpy (result_path, "");
do
{
need_clear_arg_dbval = false;
if (!use_extended)
{
/* get the required column */
if (i < xptr->val_list->val_cnt)
{
if (qexec_get_tuple_column_value (tuple_rec.tpl, i, arg_dbval_p, regu_p->domain) != NO_ERROR)
{
goto error;
}
need_clear_arg_dbval = true;
}
}
else
{
/* fetch value list */
if (fetch_val_list (thread_p, xptr->proc.connect_by.regu_list_pred, vd, NULL, NULL, tuple_rec.tpl, PEEK) !=
NO_ERROR)
{
goto error;
}
if (fetch_val_list (thread_p, xptr->proc.connect_by.regu_list_rest, vd, NULL, NULL, tuple_rec.tpl, PEEK) !=
NO_ERROR)
{
goto error;
}
/* evaluate argument expression */
if (fetch_peek_dbval (thread_p, regu_p, vd, NULL, NULL, tuple_rec.tpl, &arg_dbval_p) != NO_ERROR)
{
goto error;
}
}
if (DB_IS_NULL (arg_dbval_p))
{
db_make_null (&cast_value);
}
else
{
/* cast result to string; this call also allocates the container */
if (qdata_cast_to_domain (arg_dbval_p, &cast_value, &tp_String_domain) != NO_ERROR)
{
goto error;
}
if (need_clear_arg_dbval)
{
pr_clear_value (arg_dbval_p);
need_clear_arg_dbval = false;
}
}
len = (strlen (sep) + (DB_IS_NULL (&cast_value) ? 0 : db_get_string_size (&cast_value))
+ strlen (result_path) + 1);
if (len > len_tmp || path_tmp == NULL)
{
/* free previously alloced */
if (path_tmp)
{
db_private_free_and_init (thread_p, path_tmp);
}
len_tmp = len;
path_tmp = (char *) db_private_alloc (thread_p, sizeof (char) * len_tmp);
if (path_tmp == NULL)
{
pr_clear_value (&cast_value);
goto error;
}
}
strcpy (path_tmp, sep);
strcat (path_tmp, DB_GET_STRING_SAFE (&cast_value));
strcat (path_tmp, result_path);
/* free the container for cast_value */
if (pr_clear_value (&cast_value) != NO_ERROR)
{
goto error;
}
bool is_resize = false;
int need_size = (int) strlen (path_tmp) + 1;
while (need_size > len_result_path)
{
len_result_path += SYS_CONNECT_BY_PATH_MEM_STEP;
is_resize = true;
}
if (is_resize)
{
db_private_free_and_init (thread_p, result_path);
result_path = (char *) db_private_alloc (thread_p, sizeof (char) * len_result_path);
if (result_path == NULL)
{
goto error;
}
}
strcpy (result_path, path_tmp);
/* get the parent node */
if (qexec_get_tuple_column_value (tuple_rec.tpl, xptr->outptr_list->valptr_cnt - PCOL_PARENTPOS_TUPLE_OFFSET,
&p_pos_dbval, &tp_Bit_domain) != NO_ERROR)
{
goto error;
}
bitval = REINTERPRET_CAST (const QFILE_TUPLE_POSITION *, db_get_bit (&p_pos_dbval, &length));
if (bitval)
{
p_pos.status = s_id.status;
p_pos.position = S_ON;
p_pos.vpid = bitval->vpid;
p_pos.offset = bitval->offset;
p_pos.tpl = NULL;
p_pos.tplno = bitval->tplno;
if (qfile_jump_scan_tuple_position (thread_p, &s_id, &p_pos, &tuple_rec, PEEK) != S_SUCCESS)
{
goto error;
}
}
}
while (bitval); /* the parent tuple pos is null for the root node */
qfile_close_scan (thread_p, &s_id);
db_make_string (result_p, result_path);
result_p->need_clear = true;
if (use_extended)
{
/* restore val_list */
if (xptr->val_list->val_cnt > 0)
{
for (i = 0, valp = xptr->val_list->valp; valp && i < xptr->val_list->val_cnt; i++, valp = valp->next)
{
if (pr_clear_value (valp->val) != NO_ERROR)
{
goto error2;
}
if (pr_clone_value (save_values[i], valp->val) != NO_ERROR)
{
goto error2;
}
}
for (i = 0; i < xptr->val_list->val_cnt; i++)
{
if (save_values[i])
{
if (pr_free_ext_value (save_values[i]) != NO_ERROR)
{
goto error2;
}
save_values[i] = NULL;
}
}
db_private_free_and_init (thread_p, save_values);
}
}
if (path_tmp)
{
db_private_free_and_init (thread_p, path_tmp);
}
if (sep)
{
db_private_free_and_init (thread_p, sep);
}
if (need_clear_arg_dbval)
{
pr_clear_value (arg_dbval_p);
}
return true;
error:
qfile_close_scan (thread_p, &s_id);
if (save_values)
{
for (i = 0; i < xptr->val_list->val_cnt; i++)
{
if (save_values[i])
{
pr_free_ext_value (save_values[i]);
}
}
db_private_free_and_init (thread_p, save_values);
}
error2:
if (result_path)
{
db_private_free_and_init (thread_p, result_path);
result_p->need_clear = false;
}
if (path_tmp)
{
db_private_free_and_init (thread_p, path_tmp);
}
if (sep)
{
db_private_free_and_init (thread_p, sep);
}
if (need_clear_arg_dbval)
{
pr_clear_value (arg_dbval_p);
}
return false;
}
/*
* qdata_bit_not_dbval () - bitwise not
* return: NO_ERROR, or ER_code
* dbval_p(in) : db_value node
* result_p(out) : resultant db_value node
* domain_p(in) :
*
*/
int
qdata_bit_not_dbval (DB_VALUE * dbval_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval_p))
{
return NO_ERROR;
}
type = DB_VALUE_DOMAIN_TYPE (dbval_p);
switch (type)
{
case DB_TYPE_NULL:
db_make_null (result_p);
break;
case DB_TYPE_INTEGER:
db_make_bigint (result_p, ~((INT64) db_get_int (dbval_p)));
break;
case DB_TYPE_BIGINT:
db_make_bigint (result_p, ~db_get_bigint (dbval_p));
break;
case DB_TYPE_SHORT:
db_make_bigint (result_p, ~((INT64) db_get_short (dbval_p)));
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
return NO_ERROR;
}
/*
* qdata_bit_and_dbval () - bitwise and
* return: NO_ERROR, or ER_code
* dbval1_p(in) : first db_value node
* dbval2_p(in) : second db_value node
* result_p(out) : resultant db_value node
* domain_p(in) :
*
*/
int
qdata_bit_and_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type[2];
DB_BIGINT bi[2];
DB_VALUE *dbval[2];
int i;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type[0] = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type[1] = DB_VALUE_DOMAIN_TYPE (dbval2_p);
dbval[0] = dbval1_p;
dbval[1] = dbval2_p;
for (i = 0; i < 2; i++)
{
switch (type[i])
{
case DB_TYPE_NULL:
db_make_null (result_p);
break;
case DB_TYPE_INTEGER:
bi[i] = (DB_BIGINT) db_get_int (dbval[i]);
break;
case DB_TYPE_BIGINT:
bi[i] = db_get_bigint (dbval[i]);
break;
case DB_TYPE_SHORT:
bi[i] = (DB_BIGINT) db_get_short (dbval[i]);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (type[0] != DB_TYPE_NULL && type[1] != DB_TYPE_NULL)
{
db_make_bigint (result_p, bi[0] & bi[1]);
}
return NO_ERROR;
}
/*
* qdata_bit_or_dbval () - bitwise or
* return: NO_ERROR, or ER_code
* dbval1_p(in) : first db_value node
* dbval2_p(in) : second db_value node
* result_p(out) : resultant db_value node
* domain_p(in) :
*
*/
int
qdata_bit_or_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type[2];
DB_BIGINT bi[2];
DB_VALUE *dbval[2];
int i;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type[0] = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type[1] = DB_VALUE_DOMAIN_TYPE (dbval2_p);
dbval[0] = dbval1_p;
dbval[1] = dbval2_p;
for (i = 0; i < 2; i++)
{
switch (type[i])
{
case DB_TYPE_NULL:
db_make_null (result_p);
break;
case DB_TYPE_INTEGER:
bi[i] = (DB_BIGINT) db_get_int (dbval[i]);
break;
case DB_TYPE_BIGINT:
bi[i] = db_get_bigint (dbval[i]);
break;
case DB_TYPE_SHORT:
bi[i] = (DB_BIGINT) db_get_short (dbval[i]);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (type[0] != DB_TYPE_NULL && type[1] != DB_TYPE_NULL)
{
db_make_bigint (result_p, bi[0] | bi[1]);
}
return NO_ERROR;
}
/*
* qdata_bit_xor_dbval () - bitwise xor
* return: NO_ERROR, or ER_code
* dbval1_p(in) : first db_value node
* dbval2_p(in) : second db_value node
* result_p(out) : resultant db_value node
* domain_p(in) :
*
*/
int
qdata_bit_xor_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_TYPE type[2];
DB_BIGINT bi[2];
DB_VALUE *dbval[2];
int i;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type[0] = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type[1] = DB_VALUE_DOMAIN_TYPE (dbval2_p);
dbval[0] = dbval1_p;
dbval[1] = dbval2_p;
for (i = 0; i < 2; i++)
{
switch (type[i])
{
case DB_TYPE_NULL:
db_make_null (result_p);
break;
case DB_TYPE_INTEGER:
bi[i] = (DB_BIGINT) db_get_int (dbval[i]);
break;
case DB_TYPE_BIGINT:
bi[i] = db_get_bigint (dbval[i]);
break;
case DB_TYPE_SHORT:
bi[i] = (DB_BIGINT) db_get_short (dbval[i]);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (type[0] != DB_TYPE_NULL && type[1] != DB_TYPE_NULL)
{
db_make_bigint (result_p, bi[0] ^ bi[1]);
}
return NO_ERROR;
}
/*
* qdata_bit_shift_dbval () - bitshift
* return: NO_ERROR, or ER_code
* dbval1_p(in) : first db_value node
* dbval2_p(in) : second db_value node
* result_p(out) : resultant db_value node
* domain_p(in) :
*
*/
int
qdata_bit_shift_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, OPERATOR_TYPE op, DB_VALUE * result_p,
tp_domain * domain_p)
{
DB_TYPE type[2];
DB_BIGINT bi[2];
DB_VALUE *dbval[2];
int i;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type[0] = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type[1] = DB_VALUE_DOMAIN_TYPE (dbval2_p);
dbval[0] = dbval1_p;
dbval[1] = dbval2_p;
for (i = 0; i < 2; i++)
{
switch (type[i])
{
case DB_TYPE_NULL:
db_make_null (result_p);
break;
case DB_TYPE_INTEGER:
bi[i] = (DB_BIGINT) db_get_int (dbval[i]);
break;
case DB_TYPE_BIGINT:
bi[i] = db_get_bigint (dbval[i]);
break;
case DB_TYPE_SHORT:
bi[i] = (DB_BIGINT) db_get_short (dbval[i]);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (type[0] != DB_TYPE_NULL && type[1] != DB_TYPE_NULL)
{
if (bi[1] < (DB_BIGINT) (sizeof (DB_BIGINT) * 8) && bi[1] >= 0)
{
if (op == T_BITSHIFT_LEFT)
{
db_make_bigint (result_p, ((UINT64) bi[0]) << ((UINT64) bi[1]));
}
else
{
db_make_bigint (result_p, ((UINT64) bi[0]) >> ((UINT64) bi[1]));
}
}
else
{
db_make_bigint (result_p, 0);
}
}
return NO_ERROR;
}
/*
* qdata_divmod_dbval () - DIV/MOD operator
* return: NO_ERROR, or ER_code
* dbval1_p(in) : first db_value node
* dbval2_p(in) : second db_value node
* result_p(out) : resultant db_value node
* domain_p(in) :
*
*/
int
qdata_divmod_dbval (DB_VALUE * dbval1_p, DB_VALUE * dbval2_p, OPERATOR_TYPE op, DB_VALUE * result_p,
tp_domain * domain_p)
{
DB_TYPE type[2];
DB_BIGINT bi[2];
DB_VALUE *dbval[2];
int i;
if ((domain_p != NULL && TP_DOMAIN_TYPE (domain_p) == DB_TYPE_NULL) || DB_IS_NULL (dbval1_p) || DB_IS_NULL (dbval2_p))
{
return NO_ERROR;
}
type[0] = DB_VALUE_DOMAIN_TYPE (dbval1_p);
type[1] = DB_VALUE_DOMAIN_TYPE (dbval2_p);
dbval[0] = dbval1_p;
dbval[1] = dbval2_p;
for (i = 0; i < 2; i++)
{
switch (type[i])
{
case DB_TYPE_NULL:
db_make_null (result_p);
break;
case DB_TYPE_INTEGER:
bi[i] = (DB_BIGINT) db_get_int (dbval[i]);
break;
case DB_TYPE_BIGINT:
bi[i] = db_get_bigint (dbval[i]);
break;
case DB_TYPE_SHORT:
bi[i] = (DB_BIGINT) db_get_short (dbval[i]);
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
return ER_QPROC_INVALID_DATATYPE;
}
}
if (type[0] != DB_TYPE_NULL && type[1] != DB_TYPE_NULL)
{
if (bi[1] != 0)
{
if (op == T_INTDIV)
{
if (type[0] == DB_TYPE_INTEGER)
{
if (OR_CHECK_INT_DIV_OVERFLOW (bi[0], bi[1]))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_int (result_p, (INT32) (bi[0] / bi[1]));
}
else if (type[0] == DB_TYPE_BIGINT)
{
if (OR_CHECK_BIGINT_DIV_OVERFLOW (bi[0], bi[1]))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_bigint (result_p, bi[0] / bi[1]);
}
else
{
if (OR_CHECK_SHORT_DIV_OVERFLOW (bi[0], bi[1]))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OVERFLOW_ADDITION, 0);
return ER_QPROC_OVERFLOW_ADDITION;
}
db_make_short (result_p, (INT16) (bi[0] / bi[1]));
}
}
else
{
if (type[0] == DB_TYPE_INTEGER)
{
db_make_int (result_p, (INT32) (bi[0] % bi[1]));
}
else if (type[0] == DB_TYPE_BIGINT)
{
db_make_bigint (result_p, bi[0] % bi[1]);
}
else
{
db_make_short (result_p, (INT16) (bi[0] % bi[1]));
}
}
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_ZERO_DIVIDE, 0);
return ER_QPROC_ZERO_DIVIDE;
}
}
return NO_ERROR;
}
/*
* qdata_list_dbs () - lists all databases names
* return: NO_ERROR, or ER_code
* result_p(out) : resultant db_value node
* domain(in): domain
*/
int
qdata_list_dbs (THREAD_ENTRY * thread_p, DB_VALUE * result_p, tp_domain * domain_p)
{
DB_INFO *db_info_p;
if (cfg_read_directory (&db_info_p, false) != NO_ERROR)
{
if (er_errid () == NO_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CFG_NO_FILE, 1, DATABASES_FILENAME);
}
goto error;
}
if (db_info_p)
{
DB_INFO *list_p;
char *name_list;
size_t name_list_size = 0;
bool is_first;
for (list_p = db_info_p; list_p != NULL; list_p = list_p->next)
{
if (list_p->name)
{
name_list_size += strlen (list_p->name) + 1;
}
}
if (name_list_size != 0)
{
name_list = (char *) db_private_alloc (thread_p, name_list_size);
if (name_list == NULL)
{
cfg_free_directory (db_info_p);
goto error;
}
strcpy (name_list, "");
for (list_p = db_info_p, is_first = true; list_p != NULL; list_p = list_p->next)
{
if (list_p->name)
{
if (!is_first)
{
strcat (name_list, " ");
}
else
{
is_first = false;
}
strcat (name_list, list_p->name);
}
}
cfg_free_directory (db_info_p);
if (db_make_string (result_p, name_list) != NO_ERROR)
{
goto error;
}
result_p->need_clear = true;
}
else
{
cfg_free_directory (db_info_p);
db_make_null (result_p);
}
if (domain_p != NULL)
{
assert (TP_DOMAIN_TYPE (domain_p) == DB_VALUE_TYPE (result_p));
db_string_put_cs_and_collation (result_p, TP_DOMAIN_CODESET (domain_p), TP_DOMAIN_COLLATION (domain_p));
}
}
else
{
db_make_null (result_p);
}
return NO_ERROR;
error:
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/*
* qdata_regu_list_to_regu_array () - extracts the regu variables from
* function list to an array. Array must be
* allocated by caller
* return: NO_ERROR, or ER_FAILED code
* funcp(in) : function structure pointer
* array_size(in) : max size of array (in number of entries)
* regu_array(out) : array of pointers to regu-vars
* num_regu : number of regu vars actually found in list
*/
int
qdata_regu_list_to_regu_array (function_node * function_p, const int array_size, regu_variable_node * regu_array[],
int *num_regu)
{
REGU_VARIABLE_LIST operand = function_p->operand;
int i, num_args = 0;
assert (array_size > 0);
assert (regu_array != NULL);
assert (function_p != NULL);
assert (num_regu != NULL);
*num_regu = 0;
/* initialize the argument array */
for (i = 0; i < array_size; i++)
{
regu_array[i] = NULL;
}
while (operand)
{
if (num_args >= array_size)
{
return ER_FAILED;
}
regu_array[num_args] = &operand->value;
*num_regu = ++num_args;
operand = operand->next;
}
return NO_ERROR;
}
/*
* qdata_insert_substring_function () - Evaluates insert() function.
* return: NO_ERROR, or ER_FAILED code
* thread_p : thread context
* funcp(in) : function structure pointer
* vd(in) : value descriptor
* obj_oid(in): object identifier
* tpl(in) : tuple
*/
static int
qdata_insert_substring_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple)
{
DB_VALUE *args[NUM_F_INSERT_SUBSTRING_ARGS];
REGU_VARIABLE *regu_array[NUM_F_INSERT_SUBSTRING_ARGS];
int i, error_status = NO_ERROR;
int num_regu = 0;
/* initialize the argument array */
for (i = 0; i < NUM_F_INSERT_SUBSTRING_ARGS; i++)
{
args[i] = NULL;
regu_array[i] = NULL;
}
error_status = qdata_regu_list_to_regu_array (function_p, NUM_F_INSERT_SUBSTRING_ARGS, regu_array, &num_regu);
if (num_regu != NUM_F_INSERT_SUBSTRING_ARGS)
{
assert (false);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_GENERIC_FUNCTION_FAILURE, 0);
goto error;
}
if (error_status != NO_ERROR)
{
goto error;
}
for (i = 0; i < NUM_F_INSERT_SUBSTRING_ARGS; i++)
{
error_status = fetch_peek_dbval (thread_p, regu_array[i], val_desc_p, NULL, obj_oid_p, tuple, &args[i]);
if (error_status != NO_ERROR)
{
goto error;
}
}
error_status = db_string_insert_substring (args[0], args[1], args[2], args[3], function_p->value);
if (error_status != NO_ERROR)
{
goto error;
}
return NO_ERROR;
error:
/* no error message set, keep message already set */
return ER_FAILED;
}
/*
* qdata_elt() - returns the argument with the index in the parameter list
* equal to the value passed in the first argument. Returns
* NULL if the first arguments is NULL, is 0, is negative or is
* greater than the number of the other arguments.
*/
static int
qdata_elt (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p, OID * obj_oid_p,
QFILE_TUPLE tuple)
{
DB_VALUE *index = NULL;
REGU_VARIABLE_LIST operand;
int error_status = NO_ERROR;
DB_TYPE index_type;
DB_BIGINT idx = 0;
DB_VALUE *operand_value = NULL;
/* should sync with fetch_peek_dbval () */
assert (function_p);
assert (function_p->value);
assert (function_p->operand);
error_status = fetch_peek_dbval (thread_p, &function_p->operand->value, val_desc_p, NULL, obj_oid_p, tuple, &index);
if (error_status != NO_ERROR)
{
goto error_exit;
}
index_type = DB_VALUE_DOMAIN_TYPE (index);
switch (index_type)
{
case DB_TYPE_SMALLINT:
idx = db_get_short (index);
break;
case DB_TYPE_INTEGER:
idx = db_get_int (index);
break;
case DB_TYPE_BIGINT:
idx = db_get_bigint (index);
break;
case DB_TYPE_NULL:
db_make_null (function_p->value);
goto fast_exit;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_DATATYPE, 0);
error_status = ER_QPROC_INVALID_DATATYPE;
goto error_exit;
}
if (idx <= 0)
{
/* index is 0 or is negative */
db_make_null (function_p->value);
goto fast_exit;
}
idx--;
operand = function_p->operand->next;
while (idx > 0 && operand != NULL)
{
operand = operand->next;
idx--;
}
if (operand == NULL)
{
/* index greater than number of arguments */
db_make_null (function_p->value);
goto fast_exit;
}
error_status = fetch_peek_dbval (thread_p, &operand->value, val_desc_p, NULL, obj_oid_p, tuple, &operand_value);
if (error_status != NO_ERROR)
{
goto error_exit;
}
/*
* operand should already be cast to the right type (CHAR)
*/
error_status = pr_clone_value (operand_value, function_p->value);
fast_exit:
return error_status;
error_exit:
return error_status;
}
//
// qdata_benchmark () - "benchmark" function execution; repeatedly run nested operation
//
static int
qdata_benchmark (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p, OID * obj_oid_p,
QFILE_TUPLE tuple)
{
assert (function_p);
if (function_p == NULL || function_p->operand == NULL || function_p->operand->next == NULL)
{
assert_release (false);
return ER_FAILED;
}
if (function_p->value == NULL)
{
assert_release (false);
return ER_FAILED;
}
db_make_null (function_p->value);
REGU_VARIABLE *count_reguvar = &function_p->operand->value;
REGU_VARIABLE *target_reguvar = &function_p->operand->next->value;
DB_VALUE *count_value = NULL;
DB_VALUE *target_value = NULL;
int error = fetch_peek_dbval (thread_p, count_reguvar, val_desc_p, NULL, obj_oid_p, tuple, &count_value);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
return error;
}
if (db_value_is_null (count_value))
{
return NO_ERROR;
}
INT64 count = 0;
switch (db_value_domain_type (count_value))
{
case DB_TYPE_SMALLINT:
count = STATIC_CAST (INT64, db_get_short (count_value));
break;
case DB_TYPE_INTEGER:
count = STATIC_CAST (INT64, db_get_int (count_value));
break;
case DB_TYPE_BIGINT:
count = db_get_bigint (count_value);
break;
default:
assert (false);
return ER_FAILED;
}
if (count <= 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
return ER_OBJ_INVALID_ARGUMENTS;
}
using bench_clock = std::chrono::system_clock;
bench_clock::time_point start_timept = bench_clock::now ();
for (INT64 step = 0; step < count; step++)
{
// we're trying to benchmark the expression in target reguvar by running it many times. even if all operands are
// constant, we still have to repeat the operations. for that, we need to make sure nested regu variables are not
// flagged as constants
//
// node that they still may be other optimizations that are not so easily disabled
fetch_force_not_const_recursive (*target_reguvar);
error = fetch_peek_dbval (thread_p, target_reguvar, val_desc_p, NULL, obj_oid_p, tuple, &target_value);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
return error;
}
pr_clear_value (target_value);
}
bench_clock::time_point end_timept = bench_clock::now ();
std::chrono::duration < double >secs = end_timept - start_timept;
db_make_double (function_p->value, secs.count ());
return NO_ERROR;
}
/*
* qdata_regexp_function () - Evaluates regexp related functions.
* return: NO_ERROR, or ER_FAILED code
* thread_p : thread context
* funcp(in) : function structure pointer
* vd(in) : value descriptor
* obj_oid(in): object identifier
* tpl(in) : tuple
*/
static int
qdata_regexp_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple)
{
DB_VALUE *value;
REGU_VARIABLE_LIST operand;
int error_status = NO_ERROR;
int no_args = 0, index = 0;
DB_VALUE **args;
{
assert (function_p != NULL);
assert (function_p->value != NULL);
assert (function_p->operand != NULL);
operand = function_p->operand;
while (operand != NULL)
{
no_args++;
operand = operand->next;
}
args = (DB_VALUE **) db_private_alloc (thread_p, sizeof (DB_VALUE *) * no_args);
operand = function_p->operand;
while (operand != NULL)
{
error_status = fetch_peek_dbval (thread_p, &operand->value, val_desc_p, NULL, obj_oid_p, tuple, &value);
if (error_status != NO_ERROR)
{
goto exit;
}
args[index++] = value;
operand = operand->next;
}
assert (index == no_args);
// *INDENT-OFF*
std::function<int(DB_VALUE*, DB_VALUE*[], const int, cub_compiled_regex**)> regexp_func;
switch (function_p->ftype)
{
case F_REGEXP_COUNT:
regexp_func = db_string_regexp_count;
break;
case F_REGEXP_INSTR:
regexp_func = db_string_regexp_instr;
break;
case F_REGEXP_LIKE:
regexp_func = db_string_regexp_like;
break;
case F_REGEXP_REPLACE:
regexp_func = db_string_regexp_replace;
break;
case F_REGEXP_SUBSTR:
regexp_func = db_string_regexp_substr;
break;
default:
assert (false);
break;
}
// *INDENT-ON*
if (function_p->tmp_obj == NULL)
{
function_p->tmp_obj = new function_tmp_obj;
function_p->tmp_obj->compiled_regex = new cub_compiled_regex ();
}
cub_compiled_regex *&compiled_regex = function_p->tmp_obj->compiled_regex;
error_status = regexp_func (function_p->value, args, no_args, &compiled_regex);
if (error_status != NO_ERROR)
{
goto exit;
}
}
exit:
db_private_free (thread_p, args);
return error_status;
}
static int
qdata_convert_operands_to_value_and_call (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple,
int (*function_to_call) (DB_VALUE *, DB_VALUE * const *, int const))
{
DB_VALUE *value;
REGU_VARIABLE_LIST operand;
int error_status = NO_ERROR;
int no_args = 0, index = 0;
DB_VALUE **args;
/* should sync with fetch_peek_dbval () */
assert (function_p != NULL);
assert (function_p->value != NULL);
assert (function_p->operand != NULL);
operand = function_p->operand;
while (operand != NULL)
{
no_args++;
operand = operand->next;
}
args = (DB_VALUE **) db_private_alloc (thread_p, sizeof (DB_VALUE *) * no_args);
operand = function_p->operand;
while (operand != NULL)
{
error_status = fetch_peek_dbval (thread_p, &operand->value, val_desc_p, NULL, obj_oid_p, tuple, &value);
if (error_status != NO_ERROR)
{
goto exit;
}
args[index++] = value;
operand = operand->next;
}
assert (index == no_args);
error_status = function_to_call (function_p->value, args, no_args);
if (error_status != NO_ERROR)
{
goto exit;
}
exit:
db_private_free (thread_p, args);
return error_status;
}
/*
* qdata_get_cardinality () - gets the cardinality of an index using its name
* and partial key count
* return: NO_ERROR, or error code
* thread_p(in) : thread context
* db_class_name(in): string DB_VALUE holding name of class
* db_index_name(in): string DB_VALUE holding name of index (as it appears
* in '_db_index' system catalog table
* db_key_position(in): integer DB_VALUE holding the partial key index
* result_p(out) : cardinality (integer or NULL DB_VALUE)
*/
int
qdata_get_cardinality (THREAD_ENTRY * thread_p, DB_VALUE * db_class_name, DB_VALUE * db_index_name,
DB_VALUE * db_key_position, DB_VALUE * result_p)
{
char class_name[SM_MAX_IDENTIFIER_LENGTH];
char index_name[SM_MAX_IDENTIFIER_LENGTH];
int key_pos = 0;
int cardinality = 0;
int error = NO_ERROR;
DB_TYPE cl_name_arg_type;
DB_TYPE idx_name_arg_type;
DB_TYPE key_pos_arg_type;
int str_class_name_len;
int str_index_name_len;
db_make_null (result_p);
cl_name_arg_type = DB_VALUE_DOMAIN_TYPE (db_class_name);
idx_name_arg_type = DB_VALUE_DOMAIN_TYPE (db_index_name);
key_pos_arg_type = DB_VALUE_DOMAIN_TYPE (db_key_position);
if (DB_IS_NULL (db_class_name) || DB_IS_NULL (db_index_name) || DB_IS_NULL (db_key_position))
{
goto exit;
}
if (!QSTR_IS_CHAR (cl_name_arg_type) || !QSTR_IS_CHAR (idx_name_arg_type) || key_pos_arg_type != DB_TYPE_INTEGER)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_UNEXPECTED, 1, "Arguments type mismatching.");
error = ER_UNEXPECTED;
goto exit;
}
str_class_name_len = MIN (SM_MAX_IDENTIFIER_LENGTH - 1, db_get_string_size (db_class_name));
strncpy (class_name, db_get_string (db_class_name), str_class_name_len);
class_name[str_class_name_len] = '\0';
str_index_name_len = MIN (SM_MAX_IDENTIFIER_LENGTH - 1, db_get_string_size (db_index_name));
strncpy (index_name, db_get_string (db_index_name), str_index_name_len);
index_name[str_index_name_len] = '\0';
key_pos = db_get_int (db_key_position);
error = catalog_get_cardinality_by_name (thread_p, class_name, index_name, key_pos, &cardinality);
if (error == NO_ERROR)
{
if (cardinality < 0)
{
db_make_null (result_p);
}
else
{
db_make_int (result_p, cardinality);
}
}
exit:
return error;
}
/*
* qdata_tuple_to_values_array () - construct an array of values from a
* tuple descriptor
* return : error code or NO_ERROR
* thread_p (in) : thread entry
* tuple (in) : tuple descriptor
* values (in/out) : values array
*
* Note: Values are cloned in the values array
*/
int
qdata_tuple_to_values_array (THREAD_ENTRY * thread_p, qfile_tuple_descriptor * tuple, DB_VALUE ** values)
{
DB_VALUE *vals;
int error = NO_ERROR, i;
assert_release (tuple != NULL);
assert_release (values != NULL);
vals = (DB_VALUE *) db_private_alloc (thread_p, tuple->f_cnt * sizeof (DB_VALUE));
if (vals == NULL)
{
error = ER_FAILED;
goto error_return;
}
for (i = 0; i < tuple->f_cnt; i++)
{
error = pr_clone_value (tuple->f_valp[i], &vals[i]);
if (error != NO_ERROR)
{
goto error_return;
}
}
*values = vals;
return NO_ERROR;
error_return:
if (vals != NULL)
{
int j;
for (j = 0; j < i; j++)
{
pr_clear_value (&vals[j]);
}
db_private_free (thread_p, vals);
}
*values = NULL;
return error;
}
/*
* qdata_apply_interpolation_function_coercion () - coerce input value for use in
* MEDIAN function evaluation
* returns: error code or NO_ERROR
* f_value(in): input value
* result_dom(in/out): result domain
* d_result(out): result as double precision floating point value
* result(out): result as DB_VALUE
*/
int
qdata_apply_interpolation_function_coercion (DB_VALUE * f_value, tp_domain ** result_dom, DB_VALUE * result,
FUNC_CODE function)
{
DB_TYPE type;
double d_result = 0;
int error = NO_ERROR;
assert (f_value != NULL && result_dom != NULL && result != NULL);
/* update result */
type = db_value_type (f_value);
switch (type)
{
case DB_TYPE_SHORT:
case DB_TYPE_INTEGER:
case DB_TYPE_BIGINT:
case DB_TYPE_FLOAT:
case DB_TYPE_DOUBLE:
case DB_TYPE_MONETARY:
case DB_TYPE_NUMERIC:
/* percentile_disc returns the same type as operand while median and percentile_cont return double */
if (function != PT_PERCENTILE_DISC)
{
if (type == DB_TYPE_SHORT)
{
d_result = (double) db_get_short (f_value);
}
else if (type == DB_TYPE_INTEGER)
{
d_result = (double) db_get_int (f_value);
}
else if (type == DB_TYPE_BIGINT)
{
d_result = (double) db_get_bigint (f_value);
}
else if (type == DB_TYPE_FLOAT)
{
d_result = (double) db_get_float (f_value);
}
else if (type == DB_TYPE_DOUBLE)
{
d_result = (double) db_get_double (f_value);
}
else if (type == DB_TYPE_MONETARY)
{
d_result = (db_get_monetary (f_value))->amount;
}
else if (type == DB_TYPE_NUMERIC)
{
numeric_coerce_num_to_double (db_locate_numeric (f_value), DB_VALUE_SCALE (f_value), &d_result);
}
db_make_double (result, d_result);
}
else
{
pr_clone_value (f_value, result);
}
break;
case DB_TYPE_DATE:
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_DATETIMETZ:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
case DB_TYPE_TIME:
pr_clone_value (f_value, result);
break;
default:
type = TP_DOMAIN_TYPE (*result_dom);
if (!TP_IS_NUMERIC_TYPE (type) && !TP_IS_DATE_OR_TIME_TYPE (type))
{
error = qdata_update_interpolation_func_value_and_domain (f_value, result, result_dom);
if (error != NO_ERROR)
{
assert (error == ER_ARG_CAN_NOT_BE_CASTED_TO_DESIRED_DOMAIN);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, fcode_get_uppercase_name (function),
"DOUBLE, DATETIME, TIME");
error = ER_FAILED;
goto end;
}
}
else
{
error = db_value_coerce (f_value, result, *result_dom);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
}
}
end:
return error;
}
/*
* qdata_interpolation_function_values () - interpolate two values for use
* in MEDIAN function evaluation
* returns: error code or NO_ERROR
* f_value(in): "floor" value (i.e. first value in tuple order)
* c_value(in): "ceiling" value (i.e. second value in tuple order)
* row_num_d(in): row number as floating point value
* f_row_num_d(in): row number of f_value as floating point value
* c_row_num_d(in): row number of c_value as floating point value
* result_dom(in/out): result domain
* d_result(out): result as double precision floating point value
* result(out): result as DB_VALUE
*/
int
qdata_interpolation_function_values (DB_VALUE * f_value, DB_VALUE * c_value, double row_num_d, double f_row_num_d,
double c_row_num_d, tp_domain ** result_dom, DB_VALUE * result, FUNC_CODE function)
{
DB_DATE date;
DB_DATETIME datetime;
DB_TIMESTAMP utime;
DB_TIME time;
DB_TYPE type;
double d1, d2;
double d_result;
int error = NO_ERROR;
assert (f_value != NULL && c_value != NULL && result_dom != NULL && result != NULL);
/* calculate according to type The formular bellow is from Oracle's MEDIAN manual result = (CRN - RN) * (value for
* row at FRN) + (RN - FRN) * (value for row at CRN) */
type = db_value_type (f_value);
if (!TP_IS_NUMERIC_TYPE (type) && !TP_IS_DATE_OR_TIME_TYPE (type))
{
type = TP_DOMAIN_TYPE (*result_dom);
if (!TP_IS_NUMERIC_TYPE (type) && !TP_IS_DATE_OR_TIME_TYPE (type))
{
/* try to coerce f_value to double, datetime then time and save domain for next coerce */
error = qdata_update_interpolation_func_value_and_domain (f_value, f_value, result_dom);
if (error != NO_ERROR)
{
assert (error == ER_ARG_CAN_NOT_BE_CASTED_TO_DESIRED_DOMAIN);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, fcode_get_uppercase_name (function),
"DOUBLE, DATETIME, TIME");
error = ER_FAILED;
goto end;
}
}
else
{
error = db_value_coerce (f_value, f_value, *result_dom);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
}
/* coerce c_value */
error = db_value_coerce (c_value, c_value, *result_dom);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
}
type = db_value_type (f_value);
switch (type)
{
case DB_TYPE_SHORT:
d1 = (double) db_get_short (f_value);
d2 = (double) db_get_short (c_value);
/* calculate */
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
db_make_double (result, d_result);
break;
case DB_TYPE_INTEGER:
d1 = (double) db_get_int (f_value);
d2 = (double) db_get_int (c_value);
/* calculate */
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
db_make_double (result, d_result);
break;
case DB_TYPE_BIGINT:
d1 = (double) db_get_bigint (f_value);
d2 = (double) db_get_bigint (c_value);
/* calculate */
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
db_make_double (result, d_result);
break;
case DB_TYPE_FLOAT:
d1 = (double) db_get_float (f_value);
d2 = (double) db_get_float (c_value);
/* calculate */
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
db_make_double (result, d_result);
break;
case DB_TYPE_DOUBLE:
d1 = db_get_double (f_value);
d2 = db_get_double (c_value);
/* calculate */
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
db_make_double (result, d_result);
break;
case DB_TYPE_MONETARY:
d1 = (db_get_monetary (f_value))->amount;
d2 = (db_get_monetary (c_value))->amount;
/* calculate */
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
db_make_double (result, d_result);
break;
case DB_TYPE_NUMERIC:
numeric_coerce_num_to_double (db_locate_numeric (f_value), DB_VALUE_SCALE (f_value), &d1);
numeric_coerce_num_to_double (db_locate_numeric (c_value), DB_VALUE_SCALE (c_value), &d2);
/* calculate */
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
db_make_double (result, d_result);
break;
case DB_TYPE_DATE:
d1 = (double) *(db_get_date (f_value));
d2 = (double) *(db_get_date (c_value));
d_result = (c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2;
date = (DB_DATE) floor (d_result);
db_value_put_encoded_date (result, &date);
break;
case DB_TYPE_DATETIME:
case DB_TYPE_DATETIMELTZ:
case DB_TYPE_DATETIMETZ:
if (type == DB_TYPE_DATETIMETZ)
{
datetime = db_get_datetimetz (f_value)->datetime;
}
else
{
datetime = *(db_get_datetime (f_value));
}
d1 = ((double) datetime.date) * MILLISECONDS_OF_ONE_DAY + datetime.time;
if (type == DB_TYPE_DATETIMETZ)
{
datetime = db_get_datetimetz (c_value)->datetime;
}
else
{
datetime = *(db_get_datetime (c_value));
}
d2 = ((double) datetime.date) * MILLISECONDS_OF_ONE_DAY + datetime.time;
d_result = floor ((c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2);
datetime.date = (unsigned int) (d_result / MILLISECONDS_OF_ONE_DAY);
datetime.time = (unsigned int) (((DB_BIGINT) d_result) % MILLISECONDS_OF_ONE_DAY);
if (type == DB_TYPE_DATETIME)
{
db_make_datetime (result, &datetime);
}
else if (type == DB_TYPE_DATETIMELTZ)
{
db_make_datetimeltz (result, &datetime);
}
else
{
DB_DATETIMETZ dttz1, dttz2;
/* if the two timezones are different, we use the first timezone */
dttz1.datetime = datetime;
dttz1.tz_id = db_get_datetimetz (f_value)->tz_id;
error = tz_datetimetz_fix_zone (&dttz1, &dttz2);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
db_make_datetimetz (result, &dttz2);
}
break;
case DB_TYPE_TIMESTAMP:
case DB_TYPE_TIMESTAMPLTZ:
case DB_TYPE_TIMESTAMPTZ:
if (type == DB_TYPE_TIMESTAMPTZ)
{
db_timestamp_decode_utc (&db_get_timestamptz (f_value)->timestamp, &date, &time);
}
else
{
db_timestamp_decode_utc (db_get_timestamp (f_value), &date, &time);
}
d1 = ((double) date) * MILLISECONDS_OF_ONE_DAY + time * 1000;
if (type == DB_TYPE_TIMESTAMPTZ)
{
db_timestamp_decode_utc (&db_get_timestamptz (c_value)->timestamp, &date, &time);
}
else
{
db_timestamp_decode_utc (db_get_timestamp (c_value), &date, &time);
}
d2 = ((double) date) * MILLISECONDS_OF_ONE_DAY + time * 1000;
d_result = floor ((c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2);
date = (unsigned int) (d_result / MILLISECONDS_OF_ONE_DAY);
time = (unsigned int) (((DB_BIGINT) d_result) % MILLISECONDS_OF_ONE_DAY);
time /= 1000;
error = db_timestamp_encode_utc (&date, &time, &utime);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
if (type == DB_TYPE_TIMESTAMP)
{
db_make_timestamp (result, utime);
}
else if (type == DB_TYPE_TIMESTAMPLTZ)
{
db_make_timestampltz (result, utime);
}
else
{
DB_TIMESTAMPTZ tstz1, tstz2;
/* if the two timezones are different, we use the first timezone */
tstz1.timestamp = utime;
tstz1.tz_id = db_get_timestamptz (f_value)->tz_id;
error = tz_timestamptz_fix_zone (&tstz1, &tstz2);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
db_make_timestamptz (result, &tstz2);
}
break;
case DB_TYPE_TIME:
d1 = (double) (*db_get_time (f_value));
d2 = (double) (*db_get_time (c_value));
d_result = floor ((c_row_num_d - row_num_d) * d1 + (row_num_d - f_row_num_d) * d2);
time = (DB_TIME) d_result;
db_value_put_encoded_time (result, &time);
break;
default:
/* never be here! */
assert (false);
}
end:
return error;
}
/*
* qdata_get_interpolation_function_result () -
* return : error code or NO_ERROR
* thread_p (in) : thread entry
* scan_id (in) :
* domain (in) :
* pos (in) : the pos for REGU_VAR
* f_number_d (in) :
* c_number_d (in) :
* result (out) :
* result_dom(in/out):
*
*/
int
qdata_get_interpolation_function_result (THREAD_ENTRY * thread_p, QFILE_LIST_SCAN_ID * scan_id, tp_domain * domain,
int pos, double row_num_d, double f_row_num_d, double c_row_num_d,
DB_VALUE * result, tp_domain ** result_dom, FUNC_CODE function)
{
int error = NO_ERROR;
QFILE_TUPLE_RECORD tuple_record = { NULL, 0 };
DB_VALUE *f_value, *c_value;
DB_VALUE f_fetch_value, c_fetch_value;
REGU_VARIABLE regu_var;
SCAN_CODE scan_code;
DB_BIGINT bi;
assert (scan_id != NULL && domain != NULL && result != NULL && result_dom != NULL);
db_make_null (&f_fetch_value);
db_make_null (&c_fetch_value);
/* overflow check */
if (OR_CHECK_BIGINT_OVERFLOW (f_row_num_d))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_DATA_OVERFLOW, 0);
error = ER_FAILED;
goto end;
}
for (bi = (DB_BIGINT) f_row_num_d; bi >= 0; --bi)
{
scan_code = qfile_scan_list_next (thread_p, scan_id, &tuple_record, PEEK);
if (scan_code != S_SUCCESS)
{
error = ER_FAILED;
goto end;
}
}
regu_var.type = TYPE_POSITION;
regu_var.flags = 0;
regu_var.xasl = NULL;
regu_var.domain = domain;
regu_var.value.pos_descr.pos_no = pos;
regu_var.value.pos_descr.dom = domain;
regu_var.vfetch_to = &f_fetch_value;
error = fetch_peek_dbval (thread_p, ®u_var, NULL, NULL, NULL, tuple_record.tpl, &f_value);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
pr_clear_value (result);
if (f_row_num_d == c_row_num_d)
{
error = qdata_apply_interpolation_function_coercion (f_value, result_dom, result, function);
if (error != NO_ERROR)
{
goto end;
}
}
else
{
/* move to next tuple */
scan_code = qfile_scan_list_next (thread_p, scan_id, &tuple_record, PEEK);
if (scan_code != S_SUCCESS)
{
error = ER_FAILED;
goto end;
}
regu_var.vfetch_to = &c_fetch_value;
/* get value */
error = fetch_peek_dbval (thread_p, ®u_var, NULL, NULL, NULL, tuple_record.tpl, &c_value);
if (error != NO_ERROR)
{
error = ER_FAILED;
goto end;
}
error =
qdata_interpolation_function_values (f_value, c_value, row_num_d, f_row_num_d, c_row_num_d, result_dom, result,
function);
if (error != NO_ERROR)
{
goto end;
}
}
end:
pr_clear_value (&f_fetch_value);
pr_clear_value (&c_fetch_value);
return error;
}
/*
* qdata_update_interpolation_func_value_and_domain () -
* return: NO_ERROR or ER_ARG_CAN_NOT_BE_CASTED_TO_DESIRED_DOMAIN
* src_val(in):
* dest_val(out):
* domain(in/out):
*
*/
int
qdata_update_interpolation_func_value_and_domain (DB_VALUE * src_val, DB_VALUE * dest_val, TP_DOMAIN ** domain)
{
int error = NO_ERROR;
DB_DOMAIN *tmp_domain = NULL;
TP_DOMAIN_STATUS status;
assert (src_val != NULL && dest_val != NULL && domain != NULL);
tmp_domain = tp_domain_resolve_default (DB_TYPE_DOUBLE);
status = tp_value_cast (src_val, dest_val, tmp_domain, false);
if (status != DOMAIN_COMPATIBLE)
{
/* try datetime */
tmp_domain = tp_domain_resolve_default (DB_TYPE_DATETIME);
status = tp_value_cast (src_val, dest_val, tmp_domain, false);
}
/* try time */
if (status != DOMAIN_COMPATIBLE)
{
tmp_domain = tp_domain_resolve_default (DB_TYPE_TIME);
status = tp_value_cast (src_val, dest_val, tmp_domain, false);
}
if (status != DOMAIN_COMPATIBLE)
{
error = ER_ARG_CAN_NOT_BE_CASTED_TO_DESIRED_DOMAIN;
goto end;
}
*domain = tmp_domain;
end:
return error;
}