File xasl_stream.cpp¶
File List > cubrid > src > xasl > xasl_stream.cpp
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.
*
*/
//
// XASL stream - common interface for xasl_to_stream and stream_to_xasl
//
#include "xasl_stream.hpp"
#include "memory_alloc.h"
#include "object_representation.h"
#include "xasl.h"
#include "xasl_unpack_info.hpp"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
#if !defined(SERVER_MODE)
static int stx_Xasl_errcode = NO_ERROR;
#endif /* !SERVER_MODE */
/*
* stx_get_xasl_errcode () -
* return:
*/
int
stx_get_xasl_errcode (THREAD_ENTRY *thread_p)
{
#if defined(SERVER_MODE)
return thread_p->xasl_errcode;
#else /* SERVER_MODE */
return stx_Xasl_errcode;
#endif /* SERVER_MODE */
}
/*
* stx_set_xasl_errcode () -
* return:
* errcode(in) :
*/
void
stx_set_xasl_errcode (THREAD_ENTRY *thread_p, int errcode)
{
#if defined(SERVER_MODE)
thread_p->xasl_errcode = errcode;
#else /* SERVER_MODE */
stx_Xasl_errcode = errcode;
#endif /* SERVER_MODE */
}
/*
* stx_init_xasl_unpack_info () -
* return:
* xasl_stream(in) : pointer to xasl stream
* xasl_stream_size(in) :
*
* Note: initialize the xasl pack information.
*/
int
stx_init_xasl_unpack_info (THREAD_ENTRY *thread_p, char *xasl_stream, int xasl_stream_size)
{
size_t n;
XASL_UNPACK_INFO *unpack_info;
int head_offset, body_offset;
head_offset = sizeof (XASL_UNPACK_INFO);
head_offset = xasl_stream_make_align (head_offset);
body_offset = xasl_stream_size * UNPACK_SCALE;
body_offset = xasl_stream_make_align (body_offset);
unpack_info = (XASL_UNPACK_INFO *) db_private_alloc (thread_p, head_offset + body_offset);
set_xasl_unpack_info_ptr (thread_p, unpack_info);
if (unpack_info == NULL)
{
return ER_FAILED;
}
unpack_info->packed_xasl = xasl_stream;
unpack_info->packed_size = xasl_stream_size;
memset (unpack_info->ptr_blocks, 0x00, sizeof (unpack_info->ptr_blocks));
memset (unpack_info->ptr_lwm, 0x00, sizeof (unpack_info->ptr_lwm));
memset (unpack_info->ptr_max, 0x00, sizeof (unpack_info->ptr_max));
unpack_info->alloc_size = xasl_stream_size * UNPACK_SCALE;
unpack_info->alloc_buf = (char *) unpack_info + head_offset;
unpack_info->additional_buffers = NULL;
unpack_info->track_allocated_bufers = 0;
#if defined (SERVER_MODE)
unpack_info->thrd = thread_p;
#endif /* SERVER_MODE */
return NO_ERROR;
}
/*
* stx_mark_struct_visited () -
* return: if successful, return NO_ERROR, otherwise
* ER_FAILED and error code is set to xasl_errcode
* ptr(in) : pointer constant to be marked visited
* str(in) : where the struct pointed by 'ptr' is stored
*
* Note: mark the given pointer constant as visited to avoid
* duplicated storage of a struct which is pointed by more than one node
*/
int
stx_mark_struct_visited (THREAD_ENTRY *thread_p, const void *ptr, void *str)
{
int new_lwm;
int block_no;
XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p);
block_no = xasl_stream_get_ptr_block (ptr);
new_lwm = xasl_unpack_info->ptr_lwm[block_no];
if (xasl_unpack_info->ptr_max[block_no] == 0)
{
xasl_unpack_info->ptr_max[block_no] = START_PTR_PER_BLOCK;
xasl_unpack_info->ptr_blocks[block_no] =
(STX_VISITED_PTR *) db_private_alloc (thread_p, sizeof (STX_VISITED_PTR) * xasl_unpack_info->ptr_max[block_no]);
}
else if (xasl_unpack_info->ptr_max[block_no] <= new_lwm)
{
xasl_unpack_info->ptr_max[block_no] *= 2;
xasl_unpack_info->ptr_blocks[block_no] =
(STX_VISITED_PTR *) db_private_realloc (thread_p, xasl_unpack_info->ptr_blocks[block_no],
sizeof (STX_VISITED_PTR) * xasl_unpack_info->ptr_max[block_no]);
}
if (xasl_unpack_info->ptr_blocks[block_no] == (STX_VISITED_PTR *) NULL)
{
stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY);
return ER_FAILED;
}
xasl_unpack_info->ptr_blocks[block_no][new_lwm].ptr = ptr;
xasl_unpack_info->ptr_blocks[block_no][new_lwm].str = str;
xasl_unpack_info->ptr_lwm[block_no]++;
return NO_ERROR;
}
/*
* stx_get_struct_visited_ptr () -
* return: if the ptr is already visited, the offset of
* position where the node pointed by 'ptr' is stored,
* otherwise, ER_FAILED (xasl_errcode is NOT set)
* ptr(in) : pointer constant to be checked if visited or not
*
* Note: check if the node pointed by `ptr` is already stored or
* not to avoid multiple store of the same node
*/
void *
stx_get_struct_visited_ptr (THREAD_ENTRY *thread_p, const void *ptr)
{
int block_no;
int element_no;
XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p);
block_no = xasl_stream_get_ptr_block (ptr);
if (xasl_unpack_info->ptr_lwm[block_no] <= 0)
{
return NULL;
}
for (element_no = 0; element_no < xasl_unpack_info->ptr_lwm[block_no]; element_no++)
{
if (ptr == xasl_unpack_info->ptr_blocks[block_no][element_no].ptr)
{
return (xasl_unpack_info->ptr_blocks[block_no][element_no].str);
}
}
return NULL;
}
/*
* stx_free_visited_ptrs () -
* return:
*
* Note: free memory allocated to manage visited ptr constants
*/
void
stx_free_visited_ptrs (THREAD_ENTRY *thread_p)
{
XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p);
for (size_t i = 0; i < MAX_PTR_BLOCKS; i++)
{
if (xasl_unpack_info->ptr_blocks[i])
{
db_private_free_and_init (thread_p, xasl_unpack_info->ptr_blocks[i]);
}
}
memset (xasl_unpack_info->ptr_lwm, 0x00, sizeof (xasl_unpack_info->ptr_lwm));
memset (xasl_unpack_info->ptr_max, 0x00, sizeof (xasl_unpack_info->ptr_max));
}
/*
* stx_alloc_struct () -
* return:
* size(in) : # of bytes of the node
*
* Note: allocate storage for structures pointed to from the xasl tree.
*/
char *
stx_alloc_struct (THREAD_ENTRY *thread_p, int size)
{
char *ptr;
XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p);
if (!size)
{
return NULL;
}
size = xasl_stream_make_align (size); /* alignment */
if (size > xasl_unpack_info->alloc_size)
{
/* need to alloc */
int p_size;
p_size = MAX (size, xasl_unpack_info->packed_size);
p_size = xasl_stream_make_align (p_size); /* alignment */
ptr = (char *) db_private_alloc (thread_p, p_size);
if (ptr == NULL)
{
return NULL; /* error */
}
xasl_unpack_info->alloc_size = p_size;
xasl_unpack_info->alloc_buf = ptr;
if (xasl_unpack_info->track_allocated_bufers)
{
UNPACK_EXTRA_BUF *add_buff = NULL;
add_buff = (UNPACK_EXTRA_BUF *) db_private_alloc (thread_p, sizeof (UNPACK_EXTRA_BUF));
if (add_buff == NULL)
{
db_private_free_and_init (thread_p, ptr);
return NULL;
}
add_buff->buff = ptr;
add_buff->next = NULL;
if (xasl_unpack_info->additional_buffers == NULL)
{
xasl_unpack_info->additional_buffers = add_buff;
}
else
{
add_buff->next = xasl_unpack_info->additional_buffers;
xasl_unpack_info->additional_buffers = add_buff;
}
}
}
/* consume alloced buffer */
ptr = xasl_unpack_info->alloc_buf;
xasl_unpack_info->alloc_size -= size;
xasl_unpack_info->alloc_buf += size;
return ptr;
}
char *
stx_build_db_value (THREAD_ENTRY *thread_p, char *ptr, DB_VALUE *value)
{
ptr = or_unpack_db_value (ptr, value);
return ptr;
}
char *
stx_build_string (THREAD_ENTRY *thread_p, char *ptr, char *string)
{
int offset;
ptr = or_unpack_int (ptr, &offset);
assert_release (offset > 0);
(void) memcpy (string, ptr, offset);
ptr += offset;
return ptr;
}
char *
stx_restore_string (THREAD_ENTRY *thread_p, char *&ptr)
{
#if !defined (CS_MODE)
char *string;
int length;
int offset = 0;
ptr = or_unpack_int (ptr, &offset);
if (offset == 0)
{
return NULL;
}
char *bufptr = &get_xasl_unpack_info_ptr (thread_p)->packed_xasl[offset];
if (ptr == NULL)
{
return NULL;
}
string = (char *) stx_get_struct_visited_ptr (thread_p, bufptr);
if (string != NULL)
{
return string;
}
length = OR_GET_INT (bufptr);
if (length == -1)
{
/* unpack null-string */
assert (string == NULL);
}
else
{
assert_release (length > 0);
string = (char *) stx_alloc_struct (thread_p, length);
if (string == NULL)
{
stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY);
return NULL;
}
if (stx_mark_struct_visited (thread_p, bufptr, string) == ER_FAILED
|| stx_build_string (thread_p, bufptr, string) == NULL)
{
return NULL;
}
}
return string;
#else // CS_MODE
int dummy;
ptr = or_unpack_int (ptr, &dummy);
return NULL;
#endif // CS_MODE
}
char *
stx_build (THREAD_ENTRY *thread_p, char *ptr, cubxasl::json_table::column &jtc)
{
int temp_int;
XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p);
ptr = or_unpack_int (ptr, &temp_int);
jtc.m_function = (json_table_column_function) temp_int;
stx_restore (thread_p, ptr, jtc.m_output_value_pointer);
if (jtc.m_function == JSON_TABLE_ORDINALITY)
{
jtc.m_domain = &tp_Integer_domain;
return ptr;
}
ptr = or_unpack_domain (ptr, &jtc.m_domain, NULL);
jtc.m_path = stx_restore_string (thread_p, ptr);
jtc.m_column_name = stx_restore_string (thread_p, ptr);
if (jtc.m_function == JSON_TABLE_EXISTS)
{
return ptr;
}
ptr = stx_unpack (thread_p, ptr, jtc.m_on_error);
ptr = stx_unpack (thread_p, ptr, jtc.m_on_empty);
return ptr;
}
char *
stx_build (THREAD_ENTRY *thread_p, char *ptr, cubxasl::json_table::node &jtn)
{
int temp_int = 0;
jtn.m_iterator = nullptr;
jtn.m_path = stx_restore_string (thread_p, ptr);
ptr = or_unpack_int (ptr, &temp_int);
jtn.m_output_columns_size = (size_t) temp_int;
if (jtn.m_output_columns_size > 0)
{
jtn.m_output_columns =
(json_table_column *) stx_alloc_struct (thread_p, (int) (sizeof (json_table_column) * jtn.m_output_columns_size));
for (size_t i = 0; i < jtn.m_output_columns_size; ++i)
{
jtn.m_output_columns[i].init ();
ptr = stx_build (thread_p, ptr, jtn.m_output_columns[i]);
}
}
ptr = or_unpack_int (ptr, &temp_int);
jtn.m_nested_nodes_size = (size_t) temp_int;
if (jtn.m_nested_nodes_size > 0)
{
jtn.m_nested_nodes =
(json_table_node *) stx_alloc_struct (thread_p, (int) (sizeof (json_table_node) * jtn.m_nested_nodes_size));
for (size_t i = 0; i < jtn.m_nested_nodes_size; ++i)
{
jtn.m_nested_nodes[i].init ();
ptr = stx_build (thread_p, ptr, jtn.m_nested_nodes[i]);
}
}
ptr = or_unpack_int (ptr, &temp_int);
jtn.m_id = (size_t) temp_int;
ptr = or_unpack_int (ptr, &temp_int);
jtn.m_is_iterable_node = (bool) temp_int;
return ptr;
}
char *
stx_build (THREAD_ENTRY *thread_p, char *ptr, cubxasl::json_table::spec_node &json_table_spec)
{
json_table_spec.init ();
int node_count;
ptr = or_unpack_int (ptr, &node_count);
json_table_spec.m_node_count = (size_t) (node_count);
stx_restore (thread_p, ptr, json_table_spec.m_json_reguvar);
stx_alloc (thread_p, json_table_spec.m_root_node);
assert (json_table_spec.m_root_node != NULL);
json_table_spec.m_root_node->init ();
ptr = stx_build (thread_p, ptr, *json_table_spec.m_root_node);
return ptr;
}
char *
stx_build (THREAD_ENTRY *thread_p, char *ptr, db_value &val)
{
return stx_build_db_value (thread_p, ptr, &val);
}
char *
stx_unpack (THREAD_ENTRY *thread_p, char *ptr, json_table_column_behavior &behavior)
{
int temp;
ptr = or_unpack_int (ptr, &temp);
behavior.m_behavior = (json_table_column_behavior_type) temp;
if (behavior.m_behavior == JSON_TABLE_DEFAULT_VALUE)
{
behavior.m_default_value = (DB_VALUE *) stx_alloc_struct (thread_p, sizeof (DB_VALUE));
ptr = stx_build (thread_p, ptr, *behavior.m_default_value);
}
return ptr;
}
bool
xasl_stream_compare (const cubxasl::json_table::column &first, const cubxasl::json_table::column &second)
{
if (first.m_function != second.m_function)
{
return false;
}
return true;
}
bool
xasl_stream_compare (const cubxasl::json_table::node &first, const cubxasl::json_table::node &second)
{
if (first.m_output_columns_size != second.m_output_columns_size)
{
return false;
}
if (first.m_nested_nodes_size != second.m_nested_nodes_size)
{
return false;
}
if (first.m_id != second.m_id)
{
return false;
}
if (first.m_is_iterable_node != second.m_is_iterable_node)
{
return false;
}
return true;
}
bool
xasl_stream_compare (const cubxasl::json_table::spec_node &first, const cubxasl::json_table::spec_node &second)
{
if (first.m_node_count != second.m_node_count)
{
return false;
}
return true;
}