1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-08-10 01:22:48 +03:00
Files
mariadb-columnstore-engine/utils/mysqlcl_idb/drizzle.cc
2016-01-06 14:08:59 -06:00

762 lines
17 KiB
C++

/*
* Drizzle Client & Protocol Library
*
* Copyright (C) 2008 Eric Day (eday@oddments.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * The names of its contributors may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file
* @brief Drizzle Definitions
*/
#include <libdrizzle-2.0/common.h>
/**
* @addtogroup drizzle_static Static Drizzle Declarations
* @ingroup drizzle
* @{
*/
/**
* Names of the verbose levels provided.
*/
static const char *_verbose_name[DRIZZLE_VERBOSE_MAX]=
{
"NEVER",
"FATAL",
"ERROR",
"INFO",
"DEBUG",
"CRAZY"
};
/** @} */
/*
* Common Definitions
*/
const char *drizzle_version()
{
return PACKAGE_VERSION;
}
const char *drizzle_bugreport()
{
return PACKAGE_BUGREPORT;
}
const char *drizzle_verbose_name(drizzle_verbose_t verbose)
{
if (verbose >= DRIZZLE_VERBOSE_MAX)
{
return "UNKNOWN";
}
return _verbose_name[verbose];
}
drizzle_st *drizzle_create()
{
#if defined(_WIN32)
/* if it is MS windows, invoke WSAStartup */
WSADATA wsaData;
if ( WSAStartup( MAKEWORD(2,2), &wsaData ) != 0 )
printf("Error at WSAStartup()\n");
#else
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
#endif
drizzle_st *drizzle= new (std::nothrow) drizzle_st;
if (drizzle == NULL)
{
return NULL;
}
/* @todo remove this default free flag with new API. */
drizzle->options.is_free_objects= true;
drizzle->error_code= 0;
/* drizzle->options set above */
drizzle->verbose= DRIZZLE_VERBOSE_NEVER;
drizzle->con_count= 0;
drizzle->pfds_size= 0;
drizzle->query_count= 0;
drizzle->query_new= 0;
drizzle->query_running= 0;
drizzle->last_errno= 0;
drizzle->timeout= -1;
drizzle->con_list= NULL;
drizzle->context= NULL;
drizzle->context_free_fn= NULL;
drizzle->event_watch_fn= NULL;
drizzle->event_watch_context= NULL;
drizzle->log_fn= NULL;
drizzle->log_context= NULL;
drizzle->pfds= NULL;
drizzle->query_list= NULL;
drizzle->sqlstate[0]= 0;
drizzle->last_error[0]= 0;
return drizzle;
}
drizzle_st *drizzle_clone(const drizzle_st *source)
{
drizzle_st *drizzle= drizzle_create();
if (drizzle == NULL)
{
return NULL;
}
for (drizzle_con_st* con= source->con_list; con != NULL; con= con->next)
{
if (drizzle_con_clone(drizzle, con) == NULL)
{
drizzle_free(drizzle);
return NULL;
}
}
return drizzle;
}
void drizzle_free(drizzle_st *drizzle)
{
if (drizzle->context != NULL && drizzle->context_free_fn != NULL)
{
drizzle->context_free_fn(drizzle, drizzle->context);
}
if (drizzle->options.is_free_objects)
{
drizzle_con_free_all(drizzle);
drizzle_query_free_all(drizzle);
}
else if (drizzle->options.is_assert_dangling)
{
assert(drizzle->con_list == NULL);
assert(drizzle->query_list == NULL);
}
free(drizzle->pfds);
delete drizzle;
#if defined(_WIN32)
/* if it is MS windows, invoke WSACleanup() at the end*/
WSACleanup();
#endif
}
const char *drizzle_error(const drizzle_st *drizzle)
{
return drizzle->last_error;
}
drizzle_return_t drizzle_set_option(drizzle_st *drizzle, drizzle_options_t arg, bool set)
{
switch (arg)
{
case DRIZZLE_NON_BLOCKING:
drizzle->options.is_non_blocking= set;
return DRIZZLE_RETURN_OK;
case DRIZZLE_FREE_OBJECTS:
return DRIZZLE_RETURN_OK;
case DRIZZLE_ASSERT_DANGLING:
return DRIZZLE_RETURN_OK;
default:
break;
}
return DRIZZLE_RETURN_INVALID_ARGUMENT;
}
int drizzle_errno(const drizzle_st *drizzle)
{
return drizzle->last_errno;
}
uint16_t drizzle_error_code(const drizzle_st *drizzle)
{
return drizzle->error_code;
}
const char *drizzle_sqlstate(const drizzle_st *drizzle)
{
return drizzle->sqlstate;
}
void *drizzle_context(const drizzle_st *drizzle)
{
return drizzle->context;
}
void drizzle_set_context(drizzle_st *drizzle, void *context)
{
drizzle->context= context;
}
void drizzle_set_context_free_fn(drizzle_st *drizzle,
drizzle_context_free_fn *function)
{
drizzle->context_free_fn= function;
}
int drizzle_timeout(const drizzle_st *drizzle)
{
return drizzle->timeout;
}
void drizzle_set_timeout(drizzle_st *drizzle, int timeout)
{
drizzle->timeout= timeout;
}
drizzle_verbose_t drizzle_verbose(const drizzle_st *drizzle)
{
return drizzle->verbose;
}
void drizzle_set_verbose(drizzle_st *drizzle, drizzle_verbose_t verbose)
{
drizzle->verbose= verbose;
}
void drizzle_set_log_fn(drizzle_st *drizzle, drizzle_log_fn *function,
void *context)
{
drizzle->log_fn= function;
drizzle->log_context= context;
}
void drizzle_set_event_watch_fn(drizzle_st *drizzle,
drizzle_event_watch_fn *function,
void *context)
{
drizzle->event_watch_fn= function;
drizzle->event_watch_context= context;
}
drizzle_con_st *drizzle_con_create(drizzle_st *drizzle)
{
if (drizzle == NULL)
{
return NULL;
}
drizzle_con_st *con= new (std::nothrow) drizzle_con_st;
if (con == NULL)
{
return NULL;
}
if (drizzle->con_list != NULL)
{
drizzle->con_list->prev= con;
}
con->next= drizzle->con_list;
con->prev= NULL;
drizzle->con_list= con;
drizzle->con_count++;
con->packet_number= 0;
con->protocol_version= 0;
con->state_current= 0;
con->events= 0;
con->revents= 0;
con->capabilities= DRIZZLE_CAPABILITIES_NONE;
con->charset= 0;
con->command= DRIZZLE_COMMAND_SLEEP;
con->options|= DRIZZLE_CON_MYSQL;
con->socket_type= DRIZZLE_CON_SOCKET_TCP;
con->status= DRIZZLE_CON_STATUS_NONE;
con->max_packet_size= DRIZZLE_MAX_PACKET_SIZE;
con->result_count= 0;
con->thread_id= 0;
con->backlog= DRIZZLE_DEFAULT_BACKLOG;
con->fd= -1;
con->buffer_size= 0;
con->command_offset= 0;
con->command_size= 0;
con->command_total= 0;
con->packet_size= 0;
con->addrinfo_next= NULL;
con->buffer_ptr= con->buffer;
con->command_buffer= NULL;
con->command_data= NULL;
con->context= NULL;
con->context_free_fn= NULL;
con->drizzle= drizzle;
/* con->next set above */
/* con->prev set above */
con->query= NULL;
/* con->result doesn't need to be set */
con->result_list= NULL;
con->scramble= NULL;
con->socket.tcp.addrinfo= NULL;
con->socket.tcp.host= NULL;
con->socket.tcp.port= 0;
/* con->buffer doesn't need to be set */
con->schema[0]= 0;
con->password[0]= 0;
/* con->scramble_buffer doesn't need to be set */
con->server_version[0]= 0;
/* con->state_stack doesn't need to be set */
con->user[0]= 0;
return con;
}
drizzle_con_st *drizzle_con_clone(drizzle_st *drizzle, drizzle_con_st *source)
{
drizzle_con_st *con= drizzle_con_create(drizzle);
if (con == NULL)
{
return NULL;
}
/* Clear "operational" options such as IO status. */
con->options|= (source->options & ~(DRIZZLE_CON_ALLOCATED|DRIZZLE_CON_READY|
DRIZZLE_CON_NO_RESULT_READ|DRIZZLE_CON_IO_READY|
DRIZZLE_CON_LISTEN));
con->backlog= source->backlog;
strcpy(con->schema, source->schema);
strcpy(con->password, source->password);
strcpy(con->user, source->user);
switch (source->socket_type)
{
case DRIZZLE_CON_SOCKET_TCP:
drizzle_con_set_tcp(con, source->socket.tcp.host, source->socket.tcp.port);
break;
case DRIZZLE_CON_SOCKET_UDS:
drizzle_con_set_uds(con, source->socket.uds.sockaddr.sun_path);
break;
}
return con;
}
void drizzle_con_free(drizzle_con_st *con)
{
if (con->context != NULL && con->context_free_fn != NULL)
{
con->context_free_fn(con, con->context);
}
if (con->drizzle->options.is_free_objects)
{
drizzle_result_free_all(con);
}
else if (con->drizzle->options.is_assert_dangling)
{
assert(con->result_list == NULL);
}
if (con->fd != -1)
{
drizzle_con_close(con);
}
drizzle_con_reset_addrinfo(con);
if (con->drizzle->con_list == con)
{
con->drizzle->con_list= con->next;
}
if (con->prev != NULL)
{
con->prev->next= con->next;
}
if (con->next != NULL)
{
con->next->prev= con->prev;
}
con->drizzle->con_count--;
delete con;
}
void drizzle_con_free_all(drizzle_st *drizzle)
{
while (drizzle->con_list != NULL)
{
drizzle_con_free(drizzle->con_list);
}
}
drizzle_return_t drizzle_con_wait(drizzle_st *drizzle)
{
struct pollfd *pfds;
int ret;
drizzle_return_t dret;
if (drizzle->pfds_size < drizzle->con_count)
{
pfds= (struct pollfd *)realloc(drizzle->pfds, drizzle->con_count * sizeof(struct pollfd));
if (pfds == NULL)
{
drizzle_set_error(drizzle, "drizzle_con_wait", "realloc");
return DRIZZLE_RETURN_MEMORY;
}
drizzle->pfds= pfds;
drizzle->pfds_size= drizzle->con_count;
}
else
{
pfds= drizzle->pfds;
}
uint32_t x= 0;
for (drizzle_con_st* con= drizzle->con_list; con != NULL; con= con->next)
{
if (con->events == 0)
continue;
pfds[x].fd= con->fd;
pfds[x].events= con->events;
pfds[x].revents= 0;
x++;
}
if (x == 0)
{
drizzle_set_error(drizzle, "drizzle_con_wait",
"no active file descriptors");
return DRIZZLE_RETURN_NO_ACTIVE_CONNECTIONS;
}
while (1)
{
drizzle_log_crazy(drizzle, "poll count=%d timeout=%d", x,
drizzle->timeout);
ret= poll(pfds, x, drizzle->timeout);
drizzle_log_crazy(drizzle, "poll return=%d errno=%d", ret, errno);
if (ret == -1)
{
if (errno == EINTR)
continue;
drizzle_set_error(drizzle, "drizzle_con_wait", "poll:%d", errno);
drizzle->last_errno= errno;
return DRIZZLE_RETURN_ERRNO;
}
break;
}
if (ret == 0)
{
drizzle_set_error(drizzle, "drizzle_con_wait", "timeout reached");
return DRIZZLE_RETURN_TIMEOUT;
}
x= 0;
for (drizzle_con_st* con= drizzle->con_list; con != NULL; con= con->next)
{
if (con->events == 0)
continue;
dret= drizzle_con_set_revents(con, pfds[x].revents);
if (dret != DRIZZLE_RETURN_OK)
return dret;
x++;
}
return DRIZZLE_RETURN_OK;
}
drizzle_con_st *drizzle_con_ready(drizzle_st *drizzle)
{
/* We can't keep state between calls since connections may be removed during
processing. If this list ever gets big, we may want something faster. */
for (drizzle_con_st* con= drizzle->con_list; con != NULL; con= con->next)
{
if (con->options & DRIZZLE_CON_IO_READY)
{
con->options&= ~DRIZZLE_CON_IO_READY;
return con;
}
}
return NULL;
}
drizzle_con_st *drizzle_con_ready_listen(drizzle_st *drizzle)
{
/* We can't keep state between calls since connections may be removed during
processing. If this list ever gets big, we may want something faster. */
for (drizzle_con_st* con= drizzle->con_list; con != NULL; con= con->next)
{
if ((con->options & (DRIZZLE_CON_IO_READY | DRIZZLE_CON_LISTEN)) ==
(DRIZZLE_CON_IO_READY | DRIZZLE_CON_LISTEN))
{
con->options&= ~DRIZZLE_CON_IO_READY;
return con;
}
}
return NULL;
}
/*
* Client Definitions
*/
drizzle_con_st *drizzle_con_add_tcp(drizzle_st *drizzle,
const char *host, in_port_t port,
const char *user, const char *password,
const char *db,
drizzle_con_options_t options)
{
drizzle_con_st *con= drizzle_con_create(drizzle);
if (con == NULL)
{
return NULL;
}
drizzle_con_set_tcp(con, host, port);
drizzle_con_set_auth(con, user, password);
drizzle_con_set_db(con, db);
drizzle_con_add_options(con, options);
return con;
}
drizzle_con_st *drizzle_con_add_uds(drizzle_st *drizzle,
const char *uds, const char *user,
const char *password, const char *db,
drizzle_con_options_t options)
{
drizzle_con_st *con= drizzle_con_create(drizzle);
if (con == NULL)
{
return NULL;
}
drizzle_con_set_uds(con, uds);
drizzle_con_set_auth(con, user, password);
drizzle_con_set_db(con, db);
drizzle_con_add_options(con, options);
return con;
}
/*
* Server Definitions
*/
drizzle_con_st *drizzle_con_add_tcp_listen(drizzle_st *drizzle,
const char *host, in_port_t port,
int backlog,
drizzle_con_options_t options)
{
drizzle_con_st *con= drizzle_con_create(drizzle);
if (con == NULL)
{
return NULL;
}
drizzle_con_set_tcp(con, host, port);
drizzle_con_set_backlog(con, backlog);
drizzle_con_add_options(con, options | DRIZZLE_CON_LISTEN);
return con;
}
drizzle_con_st *drizzle_con_add_uds_listen(drizzle_st *drizzle,
const char *uds, int backlog,
drizzle_con_options_t options)
{
drizzle_con_st *con= drizzle_con_create(drizzle);
if (con == NULL)
{
return NULL;
}
drizzle_con_set_uds(con, uds);
drizzle_con_set_backlog(con, backlog);
drizzle_con_add_options(con, options | DRIZZLE_CON_LISTEN);
return con;
}
drizzle_con_st *drizzle_con_accept(drizzle_st *drizzle,
drizzle_return_t *ret_ptr)
{
drizzle_return_t unused;
if (ret_ptr == NULL)
{
ret_ptr= &unused;
}
while (1)
{
if (drizzle_con_st* ready= drizzle_con_ready_listen(drizzle))
{
int fd= accept(ready->fd, NULL, NULL);
drizzle_con_st *con= drizzle_con_create(drizzle);
if (con == NULL)
{
(void)closesocket(fd);
*ret_ptr= DRIZZLE_RETURN_MEMORY;
return NULL;
}
*ret_ptr= drizzle_con_set_fd(con, fd);
if (*ret_ptr != DRIZZLE_RETURN_OK)
{
(void)closesocket(fd);
return NULL;
}
if (ready->options & DRIZZLE_CON_MYSQL)
drizzle_con_add_options(con, DRIZZLE_CON_MYSQL);
*ret_ptr= DRIZZLE_RETURN_OK;
return con;
}
if (drizzle->options.is_non_blocking)
{
*ret_ptr= DRIZZLE_RETURN_IO_WAIT;
return NULL;
}
for (drizzle_con_st* ready= drizzle->con_list; ready != NULL; ready= ready->next)
{
if (ready->options & DRIZZLE_CON_LISTEN)
{
drizzle_con_set_events(ready, POLLIN);
}
}
*ret_ptr= drizzle_con_wait(drizzle);
if (*ret_ptr != DRIZZLE_RETURN_OK)
{
return NULL;
}
}
}
/*
* Local Definitions
*/
void drizzle_set_error(drizzle_st *drizzle, const char *function,
const char *format, ...)
{
if (drizzle == NULL)
{
return;
}
char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
size_t size= strlen(function);
char* ptr= (char *)memcpy(log_buffer, function, size);
ptr+= size;
ptr[0]= ':';
size++;
ptr++;
va_list args;
va_start(args, format);
int written= vsnprintf(ptr, DRIZZLE_MAX_ERROR_SIZE - size, format, args);
va_end(args);
if (written < 0)
{
size= DRIZZLE_MAX_ERROR_SIZE;
}
else
{
size+= written;
}
if (size >= DRIZZLE_MAX_ERROR_SIZE)
{
size= DRIZZLE_MAX_ERROR_SIZE - 1;
}
log_buffer[size]= 0;
if (drizzle->log_fn == NULL)
{
memcpy(drizzle->last_error, log_buffer, size + 1);
}
else
{
drizzle->log_fn(log_buffer, DRIZZLE_VERBOSE_ERROR, drizzle->log_context);
}
}
void drizzle_log(drizzle_st *drizzle, drizzle_verbose_t verbose,
const char *format, va_list args)
{
char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
if (drizzle == NULL)
{
return;
}
if (drizzle->log_fn == NULL)
{
printf("%5s: ", drizzle_verbose_name(verbose));
vprintf(format, args);
printf("\n");
}
else
{
vsnprintf(log_buffer, DRIZZLE_MAX_ERROR_SIZE, format, args);
log_buffer[DRIZZLE_MAX_ERROR_SIZE-1]= 0;
drizzle->log_fn(log_buffer, verbose, drizzle->log_context);
}
}