File db_query.c¶
File List > compat > db_query.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.
*
*/
/*
* db_query.c - QUERY INTERFACE MODULE (Client Side)
*/
#ident "$Id$"
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "db_query.h"
#include "error_manager.h"
#include "storage_common.h"
#include "object_representation.h"
#include "object_primitive.h"
#include "db.h"
#include "schema_manager.h"
#include "server_interface.h"
#include "system_parameter.h"
#include "xasl_generation.h"
#include "network_interface_cl.h"
#include "transaction_cl.h"
#include "dbtype.h"
#define DB_OID_INCLUDED(r) ((r)->oid_included == true)
#define DB_INVALID_INDEX(i,cnt) ((i) < 0 || (i) >= (cnt))
#define DB_INVALID_RESTYPE(t) \
((t) != T_SELECT && \
(t) != T_CALL && \
(t) != T_OBJFETCH && \
(t) != T_GET)
#define PLAN_BUF_INITIAL_LENGTH (1024)
/* A resource mechanism used to effectively handle memory allocation for the
query result structures. */
struct alloc_resource
{
int free_qres_cnt; /* number of free query_result structures */
int max_qres_cnt; /* maximum number of free structures to keep */
DB_QUERY_RESULT *free_qres_list; /* list of free query entry structures */
};
static struct
{ /* global query table variable */
int qres_cnt; /* number of active query entries */
int qres_closed_cnt; /* number of closed query entries */
int entry_cnt; /* # of result list entries */
DB_QUERY_RESULT **qres_list; /* list of query result entries */
struct alloc_resource alloc_res; /* allocation structure resource */
} Qres_table =
{
0, 0, 0, (DB_QUERY_RESULT **) NULL,
{
0, 0, (DB_QUERY_RESULT *) NULL}
}; /* query result table */
static const int QP_QRES_LIST_INIT_CNT = 10;
/* query result list initial cnt */
static const float QP_QRES_LIST_INC_RATE = 1.25f;
/* query result list increment ratio */
static char *db_Execution_plan = NULL;
static int db_Execution_plan_length = -1;
static DB_QUERY_RESULT *allocate_query_result (void);
static void free_query_result (DB_QUERY_RESULT * q_res);
static DB_QUERY_TYPE *db_cp_query_type_helper (DB_QUERY_TYPE * src, DB_QUERY_TYPE * dest);
static int or_packed_query_format_size (const DB_QUERY_TYPE * q, int *count);
static char *or_pack_query_format (char *buf, const DB_QUERY_TYPE * q, const int count);
static char *or_unpack_query_format (char *buf, DB_QUERY_TYPE ** q);
/*
* allocate_query_result() - This function allocates a query_result structure
* from the free list of query_result structures if any, or by malloc to
* allocate a new structure.
* return : DB_QUERY_RESULT pointer or NULL
*/
static DB_QUERY_RESULT *
allocate_query_result (void)
{
DB_QUERY_RESULT *q_res;
q_res = Qres_table.alloc_res.free_qres_list;
if (q_res != NULL)
{
Qres_table.alloc_res.free_qres_list = q_res->next;
Qres_table.alloc_res.free_qres_cnt--;
}
else
{
q_res = (DB_QUERY_RESULT *) malloc (DB_SIZEOF (DB_QUERY_RESULT));
if (q_res == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, DB_SIZEOF (DB_QUERY_RESULT));
}
}
return q_res;
}
/*
* free_query_result() - This function frees the query_result structure by
* putting it to the free query_result structure list if there are not
* many in the list, or by calling db_free.
* return : void
* q_res(in): Query result structure to be freed.
*/
static void
free_query_result (DB_QUERY_RESULT * q_res)
{
if (Qres_table.alloc_res.free_qres_cnt < Qres_table.alloc_res.max_qres_cnt)
{
q_res->next = Qres_table.alloc_res.free_qres_list;
Qres_table.alloc_res.free_qres_list = q_res;
Qres_table.alloc_res.free_qres_cnt++;
}
else
{
free_and_init (q_res);
}
}
/*
* db_free_query_format() - This function frees the query type area.
* return : void
* q(in): Pointer to the query type list
*
* note : p->domain is a pointer to a cached domain structure,
* and should no longer be freed.
*/
void
db_free_query_format (DB_QUERY_TYPE * q)
{
DB_QUERY_TYPE *p, *n;
n = q;
while (n != NULL)
{
p = n;
n = n->next;
if (p->name != NULL)
{
free_and_init (p->name);
}
if (p->attr_name != NULL)
{
free_and_init (p->attr_name);
}
if (p->spec_name != NULL)
{
free_and_init (p->spec_name);
}
if (p->original_name != NULL)
{
free_and_init (p->original_name);
}
if (p->src_domain != NULL)
{
sm_domain_free (p->src_domain);
}
free_and_init (p);
}
}
/*
* or_packed_query_format_size - calculate the size of the packed query format
* return: size
* columns(in): query format information
* count (out): will hold the count of columns when the function returns
*/
static int
or_packed_query_format_size (const DB_QUERY_TYPE * columns, int *count)
{
int size = 0;
int len = 0;
int columns_cnt = 0;
const DB_QUERY_TYPE *column = NULL;
/* number of columns in the list */
size = OR_INT_SIZE;
if (columns == NULL)
{
/* only an integer containing the size (0) */
return size;
}
for (column = columns; column != NULL; column = column->next)
{
/* column type */
size += OR_INT_SIZE;
/* column name */
size += or_packed_string_length (column->name, &len);
/* attribute name */
size += or_packed_string_length (column->attr_name, &len);
/* spec name */
size += or_packed_string_length (column->spec_name, &len);
/* user specified column name */
size += or_packed_string_length (column->original_name, &len);
/* column data type */
size += OR_INT_SIZE;
/* column data size */
size += OR_INT_SIZE;
/* column domain information */
size += or_packed_domain_size (column->domain, true);
/* column source domain information */
size += or_packed_domain_size (column->src_domain, true);
/* column user visible */
size += OR_INT_SIZE;
columns_cnt++;
}
*count = columns_cnt;
return size;
}
/*
* or_pack_query_format - pack a query format list
* return : advanced pointer
* buf (in) : buffer pointer
* columns (in): the query format list
* count (in) : the count of query format contained in the list
*/
static char *
or_pack_query_format (char *buf, const DB_QUERY_TYPE * columns, const int count)
{
char *ptr = NULL;
int len = 0;
const DB_QUERY_TYPE *column;
if (count != 0)
{
/* sanity check */
assert (columns != NULL);
}
/* pack the number of columns */
ptr = or_pack_int (buf, count);
if (count == 0)
{
return ptr;
}
for (column = columns; column != NULL; column = column->next)
{
/* column type */
ptr = or_pack_int (ptr, (int) column->col_type);
/* column name */
len = (column->name == NULL) ? 0 : (int) strlen (column->name);
ptr = or_pack_string_with_length (ptr, column->name, len);
/* attribute name */
len = (column->attr_name == NULL) ? 0 : (int) strlen (column->attr_name);
ptr = or_pack_string_with_length (ptr, column->attr_name, len);
/* spec name */
len = (column->spec_name == NULL) ? 0 : (int) strlen (column->spec_name);
ptr = or_pack_string_with_length (ptr, column->spec_name, len);
/* user specified column name */
len = (column->original_name == NULL) ? 0 : (int) strlen (column->original_name);
ptr = or_pack_string_with_length (ptr, column->original_name, len);
/* column data type */
ptr = or_pack_int (ptr, column->db_type);
/* column data size */
ptr = or_pack_int (ptr, column->size);
/* column domain information */
ptr = or_pack_domain (ptr, column->domain, 1, 1);
/* column source domain information */
ptr = or_pack_domain (ptr, column->src_domain, 1, 1);
/* column user visible */
ptr = or_pack_int (ptr, column->visible_type);
}
return ptr;
}
/*
* or_unpack_query_format - unpack a query format list
* return : advanced pointer
* buf (in) : buffer pointer
* columns (in/out): the columns list
* count (in/out) : the count of columns contained in the list
*
* Note: This function allocates memory for all members of the query format
* object. This memory is not allocated in the private heap of the current
* thread and needs to be released using free_and_init.
*/
static char *
or_unpack_query_format (char *buf, DB_QUERY_TYPE ** columns)
{
char *ptr = NULL;
int size = 0, i = 0;
DB_QUERY_TYPE *head = NULL, *current = NULL;
TP_DOMAIN *tp_dom = NULL;
ptr = or_unpack_int (buf, &size);
for (i = 0; i < size; i++)
{
int tmp = 0;
DB_QUERY_TYPE *column = (DB_QUERY_TYPE *) malloc (sizeof (DB_QUERY_TYPE));
if (column == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (DB_QUERY_TYPE));
goto error_cleanup;
}
/* column type */
ptr = or_unpack_int (ptr, &tmp);
column->col_type = (DB_COL_TYPE) tmp;
/* column name */
ptr = or_unpack_string_alloc (ptr, &(column->name));
/* attribute name */
ptr = or_unpack_string_alloc (ptr, &(column->attr_name));
/* spec name */
ptr = or_unpack_string_alloc (ptr, &(column->spec_name));
/* user specified column name */
ptr = or_unpack_string_alloc (ptr, &(column->original_name));
/* column data type */
ptr = or_unpack_int (ptr, &tmp);
column->db_type = (DB_TYPE) tmp;
/* column data size */
ptr = or_unpack_int (ptr, &(column->size));
/* column domain information */
ptr = or_unpack_domain (ptr, &tp_dom, NULL);
if (tp_dom != NULL)
{
column->domain = tp_domain_cache (tp_dom);
}
else
{
column->domain = NULL;
}
tp_domain_free (tp_dom);
tp_dom = NULL;
/* column source domain */
ptr = or_unpack_domain (ptr, &tp_dom, NULL);
if (tp_dom != NULL)
{
column->src_domain = sm_domain_copy (tp_dom);
}
else
{
column->src_domain = NULL;
}
tp_domain_free (tp_dom);
/* column user visible */
ptr = or_unpack_int (ptr, &tmp);
column->visible_type = (COL_VISIBLE_TYPE) tmp;
column->next = NULL;
if (head == NULL)
{
head = column;
current = head;
}
else
{
current->next = column;
current = current->next;
}
}
*columns = head;
return ptr;
error_cleanup:
while (head != NULL)
{
current = head;
head = head->next;
/* free name */
free_and_init (current->name);
/* free attribute name */
free_and_init (current->attr_name);
/* free spec name */
free_and_init (current->spec_name);
/* free user specified column name */
free_and_init (current->original_name);
free_and_init (current);
}
return ptr;
}
/*
* db_init_prepare_info () - initialize a prepare info object
* return : void
* info (in/out): prepare info
*/
void
db_init_prepare_info (DB_PREPARE_INFO * info)
{
assert (info != NULL);
info->statement = NULL;
info->columns = NULL;
info->host_variables.size = 0;
info->host_variables.vals = NULL;
info->host_var_expected_domains = NULL;
info->auto_param_count = 0;
info->recompile = 0;
info->oids_included = 0;
info->into_list = NULL;
info->into_count = 0;
/* for subquery result-cache */
info->subquery_num = 0;
info->subquery_info = NULL;
}
/*
* db_pack_prepare_info () - pack a prepare info object
* return : packed size or error
* info (in) : prepared info
* buffer (out) : buffer to pack to
*/
int
db_pack_prepare_info (const DB_PREPARE_INFO * info, char **buffer)
{
char *ptr = NULL;
int packed_size = 0, i = 0;
int query_len = 0, columns_cnt = 0;
assert (*buffer == NULL);
assert (info != NULL);
/* calculate packed size */
/* parameters */
packed_size += OR_INT_SIZE;
if (info->host_variables.size != 0)
{
int size = 0, i = 0;
for (i = 0; i < info->host_variables.size; i++)
{
size += OR_VALUE_ALIGNED_SIZE (&(info->host_variables.vals[i]));
}
packed_size += size;
size = 0;
for (i = 0; i < info->host_variables.size - info->auto_param_count; i++)
{
size += or_packed_domain_size (info->host_var_expected_domains[i], 0);
}
packed_size += size;
}
/* calculate size for columns */
packed_size += or_packed_query_format_size (info->columns, &columns_cnt);
/* packed size for query */
packed_size += or_packed_string_length (info->statement, &query_len);
/* statement type */
packed_size += OR_INT_SIZE;
/* auto parameters count */
packed_size += OR_INT_SIZE;
/* recompile */
packed_size += OR_INT_SIZE;
/* do_cache */
packed_size += OR_INT_SIZE;
/* oids included */
packed_size += OR_INT_SIZE;
/* into list length */
packed_size += OR_INT_SIZE;
/* into list names */
for (i = 0; i < info->into_count; i++)
{
packed_size += or_packed_string_length (info->into_list[i], NULL);
}
/* subquery_num */
packed_size += OR_INT_SIZE;
if (info->subquery_num > 0)
{
/* subquery's xasl_id */
packed_size += OR_XASL_ID_SIZE * info->subquery_num;
/* subquery's host_var_count */
packed_size += OR_INT_SIZE * info->subquery_num;
for (i = 0; i < info->subquery_num; i++)
{
/* subquery's host_var_index */
packed_size += OR_INT_SIZE * info->subquery_info[i].host_var_count;
}
}
ptr = (char *) malloc (packed_size);
if (ptr == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) packed_size);
return ER_FAILED;
}
*buffer = ptr;
/* begin packing */
/* columns */
ptr = or_pack_query_format (ptr, info->columns, columns_cnt);
/* query */
ptr = or_pack_string_with_length (ptr, info->statement, query_len);
/* statement type */
ptr = or_pack_int (ptr, info->stmt_type);
/* auto parameters count */
ptr = or_pack_int (ptr, info->auto_param_count);
/* recompile */
ptr = or_pack_int (ptr, info->recompile);
/* do_cache */
ptr = or_pack_int (ptr, info->do_cache);
/* oids included */
ptr = or_pack_int (ptr, info->oids_included);
/* into list length */
ptr = or_pack_int (ptr, info->into_count);
for (i = 0; i < info->into_count; i++)
{
ptr = or_pack_string (ptr, info->into_list[i]);
}
/* parameters */
if (info->host_variables.size == 0)
{
ptr = or_pack_int (ptr, 0);
}
else
{
int i = 0;
ptr = or_pack_int (ptr, info->host_variables.size);
for (i = 0; i < info->host_variables.size; i++)
{
ptr = or_pack_db_value (ptr, &(info->host_variables.vals[i]));
}
for (i = 0; i < info->host_variables.size - info->auto_param_count; i++)
{
ptr = or_pack_domain (ptr, info->host_var_expected_domains[i], 0, 0);
}
}
/* subquery */
ptr = or_pack_int (ptr, info->subquery_num);
for (i = 0; i < info->subquery_num; i++)
{
int k;
OR_PACK_XASL_ID (ptr, &(info->subquery_info[i].xasl_id));
ptr = or_pack_int (ptr, info->subquery_info[i].host_var_count);
for (k = 0; k < info->subquery_info[i].host_var_count; k++)
{
ptr = or_pack_int (ptr, info->subquery_info[i].host_var_index[k]);
}
}
return packed_size;
}
/*
* db_unpack_prepare_info () - unpack a DB_PREPARE_INFO object
* return : error code or NO_ERROR
* info (out) : DB_PREPARE_INFO object
* buffer (in): serialized form of the DB_PREPARE_INFO object
*/
int
db_unpack_prepare_info (DB_PREPARE_INFO * info, char *buffer)
{
int i, subquery_num, q = 0;
char *ptr = NULL;
assert (info != NULL);
assert (buffer != NULL);
/* unpack column info */
ptr = or_unpack_query_format (buffer, &info->columns);
/* unpack query */
ptr = or_unpack_string_alloc (ptr, &info->statement);
/* unpack statement type */
ptr = or_unpack_int (ptr, (int *) &info->stmt_type);
/* unpack auto parameters count */
ptr = or_unpack_int (ptr, &info->auto_param_count);
/* unpack recompile */
ptr = or_unpack_int (ptr, &info->recompile);
/* unpack do_cache */
ptr = or_unpack_int (ptr, &info->do_cache);
/* oids included */
ptr = or_unpack_int (ptr, &info->oids_included);
/* unpack into list length */
ptr = or_unpack_int (ptr, &info->into_count);
if (info->into_count > 0)
{
info->into_list = (char **) malloc (info->into_count * sizeof (char *));
if (info->into_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, info->into_count * sizeof (char *));
goto error;
}
for (i = 0; i < info->into_count; i++)
{
ptr = or_unpack_string_alloc (ptr, &info->into_list[i]);
}
}
/* unpack parameters */
ptr = or_unpack_int (ptr, &(info->host_variables.size));
if (info->host_variables.size > 0)
{
unsigned int i = 0, var_count;
var_count = info->host_variables.size;
info->host_variables.vals = (DB_VALUE *) malloc (var_count * sizeof (DB_VALUE));
if (info->host_variables.vals == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
info->host_variables.size * sizeof (DB_VALUE));
goto error;
}
for (i = 0; i < var_count; i++)
{
ptr = or_unpack_db_value (ptr, &(info->host_variables.vals[i]));
}
var_count = info->host_variables.size - info->auto_param_count;
info->host_var_expected_domains = (TP_DOMAIN **) malloc (var_count * sizeof (TP_DOMAIN *));
if (info->host_var_expected_domains == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, var_count * sizeof (TP_DOMAIN *));
goto error;
}
for (i = 0; i < var_count; i++)
{
ptr = or_unpack_domain (ptr, &info->host_var_expected_domains[i], NULL);
}
}
/* subquery */
ptr = or_unpack_int (ptr, &info->subquery_num);
subquery_num = info->subquery_num;
if (subquery_num > 0)
{
info->subquery_info = (DB_PREPARE_SUBQUERY_INFO *) calloc (subquery_num, sizeof (DB_PREPARE_SUBQUERY_INFO));
if (info->subquery_info == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
subquery_num * sizeof (DB_PREPARE_SUBQUERY_INFO));
goto error;
}
for (q = 0; q < subquery_num; q++)
{
OR_UNPACK_XASL_ID (ptr, &info->subquery_info[q].xasl_id);
ptr = or_unpack_int (ptr, &info->subquery_info[q].host_var_count);
if (info->subquery_info[q].host_var_count > 0)
{
info->subquery_info[q].host_var_index =
(int *) malloc (info->subquery_info[q].host_var_count * sizeof (int));
if (info->subquery_info[q].host_var_index == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
info->subquery_info[q].host_var_count * sizeof (int));
goto error;
}
for (i = 0; i < info->subquery_info[q].host_var_count; i++)
{
ptr = or_unpack_int (ptr, &info->subquery_info[q].host_var_index[i]);
}
}
}
}
return NO_ERROR;
error:
if (info->statement != NULL)
{
free_and_init (info->statement);
}
if (info->columns != NULL)
{
DB_QUERY_TYPE *col = info->columns;
DB_QUERY_TYPE *next_p = NULL;
while (col != NULL)
{
next_p = col->next;
if (col->name != NULL)
{
free_and_init (col->name);
}
if (col->attr_name != NULL)
{
free_and_init (col->attr_name);
}
if (col->spec_name != NULL)
{
free_and_init (col->spec_name);
}
if (col->original_name != NULL)
{
free_and_init (col->original_name);
}
tp_domain_free (col->domain);
tp_domain_free (col->src_domain);
free_and_init (col);
col = next_p;
}
}
if (info->host_variables.vals != NULL)
{
db_value_clear_array (&info->host_variables);
free_and_init (info->host_variables.vals);
}
if (info->host_var_expected_domains)
{
free_and_init (info->host_var_expected_domains);
}
if (info->into_list != NULL)
{
for (i = 0; i < info->into_count; i++)
{
if (info->into_list[i] != NULL)
{
free_and_init (info->into_list[i]);
}
}
free_and_init (info->into_list);
}
/* subquery */
if (info->subquery_info != NULL)
{
for (i = 0; i < q; i++)
{
if (info->subquery_info[i].host_var_index != NULL)
{
free_and_init (info->subquery_info[i].host_var_index);
}
}
free_and_init (info->subquery_info);
}
return ER_FAILED;
}
#if defined(WINDOWS) || defined (ENABLE_UNUSED_FUNCTION)
/*
* db_free_colname_list() - This function frees the column name list.
* return : void
* colname_list(in): list of column names
* cnt(in): number of names
*/
void
db_free_colname_list (char **colname_list, int cnt)
{
int i;
if (colname_list == NULL)
{
return;
}
for (i = 0; i < cnt; i++)
{
if (colname_list[i] != NULL)
{
free_and_init (colname_list[i]);
}
}
free_and_init (colname_list);
}
/*
* db_free_domain_list() - This function frees the domain list.
* return : void
* domain_list(in): List of domain pointers
* cnt(in): Number of domain pointers
*/
void
db_free_domain_list (SM_DOMAIN ** domain_list, int cnt)
{
int i;
if (domain_list == NULL)
{
return;
}
for (i = 0; i < cnt; i++)
{
if (domain_list[i] != NULL)
{
sm_domain_free (domain_list[i]);
}
}
free_and_init (domain_list);
}
#endif
/*
* db_free_query_result() - This function frees the areas allocated for the
* query result structure and also the supplied query result structure
* pointer r.
* return : void
* r(in): Query Result Structure pointer
*/
void
db_free_query_result (DB_QUERY_RESULT * r)
{
DB_VALUE **valp;
int k;
#if defined (ENABLE_UNUSED_FUNCTION)
DB_VALUE *val;
#endif
if (r == NULL)
{
return;
}
/* disconnect query result from the query table */
#if defined(QP_DEBUG)
if (Qres_table.qres_list[r->qtable_ind] != r)
{
(void) fprintf (stdout, "*WARNING*: Misconnection between the query" "result structure and query table.\n");
return;
}
#endif
Qres_table.qres_list[r->qtable_ind] = (DB_QUERY_RESULT *) NULL;
Qres_table.qres_cnt--;
if (r->status == T_CLOSED && Qres_table.qres_closed_cnt > 0)
{
Qres_table.qres_closed_cnt--;
}
/* free type list */
db_free_query_format (r->query_type);
r->query_type = NULL;
switch (r->type)
{
case T_SELECT:
break;
case T_CALL:
db_value_free (r->res.c.val_ptr);
break;
case T_OBJFETCH:
{
for (k = 0, valp = r->res.o.valptr_list; k < r->col_cnt; k++, valp++)
{
db_value_free (*valp);
}
free_and_init (r->res.o.valptr_list);
}
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
{
for (k = 0, val = r->res.g.tpl_list; k < (r->res.g.n_tuple * r->col_cnt); k++, val++)
{
db_value_clear (val);
}
free_and_init (r->res.g.tpl_list);
}
break;
#endif
default:
break;
}
r->status = T_CLOSED;
free_query_result (r);
}
/*
* db_alloc_query_format() - This function allocates specified number of type
* list nodes. And query type pointer set to the beginning of allocated list
* is returned.
* return : query type pointer or NULL on failure
* cnt(in): number of nodes in the type list
*/
DB_QUERY_TYPE *
db_alloc_query_format (int cnt)
{
DB_QUERY_TYPE *p, *q;
int k;
if (cnt == 0)
{
return NULL;
}
q = (DB_QUERY_TYPE *) malloc (DB_SIZEOF (DB_QUERY_TYPE));
if (q == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, DB_SIZEOF (DB_QUERY_TYPE));
return NULL;
}
/* initialize */
q->db_type = DB_TYPE_NULL;
q->size = 0;
q->name = (char *) NULL;
q->attr_name = (char *) NULL;
q->spec_name = (char *) NULL;
q->original_name = (char *) NULL;
q->domain = (SM_DOMAIN *) NULL;
q->src_domain = (SM_DOMAIN *) NULL;
q->visible_type = USER_COLUMN;
q->col_type = DB_COL_OTHER;
for (k = 0, p = q, p->next = NULL; k < cnt - 1; k++, p = p->next, p->next = NULL)
{
p->next = (DB_QUERY_TYPE *) malloc (DB_SIZEOF (DB_QUERY_TYPE));
if (p->next == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, DB_SIZEOF (DB_QUERY_TYPE));
db_free_query_format (q);
return NULL;
}
/* initialize */
p->next->db_type = DB_TYPE_NULL;
p->next->size = 0;
p->next->name = (char *) NULL;
p->next->attr_name = (char *) NULL;
p->next->spec_name = (char *) NULL;
p->next->original_name = (char *) NULL;
p->next->domain = (SM_DOMAIN *) NULL;
p->next->src_domain = (SM_DOMAIN *) NULL;
p->next->visible_type = USER_COLUMN;
p->next->col_type = DB_COL_OTHER;
}
return q;
}
/*
* db_alloc_query_result() - This function allocates a query result structure
* for the indicated type and column count.
* return : query result pointer or NULL on failure.
* r_type(in): query Result Structure type
* col_cnt(in): column count
*/
DB_QUERY_RESULT *
db_alloc_query_result (DB_RESULT_TYPE r_type, int col_cnt)
{
DB_QUERY_RESULT *r, **qres_ptr;
int ind, k;
int new_cnt;
#if defined(QP_DEBUG)
if (DB_INVALID_RESTYPE (r_type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return (DB_QUERY_RESULT *) NULL;
}
#endif
/* first search query table result list to see if there is place */
for (ind = 0, qres_ptr = Qres_table.qres_list; ind < Qres_table.entry_cnt && *qres_ptr != NULL; ind++, qres_ptr++)
{
; /* NULL */
}
if (ind == Qres_table.entry_cnt)
{
/* query table is full, so enlarge the table */
if (Qres_table.entry_cnt == 0)
{ /* first time allocation */
Qres_table.qres_list = (DB_QUERY_RESULT **) malloc (QP_QRES_LIST_INIT_CNT * DB_SIZEOF (DB_QUERY_RESULT *));
if (Qres_table.qres_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
QP_QRES_LIST_INIT_CNT * DB_SIZEOF (DB_QUERY_RESULT *));
return (DB_QUERY_RESULT *) NULL;
}
Qres_table.entry_cnt = QP_QRES_LIST_INIT_CNT;
/* initialize query_result allocation resource */
Qres_table.alloc_res.free_qres_cnt = 0;
Qres_table.alloc_res.max_qres_cnt = Qres_table.entry_cnt;
Qres_table.alloc_res.free_qres_list = (DB_QUERY_RESULT *) NULL;
}
else
{
/* expand the existing table */
new_cnt = (int) ((Qres_table.entry_cnt * QP_QRES_LIST_INC_RATE) + 1);
Qres_table.qres_list =
(DB_QUERY_RESULT **) realloc (Qres_table.qres_list, new_cnt * DB_SIZEOF (DB_QUERY_RESULT *));
if (Qres_table.qres_list == NULL)
{
return (DB_QUERY_RESULT *) NULL;
}
Qres_table.entry_cnt = new_cnt;
/* expand query result allocation resource */
Qres_table.alloc_res.max_qres_cnt = Qres_table.entry_cnt;
}
/* initialize newly allocated entries */
for (k = ind, qres_ptr = (DB_QUERY_RESULT **) Qres_table.qres_list + ind; k < Qres_table.entry_cnt;
k++, qres_ptr++)
{
*qres_ptr = (DB_QUERY_RESULT *) NULL;
}
}
qres_ptr = (DB_QUERY_RESULT **) Qres_table.qres_list + ind;
*qres_ptr = allocate_query_result ();
if (*qres_ptr == NULL)
{
return (DB_QUERY_RESULT *) NULL;
}
/* connect query result structure to the query table */
r = *qres_ptr;
r->qtable_ind = ind;
Qres_table.qres_cnt++;
/* allocation of query type list is done later */
r->query_type = (DB_QUERY_TYPE *) NULL;
r->type_cnt = 0;
switch (r_type)
{
case T_SELECT:
break;
case T_CALL:
r->res.c.val_ptr = (DB_VALUE *) NULL;
break;
case T_OBJFETCH:
{
r->res.o.valptr_list = (DB_VALUE **) malloc (col_cnt * DB_SIZEOF (DB_VALUE *));
if (r->res.o.valptr_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, col_cnt * DB_SIZEOF (DB_VALUE *));
db_free_query_result (r);
return NULL;
}
/*
* Initialize the vector so that db_free_query_result() doesn't go
* haywire if this QUERY_RESULT gets freed before being completely
* populated.
*/
for (k = 0; k < col_cnt; k++)
r->res.o.valptr_list[k] = NULL;
}
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
if (col_cnt <= 0)
{
r->res.g.tpl_list = NULL;
}
else
{
r->res.g.tpl_list = (DB_VALUE *) malloc (col_cnt * DB_SIZEOF (DB_VALUE));
if (r->res.g.tpl_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, col_cnt * DB_SIZEOF (DB_VALUE));
db_free_query_result (r);
return NULL;
}
for (k = 0; k < col_cnt; k++)
{
db_make_null (&r->res.g.tpl_list[k]);
}
}
break;
#endif
default:
break;
}
return r;
}
/*
* db_init_query_result() - This function initializes the query result
* structure according to the type.
* return : void
* r(out): query Result Structure
* r_type(in): query Result Structure Type
*/
void
db_init_query_result (DB_QUERY_RESULT * r, DB_RESULT_TYPE r_type)
{
if (r == NULL)
{
return;
}
r->type = r_type;
r->status = T_OPEN;
r->col_cnt = 0;
r->oid_included = false;
switch (r->type)
{
case T_SELECT:
{
r->res.s.query_id = -1;
r->res.s.stmt_id = -1;
r->res.s.stmt_type = (CUBRID_STMT_TYPE) 0;
CACHE_TIME_RESET (&r->res.s.cache_time);
}
break;
case T_CALL:
r->res.c.crs_pos = C_BEFORE;
break;
case T_OBJFETCH:
r->res.o.crs_pos = C_BEFORE;
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
{
r->res.g.crs_pos = C_BEFORE;
r->res.g.tpl_idx = 0;
}
break;
#endif
default:
break;
}
r->next = (DB_QUERY_RESULT *) NULL;
}
#if defined(WINDOWS) || defined (CUBRID_DEBUG)
/*
* db_dump_query_result() - this function dumps the content of the query result
* structure to standard output.
* return : void
* r: Query Result Structure
*/
void
db_dump_query_result (DB_QUERY_RESULT * r)
{
if (r == NULL)
{
return;
}
#if defined(QP_DEBUG)
if (DB_INVALID_RESTYPE (r->type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return;
}
#endif
fprintf (stdout, "\nQuery Result Structure: \n");
fprintf (stdout, "Type: %s \n",
(r->type == T_SELECT) ? "T_SELECT" : (r->type == T_CALL) ? "T_CALL"
: (r->type == T_OBJFETCH) ? "T_OBJFETCH" : (r->type == T_GET) ? "T_GET" : "T_UNKNOWN");
fprintf (stdout, "Status: %s \n",
(r->status == T_OPEN) ? "T_OPEN" : (r->status == T_CLOSED) ? "T_CLOSED" : "T_UNKNOWN");
fprintf (stdout, "Column Count: %d \n", r->col_cnt);
fprintf (stdout, "Oid_Included: %s \n", (r->oid_included) ? "Yes" : "No");
fprintf (stdout, "\n");
if (r->type == T_SELECT)
{
fprintf (stdout, "Query_id: %lld \n", (long long) r->res.s.query_id);
fprintf (stdout, "Stmt_id: %d \n", r->res.s.stmt_id);
fprintf (stdout, "Tuple Cnt: %lld \n", (long long) r->res.s.cursor_id.list_id.tuple_cnt);
fprintf (stdout, "Stmt_type: %d \n", r->res.s.stmt_type);
} /* if */
else if (r->type == T_GET)
{
fprintf (stdout, "Tuple Cnt: %d \n", r->res.g.n_tuple);
}
fprintf (stdout, "\n");
}
#endif
#if defined(WINDOWS) || defined (ENABLE_UNUSED_FUNCTION)
/*
* db_cp_colname_list() - This function forms a new column name list from the
* given one.
* return : column name list. NULL on error
* colname_list(in): List of column names
* cnt(in): Number of columns
*
* note : The returned column name list must be freed with db_free_colname_list
*/
char **
db_cp_colname_list (char **colname_list, int cnt)
{
char **newname_list;
int i;
size_t size;
if (colname_list == NULL)
{
return NULL;
}
newname_list = (char **) malloc (cnt * DB_SIZEOF (char *));
if (newname_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, cnt * DB_SIZEOF (char *));
return NULL;
}
for (i = 0; i < cnt; i++)
{
newname_list[i] = NULL;
}
for (i = 0; i < cnt; i++)
{
size = strlen (colname_list[i]) + 1;
newname_list[i] = (char *) malloc (size);
if (newname_list[i] == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size);
db_free_colname_list (newname_list, cnt);
return NULL;
}
memcpy (newname_list[i], colname_list[i], size);
}
return newname_list;
}
/*
* db_cp_domain_list() - This function forms a new domain list pointer.
* return : new domain list. NULL on error.
* domain_list(in): List of domain pointers
* cnt(in): Number of domain pointers
*
* note: The content of each domain pointer is NOT copied to a new area, only
* pointers are set to the contents. There the actual domain pointers
* must NOT be freed until qp_free_domain_ptr() is explicitly called.
*/
SM_DOMAIN **
db_cp_domain_list (SM_DOMAIN ** domain_list, int cnt)
{
SM_DOMAIN **newdomain_list;
int i;
if (domain_list == NULL)
{
return NULL;
}
newdomain_list = (SM_DOMAIN **) malloc (cnt * DB_SIZEOF (SM_DOMAIN *));
if (newdomain_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, cnt * DB_SIZEOF (SM_DOMAIN *));
return NULL;
}
for (i = 0; i < cnt; i++)
{
newdomain_list[i] = NULL;
}
for (i = 0; i < cnt; i++)
{
newdomain_list[i] = sm_domain_copy (domain_list[i]);
if (newdomain_list[i] == NULL)
{
db_free_domain_list (newdomain_list, cnt);
return NULL;
}
}
return newdomain_list;
}
#endif
/*
* db_clear_client_query_result() - This function is called when a transaction
* commits/aborts on the client or when the server goes down, in order to
* close the existing the query result structures.
* return : void
* notify_server(in) :
*/
void
db_clear_client_query_result (int notify_server, bool end_holdable)
{
DB_QUERY_RESULT **qres_ptr;
int k;
/* search query table result list and mark existing entries as closed */
for (k = 0, qres_ptr = Qres_table.qres_list; k < Qres_table.entry_cnt; k++, qres_ptr++)
{
if (*qres_ptr == NULL)
{
continue;
}
if (((*qres_ptr)->type == T_SELECT && !(*qres_ptr)->res.s.holdable) || end_holdable)
{
/* if end_holdable is false, only end queries that are not holdable */
db_query_end_internal (*qres_ptr, notify_server);
}
}
}
/*
* db_cp_query_type_helper() - Copies the given type to a newly allocated type
* return : dest or NULL on error.
* src(in): query type to be copied
* dest(in): query type newly allocated
*
* note : It is no longer necessary to use regu_cp_domain() to copy the
* domain field, since it is now a pointer to a cached domain structure.
*/
static DB_QUERY_TYPE *
db_cp_query_type_helper (DB_QUERY_TYPE * src, DB_QUERY_TYPE * dest)
{
size_t size;
if (TP_DOMAIN_COLLATION_FLAG (src->domain) != TP_DOMAIN_COLL_NORMAL)
{
/* special collation domain behave like VARIABLE in query output */
assert (TP_TYPE_HAS_COLLATION (src->db_type));
dest->db_type = DB_TYPE_VARIABLE;
dest->size = 0;
dest->domain = tp_domain_resolve_default (DB_TYPE_VARIABLE);
}
else
{
dest->db_type = src->db_type;
dest->size = src->size;
dest->domain = src->domain;
}
dest->name = NULL;
dest->attr_name = NULL;
dest->spec_name = NULL;
dest->original_name = NULL;
dest->src_domain = NULL;
dest->visible_type = src->visible_type;
dest->col_type = src->col_type;
if (src->name != NULL)
{
size = strlen (src->name) + 1;
dest->name = (char *) malloc (size);
if (dest->name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size);
return NULL;
}
memcpy ((char *) dest->name, src->name, size);
}
if (src->attr_name != NULL)
{
size = strlen (src->attr_name) + 1;
dest->attr_name = (char *) malloc (size);
if (dest->attr_name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size);
return NULL;
}
memcpy ((char *) dest->attr_name, src->attr_name, size);
}
if (src->spec_name != NULL)
{
size = strlen (src->spec_name) + 1;
dest->spec_name = (char *) malloc (size);
if (dest->spec_name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size);
return NULL;
}
memcpy ((char *) dest->spec_name, src->spec_name, size);
}
if (src->original_name != NULL)
{
size = strlen (src->original_name) + 1;
dest->original_name = (char *) malloc (size);
if (dest->original_name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size);
return NULL;
}
memcpy ((char *) dest->original_name, src->original_name, size);
}
if (src->src_domain != NULL)
{
dest->src_domain = sm_domain_copy (src->src_domain);
}
return dest;
}
/*
* db_cp_query_type() - This function copies the given type list into a newly
* allocated type list.
* return : new type list or NULL on error.
* query_type(in): query type list to be copied
* copy_only_user(in):
*/
DB_QUERY_TYPE *
db_cp_query_type (DB_QUERY_TYPE * query_type, int copy_only_user)
{
DB_QUERY_TYPE *q;
DB_QUERY_TYPE *ptr1, *ptr2;
int cnt;
/* find count of nodes to copy */
for (cnt = 0, ptr1 = query_type; ptr1; ptr1 = ptr1->next)
{
if ((ptr1->visible_type != SYSTEM_ADDED_COLUMN) && (!copy_only_user || ptr1->visible_type == USER_COLUMN))
{
cnt++;
}
}
q = db_alloc_query_format (cnt);
if (q == NULL)
{
return NULL;
}
for (ptr1 = query_type, ptr2 = q; ptr1; ptr1 = ptr1->next)
{
if ((ptr1->visible_type != SYSTEM_ADDED_COLUMN) && (!copy_only_user || ptr1->visible_type == USER_COLUMN))
{
ptr2 = db_cp_query_type_helper (ptr1, ptr2);
if (ptr2 == NULL)
{
db_free_query_format (q);
return NULL;
}
ptr2 = ptr2->next;
}
}
return q;
}
#if defined(WINDOWS) || defined (ENABLE_UNUSED_FUNCTION)
/*
* db_get_query_type() - This function forms a query type list structure from
* the given parmeters. The cnt field refers to number of nodes in the
* provided lists which is actual column count of the query result list file.
* If oid_included is set to true, the first node of the lists which
* correspond to the first hidden oid column is eliminated from the formed
* type list.
* return : DB_QUERY_TYPE pointer or NULL.
* type_list(in): data type list
* size_list(in): size list
* colname_list(in): column name list(can be NULL)
* attrname_list(in): attribute name list(can be NULL)
* domain_list(in): domain list(can be NULL)
* src_domain_list(in): source Domain list(can be NULL)
* cnt(in): number of columns
* oid_included(in): hidden first oid column included
*/
DB_QUERY_TYPE *
db_get_query_type (DB_TYPE * type_list, int *size_list, char **colname_list, char **attrname_list,
SM_DOMAIN ** domain_list, SM_DOMAIN ** src_domain_list, int cnt, bool oid_included)
{
DB_QUERY_TYPE *q, *type_ptr;
DB_TYPE *typep;
char **colnamep;
char **attrnamep;
SM_DOMAIN **domainp;
SM_DOMAIN **src_domainp;
int *sizep;
int k;
int type_cnt;
size_t size;
CHECK_CONNECT_NULL ();
if (type_list == NULL || size_list == NULL || cnt <= 0)
{
return NULL;
}
type_cnt = (oid_included) ? (cnt - 1) : cnt;
q = db_alloc_query_format (type_cnt);
if (q == NULL)
{
return NULL;
}
typep = type_list;
sizep = size_list;
colnamep = colname_list;
attrnamep = attrname_list;
domainp = domain_list;
src_domainp = src_domain_list;
type_ptr = q;
for (k = 0; k < cnt; k++)
{
if (!(oid_included && k == 0))
{
type_ptr->db_type = *typep;
type_ptr->size = *sizep;
type_ptr->name = (char *) NULL;
type_ptr->attr_name = (char *) NULL;
type_ptr->spec_name = (char *) NULL;
type_ptr->original_name = (char *) NULL;
type_ptr->domain = (SM_DOMAIN *) NULL;
type_ptr->src_domain = (SM_DOMAIN *) NULL;
type_ptr->visible_type = USER_COLUMN;
if (colname_list)
{
/* column names can NOT be NULL */
size = strlen (*colnamep) + 1;
type_ptr->name = (char *) malloc (size);
if (type_ptr->name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size);
db_free_query_format (q);
return NULL;
}
memcpy ((char *) type_ptr->name, *colnamep, size);
}
if (attrname_list)
{
if (*attrnamep) /* attribute names can be NULL */
{
size = strlen (*attrnamep) + 1;
type_ptr->attr_name = (char *) malloc (size);
if (type_ptr->attr_name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size);
db_free_query_format (q);
return NULL;
}
memcpy ((char *) type_ptr->attr_name, *attrnamep, size);
}
}
if (domain_list)
{
type_ptr->domain = sm_domain_copy (*domainp);
}
if (src_domain_list)
{
type_ptr->src_domain = sm_domain_copy (*src_domainp);
}
type_ptr = type_ptr->next;
}
typep++;
sizep++;
if (colname_list)
{
colnamep++;
}
if (attrname_list)
{
attrnamep++;
}
if (domain_list)
{
domainp++;
}
if (src_domain_list)
{
src_domainp++;
}
}
return q;
}
#endif
/*
* db_execute_with_values() - This function executes a dynamic sql select query
* with input values
* return : error code
* CSQL_query (IN) : query string to be executed
* result (OUT): pointer to the query result structure
* query_error (OUT): set to the error information, if any.
* arg_count (IN) : number of input values
* vals (IN) : input values
*/
int
db_execute_with_values (const char *CSQL_query, DB_QUERY_RESULT ** result, DB_QUERY_ERROR * query_error, int arg_count,
DB_VALUE * vals)
{
int error;
int stmt_no;
DB_SESSION *session = NULL;
error = db_open_buffer_and_compile_first_statement (CSQL_query, query_error, DB_NO_OIDS, &session, &stmt_no);
if (session == NULL)
{
return error;
}
if (arg_count > 0)
{
db_push_values (session, arg_count, vals);
}
if (stmt_no > 0)
{
error = db_execute_statement_local (session, stmt_no, result);
}
db_close_session_local (session);
return (error);
}
/*
* QUERY PRE-PROCESSING ROUTINES
*/
/*
* db_get_query_format() - This function is used to perform syntax and semantic
* checking on a query statement without actually causing query results to
* be generated. The returned type list contains information about each
* column in the resulting query tuples, including the name, data type, and
* size of the values in the column.
* return : error code
* CSQL_query(in): query string
* type_list(out): Set to the query format list
* query_error(out): Set to the error information, if any.
*
* note : The user should call the db_query_format_free() function when
* finished with the format list.
*/
int
db_get_query_format (const char *CSQL_query, DB_QUERY_TYPE ** result, DB_QUERY_ERROR * query_error)
{
int error;
error = db_compile_and_execute_queries_internal (CSQL_query, result, query_error, DB_NO_OIDS, 0, true);
return (error < 0 ? error : NO_ERROR);
} /* db_get_query_format */
/*
* db_query_format_next() - This function is used to scan the elements of the
* query type list returned by the db_get_query_format() function.
* return : Pointer to the next type list node, or NULL
* query_type(in): Pointer to the current type list node
*
* note : Do not pass the result of this function to the
* db_query_format_free()function.
*/
DB_QUERY_TYPE *
db_query_format_next (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_NULL (query_type);
return query_type->next;
}
/*
* db_query_format_col_type() - This function returns the column type of the
* current query type
* return : column type of the current type list node
* query_type(in): Pointer to the current type list node
*/
DB_COL_TYPE
db_query_format_col_type (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_RETURN_EXPR (query_type, DB_COL_OTHER);
return query_type->col_type;
}
/*
* db_query_format_name() - This function is used to get the name of a column
* in a query format descriptor list.
* return : Column name of the current type list node
* query_type(in): Pointer to the current type list node
*
* note : Do not free this string. it is freed with the descriptor in the
* db_query_format_free() function. If the column was derived from a
* constant expression, the column name is similarly derived.
* for example, x + 10.
*/
char *
db_query_format_name (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_NULL (query_type);
return ((char *) query_type->name);
}
/*
* db_query_format_attr_name() - This function returns attribute name of the
* current query type list node.
* return : attribute name of the current type list node
* query_type(in): pointer to the current type list node
*/
char *
db_query_format_attr_name (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_NULL (query_type);
return ((char *) query_type->attr_name);
}
/*
* db_query_format_spec_name() - This function returns the spec name of the
* current query type list node.
* return : spec name of the current type list node
* query_type(in): Pointer to the current type list node
*/
char *
db_query_format_spec_name (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_NULL (query_type);
return ((char *) query_type->spec_name);
}
/*
* db_query_format_original_name() - This function returns user-specfified text
* of the query type list node.
* return : user-specified text of the current type list node
* query_type: Pointer to the current type list node
*/
char *
db_query_format_original_name (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_NULL (query_type);
return ((char *) query_type->original_name);
}
/*
* db_query_format_domain() - This function returns domain information of
* current query type list node.
* return : domain information of the current type list node
* query_type(in): pointer to the current type list node
*/
SM_DOMAIN *
db_query_format_domain (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_NULL (query_type);
return query_type->domain;
}
/*
* db_query_format_src_domain() - Returns source domain information of current
* query type list node.
* return : source domain information of the current type node
* query_type(in): Pointer to the current type list node
*
*/
SM_DOMAIN *
db_query_format_src_domain (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_NULL (query_type);
return query_type->src_domain;
}
/*
* db_query_format_type() - This function is used to get the basic type
* identifier of a column in a query format descriptor list.
* return : basic type id of a column
* query_type(in): Pointer to the current type list node
*
* note : Use the db_query_format_domain() function for non-primitive types.
*/
DB_TYPE
db_query_format_type (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_RETURN_EXPR (query_type, DB_TYPE_NULL);
return query_type->db_type;
}
/*
* db_query_format_size() - This function is used to get the data size of a
* column in a query format descriptor list node for fixed types,
* and 0 for variable types.
* return : data size of the current type list node
* query_type(in): Pointer to the current type list node
*/
int
db_query_format_size (DB_QUERY_TYPE * query_type)
{
CHECK_1ARG_MINUSONE (query_type);
return query_type->size;
}
/*
* db_query_format_free() - This function frees a query format list. You should
* call this function when you are finished with the query format returned
* by the db_get_query_format(), db_get_query_result_format() and
* db_object_describe() functions.
* return : void
* query_type(in): pointer to the beginning of the query type list
*
* note : Make sure to pass the head of the list and not an element in the
* middle of the list. You must use the exact return value. Do not use the
* return value of the db_query_format_next() function.
*/
void
db_query_format_free (DB_QUERY_TYPE * query_type)
{
if (query_type == NULL)
{
return;
}
db_free_query_format (query_type);
}
/*
* db_query_format_class_name() - This function returns the name of the class
* which the current type list node belongs to.
* return : name of the class which the current type list node belongs to.
* query_type(in): Pointer to the current type list node
*/
const char *
db_query_format_class_name (DB_QUERY_TYPE * query_type)
{
SM_DOMAIN *src_domain = NULL;
CHECK_1ARG_NULL (query_type);
src_domain = db_query_format_src_domain (query_type);
if (src_domain == NULL)
{
return (const char *) NULL;
}
if (src_domain->class_mop == NULL)
{
return NULL;
}
return db_get_class_name (src_domain->class_mop);
}
/*
* db_query_format_is_non_null() - This function returns the nullability of
* current type list node.
* return : nullability of current type list node
* query_type(in): Pointer to the current type list node
*/
int
db_query_format_is_non_null (DB_QUERY_TYPE * query_type)
{
SM_DOMAIN *src_domain = NULL;
DB_ATTRIBUTE *attr = NULL;
CHECK_1ARG_RETURN_EXPR (query_type, ER_OBJ_INVALID_ARGUMENT);
src_domain = db_query_format_src_domain (query_type);
if (src_domain && src_domain->class_mop && query_type->attr_name)
{
attr = db_get_attribute (src_domain->class_mop, query_type->attr_name);
if (attr)
{
return db_attribute_is_non_null (attr);
}
}
/*
* query_type is not an attribute.
* It may be an expression and will be treated as nullable.
*/
return 0;
}
/*
* QUERY PROCESSING ROUTINES
*/
/*
* db_query_execute() - This function executes the given query and set query
* result. The query result structure contains a LIST FILE identifier which
* identifies the file on the server side that contains the query result as
* a set of tuples, and also a cursor identifier which is used to scan
* through this set of tuples in the query result.
* return : error code.
* CSQL_query(in): CSQL query string to be executed
* result(out): Pointer to the query result structure
* query_error(out): Set to the error information, if any.
*
* note : result must be deallocated with db_query_end() function.
*/
int
db_query_execute (const char *CSQL_query, DB_QUERY_RESULT ** result, DB_QUERY_ERROR * query_error)
{
int error;
error = db_compile_and_execute_queries_internal (CSQL_query, result, query_error, DB_NO_OIDS, 1, true);
return (error < 0 ? error : NO_ERROR);
}
/*
* db_execute() - This function is used to evaluate the CSQL_query statement(s)
* given in the string. The result descriptor is used with the cursor
* functions to access the individual tuple values. The return value is the
* row count (the number of rows) returned from the last statement executed.
* return : integer, negative implies error.
* Positive is the count of qualified rows
* CSQL_query(in): query string to be executed
* result(out): Pointer to the query result structure
* query_error(out): Set to the error information, if any.
*
* note : The DB_QUERY_RESULT structure obtained from db_execute(is invalidated
* at transaction boundaries (i.e., whenever db_commit_transaction()or
* db_abort_transaction() is executed).
* These structures should be closed with db_query_end()before committing or
* aborting the transaction. Any attempt to use such a structure after the
* end of the transaction in which it was created will result in an error.
*/
int
db_execute (const char *CSQL_query, DB_QUERY_RESULT ** result, DB_QUERY_ERROR * query_error)
{
int retval;
char *sql_buf = strdup (CSQL_query);
if (sql_buf == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, strlen (CSQL_query));
return er_errid ();
}
retval = db_compile_and_execute_queries_internal (sql_buf, result, query_error, DB_NO_OIDS, 1, true);
free (sql_buf);
return (retval);
}
/*
* db_execute_oid() -
* return :
* CSQL_query(in):
* result(out):
* query_error(out):
*/
int
db_execute_oid (const char *CSQL_query, DB_QUERY_RESULT ** result, DB_QUERY_ERROR * query_error)
{
int retval;
retval = db_compile_and_execute_queries_internal (CSQL_query, result, query_error, DB_ROW_OIDS, 1, true);
return (retval);
}
#if defined(WINDOWS) || defined (ENABLE_UNUSED_FUNCTION)
/*
* db_query_execute_immediate() -
* return :
* CSQL_query(in):
* result(out):
* query_error(out):
*/
int
db_query_execute_immediate (const char *CSQL_query, DB_QUERY_RESULT ** result, DB_QUERY_ERROR * query_error)
{
int r;
#if defined(CUBRID_DEBUG)
fprintf (stdout, "db_query_execute_immediate is a deprecated function.\n");
fprintf (stdout, "use the equivalent function db_execute.\n");
#endif
r = db_compile_and_execute_queries_internal (CSQL_query, result, query_error, DB_NO_OIDS, 1, true);
return r;
}
/*
* db_get_objfetch_query_result() - This function forms an query result
* structure from the given list of values, list of column sizes and
* column names. The query result structure for an object_fetch, is
* treated exactly as a list file of one tuple.
* return : DB_QUERY_RESULT*
* val_list(in): List of values
* val_cnt(in): Number of values
* size_list(out): List of column sizes
* colname_list(out): List of column names
* attrname_list(out): List of attribute names
*/
DB_QUERY_RESULT *
db_get_objfetch_query_result (DB_VALUE * val_list, int val_cnt, int *size_list, char **colname_list,
char **attrname_list)
{
DB_QUERY_RESULT *r;
DB_QUERY_TYPE *typep;
DB_VALUE *valp, **ovalp;
int k;
int *sizep;
char **namep;
char **attr_namep;
size_t str_size;
CHECK_CONNECT_NULL ();
CHECK_1ARG_NULL (val_list);
r = db_alloc_query_result (T_OBJFETCH, val_cnt);
if (r == NULL)
{
return NULL;
}
db_init_query_result (r, T_OBJFETCH);
r->type = T_OBJFETCH;
r->col_cnt = val_cnt;
r->oid_included = false;
/* allocate and initialize type list */
r->type_cnt = val_cnt;
r->query_type = db_alloc_query_format (val_cnt);
if (r->query_type == NULL)
{
db_free_query_result (r);
return NULL;
}
if (val_cnt > 0)
{
for (k = 0, typep = r->query_type, valp = val_list, sizep = size_list, namep = colname_list, attr_namep =
attrname_list; k < val_cnt; k++, typep = typep->next, valp++, sizep++)
{
typep->db_type = DB_VALUE_TYPE (valp);
typep->size = *sizep;
typep->name = (char *) NULL;
typep->attr_name = (char *) NULL;
typep->spec_name = (char *) NULL;
typep->original_name = (char *) NULL;
typep->domain = (SM_DOMAIN *) NULL;
typep->src_domain = (SM_DOMAIN *) NULL;
if (colname_list != NULL)
{
/* column names can NOT be NULL */
str_size = strlen (*namep) + 1;
typep->name = (char *) malloc (str_size);
if (typep->name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, str_size);
db_free_query_result (r);
return NULL;
}
memcpy ((char *) typep->name, *namep, str_size);
namep++;
}
if (attrname_list != NULL)
{
/* attribute names can be NULL */
if (*attr_namep)
{
str_size = strlen (*attr_namep) + 1;
typep->attr_name = (char *) malloc (str_size);
if (typep->attr_name == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, str_size);
db_free_query_result (r);
return NULL;
}
memcpy ((char *) typep->attr_name, *attr_namep, str_size);
}
attr_namep++;
}
}
}
r->res.o.crs_pos = C_BEFORE;
for (k = 0, ovalp = r->res.o.valptr_list, valp = val_list; k < r->col_cnt; k++, ovalp++, valp++)
{
*ovalp = db_value_copy (valp);
if ((*ovalp) == NULL)
{
db_free_query_result (r);
return NULL;
}
}
return r;
}
#endif
/*
* db_get_db_value_query_result() - This function forms a query result
* structure from the given db_value. The query result structure for the
* db_value is treated exactly like a list file of one_tuple, one_column.
* return : DB_QUERY_RESULT*
* val(in): Single Value
*/
DB_QUERY_RESULT *
db_get_db_value_query_result (DB_VALUE * val)
{
DB_QUERY_RESULT *r;
CHECK_CONNECT_NULL ();
CHECK_1ARG_NULL (val);
r = db_alloc_query_result (T_CALL, 1);
if (r == NULL)
{
return NULL;
}
db_init_query_result (r, T_CALL);
r->type = T_CALL;
r->col_cnt = 1;
r->oid_included = false;
/* allocate and initialize type list */
r->type_cnt = 1;
r->query_type = db_alloc_query_format (1);
if (r->query_type == NULL)
{
db_free_query_result (r);
return NULL;
} /* if */
r->query_type->db_type = DB_VALUE_TYPE (val);
r->query_type->name = (char *) NULL;
r->query_type->attr_name = (char *) NULL;
r->query_type->spec_name = (char *) NULL;
r->query_type->original_name = (char *) NULL;
r->query_type->domain = (SM_DOMAIN *) NULL;
r->query_type->src_domain = (SM_DOMAIN *) NULL;
r->query_type->size = 0;
r->res.c.crs_pos = C_BEFORE;
r->res.c.val_ptr = db_value_copy (val);
if (r->res.c.val_ptr == NULL)
{
db_free_query_result (r);
return NULL;
}
return r;
}
/*
* db_get_query_result_format() - The query format list of the given query
* result is returned.
* return : error code
* result(in): Pointer to the query result structure
* type_list(out): Set to the query format list
*
* note : The caller should call db_query_format_free routine to
* deallocate the allocated type list region.
*/
int
db_get_query_result_format (DB_QUERY_RESULT * result, DB_QUERY_TYPE ** type_list)
{
int retval;
CHECK_CONNECT_ERROR ();
*type_list = NULL;
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
*type_list = db_cp_query_type (result->query_type, true);
if (*type_list == NULL)
{
assert (er_errid () != NO_ERROR);
retval = er_errid ();
return (retval);
}
return NO_ERROR;
}
/*
* db_query_next_tuple() - This function makes the next tuple in the LIST FILE
* referred by the query result structure the current active tuple of the
* query result cursor and returns DB_CURSOR_SUCCESS.
* return : error code or cursor
* result(in/out): Pointer to the query result structure
*/
int
db_query_next_tuple (DB_QUERY_RESULT * result)
{
int retval;
CURSOR_POSITION *c_pos;
CHECK_CONNECT_ERROR ();
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
retval = cursor_next_tuple (&result->res.s.cursor_id);
break;
case T_CALL:
case T_OBJFETCH:
{
c_pos = ((result->type == T_CALL)
? (CURSOR_POSITION *) (&result->res.c.crs_pos) : (CURSOR_POSITION *) (&result->res.o.crs_pos));
switch (*c_pos)
{
case C_BEFORE:
*c_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
break;
case C_ON:
case C_AFTER:
*c_pos = C_AFTER;
retval = DB_CURSOR_END;
break;
default:
retval = ER_QPROC_UNKNOWN_CRSPOS;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_UNKNOWN_CRSPOS, 0);
break;
}
}
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
{
c_pos = &result->res.g.crs_pos;
if (result->res.g.n_tuple == 0)
{
*c_pos = C_AFTER;
retval = DB_CURSOR_END;
}
else
{
switch (*c_pos)
{
case C_BEFORE:
{
result->res.g.tpl_idx = 0;
*c_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
case C_ON:
{
result->res.g.tpl_idx += result->col_cnt;
if (result->res.g.tpl_idx >= (result->res.g.n_tuple * result->col_cnt))
{
*c_pos = C_AFTER;
retval = DB_CURSOR_END;
break;
}
retval = DB_CURSOR_SUCCESS;
}
break;
case C_AFTER:
retval = DB_CURSOR_END;
break;
default:
retval = ER_QPROC_UNKNOWN_CRSPOS;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_UNKNOWN_CRSPOS, 0);
break;
}
}
}
break;
#endif
default:
{
retval = ER_QPROC_INVALID_RESTYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
}
break;
}
return (retval);
}
/*
* db_query_prev_tuple() - This function makes the previous tuple in the LIST
* FILE referred by query result structure the current active tuple of the
* query result cursor and returns DB_CURSOR_SUCCESS.
* return : error code or cursor
* result(in/out): Pointer to the query result structure
*/
int
db_query_prev_tuple (DB_QUERY_RESULT * result)
{
int retval;
CURSOR_POSITION *c_pos;
CHECK_CONNECT_ERROR ();
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
retval = cursor_prev_tuple (&result->res.s.cursor_id);
break;
case T_CALL:
case T_OBJFETCH:
{
c_pos = ((result->type == T_CALL)
? (CURSOR_POSITION *) (&result->res.c.crs_pos) : (CURSOR_POSITION *) (&result->res.o.crs_pos));
switch (*c_pos)
{
case C_BEFORE:
case C_ON:
{
*c_pos = C_BEFORE;
retval = DB_CURSOR_END;
}
break;
case C_AFTER:
{
*c_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
default:
retval = ER_QPROC_UNKNOWN_CRSPOS;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_UNKNOWN_CRSPOS, 0);
break;
}
}
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
{
c_pos = &result->res.g.crs_pos;
if (result->res.g.n_tuple == 0)
{
*c_pos = C_BEFORE;
retval = DB_CURSOR_END;
break;
}
else
{
switch (*c_pos)
{
case C_BEFORE:
retval = DB_CURSOR_SUCCESS;
break;
case C_ON:
{
result->res.g.tpl_idx -= result->col_cnt;
if (result->res.g.tpl_idx < 0)
{
*c_pos = C_BEFORE;
retval = DB_CURSOR_END;
break;
}
retval = DB_CURSOR_SUCCESS;
}
break;
case C_AFTER:
{
result->res.g.tpl_idx = (result->res.g.n_tuple - 1) * result->col_cnt;
*c_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
default:
retval = ER_QPROC_UNKNOWN_CRSPOS;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_UNKNOWN_CRSPOS, 0);
break;
}
}
}
break;
#endif
default:
retval = ER_QPROC_INVALID_RESTYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
break;
}
return (retval);
}
/*
* db_query_first_tuple() - This function makes the first tuple in the LIST
* FILE referred by the query result structure the current active tuple
* of the query result cursor and DB_CURSOR_SUCCESS.
* return : error code or cursor
* result(in/out): Pointer to the query result structure
*/
int
db_query_first_tuple (DB_QUERY_RESULT * result)
{
int retval;
CHECK_CONNECT_ERROR ();
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
retval = cursor_first_tuple (&result->res.s.cursor_id);
break;
case T_CALL:
{
result->res.c.crs_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
case T_OBJFETCH:
{
result->res.o.crs_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
if (result->res.g.n_tuple == 0)
{
retval = DB_CURSOR_END;
}
else
{
result->res.g.tpl_idx = 0;
result->res.g.crs_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
#endif
default:
{
retval = ER_QPROC_INVALID_RESTYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
}
break;
}
return (retval);
}
/*
* db_query_last_tuple() - This function is used to position the cursor
* directly to the last tuple within the query result.
* return : error code or cursor
* result(in/out): Pointer to the query result structure
*/
int
db_query_last_tuple (DB_QUERY_RESULT * result)
{
int retval;
CHECK_CONNECT_ERROR ();
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
retval = cursor_last_tuple (&result->res.s.cursor_id);
break;
case T_CALL:
{
result->res.c.crs_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
case T_OBJFETCH:
{
result->res.o.crs_pos = C_ON;
retval = DB_CURSOR_SUCCESS;
}
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
if (result->res.g.n_tuple == 0)
{
retval = DB_CURSOR_END;
}
else
{
result->res.g.crs_pos = C_ON;
result->res.g.tpl_idx = (result->res.g.n_tuple - 1) * result->col_cnt;
retval = DB_CURSOR_SUCCESS;
}
break;
#endif
default:
retval = ER_QPROC_INVALID_RESTYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
break;
}
return (retval);
}
/*
* db_query_seek_tuple() - This function set the cursor to a specific tuple
* according to value of the offset and seek_mode. Seek mode can only take
* DB_CURSOR_SEEK_SET, DB_CURSOR_SEEK_CUR, DB_CURSOR_SEEK_END values.
* If offset value is n and seek_mode value is:
* DB_CURSOR_SEEK_SET: The cursor is set to the nth tuple from
* the beginning. (absolute access)
* DB_CORSOR_SEEK_CUR: The cursor is set to its current position
* _plus_ n. (relative access)
* DB_CURSOR_SEEK_END: The cursor is set to the last tuple
* position _plus_ n. (relative access)
*
* return : On success, the function returns DB_CURSOR_SUCCESS.
*
* On end_of_scan, the cursor position is changed, the function
* returns DB_CURSOR_END.
*
* On failure, the cursor position remains unchanged the function
* returns corresponding error code.
*
* result(in/out): Query result structure
* offset(in): Offset tuple count
* seek_mode(in): Tuple seek mode
*/
int
db_query_seek_tuple (DB_QUERY_RESULT * result, int offset, int seek_mode)
{
int scan;
int rel1, rel2, rel3, rel_n;
int curr_tplno, tpl_cnt;
DB_QUERY_TPLPOS *tplpos;
CURSOR_POSITION *c_pos;
CHECK_CONNECT_ERROR ();
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
{
tplpos = db_query_get_tplpos (result);
if (tplpos == NULL)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/* find the optimal relative position for the scan: relative to the beginning, current tuple position or end. */
curr_tplno = result->res.s.cursor_id.tuple_no;
// TODO: list_id.tuple_cnt could have over INT_MAX. But higher layers (CAS function, API, etc) that use this function are not supporting INT64 range.
// To support results beyond the int range, offset and tuple count have be extended to INT64 types
assert (result->res.s.cursor_id.list_id.tuple_cnt <= INT_MAX);
tpl_cnt = MIN (result->res.s.cursor_id.list_id.tuple_cnt, INT_MAX);
switch (seek_mode)
{
case DB_CURSOR_SEEK_SET:
{
rel1 = offset; /* relative to beginning */
rel2 = offset - curr_tplno; /* relative to current tuple */
rel3 = offset - (tpl_cnt - 1); /* relative to end */
}
break;
case DB_CURSOR_SEEK_CUR:
{
rel1 = curr_tplno + offset;
rel2 = offset;
rel3 = (curr_tplno + offset) - (tpl_cnt - 1);
}
break;
case DB_CURSOR_SEEK_END:
{
rel1 = (tpl_cnt - 1) + offset;
rel2 = (tpl_cnt - 1) + offset - curr_tplno;
rel3 = offset;
}
break;
default:
{
db_query_set_tplpos (result, tplpos);
db_query_free_tplpos (tplpos);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 1);
}
return ER_GENERIC_ERROR;
}
if (abs (rel1) < abs (rel2) && abs (rel1) < abs (rel3))
{
/* move relative to the beginning */
scan = db_query_first_tuple (result);
if (scan != DB_CURSOR_SUCCESS)
{
if (scan != DB_CURSOR_END)
{
db_query_set_tplpos (result, tplpos);
}
db_query_free_tplpos (tplpos);
if (scan != DB_CURSOR_END)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
else
{
return scan;
}
}
rel_n = rel1;
}
else if (abs (rel3) < abs (rel2))
{
/* move relative to the last */
scan = db_query_last_tuple (result);
if (scan != DB_CURSOR_SUCCESS)
{
if (scan != DB_CURSOR_END)
{
db_query_set_tplpos (result, tplpos);
}
db_query_free_tplpos (tplpos);
if (scan != DB_CURSOR_END)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
else
{
return scan;
}
}
rel_n = rel3;
}
else
{
/* move relative to the current tuple */
rel_n = rel2;
}
/* perform the actual scan operation in a relative manner */
if (rel_n > 0)
{
while (rel_n--)
{
scan = db_query_next_tuple (result);
if (scan != DB_CURSOR_SUCCESS)
{
if (scan != DB_CURSOR_END)
{
db_query_set_tplpos (result, tplpos);
}
db_query_free_tplpos (tplpos);
if (scan != DB_CURSOR_END)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
else
{
return scan;
}
}
}
}
else
{
while (rel_n++)
{
scan = db_query_prev_tuple (result);
if (scan != DB_CURSOR_SUCCESS)
{
if (scan != DB_CURSOR_END)
{
db_query_set_tplpos (result, tplpos);
}
db_query_free_tplpos (tplpos);
if (scan != DB_CURSOR_END)
{
assert (er_errid () != NO_ERROR);
return er_errid ();
}
else
{
return scan;
}
}
}
}
db_query_free_tplpos (tplpos);
}
break;
case T_CALL:
case T_OBJFETCH:
switch (seek_mode)
{
case DB_CURSOR_SEEK_SET:
case DB_CURSOR_SEEK_END:
c_pos = ((result->type == T_CALL)
? (CURSOR_POSITION *) (&result->res.c.crs_pos) : (CURSOR_POSITION *) (&result->res.o.crs_pos));
if (offset == 0)
{
*c_pos = C_ON;
return DB_CURSOR_SUCCESS;
}
else if (offset > 0)
{
*c_pos = C_AFTER;
return DB_CURSOR_END;
}
else
{
*c_pos = C_BEFORE;
return DB_CURSOR_END;
}
case DB_CURSOR_SEEK_CUR:
if (offset > 0)
{
return db_query_next_tuple (result);
}
else if (offset < 0)
{
return db_query_prev_tuple (result);
}
else
{
return DB_CURSOR_SUCCESS;
}
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 1);
return ER_GENERIC_ERROR;
}
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
{
int col_cnt, tpl_idx, n_tuple, index = 0;
col_cnt = result->col_cnt;
tpl_idx = result->res.g.tpl_idx;
n_tuple = result->res.g.n_tuple;
if (n_tuple == 0)
{
return DB_CURSOR_END;
}
else
{
switch (seek_mode)
{
case DB_CURSOR_SEEK_SET:
index = offset * col_cnt;
break;
case DB_CURSOR_SEEK_CUR:
index = tpl_idx + (offset * col_cnt);
break;
case DB_CURSOR_SEEK_END:
index = ((n_tuple - 1) + offset) * col_cnt;
break;
}
if (index < 0)
{
result->res.g.crs_pos = C_BEFORE;
return DB_CURSOR_END;
}
else if (index >= (n_tuple * col_cnt))
{
result->res.g.crs_pos = C_AFTER;
return DB_CURSOR_END;
}
else
{
result->res.g.tpl_idx = index;
result->res.g.crs_pos = C_ON;
return DB_CURSOR_SUCCESS;
}
}
}
break;
#endif
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return ER_QPROC_INVALID_RESTYPE;
}
return DB_CURSOR_SUCCESS;
}
/*
* db_query_get_tplpos() - This function returns the current tuple position
* information.
* return : DB_QUERY_TPLPOS*, or NULL
* result(in): Query result structure
*
* note: Even though. db_query_seek_tuple() routine can be used to position
* the cursor to a specific tuple, the combination of
* db_query_get_tplpos() and db_query_set_tplpos() provides a much
* faster way of accessing a specific tuple.
*/
DB_QUERY_TPLPOS *
db_query_get_tplpos (DB_QUERY_RESULT * result)
{
DB_QUERY_TPLPOS *tplpos;
CHECK_CONNECT_NULL ();
CHECK_1ARG_NULL (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return NULL;
}
tplpos = (DB_QUERY_TPLPOS *) malloc (DB_SIZEOF (DB_QUERY_TPLPOS));
if (tplpos == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, DB_SIZEOF (DB_QUERY_TPLPOS));
return NULL;
}
switch (result->type)
{
case T_SELECT:
tplpos->crs_pos = result->res.s.cursor_id.position;
tplpos->vpid.pageid = result->res.s.cursor_id.current_vpid.pageid;
tplpos->vpid.volid = result->res.s.cursor_id.current_vpid.volid;
tplpos->tpl_no = result->res.s.cursor_id.current_tuple_no;
tplpos->tpl_off = result->res.s.cursor_id.current_tuple_offset;
break;
case T_CALL:
tplpos->crs_pos = result->res.c.crs_pos;
break;
case T_OBJFETCH:
tplpos->crs_pos = result->res.o.crs_pos;
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
tplpos->crs_pos = result->res.g.crs_pos;
tplpos->tpl_off = result->res.g.tpl_idx / result->col_cnt;
tplpos->tpl_no = result->res.g.n_tuple;
break;
#endif
default:
free_and_init (tplpos);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return NULL;
}
return tplpos;
}
/*
* db_query_set_tplpos() - This function set cursor to point to the indicated
* tuple position.
* return : error code
* result(in): query result structure
* tplpos(out): tuple position information
*/
int
db_query_set_tplpos (DB_QUERY_RESULT * result, DB_QUERY_TPLPOS * tplpos)
{
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
/* reset cursor identifier */
if (result->res.s.cursor_id.current_vpid.pageid != tplpos->vpid.pageid
|| result->res.s.cursor_id.current_vpid.volid != tplpos->vpid.volid)
{
/* needs to get another page */
if (cursor_fetch_page_having_tuple (&result->res.s.cursor_id, &tplpos->vpid, tplpos->tpl_no, tplpos->tpl_off)
!= NO_ERROR)
{
return ER_FAILED;
}
result->res.s.cursor_id.current_vpid = tplpos->vpid;
}
result->res.s.cursor_id.position = tplpos->crs_pos;
break;
case T_CALL:
result->res.c.crs_pos = tplpos->crs_pos;
break;
case T_OBJFETCH:
result->res.o.crs_pos = tplpos->crs_pos;
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
result->res.g.crs_pos = tplpos->crs_pos;
result->res.g.tpl_idx = tplpos->tpl_off * result->col_cnt;
result->res.g.n_tuple = tplpos->tpl_no;
break;
#endif
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return ER_QPROC_INVALID_RESTYPE;
}
return NO_ERROR;
}
/*
* db_query_free_tplpos() - This function frees the area pointed by the tplpos
* pointer.
* return : void
* tplpos(in): Tuple position information
*/
void
db_query_free_tplpos (DB_QUERY_TPLPOS * tplpos)
{
free_and_init (tplpos);
}
/*
* db_query_get_tuple_value() - This function is used to get the value for a
* column in the current tuple of a query result. The current tuple is
* specified by using the cursor control functions.
* return : error code
* result: pointer to the query result structure
* index(in): position of the tuple value of interest (0 for the first one)
* value(out): value container for column value
*/
int
db_query_get_tuple_value (DB_QUERY_RESULT * result, int index, DB_VALUE * value)
{
int retval;
DB_VALUE *valp;
#if defined (ENABLE_UNUSED_FUNCTION)
int current;
#endif
CHECK_CONNECT_ERROR ();
CHECK_2ARGS_ERROR (result, value);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
if (DB_INVALID_INDEX (DB_OID_INCLUDED (result) ? index + 1 : index, result->col_cnt))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_TPLVAL_INDEX, 1,
DB_OID_INCLUDED (result) ? index + 1 : index);
return ER_QPROC_INVALID_TPLVAL_INDEX;
}
retval = cursor_get_tuple_value (&result->res.s.cursor_id, index, value);
break;
case T_OBJFETCH:
if (DB_OID_INCLUDED (result))
{
index++;
}
if (DB_INVALID_INDEX (index, result->col_cnt))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_TPLVAL_INDEX, 1, index);
return ER_QPROC_INVALID_TPLVAL_INDEX;
}
valp = result->res.o.valptr_list[index];
pr_clone_value (valp, value);
retval = NO_ERROR;
break;
case T_CALL:
valp = result->res.c.val_ptr;
pr_clone_value (valp, value);
retval = NO_ERROR;
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
if (DB_INVALID_INDEX (index, result->col_cnt))
{
retval = ER_QPROC_INVALID_TPLVAL_INDEX;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_TPLVAL_INDEX, 1, index);
break;
}
current = result->res.g.tpl_idx;
valp = &result->res.g.tpl_list[current + index];
pr_clone_value (valp, value);
retval = NO_ERROR;
break;
#endif
default:
retval = ER_QPROC_INVALID_RESTYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
break;
}
return (retval);
}
/*
* db_query_get_tuple_value_by_name() - This function is used to get the value
* for a column in the current tuple of a query result. The current tuple is
* specified using the cursor control functions. In this function, the
* desired column is specified by name.
* return : error code
* result(in): pointer to the query result structure
* column_name(in): name of the desired column
* value(out): value container for column value
*/
int
db_query_get_tuple_value_by_name (DB_QUERY_RESULT * result, char *column_name, DB_VALUE * value)
{
int retval;
DB_QUERY_TYPE *typep;
int ind;
CHECK_CONNECT_ERROR ();
CHECK_3ARGS_ERROR (result, column_name, value);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
case T_OBJFETCH:
case T_GET:
typep = result->query_type;
for (ind = 0; typep; ind++, typep = typep ? typep->next : NULL)
{
if (!ansisql_strcasecmp (column_name, typep->name))
{
break;
}
else if (typep->original_name)
{ /* retry with original name */
if (!ansisql_strcasecmp (column_name, typep->original_name))
{
break;
}
}
}
if (typep == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_COLNAME, 1, column_name);
return ER_QPROC_INVALID_COLNAME;
}
retval = db_query_get_tuple_value (result, ind, value);
break;
case T_CALL:
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return ER_QPROC_INVALID_RESTYPE;
break;
}
return (retval);
}
/*
* db_query_get_tuple_valuelist() - This function can be used to get all of the
* column values for the current tuple of a query result. The current tuple
* is specified using the cursor control functions. The values for the
* columns up to the number specified by the size argument are copied into
* the value array.
* return : error code.
* result(in): Pointer to the query result structure
* size(in): Number of values in the value list
* value_list(out): an array of DB_VALUE structures
*/
int
db_query_get_tuple_valuelist (DB_QUERY_RESULT * result, int size, DB_VALUE * value_list)
{
int retval;
DB_VALUE *valp;
int k;
CHECK_CONNECT_ERROR ();
CHECK_2ARGS_ERROR (result, value_list);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
if (DB_INVALID_INDEX (DB_OID_INCLUDED (result) ? size : size - 1, result->col_cnt))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_TPLVAL_INDEX, 1,
DB_OID_INCLUDED (result) ? size : size - 1);
return ER_QPROC_INVALID_TPLVAL_INDEX;
}
retval = cursor_get_tuple_value_list (&result->res.s.cursor_id, size, value_list);
break;
case T_CALL:
retval = db_query_get_tuple_value (result, 0, value_list);
break;
case T_GET:
case T_OBJFETCH:
for (k = 0, valp = value_list; k < size; k++, valp++)
if ((db_query_get_tuple_value (result, k, valp)) < 0)
{
assert (er_errid () != NO_ERROR);
retval = er_errid ();
return (retval);
}
retval = NO_ERROR;
break;
default:
retval = ER_QPROC_INVALID_RESTYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
break;
}
return (retval);
}
/*
* db_query_tuple_count() - This function calculates the total number of result
* tuples in the query result.
* return : number of tuples in the query result or -1 on error.
* result(in): Pointer to the query result structure
*
* note : If an error is detected, the function returns -1 and the
* db_error_string() function can be used to see a description of the error.
*/
int
db_query_tuple_count (DB_QUERY_RESULT * result)
{
int retval;
CHECK_1ARG_MINUSONE (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return -1;
}
switch (result->type)
{
case T_SELECT:
// TODO: To support results beyond the int range, offset and tuple count have be extended to INT64 types
assert (result->res.s.cursor_id.list_id.tuple_cnt <= INT_MAX);
retval = MIN (result->res.s.cursor_id.list_id.tuple_cnt, INT_MAX);
break;
case T_CALL:
case T_OBJFETCH:
retval = 1;
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
retval = result->res.g.n_tuple;
break;
#endif
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
retval = -1;
break;
}
return retval;
}
/*
* db_query_column_count() - This function calculates the number of columns in
* each tuple of the query result.
* return : number of columns.
* result(in): Pointer to the query result structure
*/
int
db_query_column_count (DB_QUERY_RESULT * result)
{
DB_QUERY_TYPE *t;
int num_cols = 0;
CHECK_1ARG_MINUSONE (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return -1;
}
if (DB_INVALID_RESTYPE (result->type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return -1;
}
for (t = result->query_type; t != NULL; t = db_query_format_next (t))
{
num_cols++;
}
return num_cols;
}
#if defined(WINDOWS) || defined (ENABLE_UNUSED_FUNCTION)
/*
* db_query_stmt_id() - This function returns the statement identifier for the
* query or -1 if the query is not select type.
* return : statement id or -1
* result(in): Pointer to the query result structure
*/
int
db_query_stmt_id (DB_QUERY_RESULT * result)
{
CHECK_1ARG_MINUSONE (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return -1;
}
if (DB_INVALID_RESTYPE (result->type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return -1;
}
return result->res.s.stmt_id;
}
#endif
/*
* db_query_get_tuple_oid() - This function returns an OID in the form of a
* DB_VALUE pointer.
* return : error code
* result(in): Pointer to the query result structure
* db_value(out): contains the pointer to the cursor current OID
*
* note : For this function to process without error, the query that yields
* the DB_QUERY_RESULT pointed to by result must be updatable.
* The db_query_get_tuple_oid() function must be preceded by the
* db_include_oid(), db_compile_statement() and the db_execute_statement()
* functions, or simply by the db_execute_oid() function.
*/
int
db_query_get_tuple_oid (DB_QUERY_RESULT * result, DB_VALUE * db_value)
{
int retval;
CHECK_CONNECT_ERROR ();
CHECK_2ARGS_ERROR (result, db_value);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
if (DB_INVALID_RESTYPE (result->type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return ER_QPROC_INVALID_RESTYPE;
}
if (!DB_OID_INCLUDED (result))
{
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_CRSOPR, 0);
return ER_QPROC_INVALID_CRSOPR;
}
retval = cursor_get_current_oid (&result->res.s.cursor_id, db_value);
return (retval);
}
#if defined(WINDOWS) || defined (ENABLE_UNUSED_FUNCTION)
/*
* db_query_get_value_type() - This function returns the type of the specified
* result column, or DB_TYPE_NULL on error
* return : DB_TYPE
* result(in) : pointer to query result structure
* index(in) : column index
*/
DB_TYPE
db_query_get_value_type (DB_QUERY_RESULT * result, int index)
{
DB_QUERY_TYPE *typep;
int k;
CHECK_1ARG_RETURN_EXPR (result, DB_TYPE_NULL);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return DB_TYPE_NULL;
}
if (DB_INVALID_RESTYPE (result->type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return DB_TYPE_NULL;
}
if (DB_INVALID_INDEX (index, result->type_cnt))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_TPLVAL_INDEX, 1, index);
return DB_TYPE_NULL;
}
for (k = 0, typep = result->query_type; k < index && typep; k++, typep = typep->next)
;
return typep ? typep->db_type : DB_TYPE_NULL;
}
/*
* db_query_get_value_length() - This functionreturns the length of the
* specified result column
* return : length of column or -1 on error
* result(in) : pointer to query result structure
* index(in) : which result column
*/
int
db_query_get_value_length (DB_QUERY_RESULT * result, int index)
{
DB_QUERY_TYPE *typep;
int k;
CHECK_1ARG_MINUSONE (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return -1;
}
if (DB_INVALID_RESTYPE (result->type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
return -1;
}
if (DB_INVALID_INDEX (index, result->type_cnt))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_TPLVAL_INDEX, 1, index);
return -1;
}
for (k = 0, typep = result->query_type; k < index; k++, typep = typep->next)
{
; /* NULL */
}
return typep ? typep->size : -1;
}
#endif
#if defined(WINDOWS) || defined (CUBRID_DEBUG)
/*
* db_sqlx_debug_print_result() - This function displays the result on
* standard output.
* return : void
* result(in): result to be displayed
*
* note: this function is only for DEBUGGING purpose. No product can use
* this function to display the result.
*/
void
db_sqlx_debug_print_result (DB_QUERY_RESULT * result)
{
if (result == NULL)
{
fprintf (stdout, "There is no result.\n\n");
return;
}
switch (result->type)
{
case T_SELECT:
cursor_print_list (result->res.s.query_id, &result->res.s.cursor_id.list_id);
break;
case T_CALL:
db_value_print (result->res.c.val_ptr);
break;
default:
(void) fprintf (stdout, "Invalid query result structure type: %d.\n", result->type);
break;
}
}
#endif
/*
* QUERY POST-PROCESSING ROUTINES
*/
/*
* db_query_end() - This function must be called when the application is
* finished with the query result descriptor that was returned by either
* db_execute() or db_execute_oid() function.
* This frees the descriptor and all storage related to the query results.
* Since query results can be of considerable size,
* it is important that they be freed as soon as they are no longer necessary.
* return : error code
* result(in): Pointer to the query result structure
*
*/
int
db_query_end (DB_QUERY_RESULT * result)
{
bool notify_server;
if (tran_was_latest_query_ended ())
{
/* Query ended with latest executed query. No need to notify server. */
notify_server = false;
}
else
{
notify_server = true;
}
return db_query_end_internal (result, notify_server);
}
/*
* db_query_set_copy_tplvalue() -
* return : error code
* result(in/out):
* copy(in):
*/
int
db_query_set_copy_tplvalue (DB_QUERY_RESULT * result, int copy)
{
int retval = NO_ERROR;
CHECK_CONNECT_ERROR ();
CHECK_1ARG_ERROR (result);
if (result->status == T_CLOSED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_OPR_ON_CLOSED_QRES, 0);
return ER_QPROC_OPR_ON_CLOSED_QRES;
}
switch (result->type)
{
case T_SELECT:
(void) cursor_set_copy_tuple_value (&result->res.s.cursor_id, copy ? true : false);
break;
case T_CALL:
break;
case T_OBJFETCH:
break;
#if defined (ENABLE_UNUSED_FUNCTION)
case T_GET:
break;
#endif
default:
{
retval = ER_QPROC_INVALID_RESTYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_RESTYPE, 0);
}
break;
}
return retval;
}
/*
* db_is_client_cache_reusable() -
* return :
* result(in):
*/
bool
db_is_client_cache_reusable (DB_QUERY_RESULT * result)
{
if (result && result->type == T_CACHE_HIT)
{
return true;
}
else
{
return false;
}
}
/*
* db_query_get_cache_time() -
* return :
* result(in):
* cache_time(out):
*/
int
db_query_get_cache_time (DB_QUERY_RESULT * result, CACHE_TIME * cache_time)
{
if (cache_time)
{
CACHE_TIME_RESET (cache_time);
}
if (result != NULL && result->status != T_CLOSED && result->type == T_SELECT && cache_time)
{
*cache_time = result->res.s.cache_time;
}
return NO_ERROR;
}
/*
* db_query_end_internal() -
* return :
* result(in):
* notify_server(in):
*/
int
db_query_end_internal (DB_QUERY_RESULT * result, bool notify_server)
{
int error = NO_ERROR;
if (db_Connect_status != DB_CONNECTION_STATUS_CONNECTED)
{
error = ER_OBJ_NO_CONNECT;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_NO_CONNECT, 0);
}
/* Silently return if the result structure has already been freed */
if ((result) && (result->status == T_CLOSED))
{
return NO_ERROR;
}
if (result)
{
if (result->type == T_SELECT)
{
if (notify_server && error == NO_ERROR)
{
if (qmgr_end_query (result->res.s.query_id) != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
}
}
cursor_close (&result->res.s.cursor_id);
}
db_free_query_result (result);
}
return error;
}
/*
* db_query_prefetch_columns() -
* return : error code
* result(in):
* columns(out):
* col_count(in):
*
* note : This function was added in order to have reasonable performance.
*/
int
db_query_prefetch_columns (DB_QUERY_RESULT * result, int *columns, int col_count)
{
int error = NO_ERROR;
int status;
status = cursor_set_oid_columns (&result->res.s.cursor_id, columns, col_count);
if (status != NO_ERROR)
{
/* should be setting an error */
error = ER_GENERIC_ERROR;
}
return error;
}
/*
* db_query_plan_dump_file() -
* return :
* filename(in):
*/
int
db_query_plan_dump_file (char *filename)
{
if (query_Plan_dump_filename != NULL)
{
free (query_Plan_dump_filename);
}
query_Plan_dump_filename = NULL;
if (filename != NULL)
{
query_Plan_dump_filename = strdup (filename);
}
return NO_ERROR;
}
/*
* db_query_get_plan_dump_file() -
* return : query dump file
*/
char *
db_query_get_plan_dump_file ()
{
return query_Plan_dump_filename;
}
/*
* db_query_is_plan_dump_opened() -
* return : is fp opened
*/
bool
db_query_is_plan_dump_opened ()
{
return query_Plan_dump_fp_open;
}
/*
* db_query_plan_dump_fp_open() -
* return : FILE *
*/
FILE *
db_query_plan_dump_fp_open ()
{
if (query_Plan_dump_fp_open)
{
return query_Plan_dump_fp;
}
if (query_Plan_dump_filename != NULL)
{
if (query_Plan_dump_fp == NULL || query_Plan_dump_fp == stdout)
{
query_Plan_dump_fp = fopen (query_Plan_dump_filename, "a");
if (query_Plan_dump_fp != NULL)
{
query_Plan_dump_fp_open = true;
}
}
}
if (query_Plan_dump_fp == NULL)
{
query_Plan_dump_fp = stdout;
}
return query_Plan_dump_fp;
}
/*
* db_query_plan_dump_fp_close() -
* return : void
*/
void
db_query_plan_dump_fp_close ()
{
/* close file handle if this function open it */
if (query_Plan_dump_fp_open)
{
assert (query_Plan_dump_fp != NULL && query_Plan_dump_fp != stdout);
fclose (query_Plan_dump_fp);
query_Plan_dump_fp = NULL;
query_Plan_dump_fp_open = false;
}
}
/*
* db_query_get_plan_dump_fp() -
* return : FILE *
*/
FILE *
db_query_get_plan_dump_fp ()
{
if (query_Plan_dump_fp == NULL)
{
return stdout;
}
return query_Plan_dump_fp;
}
/*
* db_set_execution_plan
* plan(in):
* length(in):
*
* return:
*
*/
void
db_set_execution_plan (char *plan, int length)
{
int null_padded_length = 0;
if (plan == NULL)
{
if (db_Execution_plan != NULL)
{
db_Execution_plan[0] = '\0';
}
return;
}
null_padded_length = length + 1;
if (db_Execution_plan == NULL)
{
db_Execution_plan_length = PLAN_BUF_INITIAL_LENGTH;
while (db_Execution_plan_length < null_padded_length)
{
db_Execution_plan_length *= 2;
}
db_Execution_plan = (char *) malloc (db_Execution_plan_length * sizeof (char));
}
else if (db_Execution_plan_length < null_padded_length)
{
while (db_Execution_plan_length < null_padded_length)
{
db_Execution_plan_length *= 2;
}
free (db_Execution_plan);
db_Execution_plan = (char *) malloc (db_Execution_plan_length * sizeof (char));
}
if (db_Execution_plan == NULL)
{
db_Execution_plan_length = -1;
er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) db_Execution_plan_length);
return;
}
strncpy (db_Execution_plan, plan, length);
db_Execution_plan[length] = '\0';
}
/*
* db_get_execution_plan
*
* return:
*
*/
char *
db_get_execution_plan (void)
{
if (db_Execution_plan == NULL)
{
return NULL;
}
return db_Execution_plan;
}
/*
* db_free_execution_plan :
*
* return:
*
*/
void
db_free_execution_plan (void)
{
if (db_Execution_plan != NULL)
{
free_and_init (db_Execution_plan);
db_Execution_plan_length = -1;
}
}