From 9338735aea153346d6a5f83e2878878d4a70ca27 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 12 Jun 2020 06:03:00 +0000 Subject: [PATCH] adding a primitive mariadb client device --- mio/bin/t04.c | 41 ++-- mio/lib/maria.c | 443 ++++++++++++++++++++++++++++++++++++++++++++ mio/lib/mio-maria.h | 203 ++++++++++++++++++++ 3 files changed, 676 insertions(+), 11 deletions(-) create mode 100644 mio/lib/maria.c create mode 100644 mio/lib/mio-maria.h diff --git a/mio/bin/t04.c b/mio/bin/t04.c index 31ce5a3..aef925f 100644 --- a/mio/bin/t04.c +++ b/mio/bin/t04.c @@ -4,36 +4,55 @@ #include #include +#include + static void maria_on_disconnect (mio_dev_maria_t* dev) { } static void maria_on_connect (mio_dev_maria_t* dev) { -printf ("CONNEcTED...\n"); +printf ("CONNECTED...\n"); if (mio_dev_maria_querywithbchars(dev, "SHOW STATUS", 11) <= -1) { mio_dev_maria_halt (dev); } } -static void maria_on_query_started (mio_dev_maria_t* dev) +static void maria_on_query_started (mio_dev_maria_t* dev, int maria_ret) { -printf ("QUERY SENT...\n"); - if (mio_dev_maria_fetchrow(dev) <= -1) + if (maria_ret != 0) { -printf ("FETCH ROW FAILURE\n"); - mio_dev_maria_halt (dev); +printf ("QUERY NOT SENT PROPERLY..%s\n", mysql_error(dev->hnd)); + } + else + { +printf ("QUERY SENT..\n"); + if (mio_dev_maria_fetchrows(dev) <= -1) + { +printf ("FETCH ROW FAILURE - %s\n", mysql_error(dev->hnd)); + mio_dev_maria_halt (dev); + } } } -static void maria_on_row_fetched (mio_dev_maria_t* dev, void* row) +static void maria_on_row_fetched (mio_dev_maria_t* dev, void* data) { - if (!row) printf ("NO MORE ROW..\n"); + MYSQL_ROW row = (MYSQL_ROW)data; + static int x = 0; + if (!row) + { + printf ("NO MORE ROW..\n"); + if (x == 0 && mio_dev_maria_querywithbchars(dev, "SELECT * FROM pdns.records", 26) <= -1) mio_dev_maria_halt (dev); + x++; + } else - { - printf ("GOT ROW\n"); - mio_dev_maria_fetchrow (dev); + { + if (x == 0) + printf ("%s %s\n", row[0], row[1]); + else if (x == 1) + printf ("%s %s %s %s %s\n", row[0], row[1], row[2], row[3], row[4]); + //printf ("GOT ROW\n"); } } diff --git a/mio/lib/maria.c b/mio/lib/maria.c new file mode 100644 index 0000000..cca5551 --- /dev/null +++ b/mio/lib/maria.c @@ -0,0 +1,443 @@ +/* + * $Id$ + * + Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. 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. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR 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. + */ + +#include +#include "mio-prv.h" + +#include + + +/* ========================================================================= */ + +static int dev_maria_make (mio_dev_t* dev, void* ctx) +{ + mio_t* mio = dev->mio; + mio_dev_maria_t* rdev = (mio_dev_maria_t*)dev; + mio_dev_maria_make_t* mi = (mio_dev_maria_make_t*)ctx; + + rdev->hnd = mysql_init(MIO_NULL); + if (MIO_UNLIKELY(!rdev->hnd)) + { + mio_seterrnum (mio, MIO_ESYSMEM); + return -1; + } + + if (mysql_options(rdev->hnd, MYSQL_OPT_NONBLOCK, 0) != 0) + { + mio_seterrbfmt (mio, MIO_ESYSERR, "%s", mysql_error(rdev->hnd)); + mysql_close (rdev->hnd); + rdev->hnd = MIO_NULL; + return -1; + } + + { + my_bool x = 0; + mysql_options(rdev->hnd, MYSQL_OPT_RECONNECT, &x); + } + + rdev->dev_cap = MIO_DEV_CAP_IN | MIO_DEV_CAP_OUT | MIO_DEV_CAP_VIRTUAL; /* mysql_init() doesn't create a socket. so no IO is possible at this point */ + rdev->on_read = mi->on_read; + rdev->on_write = mi->on_write; + rdev->on_connect = mi->on_connect; + rdev->on_disconnect = mi->on_disconnect; + rdev->on_query_started = mi->on_query_started; + rdev->on_row_fetched = mi->on_row_fetched; + return 0; +} + +static int dev_maria_kill (mio_dev_t* dev, int force) +{ + /*mio_t* mio = dev->mio;*/ + mio_dev_maria_t* rdev = (mio_dev_maria_t*)dev; + + if (rdev->on_disconnect) rdev->on_disconnect (rdev); + + if (rdev->hnd) + { + mysql_close (rdev->hnd); + rdev->hnd = MIO_NULL; + } + + return 0; +} + +static mio_syshnd_t dev_maria_getsyshnd (mio_dev_t* dev) +{ + mio_dev_maria_t* rdev = (mio_dev_maria_t*)dev; + return (mio_syshnd_t)mysql_get_socket(rdev->hnd); +} + +static int events_to_mysql_wstatus (int events) +{ + int wstatus = 0; + if (events & MIO_DEV_EVENT_IN) wstatus |= MYSQL_WAIT_READ; + if (events & MIO_DEV_EVENT_OUT) wstatus |= MYSQL_WAIT_WRITE; + if (events & MIO_DEV_EVENT_PRI) wstatus |= MYSQL_WAIT_EXCEPT; + return wstatus; +} + +static int mysql_wstatus_to_events (int wstatus) +{ + int events = 0; + if (wstatus & MYSQL_WAIT_READ) events |= MIO_DEV_EVENT_IN; + if (wstatus & MYSQL_WAIT_WRITE) events |= MIO_DEV_EVENT_OUT; + if (wstatus & MYSQL_WAIT_EXCEPT) events |= MIO_DEV_EVENT_PRI; +/* TODO: wstatus& MYSQL_WAIT_TIMEOUT? */ + return events; +} + +static MIO_INLINE void watch_mysql (mio_dev_maria_t* rdev, int wstatus) +{ + if (mio_dev_watch((mio_dev_t*)rdev, MIO_DEV_WATCH_UPDATE, mysql_wstatus_to_events(wstatus)) <= -1) + { + /* watcher update failure. it's critical */ + mio_stop (rdev->mio, MIO_STOPREQ_WATCHER_ERROR); + } +} + + +static void start_fetch_row (mio_dev_maria_t* rdev) +{ + MYSQL_ROW row; + int status; + + status = mysql_fetch_row_start(&row, rdev->res); + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_ROW_FETCHING); + if (status) + { + /* row fetched */ + rdev->row_fetched = 0; + watch_mysql (rdev, status); + } + else + { + /* row fetched - don't handle it immediately here */ + rdev->row_fetched = 1; + rdev->row_wstatus = status; + rdev->row = row; + watch_mysql (rdev, MYSQL_WAIT_READ | MYSQL_WAIT_WRITE); + } +} + + +static int dev_maria_ioctl (mio_dev_t* dev, int cmd, void* arg) +{ + mio_t* mio = dev->mio; + mio_dev_maria_t* rdev = (mio_dev_maria_t*)dev; + + switch (cmd) + { + case MIO_DEV_MARIA_CONNECT: + { + mio_dev_maria_connect_t* ci = (mio_dev_maria_connect_t*)arg; + MYSQL* ret; + int status; + + + if (MIO_DEV_MARIA_GET_PROGRESS(rdev)) + { + /* can't connect again */ + mio_seterrbfmt (mio, MIO_EPERM, "operation in progress. disallowed to connect again"); + return -1; + } + + status = mysql_real_connect_start(&ret, rdev->hnd, ci->host, ci->username, ci->password, ci->dbname, ci->port, MIO_NULL, 0); + rdev->dev_cap &= ~MIO_DEV_CAP_VIRTUAL; /* a socket is created in mysql_real_connect_start() */ + if (status) + { + /* not connected */ + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_CONNECTING); + rdev->connected = 0; + watch_mysql (rdev, status); + } + else + { + /* connected immediately */ + if (MIO_UNLIKELY(!ret)) + { + mio_seterrbfmt (mio, MIO_ESYSERR, "%s", mysql_error(rdev->hnd)); + return -1; + } + + /* regiter it in the multiplexer so that the ready() handler is + * invoked to call the on_connect() callback */ + rdev->connected = 1; + watch_mysql (rdev, MYSQL_WAIT_READ | MYSQL_WAIT_WRITE); /* TODO: verify this */ + } + return 0; + } + + case MIO_DEV_MARIA_QUERY_WITH_BCS: + { + const mio_bcs_t* qstr = (const mio_bcs_t*)arg; + int err, status; + + if (rdev->res) /* TODO: more accurate check */ + { + mio_seterrbfmt (mio, MIO_EPERM, "operation in progress. disallowed to query again"); + return -1; + } + + status = mysql_real_query_start(&err, rdev->hnd, qstr->ptr, qstr->len); + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_QUERY_STARTING); + if (status) + { + /* not done */ + rdev->query_started = 0; + watch_mysql (rdev, status); + } + else + { + /* query sent immediately */ + if (MIO_UNLIKELY(err)) + { + mio_seterrbfmt (mio, MIO_ESYSERR, "%s", mysql_error(rdev->hnd)); + return -1; + } + + rdev->query_started = 1; + rdev->query_ret = err; + watch_mysql (rdev, MYSQL_WAIT_READ | MYSQL_WAIT_WRITE); + } + return 0; + } + + case MIO_DEV_MARIA_FETCH_ROW: + { + int status; + + if (!rdev->res) + { + rdev->res = mysql_use_result(rdev->hnd); + if (MIO_UNLIKELY(!rdev->res)) + { + mio_seterrbfmt (mio, MIO_ESYSERR, "%s", mysql_error(rdev->hnd)); + return -1; + } + } + + start_fetch_row (rdev); + return 0; + } + + default: + mio_seterrnum (mio, MIO_EINVAL); + return -1; + } +} + +static mio_dev_mth_t dev_maria_methods = +{ + dev_maria_make, + dev_maria_kill, + dev_maria_getsyshnd, + + MIO_NULL, + MIO_NULL, + MIO_NULL, + dev_maria_ioctl +}; + +/* ========================================================================= */ + + +static int dev_evcb_maria_ready (mio_dev_t* dev, int events) +{ + mio_t* mio = dev->mio; + mio_dev_maria_t* rdev = (mio_dev_maria_t*)dev; + +#if 0 + if (events & MIO_DEV_EVENT_ERR) + { + int errcode; + mio_scklen_t len; + + len = MIO_SIZEOF(errcode); + if (getsockopt(mysql_get_socket(rdev->hnd), SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) + { + /* the error number is set to the socket error code. + * errno resulting from getsockopt() doesn't reflect the actual + * socket error. so errno is not used to set the error number. + * instead, the generic device error MIO_EDEVERRR is used */ + mio_seterrbfmt (mio, MIO_EDEVERR, "device error - unable to get SO_ERROR"); + } + else + { + mio_seterrwithsyserr (mio, 0, errcode); + } + + return -1; + } +#endif + + switch (MIO_DEV_MARIA_GET_PROGRESS(rdev)) + { + case MIO_DEV_MARIA_CONNECTING: + + if (rdev->connected) + { + rdev->connected = 0; + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_CONNECTED); + if (rdev->on_connect) rdev->on_connect (rdev); + } + else + { + int status; + MYSQL* tmp; + + status = mysql_real_connect_cont(&tmp, rdev->hnd, events_to_mysql_wstatus(events)); + watch_mysql (rdev, status); + + if (!status) + { + /* connected */ + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_CONNECTED); + if (rdev->on_connect) rdev->on_connect (rdev); + } + } + break; + + case MIO_DEV_MARIA_QUERY_STARTING: + if (rdev->query_started) + { + rdev->query_started = 0; + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_QUERY_STARTED); + if (rdev->on_query_started) rdev->on_query_started (rdev, rdev->query_ret); + } + else + { + int status; + int tmp; + + status = mysql_real_query_cont(&tmp, rdev->hnd, events_to_mysql_wstatus(events)); + watch_mysql (rdev, status); + + if (!status) + { + /* query sent */ + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_QUERY_STARTED); + if (rdev->on_query_started) rdev->on_query_started (rdev, tmp); + } + } + + break; + + case MIO_DEV_MARIA_ROW_FETCHING: + { + int status; + MYSQL_ROW row; + + if (rdev->row_fetched) + { + row = (MYSQL_ROW)rdev->row; + rdev->row_fetched = 0; + + if (!row) + { + MIO_ASSERT (mio, rdev->res != MIO_NULL); + mysql_free_result (rdev->res); /* this doesn't block after the last row */ + rdev->res = MIO_NULL; + + watch_mysql (rdev, rdev->row_wstatus); + } + + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_ROW_FETCHED); + if (rdev->on_row_fetched) rdev->on_row_fetched (rdev, row); + + if (row) start_fetch_row (rdev); + } + else + { + /* TODO: if rdev->res is MIO_NULL, error.. */ + status = mysql_fetch_row_cont(&row, rdev->res, events_to_mysql_wstatus(events)); + + if (!status) + { + if (!row) + { + /* the last row has been received - cleanup before invoking the callback */ + watch_mysql (rdev, status); + + MIO_ASSERT (mio, rdev->res != MIO_NULL); + mysql_free_result (rdev->res); /* this doesn't block after the last row */ + rdev->res = MIO_NULL; + } + + MIO_DEV_MARIA_SET_PROGRESS (rdev, MIO_DEV_MARIA_ROW_FETCHED); + if (rdev->on_row_fetched) rdev->on_row_fetched (rdev, row); + + if (row) start_fetch_row (rdev); /* arrange to fetch the next row */ + } + else + { + watch_mysql (rdev, status); + } + } + + break; + } + + default: + mio_seterrbfmt (mio, MIO_EINTERN, "invalid progress state in maria"); + return -1; + } + + return 0; /* success. but skip core event handling */ +} + +static mio_dev_evcb_t dev_maria_event_callbacks = +{ + dev_evcb_maria_ready, + MIO_NULL, /* no read callback */ + MIO_NULL /* no write callback */ +}; + + +/* ========================================================================= */ + + +mio_dev_maria_t* mio_dev_maria_make (mio_t* mio, mio_oow_t xtnsize, const mio_dev_maria_make_t* mi) +{ + return (mio_dev_maria_t*)mio_dev_make( + mio, MIO_SIZEOF(mio_dev_maria_t) + xtnsize, + &dev_maria_methods, &dev_maria_event_callbacks, (void*)mi); +} + +int mio_dev_maria_connect (mio_dev_maria_t* dev, mio_dev_maria_connect_t* ci) +{ + return mio_dev_ioctl((mio_dev_t*)dev, MIO_DEV_MARIA_CONNECT, ci); +} + +int mio_dev_maria_querywithbchars (mio_dev_maria_t* dev, const mio_bch_t* qstr, mio_oow_t qlen) +{ + mio_bcs_t bcs = { (mio_bch_t*)qstr, qlen}; + return mio_dev_ioctl((mio_dev_t*)dev, MIO_DEV_MARIA_QUERY_WITH_BCS, &bcs); +} + +int mio_dev_maria_fetchrows (mio_dev_maria_t* dev) +{ + return mio_dev_ioctl((mio_dev_t*)dev, MIO_DEV_MARIA_FETCH_ROW, MIO_NULL); +} diff --git a/mio/lib/mio-maria.h b/mio/lib/mio-maria.h new file mode 100644 index 0000000..cb3f741 --- /dev/null +++ b/mio/lib/mio-maria.h @@ -0,0 +1,203 @@ +/* + * $Id$ + * + Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted mariavided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must remariaduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials mariavided with the distribution. + + THIS SOFTWARE IS PIPEVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PIPECUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PIPEFITS; 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. + */ + +#ifndef _MIO_PIPE_H_ +#define _MIO_PIPE_H_ + +#include + +typedef struct mio_dev_maria_t mio_dev_maria_t; + +enum mio_dev_maria_state_t +{ + /* the following items(progress bits) are mutually exclusive */ + MIO_DEV_MARIA_CONNECTING = (1 << 0), + MIO_DEV_MARIA_CONNECTED = (1 << 1), + MIO_DEV_MARIA_QUERY_STARTING = (1 << 2), + MIO_DEV_MARIA_QUERY_STARTED = (1 << 3), + MIO_DEV_MARIA_ROW_FETCHING = (1 << 4), + MIO_DEV_MARIA_ROW_FETCHED = (1 << 5), + + +#if 0 + /* the following items can be bitwise-ORed with an exclusive item above */ + MIO_DEV_MARIA_LENIENT = (1 << 14), + MIO_DEV_MARIA_INTERCEPTED = (1 << 15), +#endif + + /* convenience bit masks */ + MIO_DEV_MARIA_ALL_PROGRESS_BITS = (MIO_DEV_MARIA_CONNECTING | + MIO_DEV_MARIA_CONNECTED | + MIO_DEV_MARIA_QUERY_STARTING | + MIO_DEV_MARIA_QUERY_STARTED | + MIO_DEV_MARIA_ROW_FETCHING | + MIO_DEV_MARIA_ROW_FETCHED) +}; +typedef enum mio_dev_maria_state_t mio_dev_maria_state_t; + +#define MIO_DEV_MARIA_SET_PROGRESS(dev,bit) do { \ + (dev)->state &= ~MIO_DEV_MARIA_ALL_PROGRESS_BITS; \ + (dev)->state |= (bit); \ +} while(0) + +#define MIO_DEV_MARIA_GET_PROGRESS(dev) ((dev)->state & MIO_DEV_MARIA_ALL_PROGRESS_BITS) + + +typedef int (*mio_dev_maria_on_read_t) ( + mio_dev_maria_t* dev, + const void* data, + mio_iolen_t len +); + +typedef int (*mio_dev_maria_on_write_t) ( + mio_dev_maria_t* dev, + mio_iolen_t wrlen, + void* wrctx +); + +typedef void (*mio_dev_maria_on_connect_t) ( + mio_dev_maria_t* dev +); + +typedef void (*mio_dev_maria_on_disconnect_t) ( + mio_dev_maria_t* dev +); + +typedef void (*mio_dev_maria_on_query_started_t) ( + mio_dev_maria_t* dev, + int maria_ret +); + +typedef void (*mio_dev_maria_on_row_fetched_t) ( + mio_dev_maria_t* dev, + void* row_data +); + +struct mio_dev_maria_t +{ + MIO_DEV_HEADER; + + void* hnd; + void* res; + int state; + + unsigned int connected; + unsigned int query_started; + unsigned int row_fetched; + + int query_ret; + int row_wstatus; + void* row; + + mio_dev_maria_on_read_t on_read; + mio_dev_maria_on_write_t on_write; + mio_dev_maria_on_connect_t on_connect; + mio_dev_maria_on_disconnect_t on_disconnect; + mio_dev_maria_on_query_started_t on_query_started; + mio_dev_maria_on_row_fetched_t on_row_fetched; +}; + +typedef struct mio_dev_maria_make_t mio_dev_maria_make_t; +struct mio_dev_maria_make_t +{ + mio_dev_maria_on_write_t on_write; /* mandatory */ + mio_dev_maria_on_read_t on_read; /* mandatory */ + mio_dev_maria_on_connect_t on_connect; /* optional */ + mio_dev_maria_on_disconnect_t on_disconnect; /* optional */ + mio_dev_maria_on_query_started_t on_query_started; + mio_dev_maria_on_row_fetched_t on_row_fetched; +}; + +typedef struct mio_dev_maria_connect_t mio_dev_maria_connect_t; +struct mio_dev_maria_connect_t +{ + const mio_bch_t* host; + const mio_bch_t* username; + const mio_bch_t* password; + const mio_bch_t* dbname; + mio_uint16_t port; +}; + +enum mio_dev_maria_ioctl_cmd_t +{ + MIO_DEV_MARIA_CONNECT, + MIO_DEV_MARIA_QUERY_WITH_BCS, + MIO_DEV_MARIA_FETCH_ROW +}; +typedef enum mio_dev_maria_ioctl_cmd_t mio_dev_maria_ioctl_cmd_t; + +#ifdef __cplusplus +extern "C" { +#endif + +MIO_EXPORT mio_dev_maria_t* mio_dev_maria_make ( + mio_t* mio, + mio_oow_t xtnsize, + const mio_dev_maria_make_t* data +); + +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE mio_t* mio_dev_maria_getmio (mio_dev_maria_t* maria) { return mio_dev_getmio((mio_dev_t*)maria); } +#else +# define mio_dev_maria_getmio(maria) mio_dev_getmio(maria) +#endif + +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void* mio_dev_maria_getxtn (mio_dev_maria_t* maria) { return (void*)(maria + 1); } +#else +# define mio_dev_maria_getxtn(maria) ((void*)(((mio_dev_maria_t*)maria) + 1)) +#endif + + +MIO_EXPORT int mio_dev_maria_connect ( + mio_dev_maria_t* maria, + mio_dev_maria_connect_t* ci +); + +MIO_EXPORT int mio_dev_maria_querywithbchars ( + mio_dev_maria_t* maria, + const mio_bch_t* qstr, + mio_oow_t qlen +); + +MIO_EXPORT int mio_dev_maria_fetchrows ( + mio_dev_maria_t* maria +); + +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void mio_dev_maria_kill (mio_dev_maria_t* maria) { mio_dev_kill ((mio_dev_t*)maria); } +static MIO_INLINE void mio_dev_maria_halt (mio_dev_maria_t* maria) { mio_dev_halt ((mio_dev_t*)maria); } +#else +# define mio_dev_maria_kill(maria) mio_dev_kill((mio_dev_t*)maria) +# define mio_dev_maria_halt(maria) mio_dev_halt((mio_dev_t*)maria) +#endif + + +#ifdef __cplusplus +} +#endif + +#endif