"Fossies" - the Fresh Open Source Software Archive

Member "mariadb-connector-c-3.0.8-src/libmariadb/mariadb_lib.c" (18 Dec 2018, 118900 Bytes) of package /linux/misc/mariadb-connector-c-3.0.8-src.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "mariadb_lib.c": 3.0.7_vs_3.0.8.

    1 /************************************************************************************
    2     Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
    3                  Monty Program AB
    4 
    5    This library is free software; you can redistribute it and/or
    6    modify it under the terms of the GNU Library General Public
    7    License as published by the Free Software Foundation; either
    8    version 2 of the License, or (at your option) any later version.
    9 
   10    This library is distributed in the hope that it will be useful,
   11    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13    Library General Public License for more details.
   14 
   15    You should have received a copy of the GNU Library General Public
   16    License along with this library; if not see <http://www.gnu.org/licenses>
   17    or write to the Free Software Foundation, Inc.,
   18    51 Franklin St., Fifth Floor, Boston, MA 02110, USA
   19 
   20    Part of this code includes code from the PHP project which
   21    is freely available from http://www.php.net
   22 *************************************************************************************/
   23 
   24 #include <ma_global.h>
   25 
   26 #include <ma_sys.h>
   27 #include <ma_string.h>
   28 #include <mariadb_ctype.h>
   29 #include <ma_common.h>
   30 #include "ma_context.h"
   31 #include "mysql.h"
   32 #include "mariadb_version.h"
   33 #include "ma_server_error.h"
   34 #include <mariadb/ma_io.h>
   35 #include "errmsg.h"
   36 #include <sys/stat.h>
   37 #include <signal.h>
   38 #include <time.h>
   39 #include <mariadb_dyncol.h>
   40 
   41 #ifdef HAVE_PWD_H
   42 #include <pwd.h>
   43 #endif
   44 #if !defined(MSDOS) && !defined(_WIN32)
   45 #include <sys/socket.h>
   46 #include <netinet/in.h>
   47 #include <arpa/inet.h>
   48 #include <netdb.h>
   49 #ifdef HAVE_SELECT_H
   50 #  include <select.h>
   51 #endif
   52 #ifdef HAVE_SYS_SELECT_H
   53 #include <sys/select.h>
   54 #endif
   55 #endif
   56 #ifdef HAVE_SYS_UN_H
   57 #  include <sys/un.h>
   58 #endif
   59 #ifndef INADDR_NONE
   60 #define INADDR_NONE -1
   61 #endif
   62 #include <ma_sha1.h>
   63 #ifndef _WIN32
   64 #include <poll.h>
   65 #endif
   66 #include <ma_pvio.h>
   67 #ifdef HAVE_TLS
   68 #include <ma_tls.h>
   69 #endif
   70 #include <mysql/client_plugin.h>
   71 #ifdef _WIN32
   72 #include "Shlwapi.h"
   73 #endif
   74 
   75 #define ASYNC_CONTEXT_DEFAULT_STACK_SIZE (4096*15)
   76 #define MA_RPL_VERSION_HACK "5.5.5-"
   77 
   78 #undef max_allowed_packet
   79 #undef net_buffer_length
   80 extern ulong max_allowed_packet; /* net.c */
   81 extern ulong net_buffer_length;  /* net.c */
   82 
   83 static MYSQL_PARAMETERS mariadb_internal_parameters= {&max_allowed_packet, &net_buffer_length, 0};
   84 static my_bool mysql_client_init=0;
   85 static void mysql_close_options(MYSQL *mysql);
   86 extern void release_configuration_dirs();
   87 extern char **get_default_configuration_dirs();
   88 extern my_bool  ma_init_done;
   89 extern my_bool  mysql_ps_subsystem_initialized;
   90 extern my_bool mysql_handle_local_infile(MYSQL *mysql, const char *filename);
   91 extern const MARIADB_CHARSET_INFO * mysql_find_charset_nr(uint charsetnr);
   92 extern const MARIADB_CHARSET_INFO * mysql_find_charset_name(const char * const name);
   93 extern my_bool set_default_charset_by_name(const char *cs_name, myf flags __attribute__((unused)));
   94 extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
   95                            const char *data_plugin, const char *db);
   96 extern int net_add_multi_command(NET *net, uchar command, const uchar *packet,
   97                                  size_t length);
   98 
   99 extern LIST *pvio_callback;
  100 
  101 /* prepare statement methods from my_stmt.c */
  102 extern my_bool mthd_supported_buffer_type(enum enum_field_types type);
  103 extern my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt);
  104 extern my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt);
  105 extern my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt);
  106 extern int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row);
  107 extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row);
  108 extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt);
  109 extern void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt);
  110 extern my_bool _mariadb_read_options(MYSQL *mysql, const char *dir, const char *config_file, char *group, unsigned int recursion);
  111 extern unsigned char *mysql_net_store_length(unsigned char *packet, size_t length);
  112 
  113 extern void
  114 my_context_install_suspend_resume_hook(struct mysql_async_context *b,
  115                                        void (*hook)(my_bool, void *),
  116                                        void *user_data);
  117 
  118 uint mysql_port=0;
  119 my_string mysql_unix_port=0;
  120 
  121 #define CONNECT_TIMEOUT 0
  122 
  123 struct st_mariadb_methods MARIADB_DEFAULT_METHODS;
  124 
  125 #if defined(MSDOS) || defined(_WIN32)
  126 // socket_errno is defined in ma_global.h for all platforms
  127 #define perror(A)
  128 #else
  129 #include <errno.h>
  130 #define SOCKET_ERROR -1
  131 #endif /* _WIN32 */
  132 
  133 #include <mysql/client_plugin.h>
  134 
  135 #define native_password_plugin_name "mysql_native_password"
  136 
  137 #define IS_CONNHDLR_ACTIVE(mysql)\
  138   ((mysql)->extension && (mysql)->extension->conn_hdlr)
  139 
  140 static void end_server(MYSQL *mysql);
  141 static void mysql_close_memory(MYSQL *mysql);
  142 void read_user_name(char *name);
  143 my_bool STDCALL mariadb_reconnect(MYSQL *mysql);
  144 static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length);
  145 
  146 extern int mysql_client_plugin_init();
  147 extern void mysql_client_plugin_deinit();
  148 
  149 /* net_get_error */
  150 void net_get_error(char *buf, size_t buf_len,
  151        char *error, size_t error_len,
  152        unsigned int *error_no,
  153        char *sqlstate)
  154 {
  155   char *p= buf;
  156   size_t error_msg_len= 0;
  157 
  158   if (buf_len > 2)
  159   {
  160     *error_no= uint2korr(p);
  161     p+= 2;
  162 
  163     /* since 4.1 sqlstate is following */
  164     if (*p == '#')
  165     {
  166       memcpy(sqlstate, ++p, SQLSTATE_LENGTH);
  167       p+= SQLSTATE_LENGTH;
  168     }
  169     error_msg_len= buf_len - (p - buf);
  170     error_msg_len= MIN(error_msg_len, error_len - 1);
  171     memcpy(error, p, error_msg_len);
  172   }
  173   else
  174   {
  175     *error_no= CR_UNKNOWN_ERROR;
  176     memcpy(sqlstate, SQLSTATE_UNKNOWN, SQLSTATE_LENGTH);
  177   }
  178 }
  179 
  180 /*****************************************************************************
  181 ** read a packet from server. Give error message if socket was down
  182 ** or packet is an error message
  183 *****************************************************************************/
  184 
  185 ulong
  186 ma_net_safe_read(MYSQL *mysql)
  187 {
  188   NET *net= &mysql->net;
  189   ulong len=0;
  190 
  191 restart:
  192   if (net->pvio != 0)
  193     len=ma_net_read(net);
  194 
  195   if (len == packet_error || len == 0)
  196   {
  197     end_server(mysql);
  198     my_set_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
  199              CR_NET_PACKET_TOO_LARGE:
  200              CR_SERVER_LOST,
  201          SQLSTATE_UNKNOWN, 0, errno);
  202     return(packet_error);
  203   }
  204   if (net->read_pos[0] == 255)
  205   {
  206     if (len > 3)
  207     {
  208       char *pos=(char*) net->read_pos+1;
  209       uint last_errno=uint2korr(pos);
  210       pos+=2;
  211       len-=2;
  212 
  213       if (last_errno== 65535 &&
  214           ((mariadb_connection(mysql) && (mysql->server_capabilities & CLIENT_PROGRESS)) ||
  215            (!(mysql->extension->mariadb_server_capabilities & MARIADB_CLIENT_PROGRESS << 32))))
  216       {
  217         if (cli_report_progress(mysql, (uchar *)pos, (uint) (len-1)))
  218         {
  219           /* Wrong packet */
  220           my_set_error(mysql, CR_MALFORMED_PACKET, SQLSTATE_UNKNOWN, 0);
  221           return (packet_error);
  222         }
  223         goto restart;
  224       }
  225       net->last_errno= last_errno;
  226       if (pos[0]== '#')
  227       {
  228         ma_strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
  229         pos+= SQLSTATE_LENGTH + 1;
  230       }
  231       else
  232       {
  233         strncpy(net->sqlstate, SQLSTATE_UNKNOWN, SQLSTATE_LENGTH);
  234       }
  235       ma_strmake(net->last_error,(char*) pos,
  236               min(len,sizeof(net->last_error)-1));
  237     }
  238     else
  239     {
  240       my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
  241     }
  242 
  243     mysql->server_status&= ~SERVER_MORE_RESULTS_EXIST;
  244 
  245     return(packet_error);
  246   }
  247   return len;
  248 }
  249 
  250 /*
  251   Report progress to the client
  252 
  253   RETURN VALUES
  254     0  ok
  255     1  error
  256 */
  257 static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length)
  258 {
  259   uint stage, max_stage, proc_length;
  260   double progress;
  261   uchar *start= packet;
  262 
  263   if (length < 5)
  264     return 1;                         /* Wrong packet */
  265 
  266   if (!(mysql->options.extension && mysql->options.extension->report_progress))
  267     return 0;                         /* No callback, ignore packet */
  268 
  269   packet++;                           /* Ignore number of strings */
  270   stage= (uint) *packet++;
  271   max_stage= (uint) *packet++;
  272   progress= uint3korr(packet)/1000.0;
  273   packet+= 3;
  274   proc_length= net_field_length(&packet);
  275   if (packet + proc_length > start + length)
  276     return 1;                         /* Wrong packet */
  277   (*mysql->options.extension->report_progress)(mysql, stage, max_stage,
  278                                                progress, (char*) packet,
  279                                                proc_length);
  280   return 0;
  281 }
  282 
  283 /* Get the length of next field. Change parameter to point at fieldstart */
  284 ulong
  285 net_field_length(uchar **packet)
  286 {
  287   reg1 uchar *pos= *packet;
  288   if (*pos < 251)
  289   {
  290     (*packet)++;
  291     return (ulong) *pos;
  292   }
  293   if (*pos == 251)
  294   {
  295     (*packet)++;
  296     return NULL_LENGTH;
  297   }
  298   if (*pos == 252)
  299   {
  300     (*packet)+=3;
  301     return (ulong) uint2korr(pos+1);
  302   }
  303   if (*pos == 253)
  304   {
  305     (*packet)+=4;
  306     return (ulong) uint3korr(pos+1);
  307   }
  308   (*packet)+=9;                 /* Must be 254 when here */
  309   return (ulong) uint4korr(pos+1);
  310 }
  311 
  312 /* Same as above, but returns ulonglong values */
  313 
  314 static unsigned long long
  315 net_field_length_ll(uchar **packet)
  316 {
  317   reg1 uchar *pos= *packet;
  318   if (*pos < 251)
  319   {
  320     (*packet)++;
  321     return (unsigned long long) *pos;
  322   }
  323   if (*pos == 251)
  324   {
  325     (*packet)++;
  326     return (unsigned long long) NULL_LENGTH;
  327   }
  328   if (*pos == 252)
  329   {
  330     (*packet)+=3;
  331     return (unsigned long long) uint2korr(pos+1);
  332   }
  333   if (*pos == 253)
  334   {
  335     (*packet)+=4;
  336     return (unsigned long long) uint3korr(pos+1);
  337   }
  338   (*packet)+=9;                 /* Must be 254 when here */
  339 #ifdef NO_CLIENT_LONGLONG
  340   return (unsigned long long) uint4korr(pos+1);
  341 #else
  342   return (unsigned long long) uint8korr(pos+1);
  343 #endif
  344 }
  345 
  346 
  347 void free_rows(MYSQL_DATA *cur)
  348 {
  349   if (cur)
  350   {
  351     ma_free_root(&cur->alloc,MYF(0));
  352     free(cur);
  353   }
  354 }
  355 
  356 int
  357 mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
  358            size_t length, my_bool skipp_check, void *opt_arg)
  359 {
  360   NET *net= &mysql->net;
  361   int result= -1;
  362   if (mysql->net.pvio == 0)
  363   {
  364     /* Do reconnect if possible */
  365     if (mariadb_reconnect(mysql))
  366       return(1);
  367   }
  368   if (mysql->status != MYSQL_STATUS_READY ||
  369       mysql->server_status & SERVER_MORE_RESULTS_EXIST)
  370   {
  371     SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
  372     goto end;
  373   }
  374 
  375   if (IS_CONNHDLR_ACTIVE(mysql))
  376   {
  377     result= mysql->extension->conn_hdlr->plugin->set_connection(mysql, command, arg, length, skipp_check, opt_arg);
  378     if (result== -1)
  379       return(result);
  380   }
  381 
  382   CLEAR_CLIENT_ERROR(mysql);
  383 
  384   mysql->info=0;
  385   mysql->affected_rows= ~(unsigned long long) 0;
  386   ma_net_clear(net);            /* Clear receive buffer */
  387   if (!arg)
  388     arg="";
  389 
  390   if (net->extension->multi_status== COM_MULTI_ENABLED)
  391   {
  392     return net_add_multi_command(net, command, (const uchar *)arg, length);
  393   }
  394 
  395   if (ma_net_write_command(net,(uchar) command,arg,
  396             length ? length : (ulong) strlen(arg), 0))
  397   {
  398     if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
  399     {
  400       my_set_error(mysql, CR_NET_PACKET_TOO_LARGE, SQLSTATE_UNKNOWN, 0);
  401       goto end;
  402     }
  403     end_server(mysql);
  404     if (mariadb_reconnect(mysql))
  405       goto end;
  406     if (ma_net_write_command(net,(uchar) command,arg,
  407               length ? length : (ulong) strlen(arg), 0))
  408     {
  409       my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
  410       goto end;
  411     }
  412   }
  413   result=0;
  414 
  415   if (net->extension->multi_status > COM_MULTI_OFF)
  416     skipp_check= 1;
  417 
  418   if (!skipp_check)
  419   {
  420     result= ((mysql->packet_length=ma_net_safe_read(mysql)) == packet_error ?
  421          1 : 0);
  422   }
  423  end:
  424   return(result);
  425 }
  426 
  427 int
  428 ma_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
  429            size_t length, my_bool skipp_check, void *opt_arg)
  430 {
  431   return mysql->methods->db_command(mysql, command, arg, length, skipp_check, opt_arg);
  432 }
  433 
  434 int ma_multi_command(MYSQL *mysql, enum enum_multi_status status)
  435 {
  436   NET *net= &mysql->net;
  437 
  438   switch (status) {
  439   case COM_MULTI_OFF:
  440     ma_net_clear(net);
  441     net->extension->multi_status= status;
  442     return 0;
  443   case COM_MULTI_ENABLED:
  444     if (net->extension->multi_status > COM_MULTI_DISABLED)
  445       return 1;
  446     ma_net_clear(net);
  447     net->extension->multi_status= status;
  448     return 0;
  449   case COM_MULTI_DISABLED:
  450     /* Opposite to COM_MULTI_OFF we don't clear net buffer,
  451        next command or com_nulti_end will flush entire buffer */
  452     net->extension->multi_status= status;
  453     return 0;
  454   case COM_MULTI_END:
  455   {
  456     size_t len= net->write_pos - net->buff - NET_HEADER_SIZE;
  457 
  458     if (len < NET_HEADER_SIZE) /* don't send empty COM_MULTI */
  459     {
  460       ma_net_clear(net);
  461       return 1;
  462     }
  463     net->extension->multi_status= COM_MULTI_OFF;
  464     return ma_net_flush(net);
  465   }
  466   case COM_MULTI_CANCEL:
  467     ma_net_clear(net);
  468     net->extension->multi_status= COM_MULTI_OFF;
  469     return 0;
  470   default:
  471     return 1;
  472   }
  473 }
  474 
  475 static void free_old_query(MYSQL *mysql)
  476 {
  477   if (mysql->fields)
  478     ma_free_root(&mysql->field_alloc,MYF(0));
  479   ma_init_alloc_root(&mysql->field_alloc,8192,0);   /* Assume rowlength < 8192 */
  480   mysql->fields=0;
  481   mysql->field_count=0;             /* For API */
  482   mysql->info= 0;
  483   return;
  484 }
  485 
  486 #if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
  487 struct passwd *getpwuid(uid_t);
  488 char* getlogin(void);
  489 #endif
  490 
  491 #if !defined(MSDOS) && ! defined(VMS) && !defined(_WIN32) && !defined(OS2)
  492 void read_user_name(char *name)
  493 {
  494   if (geteuid() == 0)
  495     strcpy(name,"root");        /* allow use of surun */
  496   else
  497   {
  498 #ifdef HAVE_GETPWUID
  499     struct passwd *skr;
  500     const char *str;
  501     if ((str=getlogin()) == NULL)
  502     {
  503       if ((skr=getpwuid(geteuid())) != NULL)
  504     str=skr->pw_name;
  505       else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
  506            !(str=getenv("LOGIN")))
  507     str="UNKNOWN_USER";
  508     }
  509     ma_strmake(name,str,USERNAME_LENGTH);
  510 #elif defined(HAVE_CUSERID)
  511     (void) cuserid(name);
  512 #else
  513     ma_strmake(name,"UNKNOWN_USER", USERNAME_LENGTH);
  514 #endif
  515   }
  516   return;
  517 }
  518 
  519 #else /* If MSDOS || VMS */
  520 
  521 void read_user_name(char *name)
  522 {
  523   char *str=getenv("USERNAME");     /* ODBC will send user variable */
  524   ma_strmake(name,str ? str : "ODBC", USERNAME_LENGTH);
  525 }
  526 
  527 #endif
  528 
  529 
  530 /**************************************************************************
  531 ** Shut down connection
  532 **************************************************************************/
  533 
  534 static void
  535 end_server(MYSQL *mysql)
  536 {
  537   /* if net->error 2 and reconnect is activated, we need to inforn
  538      connection handler */
  539   if (mysql->net.pvio != 0)
  540   {
  541     ma_pvio_close(mysql->net.pvio);
  542     mysql->net.pvio= 0;    /* Marker */
  543   }
  544   ma_net_end(&mysql->net);
  545   free_old_query(mysql);
  546   return;
  547 }
  548 
  549 void mthd_my_skip_result(MYSQL *mysql)
  550 {
  551   ulong pkt_len;
  552 
  553   do {
  554     pkt_len= ma_net_safe_read(mysql);
  555     if (pkt_len == packet_error)
  556       break;
  557   } while (pkt_len > 8 || mysql->net.read_pos[0] != 254);
  558   return;
  559 }
  560 
  561 void STDCALL
  562 mysql_free_result(MYSQL_RES *result)
  563 {
  564   if (result)
  565   {
  566     if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
  567     {
  568       result->handle->methods->db_skip_result(result->handle);
  569       result->handle->status=MYSQL_STATUS_READY;
  570     }
  571     free_rows(result->data);
  572     if (result->fields)
  573       ma_free_root(&result->field_alloc,MYF(0));
  574     if (result->row)
  575       free(result->row);
  576     free(result);
  577   }
  578   return;
  579 }
  580 
  581 
  582 /****************************************************************************
  583 ** Get options from my.cnf
  584 ****************************************************************************/
  585 enum enum_option_type {
  586   MARIADB_OPTION_NONE,
  587   MARIADB_OPTION_BOOL,
  588   MARIADB_OPTION_INT,
  589   MARIADB_OPTION_SIZET,
  590   MARIADB_OPTION_STR,
  591 };
  592 
  593 struct st_default_options {
  594   enum mysql_option option;
  595   enum enum_option_type type;
  596   const char *conf_key;
  597 };
  598 
  599 struct st_default_options mariadb_defaults[] =
  600 {
  601   {MARIADB_OPT_PORT, MARIADB_OPTION_INT,"port"},
  602   {MARIADB_OPT_UNIXSOCKET, MARIADB_OPTION_STR, "socket"},
  603   {MYSQL_OPT_COMPRESS, MARIADB_OPTION_BOOL, "compress"},
  604   {MARIADB_OPT_PASSWORD, MARIADB_OPTION_STR, "password"},
  605   {MYSQL_OPT_NAMED_PIPE, MARIADB_OPTION_BOOL, "pipe"},
  606   {MYSQL_OPT_CONNECT_TIMEOUT, MARIADB_OPTION_INT, "timeout"},
  607   {MARIADB_OPT_USER, MARIADB_OPTION_STR, "user"},
  608   {MYSQL_INIT_COMMAND, MARIADB_OPTION_STR, "init-command"},
  609   {MARIADB_OPT_HOST, MARIADB_OPTION_STR, "host"},
  610   {MARIADB_OPT_SCHEMA, MARIADB_OPTION_STR, "database"},
  611   {MARIADB_OPT_DEBUG, MARIADB_OPTION_STR, "debug"},
  612   {MARIADB_OPT_FOUND_ROWS, MARIADB_OPTION_NONE, "return-found-rows"},
  613   {MYSQL_OPT_SSL_KEY, MARIADB_OPTION_STR, "ssl-key"},
  614   {MYSQL_OPT_SSL_CERT, MARIADB_OPTION_STR,"ssl-cert"},
  615   {MYSQL_OPT_SSL_CA, MARIADB_OPTION_STR,"ssl-ca"},
  616   {MYSQL_OPT_SSL_CAPATH, MARIADB_OPTION_STR,"ssl-capath"},
  617   {MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MARIADB_OPTION_BOOL,"ssl-verify-server-cert"},
  618   {MYSQL_SET_CHARSET_DIR, MARIADB_OPTION_STR, "character-sets-dir"},
  619   {MYSQL_SET_CHARSET_NAME, MARIADB_OPTION_STR, "default-character-set"},
  620   {MARIADB_OPT_INTERACTIVE, MARIADB_OPTION_NONE, "interactive-timeout"},
  621   {MYSQL_OPT_CONNECT_TIMEOUT, MARIADB_OPTION_INT, "connect-timeout"},
  622   {MYSQL_OPT_LOCAL_INFILE, MARIADB_OPTION_BOOL, "local-infile"},
  623   {0, 0 ,"disable-local-infile",},
  624   {MYSQL_OPT_SSL_CIPHER, MARIADB_OPTION_STR, "ssl-cipher"},
  625   {MYSQL_OPT_MAX_ALLOWED_PACKET, MARIADB_OPTION_SIZET, "max-allowed-packet"},
  626   {MYSQL_OPT_NET_BUFFER_LENGTH, MARIADB_OPTION_SIZET, "net-buffer-length"},
  627   {MYSQL_OPT_PROTOCOL, MARIADB_OPTION_INT, "protocol"},
  628   {MYSQL_SHARED_MEMORY_BASE_NAME, MARIADB_OPTION_STR,"shared-memory-base-name"},
  629   {MARIADB_OPT_MULTI_RESULTS, MARIADB_OPTION_NONE, "multi-results"},
  630   {MARIADB_OPT_MULTI_STATEMENTS, MARIADB_OPTION_STR, "multi-statements"},
  631   {MARIADB_OPT_MULTI_STATEMENTS, MARIADB_OPTION_STR, "multi-queries"},
  632   {MYSQL_SECURE_AUTH, MARIADB_OPTION_BOOL, "secure-auth"},
  633   {MYSQL_REPORT_DATA_TRUNCATION, MARIADB_OPTION_BOOL, "report-data-truncation"},
  634   {MYSQL_OPT_RECONNECT, MARIADB_OPTION_BOOL, "reconnect"},
  635   {MYSQL_PLUGIN_DIR, MARIADB_OPTION_STR, "plugin-dir"},
  636   {MYSQL_DEFAULT_AUTH, MARIADB_OPTION_STR, "default-auth"},
  637   {MARIADB_OPT_SSL_FP, MARIADB_OPTION_STR, "ssl-fp"},
  638   {MARIADB_OPT_SSL_FP_LIST, MARIADB_OPTION_STR, "ssl-fp-list"},
  639   {MARIADB_OPT_SSL_FP_LIST, MARIADB_OPTION_STR, "ssl-fplist"},
  640   {MARIADB_OPT_TLS_PASSPHRASE, MARIADB_OPTION_STR, "ssl-passphrase"},
  641   {MARIADB_OPT_TLS_VERSION, MARIADB_OPTION_STR, "tls_version"},
  642   {MYSQL_SERVER_PUBLIC_KEY, MARIADB_OPTION_STR, "server_public_key"},
  643   {MYSQL_OPT_BIND, MARIADB_OPTION_STR, "bind-address"},
  644   {0, 0, NULL}
  645 };
  646 
  647 #define CHECK_OPT_EXTENSION_SET(OPTS)\
  648     if (!(OPTS)->extension)                                     \
  649       (OPTS)->extension= (struct st_mysql_options_extension *)  \
  650         calloc(1, sizeof(struct st_mysql_options_extension));
  651 
  652 #define OPT_SET_EXTENDED_VALUE_STR(OPTS, KEY, VAL)               \
  653     CHECK_OPT_EXTENSION_SET(OPTS)                                \
  654     free((gptr)(OPTS)->extension->KEY);                          \
  655     if((VAL))                                                   \
  656       (OPTS)->extension->KEY= strdup((char *)(VAL));             \
  657     else                                                         \
  658       (OPTS)->extension->KEY= NULL
  659 
  660 #define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL)                \
  661     CHECK_OPT_EXTENSION_SET(OPTS)                                 \
  662     (OPTS)->extension->KEY= (VAL)
  663 
  664 #define OPT_SET_EXTENDED_VALUE_INT(A,B,C) OPT_SET_EXTENDED_VALUE(A,B,C)
  665 
  666 #define OPT_SET_VALUE_STR(OPTS, KEY, VAL)                        \
  667     free((OPTS)->KEY);                                           \
  668     if((VAL))                                                   \
  669       (OPTS)->KEY= strdup((char *)(VAL));                        \
  670     else                                                         \
  671       (OPTS)->KEY= NULL
  672 
  673 #define OPT_SET_VALUE_INT(OPTS, KEY, VAL)                         \
  674     (OPTS)->KEY= (VAL)
  675 
  676 static void options_add_initcommand(struct st_mysql_options *options,
  677                                      const char *init_cmd)
  678 {
  679   char *insert= strdup(init_cmd);
  680   if (!options->init_command)
  681   {
  682     options->init_command= (DYNAMIC_ARRAY*)malloc(sizeof(DYNAMIC_ARRAY));
  683     ma_init_dynamic_array(options->init_command, sizeof(char*), 5, 5);
  684   }
  685 
  686   if (ma_insert_dynamic(options->init_command, (gptr)&insert))
  687     free(insert);
  688 }
  689 my_bool _mariadb_set_conf_option(MYSQL *mysql, const char *config_option, const char *config_value)
  690 {
  691   if (config_option)
  692   {
  693     int i;
  694 
  695     for (i=0; mariadb_defaults[i].conf_key; i++)
  696     {
  697       if (!strcmp(mariadb_defaults[i].conf_key, config_option))
  698       {
  699         my_bool val_bool;
  700         int     val_int;
  701         size_t  val_sizet;
  702         int rc;
  703         void *option_val= NULL;
  704         switch (mariadb_defaults[i].type) {
  705         case MARIADB_OPTION_BOOL:
  706           val_bool= 0;
  707           if (config_value)
  708             val_bool= atoi(config_value);
  709           option_val= &val_bool;
  710           break;
  711         case MARIADB_OPTION_INT:
  712           val_int= 0;
  713           if (config_value)
  714             val_int= atoi(config_value);
  715           option_val= &val_int;
  716           break;
  717         case MARIADB_OPTION_SIZET:
  718           val_sizet= 0;
  719           if (config_value)
  720             val_sizet= strtol(config_value, NULL, 10);
  721           option_val= &val_sizet;
  722           break;
  723         case MARIADB_OPTION_STR:
  724           option_val= (void*)config_value;
  725           break;
  726         case MARIADB_OPTION_NONE:
  727           break;
  728         }
  729         rc= mysql_optionsv(mysql, mariadb_defaults[i].option, option_val);
  730         return(test(rc));
  731       }
  732     }
  733   }
  734   /* unknown key */
  735   return 1;
  736 }
  737 
  738 /***************************************************************************
  739 ** Change field rows to field structs
  740 ***************************************************************************/
  741 
  742 static size_t rset_field_offsets[]= {
  743   OFFSET(MYSQL_FIELD, catalog),
  744   OFFSET(MYSQL_FIELD, catalog_length),
  745   OFFSET(MYSQL_FIELD, db),
  746   OFFSET(MYSQL_FIELD, db_length),
  747   OFFSET(MYSQL_FIELD, table),
  748   OFFSET(MYSQL_FIELD, table_length),
  749   OFFSET(MYSQL_FIELD, org_table),
  750   OFFSET(MYSQL_FIELD, org_table_length),
  751   OFFSET(MYSQL_FIELD, name),
  752   OFFSET(MYSQL_FIELD, name_length),
  753   OFFSET(MYSQL_FIELD, org_name),
  754   OFFSET(MYSQL_FIELD, org_name_length)
  755 };
  756 
  757 MYSQL_FIELD *
  758 unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields,
  759           my_bool default_value, my_bool long_flag_protocol __attribute__((unused)))
  760 {
  761   MYSQL_ROWS    *row;
  762   MYSQL_FIELD   *field,*result;
  763   char    *p;
  764   unsigned int i, field_count= sizeof(rset_field_offsets)/sizeof(size_t)/2;
  765 
  766   field=result=(MYSQL_FIELD*) ma_alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
  767   if (!result)
  768     return(0);
  769 
  770   for (row=data->data; row ; row = row->next,field++)
  771   {
  772     if (field >= result + fields)
  773       goto error;
  774 
  775     for (i=0; i < field_count; i++)
  776     {
  777       switch(row->data[i][0]) {
  778       case 0:
  779        *(char **)(((char *)field) + rset_field_offsets[i*2])= ma_strdup_root(alloc, "");
  780        *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])= 0;
  781        break;
  782      default:
  783        *(char **)(((char *)field) + rset_field_offsets[i*2])=
  784          ma_strdup_root(alloc, (char *)row->data[i]);
  785        *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])=
  786          (uint)(row->data[i+1] - row->data[i] - 1);
  787        break;
  788       }
  789     }
  790 
  791     p= (char *)row->data[6];
  792     /* filler */
  793     field->charsetnr= uint2korr(p);
  794     p+= 2;
  795     field->length= (uint) uint4korr(p);
  796     p+= 4;
  797     field->type=   (enum enum_field_types)uint1korr(p);
  798     p++;
  799     field->flags= uint2korr(p);
  800     p+= 2;
  801     field->decimals= (uint) p[0];
  802     p++;
  803 
  804     /* filler */
  805     p+= 2;
  806 
  807     if (INTERNAL_NUM_FIELD(field))
  808       field->flags|= NUM_FLAG;
  809 
  810     if (default_value && row->data[7])
  811       field->def=ma_strdup_root(alloc,(char*) row->data[7]);
  812     else
  813       field->def=0;
  814     field->max_length= 0;
  815   }
  816   if (field < result + fields)
  817     goto error;
  818   free_rows(data);              /* Free old data */
  819   return(result);
  820 error:
  821   free_rows(data);
  822   ma_free_root(alloc, MYF(0));
  823   return(0);
  824 }
  825 
  826 
  827 /* Read all rows (fields or data) from server */
  828 
  829 MYSQL_DATA *mthd_my_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
  830                  uint fields)
  831 {
  832   uint  field;
  833   ulong pkt_len;
  834   ulong len;
  835   uchar *cp;
  836   char  *to, *end_to;
  837   MYSQL_DATA *result;
  838   MYSQL_ROWS **prev_ptr,*cur;
  839   NET *net = &mysql->net;
  840 
  841   if ((pkt_len= ma_net_safe_read(mysql)) == packet_error)
  842     return(0);
  843   if (!(result=(MYSQL_DATA*) calloc(1, sizeof(MYSQL_DATA))))
  844   {
  845     SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
  846     return(0);
  847   }
  848   ma_init_alloc_root(&result->alloc,8192,0);    /* Assume rowlength < 8192 */
  849   result->alloc.min_malloc=sizeof(MYSQL_ROWS);
  850   prev_ptr= &result->data;
  851   result->rows=0;
  852   result->fields=fields;
  853 
  854   while (*(cp=net->read_pos) != 254 || pkt_len >= 8)
  855   {
  856     result->rows++;
  857     if (!(cur= (MYSQL_ROWS*) ma_alloc_root(&result->alloc,
  858                         sizeof(MYSQL_ROWS))) ||
  859           !(cur->data= ((MYSQL_ROW)
  860               ma_alloc_root(&result->alloc,
  861                      (fields+1)*sizeof(char *)+fields+pkt_len))))
  862     {
  863       free_rows(result);
  864       SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
  865       return(0);
  866     }
  867     *prev_ptr=cur;
  868     prev_ptr= &cur->next;
  869     to= (char*) (cur->data+fields+1);
  870     end_to=to+fields+pkt_len-1;
  871     for (field=0 ; field < fields ; field++)
  872     {
  873       if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
  874       {                     /* null field */
  875         cur->data[field] = 0;
  876       }
  877       else
  878       {
  879         cur->data[field] = to;
  880         if (len > (ulong)(end_to - to) || to > end_to)
  881         {
  882           free_rows(result);
  883           SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
  884           return(0);
  885         }
  886         memcpy(to,(char*) cp,len); to[len]=0;
  887         to+=len+1;
  888         cp+=len;
  889         if (mysql_fields)
  890         {
  891           if (mysql_fields[field].max_length < len)
  892             mysql_fields[field].max_length=len;
  893          }
  894       }
  895     }
  896     cur->data[field]=to;            /* End of last field */
  897     if ((pkt_len=ma_net_safe_read(mysql)) == packet_error)
  898     {
  899       free_rows(result);
  900       return(0);
  901     }
  902   }
  903   *prev_ptr=0;                  /* last pointer is null */
  904   /* save status */
  905   if (pkt_len > 1)
  906   {
  907     cp++;
  908     mysql->warning_count= uint2korr(cp);
  909     cp+= 2;
  910     mysql->server_status= uint2korr(cp);
  911   }
  912   return(result);
  913 }
  914 
  915 
  916 /*
  917 ** Read one row. Uses packet buffer as storage for fields.
  918 ** When next packet is read, the previous field values are destroyed
  919 */
  920 
  921 
  922 int mthd_my_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
  923 {
  924   uint field;
  925   ulong pkt_len,len;
  926   uchar *pos,*prev_pos, *end_pos;
  927 
  928   if ((pkt_len=(uint) ma_net_safe_read(mysql)) == packet_error)
  929     return -1;
  930 
  931   if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
  932   {
  933     mysql->warning_count= uint2korr(mysql->net.read_pos + 1);
  934     mysql->server_status= uint2korr(mysql->net.read_pos + 3);
  935     return 1;               /* End of data */
  936   }
  937   prev_pos= 0;              /* allowed to write at packet[-1] */
  938   pos=mysql->net.read_pos;
  939   end_pos=pos+pkt_len;
  940   for (field=0 ; field < fields ; field++)
  941   {
  942     if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
  943     {                       /* null field */
  944       row[field] = 0;
  945       *lengths++=0;
  946     }
  947     else
  948     {
  949       if (len > (ulong) (end_pos - pos) || pos > end_pos)
  950       {
  951         mysql->net.last_errno=CR_UNKNOWN_ERROR;
  952         strncpy(mysql->net.last_error,ER(mysql->net.last_errno),
  953                 MYSQL_ERRMSG_SIZE - 1);
  954         return -1;
  955       }
  956       row[field] = (char*) pos;
  957       pos+=len;
  958       *lengths++=len;
  959     }
  960     if (prev_pos)
  961       *prev_pos=0;              /* Terminate prev field */
  962     prev_pos=pos;
  963   }
  964   row[field]=(char*) prev_pos+1;        /* End of last field */
  965   *prev_pos=0;                  /* Terminate last field */
  966   return 0;
  967 }
  968 
  969 /****************************************************************************
  970 ** Init MySQL structure or allocate one
  971 ****************************************************************************/
  972 
  973 MYSQL * STDCALL
  974 mysql_init(MYSQL *mysql)
  975 {
  976   if (mysql_server_init(0, NULL, NULL))
  977     return NULL;
  978   if (!mysql)
  979   {
  980     if (!(mysql=(MYSQL*) calloc(1, sizeof(MYSQL))))
  981       return 0;
  982     mysql->free_me=1;
  983     mysql->net.pvio= 0;
  984     mysql->net.extension= 0;
  985   }
  986   else
  987   {
  988     memset((char*) (mysql), 0, sizeof(*(mysql)));
  989     mysql->net.pvio= 0;
  990     mysql->free_me= 0;
  991     mysql->net.extension= 0;
  992   }
  993 
  994   if (!(mysql->net.extension= (struct st_mariadb_net_extension *)
  995                                calloc(1, sizeof(struct st_mariadb_net_extension))) ||
  996       !(mysql->extension= (struct st_mariadb_extension *)
  997                           calloc(1, sizeof(struct st_mariadb_extension))))
  998     goto error;
  999   mysql->options.report_data_truncation= 1;
 1000   mysql->options.connect_timeout=CONNECT_TIMEOUT;
 1001   mysql->charset= mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
 1002   mysql->methods= &MARIADB_DEFAULT_METHODS;
 1003   strcpy(mysql->net.sqlstate, "00000");
 1004   mysql->net.last_error[0]= mysql->net.last_errno= 0;
 1005 
 1006 /*
 1007   Only enable LOAD DATA INFILE by default if configured with
 1008   --enable-local-infile
 1009 */
 1010 #ifdef ENABLED_LOCAL_INFILE
 1011   mysql->options.client_flag|= CLIENT_LOCAL_FILES;
 1012 #endif
 1013   mysql->options.reconnect= 0;
 1014   return mysql;
 1015 error:
 1016   if (mysql->free_me)
 1017     free(mysql);
 1018   return 0;
 1019 }
 1020 
 1021 int STDCALL
 1022 mysql_ssl_set(MYSQL *mysql __attribute__((unused)),
 1023               const char *key __attribute__((unused)),
 1024               const char *cert __attribute__((unused)),
 1025               const char *ca __attribute__((unused)),
 1026               const char *capath __attribute__((unused)),
 1027               const char *cipher __attribute__((unused)))
 1028 {
 1029 #ifdef HAVE_TLS
 1030   char enable= 1;
 1031   return (mysql_optionsv(mysql, MYSQL_OPT_SSL_ENFORCE, &enable) |
 1032           mysql_optionsv(mysql, MYSQL_OPT_SSL_KEY, key) |
 1033           mysql_optionsv(mysql, MYSQL_OPT_SSL_CERT, cert) |
 1034           mysql_optionsv(mysql, MYSQL_OPT_SSL_CA, ca) |
 1035           mysql_optionsv(mysql, MYSQL_OPT_SSL_CAPATH, capath) |
 1036           mysql_optionsv(mysql, MYSQL_OPT_SSL_CIPHER, cipher)) ? 1 : 0;
 1037 #else
 1038   return 0;
 1039 #endif
 1040 }
 1041 
 1042 /**************************************************************************
 1043 **************************************************************************/
 1044 
 1045 const char * STDCALL
 1046 mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
 1047 {
 1048 #ifdef HAVE_TLS
 1049   if (mysql->net.pvio && mysql->net.pvio->ctls)
 1050   {
 1051     return ma_pvio_tls_cipher(mysql->net.pvio->ctls);
 1052   }
 1053 #endif
 1054   return(NULL);
 1055 }
 1056 
 1057 /**************************************************************************
 1058 ** Free strings in the SSL structure and clear 'use_ssl' flag.
 1059 ** NB! Errors are not reported until you do mysql_real_connect.
 1060 **************************************************************************/
 1061 
 1062 char *ma_send_connect_attr(MYSQL *mysql, unsigned char *buffer)
 1063 {
 1064   if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS)
 1065   {
 1066     buffer= (unsigned char *)mysql_net_store_length((unsigned char *)buffer, (mysql->options.extension) ?
 1067                              mysql->options.extension->connect_attrs_len : 0);
 1068     if (mysql->options.extension &&
 1069         hash_inited(&mysql->options.extension->connect_attrs))
 1070     {
 1071       uint i;
 1072       for (i=0; i < mysql->options.extension->connect_attrs.records; i++)
 1073       {
 1074         size_t len;
 1075         uchar *p= hash_element(&mysql->options.extension->connect_attrs, i);
 1076 
 1077         len= strlen((char *)p);
 1078         buffer= mysql_net_store_length(buffer, len);
 1079         memcpy(buffer, p, len);
 1080         buffer+= (len);
 1081         p+= (len + 1);
 1082         len= strlen((char *)p);
 1083         buffer= mysql_net_store_length(buffer, len);
 1084         memcpy(buffer, p, len);
 1085         buffer+= len;
 1086       }
 1087     }
 1088   }
 1089   return (char *)buffer;
 1090 }
 1091 
 1092 /** set some default attributes */
 1093 static my_bool
 1094 ma_set_connect_attrs(MYSQL *mysql, const char *host)
 1095 {
 1096   char buffer[255];
 1097   int rc= 0;
 1098 
 1099   rc= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name") +
 1100       mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version") +
 1101       mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os") +
 1102       mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_server_host") +
 1103 #ifdef _WIN32
 1104       mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread") +
 1105 #endif
 1106       mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid") +
 1107       mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
 1108 
 1109   rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "libmariadb")
 1110        + mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_version", MARIADB_PACKAGE_VERSION)
 1111        + mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_os", MARIADB_SYSTEM_TYPE);
 1112 
 1113   if (host && *host)
 1114     rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_server_host", host);
 1115 
 1116 #ifdef _WIN32
 1117   snprintf(buffer, 255, "%lu", (ulong) GetCurrentThreadId());
 1118   rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buffer);
 1119   snprintf(buffer, 255, "%lu", (ulong) GetCurrentProcessId());
 1120 #else
 1121   snprintf(buffer, 255, "%lu", (ulong) getpid());
 1122 #endif
 1123   rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buffer);
 1124 
 1125   rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_platform", MARIADB_MACHINE_TYPE);
 1126   return(test(rc>0));
 1127 }
 1128 
 1129 /*
 1130 ** Note that the mysql argument must be initialized with mysql_init()
 1131 ** before calling mysql_real_connect !
 1132 */
 1133 
 1134 MYSQL * STDCALL
 1135 mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
 1136            const char *passwd, const char *db,
 1137            uint port, const char *unix_socket,unsigned long client_flag)
 1138 {
 1139   char *end= NULL;
 1140   char *connection_handler= (mysql->options.extension) ?
 1141                             mysql->options.extension->connection_handler : 0;
 1142 
 1143   if (!mysql->methods)
 1144     mysql->methods= &MARIADB_DEFAULT_METHODS;
 1145 
 1146   if (connection_handler ||
 1147       (host && (end= strstr(host, "://"))))
 1148   {
 1149     MARIADB_CONNECTION_PLUGIN *plugin;
 1150     char plugin_name[64];
 1151 
 1152     if (!connection_handler || !connection_handler[0])
 1153     {
 1154       memset(plugin_name, 0, 64);
 1155       ma_strmake(plugin_name, host, MIN(end - host, 63));
 1156       end+= 3;
 1157     }
 1158     else
 1159       ma_strmake(plugin_name, connection_handler, MIN(63, strlen(connection_handler)));
 1160 
 1161     if (!(plugin= (MARIADB_CONNECTION_PLUGIN *)mysql_client_find_plugin(mysql, plugin_name, MARIADB_CLIENT_CONNECTION_PLUGIN)))
 1162       return NULL;
 1163 
 1164     if (!(mysql->extension->conn_hdlr= (MA_CONNECTION_HANDLER *)calloc(1, sizeof(MA_CONNECTION_HANDLER))))
 1165     {
 1166       SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 1167       return NULL;
 1168     }
 1169 
 1170     /* save URL for reconnect */
 1171     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, url, host);
 1172 
 1173     mysql->extension->conn_hdlr->plugin= plugin;
 1174 
 1175     if (plugin && plugin->connect)
 1176     {
 1177       MYSQL *my= plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag);
 1178       if (!my)
 1179       {
 1180         free(mysql->extension->conn_hdlr);
 1181         mysql->extension->conn_hdlr= NULL;
 1182       }
 1183       return my;
 1184     }
 1185   }
 1186 
 1187   return mysql->methods->db_connect(mysql, host, user, passwd,
 1188                                     db, port, unix_socket, client_flag);
 1189 }
 1190 
 1191 MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
 1192            const char *passwd, const char *db,
 1193            uint port, const char *unix_socket, unsigned long client_flag)
 1194 {
 1195   char      buff[NAME_LEN+USERNAME_LENGTH+100];
 1196   char      *end, *end_pkt, *host_info;
 1197   MA_PVIO_CINFO  cinfo= {NULL, NULL, 0, -1, NULL};
 1198   MARIADB_PVIO   *pvio= NULL;
 1199   char    *scramble_data;
 1200   my_bool is_maria= 0;
 1201   const char *scramble_plugin;
 1202   uint pkt_length, scramble_len, pkt_scramble_len= 0;
 1203   NET   *net= &mysql->net;
 1204 
 1205   if (!mysql->methods)
 1206     mysql->methods= &MARIADB_DEFAULT_METHODS;
 1207 
 1208   if (!host || !host[0])
 1209     host = mysql->options.host;
 1210 
 1211   ma_set_connect_attrs(mysql, host);
 1212 
 1213   if (net->pvio)  /* check if we are already connected */
 1214   {
 1215     SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0);
 1216     return(NULL);
 1217   }
 1218 
 1219   /* use default options */
 1220   if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
 1221   {
 1222     _mariadb_read_options(mysql, NULL,
 1223               (mysql->options.my_cnf_file ?
 1224                mysql->options.my_cnf_file : NULL),
 1225                mysql->options.my_cnf_group, 0);
 1226     free(mysql->options.my_cnf_file);
 1227     free(mysql->options.my_cnf_group);
 1228     mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
 1229   }
 1230 
 1231 #ifndef WIN32
 1232   if (mysql->options.protocol > MYSQL_PROTOCOL_SOCKET)
 1233   {
 1234     SET_CLIENT_ERROR(mysql, CR_CONN_UNKNOWN_PROTOCOL, SQLSTATE_UNKNOWN, 0);
 1235     return(NULL);
 1236   }
 1237 #endif
 1238 
 1239   /* Some empty-string-tests are done because of ODBC */
 1240   if (!user || !user[0])
 1241     user=mysql->options.user;
 1242   if (!passwd)
 1243   {
 1244     passwd=mysql->options.password;
 1245 #ifndef DONT_USE_MYSQL_PWD
 1246     if (!passwd)
 1247       passwd=getenv("MYSQL_PWD");  /* get it from environment (haneke) */
 1248     if (!passwd)
 1249       passwd= "";
 1250 #endif
 1251   }
 1252   if (!db || !db[0])
 1253     db=mysql->options.db;
 1254   if (!port)
 1255     port=mysql->options.port;
 1256   if (!unix_socket)
 1257     unix_socket=mysql->options.unix_socket;
 1258 
 1259   mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
 1260 
 1261   /* try to connect via pvio_init */
 1262   cinfo.host= host;
 1263   cinfo.unix_socket= unix_socket;
 1264   cinfo.port= port;
 1265   cinfo.mysql= mysql;
 1266 
 1267   /*
 1268   ** Grab a socket and connect it to the server
 1269   */
 1270 #ifndef _WIN32
 1271 #if defined(HAVE_SYS_UN_H)
 1272   if ((!host ||  strcmp(host,LOCAL_HOST) == 0) &&
 1273       mysql->options.protocol != MYSQL_PROTOCOL_TCP &&
 1274       (unix_socket || mysql_unix_port))
 1275   {
 1276     cinfo.host= LOCAL_HOST;
 1277     cinfo.unix_socket= (unix_socket) ? unix_socket : mysql_unix_port;
 1278     cinfo.type= PVIO_TYPE_UNIXSOCKET;
 1279     sprintf(host_info=buff,ER(CR_LOCALHOST_CONNECTION),cinfo.host);
 1280   }
 1281   else
 1282 #endif
 1283 #else
 1284   if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
 1285   {
 1286     cinfo.host= mysql->options.shared_memory_base_name;
 1287     cinfo.type= PVIO_TYPE_SHAREDMEM;
 1288     sprintf(host_info=buff,ER(CR_SHARED_MEMORY_CONNECTION), cinfo.host ? cinfo.host : SHM_DEFAULT_NAME);
 1289   }
 1290    /* named pipe */
 1291   else if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
 1292       (host && strcmp(host,LOCAL_HOST_NAMEDPIPE) == 0))
 1293   {
 1294     cinfo.type= PVIO_TYPE_NAMEDPIPE;
 1295     sprintf(host_info=buff,ER(CR_NAMEDPIPE_CONNECTION),cinfo.host);
 1296   }
 1297   else
 1298 #endif
 1299   {
 1300     cinfo.unix_socket=0;                /* This is not used */
 1301     if (!port)
 1302       port=mysql_port;
 1303     if (!host)
 1304       host=LOCAL_HOST;
 1305     cinfo.host= host;
 1306     cinfo.port= port;
 1307     cinfo.type= PVIO_TYPE_SOCKET;
 1308     sprintf(host_info=buff,ER(CR_TCP_CONNECTION), cinfo.host);
 1309   }
 1310   /* Initialize and load pvio plugin */
 1311   if (!(pvio= ma_pvio_init(&cinfo)))
 1312     goto error;
 1313 
 1314   /* try to connect */
 1315   if (ma_pvio_connect(pvio, &cinfo) != 0)
 1316   {
 1317     ma_pvio_close(pvio);
 1318     goto error;
 1319   }
 1320 
 1321   if (mysql->options.extension && mysql->options.extension->proxy_header)
 1322   {
 1323     char *hdr = mysql->options.extension->proxy_header;
 1324     size_t len = mysql->options.extension->proxy_header_len;
 1325     if (ma_pvio_write(pvio, (unsigned char *)hdr, len) <= 0)
 1326     {
 1327       ma_pvio_close(pvio);
 1328       goto error;
 1329     }
 1330   }
 1331 
 1332   if (ma_net_init(net, pvio))
 1333     goto error;
 1334 
 1335   if (mysql->options.max_allowed_packet)
 1336     net->max_packet_size= mysql->options.max_allowed_packet;
 1337 
 1338   ma_pvio_keepalive(net->pvio);
 1339   strcpy(mysql->net.sqlstate, "00000");
 1340 
 1341   /* Get version info */
 1342   mysql->protocol_version= PROTOCOL_VERSION;    /* Assume this */
 1343 /*
 1344   if (ma_pvio_wait_io_or_timeout(net->pvio, FALSE, 0) < 1)
 1345   {
 1346     my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
 1347                  ER(CR_SERVER_LOST_EXTENDED),
 1348                  "handshake: waiting for inital communication packet",
 1349                  errno);
 1350     goto error;
 1351   }
 1352  */
 1353   if ((pkt_length=ma_net_safe_read(mysql)) == packet_error)
 1354   {
 1355     if (mysql->net.last_errno == CR_SERVER_LOST)
 1356       my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
 1357                  ER(CR_SERVER_LOST_EXTENDED),
 1358                  "handshake: reading inital communication packet",
 1359                  errno);
 1360 
 1361     goto error;
 1362   }
 1363   end= (char *)net->read_pos;
 1364   end_pkt= (char *)net->read_pos + pkt_length;
 1365 
 1366   /* Check if version of protocol matches current one */
 1367 
 1368   mysql->protocol_version= end[0];
 1369   end++;
 1370 
 1371   /* Check if server sends an error */
 1372   if (mysql->protocol_version == 0XFF)
 1373   {
 1374     net_get_error(end, pkt_length - 1, net->last_error, sizeof(net->last_error),
 1375       &net->last_errno, net->sqlstate);
 1376     /* fix for bug #26426 */
 1377     if (net->last_errno == 1040)
 1378       memcpy(net->sqlstate, "08004", SQLSTATE_LENGTH);
 1379     goto error;
 1380   }
 1381 
 1382   if (mysql->protocol_version <  PROTOCOL_VERSION)
 1383   {
 1384     net->last_errno= CR_VERSION_ERROR;
 1385     sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
 1386         PROTOCOL_VERSION);
 1387     goto error;
 1388   }
 1389   /* Save connection information */
 1390   if (!user) user="";
 1391 
 1392   if (!(mysql->host_info= strdup(host_info)) ||
 1393       !(mysql->host= strdup(cinfo.host ? cinfo.host : "")) ||
 1394       !(mysql->user=strdup(user)) ||
 1395       !(mysql->passwd=strdup(passwd)))
 1396   {
 1397     SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 1398     goto error;
 1399   }
 1400   if (cinfo.unix_socket)
 1401     mysql->unix_socket= strdup(cinfo.unix_socket);
 1402   else
 1403     mysql->unix_socket=0;
 1404   mysql->port=port;
 1405   client_flag|=mysql->options.client_flag;
 1406 
 1407   if (strncmp(end, MA_RPL_VERSION_HACK, sizeof(MA_RPL_VERSION_HACK) - 1) == 0)
 1408   {
 1409     mysql->server_version= strdup(end + sizeof(MA_RPL_VERSION_HACK) - 1);
 1410     is_maria= 1;
 1411   }
 1412   else
 1413   {
 1414     if (!(mysql->server_version= strdup(end)))
 1415     {
 1416       SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 1417       goto error;
 1418     }
 1419   }
 1420   end+= strlen(end) + 1;
 1421 
 1422   mysql->thread_id=uint4korr(end);
 1423   end+=4;
 1424 
 1425   /* This is the first part of scramble packet. In 4.1 and later
 1426      a second package will follow later */
 1427   scramble_data= end;
 1428   scramble_len= SCRAMBLE_LENGTH_323 + 1;
 1429   scramble_plugin= old_password_plugin_name;
 1430   end+= SCRAMBLE_LENGTH_323;
 1431 
 1432   /* 1st pad */
 1433   end++;
 1434 
 1435   if (end + 1<= end_pkt)
 1436   {
 1437     mysql->server_capabilities=uint2korr(end);
 1438   }
 1439 
 1440   /* mysql 5.5 protocol */
 1441   if (end + 18 <= end_pkt)
 1442   {
 1443     mysql->server_language= uint1korr(end + 2);
 1444     mysql->server_status= uint2korr(end + 3);
 1445     mysql->server_capabilities|= (unsigned int)(uint2korr(end + 5) << 16);
 1446     pkt_scramble_len= uint1korr(end + 7);
 1447 
 1448     /* check if MariaD2B specific capabilities are available */
 1449     if (is_maria && !(mysql->server_capabilities & CLIENT_MYSQL))
 1450     {
 1451       mysql->extension->mariadb_server_capabilities= (ulonglong) uint4korr(end + 14);
 1452     }
 1453   }
 1454 
 1455   /* pad 2 */
 1456   end+= 18;
 1457 
 1458   /* second scramble package */
 1459   if (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 <= end_pkt)
 1460   {
 1461     memcpy(end - SCRAMBLE_LENGTH_323, scramble_data, SCRAMBLE_LENGTH_323);
 1462     scramble_data= end - SCRAMBLE_LENGTH_323;
 1463     if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
 1464     {
 1465       scramble_len= pkt_scramble_len;
 1466       scramble_plugin= scramble_data + scramble_len;
 1467       if (scramble_data + scramble_len > end_pkt)
 1468         scramble_len= (uint)(end_pkt - scramble_data);
 1469     } else
 1470     {
 1471       scramble_len= (uint)(end_pkt - scramble_data);
 1472       scramble_plugin= native_password_plugin_name;
 1473     }
 1474   } else
 1475   {
 1476     mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
 1477     if (mysql->options.secure_auth)
 1478     {
 1479       SET_CLIENT_ERROR(mysql, CR_SECURE_AUTH, SQLSTATE_UNKNOWN, 0);
 1480       goto error;
 1481     }
 1482   }
 1483 
 1484   /* Set character set */
 1485   if (mysql->options.charset_name)
 1486     mysql->charset= mysql_find_charset_name(mysql->options.charset_name);
 1487   else
 1488     mysql->charset=mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
 1489 
 1490   if (!mysql->charset)
 1491   {
 1492     net->last_errno=CR_CANT_READ_CHARSET;
 1493     sprintf(net->last_error,ER(net->last_errno),
 1494       mysql->options.charset_name ? mysql->options.charset_name : 
 1495                                     MARIADB_DEFAULT_CHARSET,
 1496       "compiled_in");
 1497     goto error;
 1498   }
 1499 
 1500   mysql->client_flag= client_flag;
 1501 
 1502   if (run_plugin_auth(mysql, scramble_data, scramble_len,
 1503                              scramble_plugin, db))
 1504     goto error;
 1505 
 1506   if (mysql->client_flag & CLIENT_COMPRESS)
 1507     net->compress= 1;
 1508 
 1509   /* last part: select default db */
 1510   if (!(mysql->server_capabilities & CLIENT_CONNECT_WITH_DB) &&
 1511       (db && !mysql->db))
 1512   {
 1513     if (mysql_select_db(mysql, db))
 1514     {
 1515       my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
 1516                           ER(CR_SERVER_LOST_EXTENDED),
 1517                           "Setting intital database",
 1518                           errno);
 1519       goto error;
 1520     }
 1521   }
 1522 
 1523   if (mysql->options.init_command)
 1524   {
 1525     char **begin= (char **)mysql->options.init_command->buffer;
 1526     char **end= begin + mysql->options.init_command->elements;
 1527 
 1528     /* Avoid reconnect in mysql_real_connect */
 1529     my_bool save_reconnect= mysql->options.reconnect;
 1530     mysql->options.reconnect= 0;
 1531 
 1532     for (;begin < end; begin++)
 1533     {
 1534       if (mysql_real_query(mysql, *begin, (unsigned long)strlen(*begin)))
 1535         goto error;
 1536 
 1537     /* check if query produced a result set */
 1538       do {
 1539         MYSQL_RES *res;
 1540         if ((res= mysql_use_result(mysql)))
 1541           mysql_free_result(res);
 1542       } while (!mysql_next_result(mysql));
 1543     }
 1544     mysql->options.reconnect= save_reconnect;
 1545   }
 1546 
 1547   strcpy(mysql->net.sqlstate, "00000");
 1548 
 1549   /* connection established, apply timeouts */
 1550   ma_pvio_set_timeout(mysql->net.pvio, PVIO_READ_TIMEOUT, mysql->options.read_timeout);
 1551   ma_pvio_set_timeout(mysql->net.pvio, PVIO_WRITE_TIMEOUT, mysql->options.write_timeout);
 1552   return(mysql);
 1553 
 1554 error:
 1555   /* Free alloced memory */
 1556   end_server(mysql);
 1557   /* only free the allocated memory, user needs to call mysql_close */
 1558   mysql_close_memory(mysql);
 1559   if (!(client_flag & CLIENT_REMEMBER_OPTIONS) &&
 1560       !mysql->options.extension->async_context)
 1561     mysql_close_options(mysql);
 1562   return(0);
 1563 }
 1564 
 1565 struct my_hook_data {
 1566   MYSQL *orig_mysql;
 1567   MYSQL *new_mysql;
 1568   /* This is always NULL currently, but restoring does not hurt just in case. */
 1569   MARIADB_PVIO *orig_pvio;
 1570 };
 1571 /*
 1572   Callback hook to make the new VIO accessible via the old MYSQL to calling
 1573   application when suspending a non-blocking call during automatic reconnect.
 1574 */
 1575 static void
 1576 my_suspend_hook(my_bool suspend, void *data)
 1577 {
 1578   struct my_hook_data *hook_data= (struct my_hook_data *)data;
 1579   if (suspend)
 1580   {
 1581     hook_data->orig_pvio= hook_data->orig_mysql->net.pvio;
 1582     hook_data->orig_mysql->net.pvio= hook_data->new_mysql->net.pvio;
 1583   }
 1584   else
 1585     hook_data->orig_mysql->net.pvio= hook_data->orig_pvio;
 1586 }
 1587 
 1588 my_bool STDCALL mariadb_reconnect(MYSQL *mysql)
 1589 {
 1590   MYSQL tmp_mysql;
 1591   struct my_hook_data hook_data;
 1592   struct mysql_async_context *ctxt= NULL;
 1593   LIST *li_stmt= mysql->stmts;
 1594 
 1595   /* check if connection handler is active */
 1596   if (IS_CONNHDLR_ACTIVE(mysql))
 1597   {
 1598     if (mysql->extension->conn_hdlr->plugin && mysql->extension->conn_hdlr->plugin->reconnect)
 1599       return(mysql->extension->conn_hdlr->plugin->reconnect(mysql));
 1600   }
 1601 
 1602   if (!mysql->options.reconnect ||
 1603       (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
 1604   {
 1605    /* Allow reconnect next time */
 1606     mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
 1607     my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
 1608     return(1);
 1609   }
 1610 
 1611   mysql_init(&tmp_mysql);
 1612   tmp_mysql.free_me= 0;
 1613   tmp_mysql.options=mysql->options;
 1614   if (mysql->extension->conn_hdlr)
 1615   {
 1616     tmp_mysql.extension->conn_hdlr= mysql->extension->conn_hdlr;
 1617     mysql->extension->conn_hdlr= 0;
 1618   }
 1619 
 1620   /* don't reread options from configuration files */
 1621   tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL;
 1622   if (IS_MYSQL_ASYNC_ACTIVE(mysql))
 1623   {
 1624     ctxt= mysql->options.extension->async_context;
 1625     hook_data.orig_mysql= mysql;
 1626     hook_data.new_mysql= &tmp_mysql;
 1627     hook_data.orig_pvio= mysql->net.pvio;
 1628     my_context_install_suspend_resume_hook(ctxt, my_suspend_hook, &hook_data);
 1629   }
 1630 
 1631   if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
 1632               mysql->db, mysql->port, mysql->unix_socket,
 1633               mysql->client_flag | CLIENT_REMEMBER_OPTIONS) ||
 1634       mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
 1635   {
 1636     if (ctxt)
 1637       my_context_install_suspend_resume_hook(ctxt, NULL, NULL);
 1638     /* don't free options (CONC-118) */
 1639     memset(&tmp_mysql.options, 0, sizeof(struct st_mysql_options));
 1640     my_set_error(mysql, tmp_mysql.net.last_errno,
 1641                         tmp_mysql.net.sqlstate,
 1642                         tmp_mysql.net.last_error);
 1643     mysql_close(&tmp_mysql);
 1644     return(1);
 1645   }
 1646 
 1647   for (;li_stmt;li_stmt= li_stmt->next)
 1648   {
 1649     MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
 1650 
 1651     if (stmt->state != MYSQL_STMT_INITTED)
 1652     {
 1653       stmt->state= MYSQL_STMT_INITTED;
 1654       SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
 1655     }
 1656   }
 1657 
 1658   tmp_mysql.free_me= mysql->free_me;
 1659   tmp_mysql.stmts= mysql->stmts;
 1660   mysql->stmts= NULL;
 1661 
 1662   if (ctxt)
 1663     my_context_install_suspend_resume_hook(ctxt, NULL, NULL);
 1664   /* Don't free options, we moved them to tmp_mysql */
 1665   memset(&mysql->options, 0, sizeof(mysql->options));
 1666   mysql->free_me=0;
 1667   mysql_close(mysql);
 1668   *mysql=tmp_mysql;
 1669   mysql->net.pvio->mysql= mysql;
 1670   ma_net_clear(&mysql->net);
 1671   mysql->affected_rows= ~(unsigned long long) 0;
 1672   mysql->info= 0;
 1673   return(0);
 1674 }
 1675 
 1676 void ma_invalidate_stmts(MYSQL *mysql, const char *function_name)
 1677 {
 1678   if (mysql->stmts)
 1679   {
 1680     LIST *li_stmt= mysql->stmts;
 1681 
 1682     for (; li_stmt; li_stmt= li_stmt->next)
 1683     {
 1684       MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
 1685       stmt->mysql= NULL;
 1686       SET_CLIENT_STMT_ERROR(stmt, CR_STMT_CLOSED, SQLSTATE_UNKNOWN, function_name);
 1687     }
 1688     mysql->stmts= NULL;
 1689   }
 1690 }
 1691 
 1692 /*
 1693   Legacy support of the MariaDB 5.5 version, where timeouts where only in
 1694   seconds resolution. Applications that use this will be asked to set a timeout
 1695   at the nearest higher whole-seconds value.
 1696 */
 1697 unsigned int STDCALL
 1698 mysql_get_timeout_value(const MYSQL *mysql)
 1699 {
 1700   unsigned int timeout= mysql->options.extension->async_context->timeout_value;
 1701   /* Avoid overflow. */
 1702   if (timeout > UINT_MAX - 999)
 1703     return (timeout - 1)/1000 + 1;
 1704   else
 1705     return (timeout+999)/1000;
 1706 }
 1707 
 1708 
 1709 unsigned int STDCALL
 1710 mysql_get_timeout_value_ms(const MYSQL *mysql)
 1711 {
 1712   return mysql->options.extension->async_context->timeout_value;
 1713 }
 1714 
 1715 /**************************************************************************
 1716 ** Change user and database
 1717 **************************************************************************/
 1718 
 1719 my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
 1720                   const char *passwd, const char *db)
 1721 {
 1722   const MARIADB_CHARSET_INFO *s_cs= mysql->charset;
 1723   char *s_user= mysql->user,
 1724        *s_passwd= mysql->passwd,
 1725        *s_db= mysql->db;
 1726   int rc;
 1727 
 1728   if (mysql->options.charset_name)
 1729     mysql->charset= mysql_find_charset_name(mysql->options.charset_name);
 1730   else
 1731     mysql->charset=mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
 1732 
 1733   mysql->user= strdup(user ? user : "");
 1734   mysql->passwd= strdup(passwd ? passwd : "");
 1735 
 1736   /* db will be set in run_plugin_auth */
 1737   mysql->db= 0;
 1738   rc= run_plugin_auth(mysql, 0, 0, 0, db);
 1739 
 1740   /* COM_CHANGE_USER always releases prepared statements, so we need to invalidate them */
 1741   ma_invalidate_stmts(mysql, "mysql_change_user()");
 1742 
 1743   if (rc==0)
 1744   {
 1745     free(s_user);
 1746     free(s_passwd);
 1747     free(s_db);
 1748 
 1749     if (!mysql->db && db && !(mysql->db= strdup(db)))
 1750     {
 1751       SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 1752       rc= 1;
 1753     }
 1754   } else
 1755   {
 1756     free(mysql->user);
 1757     free(mysql->passwd);
 1758     free(mysql->db);
 1759 
 1760     mysql->user= s_user;
 1761     mysql->passwd= s_passwd;
 1762     mysql->db= s_db;
 1763     mysql->charset= s_cs;
 1764   }
 1765   return(rc);
 1766 }
 1767 
 1768 
 1769 /**************************************************************************
 1770 ** Set current database
 1771 **************************************************************************/
 1772 
 1773 int STDCALL
 1774 mysql_select_db(MYSQL *mysql, const char *db)
 1775 {
 1776   int error;
 1777 
 1778   if (!db)
 1779     return 1;
 1780 
 1781   if ((error=ma_simple_command(mysql, COM_INIT_DB, db,
 1782                                (uint) strlen(db),0,0)))
 1783     return(error);
 1784   free(mysql->db);
 1785   mysql->db=strdup(db);
 1786   return(0);
 1787 }
 1788 
 1789 
 1790 /*************************************************************************
 1791 ** Send a QUIT to the server and close the connection
 1792 ** If handle is alloced by mysql connect free it.
 1793 *************************************************************************/
 1794 
 1795 static void mysql_close_options(MYSQL *mysql)
 1796 {
 1797   if (mysql->options.init_command)
 1798   {
 1799     char **begin= (char **)mysql->options.init_command->buffer;
 1800     char **end= begin + mysql->options.init_command->elements;
 1801 
 1802     for (;begin < end; begin++)
 1803       free(*begin);
 1804     ma_delete_dynamic(mysql->options.init_command);
 1805     free(mysql->options.init_command);
 1806   }
 1807   free(mysql->options.user);
 1808   free(mysql->options.host);
 1809   free(mysql->options.password);
 1810   free(mysql->options.unix_socket);
 1811   free(mysql->options.db);
 1812   free(mysql->options.my_cnf_file);
 1813   free(mysql->options.my_cnf_group);
 1814   free(mysql->options.charset_dir);
 1815   free(mysql->options.charset_name);
 1816   free(mysql->options.bind_address);
 1817   free(mysql->options.ssl_key);
 1818   free(mysql->options.ssl_cert);
 1819   free(mysql->options.ssl_ca);
 1820   free(mysql->options.ssl_capath);
 1821   free(mysql->options.ssl_cipher);
 1822 
 1823   if (mysql->options.extension)
 1824   {
 1825     struct mysql_async_context *ctxt;
 1826     if ((ctxt = mysql->options.extension->async_context))
 1827     {
 1828       my_context_destroy(&ctxt->async_context);
 1829       free(ctxt);
 1830       mysql->options.extension->async_context= 0;
 1831     }
 1832     free(mysql->options.extension->plugin_dir);
 1833     free(mysql->options.extension->default_auth);
 1834     free(mysql->options.extension->db_driver);
 1835     free(mysql->options.extension->ssl_crl);
 1836     free(mysql->options.extension->ssl_crlpath);
 1837     free(mysql->options.extension->tls_fp);
 1838     free(mysql->options.extension->tls_fp_list);
 1839     free(mysql->options.extension->tls_pw);
 1840     free(mysql->options.extension->tls_version);
 1841     free(mysql->options.extension->url);
 1842     free(mysql->options.extension->connection_handler);
 1843     if(hash_inited(&mysql->options.extension->connect_attrs))
 1844       hash_free(&mysql->options.extension->connect_attrs);
 1845     if (hash_inited(&mysql->options.extension->userdata))
 1846       hash_free(&mysql->options.extension->userdata);
 1847 
 1848   }
 1849   free(mysql->options.extension);
 1850   /* clear all pointer */
 1851   memset(&mysql->options, 0, sizeof(mysql->options));
 1852 }
 1853 
 1854 static void mysql_close_memory(MYSQL *mysql)
 1855 {
 1856   free(mysql->host_info);
 1857   free(mysql->host);
 1858   free(mysql->user);
 1859   free(mysql->passwd);
 1860   free(mysql->db);
 1861   free(mysql->unix_socket);
 1862   free(mysql->server_version);
 1863   mysql->host_info= mysql->host= mysql->unix_socket=
 1864                     mysql->server_version=mysql->user=mysql->passwd=mysql->db=0;
 1865 }
 1866 
 1867 void my_set_error(MYSQL *mysql,
 1868                   unsigned int error_nr,
 1869                   const char *sqlstate,
 1870                   const char *format,
 1871                   ...)
 1872 {
 1873   va_list ap;
 1874 
 1875   mysql->net.last_errno= error_nr;
 1876   ma_strmake(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH);
 1877   va_start(ap, format);
 1878   vsnprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE,
 1879             format ? format : ER(error_nr), ap);
 1880   va_end(ap);
 1881   return;
 1882 }
 1883 
 1884 void mysql_close_slow_part(MYSQL *mysql)
 1885 {
 1886   if (mysql->net.pvio)
 1887   {
 1888     free_old_query(mysql);
 1889     mysql->status=MYSQL_STATUS_READY; /* Force command */
 1890     mysql->options.reconnect=0;
 1891     if (mysql->net.pvio && mysql->net.buff)
 1892       ma_simple_command(mysql, COM_QUIT,NullS,0,1,0);
 1893     end_server(mysql);
 1894   }
 1895 }
 1896 
 1897 void ma_clear_session_state(MYSQL *mysql)
 1898 {
 1899   uint i;
 1900 
 1901   if (!mysql || !mysql->extension)
 1902     return;
 1903 
 1904   for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++)
 1905   {
 1906     /* we acquired memory via ma_multi_alloc, so we don't need to free data */
 1907     list_free(mysql->extension->session_state[i].list, 0);
 1908   }
 1909   memset(mysql->extension->session_state, 0, sizeof(struct st_mariadb_session_state) * SESSION_TRACK_TYPES);
 1910 }
 1911 
 1912 void STDCALL
 1913 mysql_close(MYSQL *mysql)
 1914 {
 1915   if (mysql)                    /* Some simple safety */
 1916   {
 1917     if (mysql->extension && mysql->extension->conn_hdlr)
 1918     {
 1919       MA_CONNECTION_HANDLER *p= mysql->extension->conn_hdlr;
 1920       if (p->plugin->close)
 1921         p->plugin->close(mysql);
 1922       free(p);
 1923       /* Fix for CONC-294: Since we already called plugin->close function
 1924          we need to prevent that mysql_close_slow_part (which sends COM_QUIT
 1925          to the server) will be handled by plugin again. */
 1926       mysql->extension->conn_hdlr= NULL;
 1927     }
 1928 
 1929     if (mysql->methods)
 1930       mysql->methods->db_close(mysql);
 1931 
 1932     /* reset the connection in all active statements */
 1933     ma_invalidate_stmts(mysql, "mysql_close()");
 1934 
 1935     mysql_close_memory(mysql);
 1936     mysql_close_options(mysql);
 1937     ma_clear_session_state(mysql);
 1938 
 1939     if (mysql->net.extension)
 1940       free(mysql->net.extension);
 1941 
 1942     mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
 1943 
 1944     /* Clear pointers for better safety */
 1945     memset((char*) &mysql->options, 0, sizeof(mysql->options));
 1946 
 1947     if (mysql->extension)
 1948       free(mysql->extension);
 1949 
 1950     mysql->net.pvio= 0;
 1951     if (mysql->free_me)
 1952       free(mysql);
 1953   }
 1954   return;
 1955 }
 1956 
 1957 
 1958 /**************************************************************************
 1959 ** Do a query. If query returned rows, free old rows.
 1960 ** Read data by mysql_store_result or by repeating calls to mysql_fetch_row
 1961 **************************************************************************/
 1962 
 1963 int STDCALL
 1964 mysql_query(MYSQL *mysql, const char *query)
 1965 {
 1966   return mysql_real_query(mysql,query, (unsigned long) strlen(query));
 1967 }
 1968 
 1969 /*
 1970   Send the query and return so we can do something else.
 1971   Needs to be followed by mysql_read_query_result() when we want to
 1972   finish processing it.
 1973 */
 1974 
 1975 int STDCALL
 1976 mysql_send_query(MYSQL* mysql, const char* query, unsigned long length)
 1977 {
 1978   return ma_simple_command(mysql, COM_QUERY, query, length, 1,0);
 1979 }
 1980 
 1981 int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
 1982 {
 1983   size_t item_len;
 1984   mysql->affected_rows= net_field_length_ll(&pos);
 1985   mysql->insert_id=   net_field_length_ll(&pos);
 1986   mysql->server_status=uint2korr(pos);
 1987   pos+=2;
 1988   mysql->warning_count=uint2korr(pos);
 1989   pos+=2;
 1990   if (pos < mysql->net.read_pos+length)
 1991   {
 1992     if ((item_len= net_field_length(&pos)))
 1993       mysql->info=(char*) pos;
 1994 
 1995     /* check if server supports session tracking */
 1996     if (mysql->server_capabilities & CLIENT_SESSION_TRACKING)
 1997     {
 1998       ma_clear_session_state(mysql);
 1999       pos+= item_len;
 2000 
 2001       if (mysql->server_status & SERVER_SESSION_STATE_CHANGED)
 2002       {
 2003         int i;
 2004         if (pos < mysql->net.read_pos + length)
 2005         {
 2006           LIST *session_item;
 2007           MYSQL_LEX_STRING *str= NULL;
 2008           enum enum_session_state_type si_type;
 2009           uchar *old_pos= pos;
 2010           size_t item_len= net_field_length(&pos);  /* length for all items */
 2011 
 2012           /* length was already set, so make sure that info will be zero terminated */
 2013           if (mysql->info)
 2014             *old_pos= 0;
 2015 
 2016           while (item_len > 0)
 2017           {
 2018             size_t plen;
 2019             char *data;
 2020             old_pos= pos;
 2021             si_type= (enum enum_session_state_type)net_field_length(&pos);
 2022             switch(si_type) {
 2023             case SESSION_TRACK_SCHEMA:
 2024             case SESSION_TRACK_STATE_CHANGE:
 2025             case SESSION_TRACK_TRANSACTION_CHARACTERISTICS:
 2026             case SESSION_TRACK_SYSTEM_VARIABLES:
 2027               net_field_length(&pos); /* ignore total length, item length will follow next */
 2028               plen= net_field_length(&pos);
 2029               if (!ma_multi_malloc(0,
 2030                                   &session_item, sizeof(LIST),
 2031                                   &str, sizeof(MYSQL_LEX_STRING),
 2032                                   &data, plen,
 2033                                   NULL))
 2034               {
 2035                 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2036                 return -1;
 2037               }
 2038               str->length= plen;
 2039               str->str= data;
 2040               memcpy(str->str, (char *)pos, plen);
 2041               pos+= plen;
 2042               session_item->data= str;
 2043               mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item);
 2044 
 2045               /* in case schema has changed, we have to update mysql->db */
 2046               if (si_type == SESSION_TRACK_SCHEMA)
 2047               {
 2048                 free(mysql->db);
 2049                 mysql->db= malloc(plen + 1);
 2050                 memcpy(mysql->db, str->str, plen);
 2051                 mysql->db[plen]= 0;
 2052               }
 2053               else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES)
 2054               {
 2055                 my_bool set_charset= 0;
 2056                 /* make sure that we update charset in case it has changed */
 2057                 if (!strncmp(str->str, "character_set_client", str->length))
 2058                   set_charset= 1;
 2059                 plen= net_field_length(&pos);
 2060                 if (!ma_multi_malloc(0,
 2061                                     &session_item, sizeof(LIST),
 2062                                     &str, sizeof(MYSQL_LEX_STRING),
 2063                                     &data, plen,
 2064                                     NULL))
 2065                 {
 2066                   SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2067                   return -1;
 2068                 }
 2069                 str->length= plen;
 2070                 str->str= data;
 2071                 memcpy(str->str, (char *)pos, plen);
 2072                 pos+= plen;
 2073                 session_item->data= str;
 2074                 mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item);
 2075                 if (set_charset &&
 2076                     strncmp(mysql->charset->csname, str->str, str->length) != 0)
 2077                 {
 2078                   char cs_name[64];
 2079                   MARIADB_CHARSET_INFO *cs_info;
 2080                   memcpy(cs_name, str->str, str->length);
 2081                   cs_name[str->length]= 0;
 2082                   if ((cs_info = (MARIADB_CHARSET_INFO *)mysql_find_charset_name(cs_name)))
 2083                     mysql->charset= cs_info;
 2084                 }
 2085               }
 2086               break;
 2087             default:
 2088               /* not supported yet */
 2089               plen= net_field_length(&pos);
 2090               pos+= plen;
 2091               break;
 2092             }
 2093             item_len-= (pos - old_pos);
 2094           }
 2095         }
 2096         for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++)
 2097         {
 2098           mysql->extension->session_state[i].list= list_reverse(mysql->extension->session_state[i].list);
 2099           mysql->extension->session_state[i].current= mysql->extension->session_state[i].list;
 2100         }
 2101       }
 2102     }
 2103   }
 2104   /* CONC-351: clear session state information */
 2105   else if (mysql->server_capabilities & CLIENT_SESSION_TRACKING)
 2106     ma_clear_session_state(mysql);
 2107   return(0);
 2108 }
 2109 
 2110 int mthd_my_read_query_result(MYSQL *mysql)
 2111 {
 2112   uchar *pos;
 2113   ulong field_count;
 2114   MYSQL_DATA *fields;
 2115   ulong length;
 2116 
 2117   if (!mysql || (length = ma_net_safe_read(mysql)) == packet_error)
 2118   {
 2119     return(1);
 2120   }
 2121   free_old_query(mysql);            /* Free old result */
 2122 get_info:
 2123   pos=(uchar*) mysql->net.read_pos;
 2124   if ((field_count= net_field_length(&pos)) == 0)
 2125     return ma_read_ok_packet(mysql, pos, length);
 2126   if (field_count == NULL_LENGTH)       /* LOAD DATA LOCAL INFILE */
 2127   {
 2128     int error=mysql_handle_local_infile(mysql, (char *)pos);
 2129 
 2130     if ((length=ma_net_safe_read(mysql)) == packet_error || error)
 2131       return(-1);
 2132     goto get_info;              /* Get info packet */
 2133   }
 2134   if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
 2135     mysql->server_status|= SERVER_STATUS_IN_TRANS;
 2136 
 2137   mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
 2138   if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
 2139     return(-1);
 2140   if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
 2141                     (uint) field_count,1,
 2142                     (my_bool) test(mysql->server_capabilities &
 2143                            CLIENT_LONG_FLAG))))
 2144     return(-1);
 2145   mysql->status=MYSQL_STATUS_GET_RESULT;
 2146   mysql->field_count=field_count;
 2147   return(0);
 2148 }
 2149 
 2150 int STDCALL mysql_session_track_get_next(MYSQL *mysql, enum enum_session_state_type type,
 2151                                          const char **data, size_t *length)
 2152 {
 2153   MYSQL_LEX_STRING *str;
 2154   if (!mysql->extension->session_state[type].current)
 2155     return 1;
 2156 
 2157   str= (MYSQL_LEX_STRING *)mysql->extension->session_state[type].current->data;
 2158   mysql->extension->session_state[type].current= mysql->extension->session_state[type].current->next;
 2159 
 2160   *data= str->str ? str->str : NULL;
 2161   *length= str->str ? str->length : 0;
 2162   return 0;
 2163 }
 2164 
 2165 int STDCALL mysql_session_track_get_first(MYSQL *mysql, enum enum_session_state_type type,
 2166                                           const char **data, size_t *length)
 2167 {
 2168   mysql->extension->session_state[type].current= mysql->extension->session_state[type].list;
 2169   return mysql_session_track_get_next(mysql, type, data, length);
 2170 }
 2171 
 2172 my_bool STDCALL
 2173 mysql_read_query_result(MYSQL *mysql)
 2174 {
 2175   return test(mysql->methods->db_read_query_result(mysql)) ? 1 : 0;
 2176 }
 2177 
 2178 int STDCALL
 2179 mysql_real_query(MYSQL *mysql, const char *query, unsigned long length)
 2180 {
 2181   my_bool skip_result= OPT_EXT_VAL(mysql, multi_command);
 2182 
 2183   if (length == (unsigned long)-1)
 2184     length= (unsigned long)strlen(query);
 2185 
 2186   free_old_query(mysql);
 2187 
 2188   if (ma_simple_command(mysql, COM_QUERY,query,length,1,0))
 2189     return(-1);
 2190   if (!skip_result)
 2191     return(mysql->methods->db_read_query_result(mysql));
 2192   return(0);
 2193 }
 2194 
 2195 /**************************************************************************
 2196 ** Alloc result struct for buffered results. All rows are read to buffer.
 2197 ** mysql_data_seek may be used.
 2198 **************************************************************************/
 2199 
 2200 MYSQL_RES * STDCALL
 2201 mysql_store_result(MYSQL *mysql)
 2202 {
 2203   MYSQL_RES *result;
 2204 
 2205   if (!mysql->fields)
 2206     return(0);
 2207   if (mysql->status != MYSQL_STATUS_GET_RESULT)
 2208   {
 2209     SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
 2210     return(0);
 2211   }
 2212   mysql->status=MYSQL_STATUS_READY;     /* server is ready */
 2213   if (!(result=(MYSQL_RES*) calloc(1, sizeof(MYSQL_RES)+
 2214                        sizeof(ulong)*mysql->field_count)))
 2215   {
 2216     SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2217     return(0);
 2218   }
 2219   result->eof=1;                /* Marker for buffered */
 2220   result->lengths=(ulong*) (result+1);
 2221   if (!(result->data=mysql->methods->db_read_rows(mysql,mysql->fields,mysql->field_count)))
 2222   {
 2223     free(result);
 2224     return(0);
 2225   }
 2226   mysql->affected_rows= result->row_count= result->data->rows;
 2227   result->data_cursor=  result->data->data;
 2228   result->fields=   mysql->fields;
 2229   result->field_alloc=  mysql->field_alloc;
 2230   result->field_count=  mysql->field_count;
 2231   result->current_field=0;
 2232   result->current_row=0;            /* Must do a fetch first */
 2233   mysql->fields=0;              /* fields is now in result */
 2234   return(result);               /* Data fetched */
 2235 }
 2236 
 2237 
 2238 /**************************************************************************
 2239 ** Alloc struct for use with unbuffered reads. Data is fetched by domand
 2240 ** when calling to mysql_fetch_row.
 2241 ** mysql_data_seek is a noop.
 2242 **
 2243 ** No other queries may be specified with the same MYSQL handle.
 2244 ** There shouldn't be much processing per row because mysql server shouldn't
 2245 ** have to wait for the client (and will not wait more than 30 sec/packet).
 2246 **************************************************************************/
 2247 
 2248 MYSQL_RES * STDCALL
 2249 mysql_use_result(MYSQL *mysql)
 2250 {
 2251   MYSQL_RES *result;
 2252 
 2253   if (!mysql->fields)
 2254     return(0);
 2255   if (mysql->status != MYSQL_STATUS_GET_RESULT)
 2256   {
 2257     SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
 2258     return(0);
 2259   }
 2260   if (!(result=(MYSQL_RES*) calloc(1, sizeof(*result)+
 2261                       sizeof(ulong)*mysql->field_count)))
 2262     return(0);
 2263   result->lengths=(ulong*) (result+1);
 2264   if (!(result->row=(MYSQL_ROW)
 2265     malloc(sizeof(result->row[0])*(mysql->field_count+1))))
 2266   {                 /* Ptrs: to one row */
 2267     free(result);
 2268     return(0);
 2269   }
 2270   result->fields=   mysql->fields;
 2271   result->field_alloc=  mysql->field_alloc;
 2272   result->field_count=  mysql->field_count;
 2273   result->current_field=0;
 2274   result->handle=   mysql;
 2275   result->current_row=  0;
 2276   mysql->fields=0;          /* fields is now in result */
 2277   mysql->status=MYSQL_STATUS_USE_RESULT;
 2278   return(result);           /* Data is read to be fetched */
 2279 }
 2280 
 2281 /**************************************************************************
 2282 ** Return next field of the query results
 2283 **************************************************************************/
 2284 MYSQL_FIELD * STDCALL
 2285 mysql_fetch_field(MYSQL_RES *result)
 2286 {
 2287   if (result->current_field >= result->field_count)
 2288     return(NULL);
 2289   return &result->fields[result->current_field++];
 2290 }
 2291 
 2292 /**************************************************************************
 2293 **  Return next row of the query results
 2294 **************************************************************************/
 2295 MYSQL_ROW STDCALL
 2296 mysql_fetch_row(MYSQL_RES *res)
 2297 {
 2298   if (!res)
 2299     return 0;
 2300   if (res->handle)
 2301   {
 2302     if (res->handle->status != MYSQL_STATUS_USE_RESULT &&
 2303         res->handle->status != MYSQL_STATUS_GET_RESULT)
 2304       return 0;
 2305   }
 2306   if (!res->data)
 2307   {                     /* Unbufferred fetch */
 2308     if (!res->eof && res->handle)
 2309     {
 2310       if (!(res->handle->methods->db_read_one_row(res->handle,res->field_count,res->row, res->lengths)))
 2311       {
 2312         res->row_count++;
 2313         return(res->current_row=res->row);
 2314       }
 2315       res->eof=1;
 2316       res->handle->status=MYSQL_STATUS_READY;
 2317        /* Don't clear handle in mysql_free_results */
 2318       res->handle=0;
 2319     }
 2320     return((MYSQL_ROW) NULL);
 2321   }
 2322   {
 2323     MYSQL_ROW tmp;
 2324     if (!res->data_cursor)
 2325     {
 2326       return(res->current_row=(MYSQL_ROW) NULL);
 2327     }
 2328     tmp = res->data_cursor->data;
 2329     res->data_cursor = res->data_cursor->next;
 2330     return(res->current_row=tmp);
 2331   }
 2332 }
 2333 
 2334 /**************************************************************************
 2335 ** Get column lengths of the current row
 2336 ** If one uses mysql_use_result, res->lengths contains the length information,
 2337 ** else the lengths are calculated from the offset between pointers.
 2338 **************************************************************************/
 2339 
 2340 ulong * STDCALL
 2341 mysql_fetch_lengths(MYSQL_RES *res)
 2342 {
 2343   ulong *lengths,*prev_length;
 2344   char *start;
 2345   MYSQL_ROW column,end;
 2346 
 2347   if (!(column=res->current_row))
 2348     return 0;                   /* Something is wrong */
 2349   if (res->data)
 2350   {
 2351     start=0;
 2352     prev_length=0;              /* Keep gcc happy */
 2353     lengths=res->lengths;
 2354     for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
 2355     {
 2356       if (!*column)
 2357       {
 2358     *lengths=0;             /* Null */
 2359     continue;
 2360       }
 2361       if (start)                /* Found end of prev string */
 2362     *prev_length= (uint) (*column-start-1);
 2363       start= *column;
 2364       prev_length=lengths;
 2365     }
 2366   }
 2367   return res->lengths;
 2368 }
 2369 
 2370 /**************************************************************************
 2371 ** Move to a specific row and column
 2372 **************************************************************************/
 2373 
 2374 void STDCALL
 2375 mysql_data_seek(MYSQL_RES *result, unsigned long long row)
 2376 {
 2377   MYSQL_ROWS    *tmp=0;
 2378   if (result->data)
 2379     for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
 2380   result->current_row=0;
 2381   result->data_cursor = tmp;
 2382 }
 2383 
 2384 /*************************************************************************
 2385 ** put the row or field cursor one a position one got from mysql_row_tell()
 2386 ** This doesn't restore any data. The next mysql_fetch_row or
 2387 ** mysql_fetch_field will return the next row or field after the last used
 2388 *************************************************************************/
 2389 
 2390 MYSQL_ROW_OFFSET STDCALL
 2391 mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
 2392 {
 2393   MYSQL_ROW_OFFSET return_value=result->data_cursor;
 2394   result->current_row= 0;
 2395   result->data_cursor= row;
 2396   return return_value;
 2397 }
 2398 
 2399 
 2400 MYSQL_FIELD_OFFSET STDCALL
 2401 mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
 2402 {
 2403   MYSQL_FIELD_OFFSET return_value=result->current_field;
 2404   result->current_field=field_offset;
 2405   return return_value;
 2406 }
 2407 
 2408 /*****************************************************************************
 2409 ** List all databases
 2410 *****************************************************************************/
 2411 
 2412 MYSQL_RES * STDCALL
 2413 mysql_list_dbs(MYSQL *mysql, const char *wild)
 2414 {
 2415   char buff[255];
 2416   snprintf(buff, 255, "SHOW DATABASES LIKE '%s'", wild ? wild : "%");
 2417   if (mysql_query(mysql,buff))
 2418     return(0);
 2419   return (mysql_store_result(mysql));
 2420 }
 2421 
 2422 
 2423 /*****************************************************************************
 2424 ** List all tables in a database
 2425 ** If wild is given then only the tables matching wild are returned
 2426 *****************************************************************************/
 2427 
 2428 MYSQL_RES * STDCALL
 2429 mysql_list_tables(MYSQL *mysql, const char *wild)
 2430 {
 2431   char buff[255];
 2432 
 2433   snprintf(buff, 255, "SHOW TABLES LIKE '%s'", wild ? wild : "%");
 2434   if (mysql_query(mysql,buff))
 2435     return(0);
 2436   return (mysql_store_result(mysql));
 2437 }
 2438 
 2439 
 2440 /**************************************************************************
 2441 ** List all fields in a table
 2442 ** If wild is given then only the fields matching wild are returned
 2443 ** Instead of this use query:
 2444 ** show fields in 'table' like "wild"
 2445 **************************************************************************/
 2446 
 2447 MYSQL_RES * STDCALL
 2448 mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
 2449 {
 2450   MYSQL_RES *result;
 2451   MYSQL_DATA *query;
 2452   char buff[255];
 2453   int length= 0;
 2454 
 2455   LINT_INIT(query);
 2456 
 2457   length= snprintf(buff, 128, "%s%c%s", table, '\0', wild ? wild : "");
 2458 
 2459   if (ma_simple_command(mysql, COM_FIELD_LIST,buff,length,1,0) ||
 2460       !(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
 2461     return(NULL);
 2462 
 2463   free_old_query(mysql);
 2464   if (!(result = (MYSQL_RES *) calloc(1, sizeof(MYSQL_RES))))
 2465   {
 2466     free_rows(query);
 2467     return(NULL);
 2468   }
 2469   result->field_alloc=mysql->field_alloc;
 2470   mysql->fields=0;
 2471   result->eof=1;
 2472   result->field_count = (uint) query->rows;
 2473   result->fields= unpack_fields(query,&result->field_alloc,
 2474                 result->field_count,1,
 2475                 (my_bool) test(mysql->server_capabilities &
 2476                            CLIENT_LONG_FLAG));
 2477   if (result->fields)
 2478     return(result);
 2479 
 2480   free(result);
 2481   return(NULL);
 2482 }
 2483 
 2484 /* List all running processes (threads) in server */
 2485 
 2486 MYSQL_RES * STDCALL
 2487 mysql_list_processes(MYSQL *mysql)
 2488 {
 2489   MYSQL_DATA *fields;
 2490   uint field_count;
 2491   uchar *pos;
 2492 
 2493   LINT_INIT(fields);
 2494   if (ma_simple_command(mysql, COM_PROCESS_INFO,0,0,0,0))
 2495     return(NULL);
 2496   free_old_query(mysql);
 2497   pos=(uchar*) mysql->net.read_pos;
 2498   field_count=(uint) net_field_length(&pos);
 2499   if (!(fields = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
 2500     return(NULL);
 2501   if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
 2502                     (my_bool) test(mysql->server_capabilities &
 2503                            CLIENT_LONG_FLAG))))
 2504     return(NULL);
 2505   mysql->status=MYSQL_STATUS_GET_RESULT;
 2506   mysql->field_count=field_count;
 2507   return(mysql_store_result(mysql));
 2508 }
 2509 
 2510 /* In 5.0 this version became an additional parameter shutdown_level */
 2511 int STDCALL
 2512 mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
 2513 {
 2514   uchar s_level[2];
 2515   s_level[0]= (uchar)shutdown_level;
 2516   return(ma_simple_command(mysql, COM_SHUTDOWN, (char *)s_level, 1, 0, 0));
 2517 }
 2518 
 2519 int STDCALL
 2520 mysql_refresh(MYSQL *mysql,uint options)
 2521 {
 2522   uchar bits[1];
 2523   bits[0]= (uchar) options;
 2524   return(ma_simple_command(mysql, COM_REFRESH,(char*) bits,1,0,0));
 2525 }
 2526 
 2527 int STDCALL
 2528 mysql_kill(MYSQL *mysql,ulong pid)
 2529 {
 2530   char buff[12];
 2531   int4store(buff,pid);
 2532   /* if we kill our own thread, reading the response packet will fail */
 2533   return(ma_simple_command(mysql, COM_PROCESS_KILL,buff,4,0,0));
 2534 }
 2535 
 2536 
 2537 int STDCALL
 2538 mysql_dump_debug_info(MYSQL *mysql)
 2539 {
 2540   return(ma_simple_command(mysql, COM_DEBUG,0,0,0,0));
 2541 }
 2542 
 2543 char * STDCALL
 2544 mysql_stat(MYSQL *mysql)
 2545 {
 2546   if (ma_simple_command(mysql, COM_STATISTICS,0,0,0,0))
 2547     return mysql->net.last_error;
 2548   mysql->net.read_pos[mysql->packet_length]=0;  /* End of stat string */
 2549   if (!mysql->net.read_pos[0])
 2550   {
 2551     SET_CLIENT_ERROR(mysql, CR_WRONG_HOST_INFO , SQLSTATE_UNKNOWN, 0);
 2552     return mysql->net.last_error;
 2553   }
 2554   return((char*) mysql->net.read_pos);
 2555 }
 2556 
 2557 int STDCALL
 2558 mysql_ping(MYSQL *mysql)
 2559 {
 2560   int rc;
 2561   rc= ma_simple_command(mysql, COM_PING, 0, 0, 0, 0);
 2562   if (rc && mysql->options.reconnect)
 2563     rc= ma_simple_command(mysql, COM_PING, 0, 0, 0, 0);
 2564   return rc;
 2565 }
 2566 
 2567 char * STDCALL
 2568 mysql_get_server_info(MYSQL *mysql)
 2569 {
 2570   return((char*) mysql->server_version);
 2571 }
 2572 
 2573 static size_t mariadb_server_version_id(MYSQL *mysql)
 2574 {
 2575   size_t major, minor, patch;
 2576   char *p;
 2577 
 2578   if (!(p = mysql->server_version)) {
 2579     return 0;
 2580   }
 2581 
 2582   major = strtol(p, &p, 10);
 2583   p += 1; /* consume the dot */
 2584   minor = strtol(p, &p, 10);
 2585   p += 1; /* consume the dot */
 2586   patch = strtol(p, &p, 10);
 2587 
 2588   return (major * 10000L + (unsigned long)(minor * 100L + patch));
 2589 }
 2590 
 2591 unsigned long STDCALL mysql_get_server_version(MYSQL *mysql)
 2592 {
 2593   return (unsigned long)mariadb_server_version_id(mysql);
 2594 }
 2595 
 2596 char * STDCALL
 2597 mysql_get_host_info(MYSQL *mysql)
 2598 {
 2599   return(mysql->host_info);
 2600 }
 2601 
 2602 uint STDCALL
 2603 mysql_get_proto_info(MYSQL *mysql)
 2604 {
 2605   return (mysql->protocol_version);
 2606 }
 2607 
 2608 const char * STDCALL
 2609 mysql_get_client_info(void)
 2610 {
 2611   return (char*) MARIADB_CLIENT_VERSION_STR;
 2612 }
 2613 
 2614 static size_t get_store_length(size_t length)
 2615 {
 2616   if (length < (size_t) L64(251))
 2617     return 1;
 2618   if (length < (size_t) L64(65536))
 2619     return 2;
 2620   if (length < (size_t) L64(16777216))
 2621     return 3;
 2622   return 9;
 2623 }
 2624 
 2625 uchar *ma_get_hash_keyval(const uchar *hash_entry,
 2626                        unsigned int *length,
 2627                        my_bool not_used __attribute__((unused)))
 2628 {
 2629   /* Hash entry has the following format:
 2630      Offset: 0               key (\0 terminated)
 2631              key_length + 1  value (\0 terminated)
 2632   */
 2633   uchar *p= (uchar *)hash_entry;
 2634   size_t len= strlen((char *)p);
 2635   *length= (unsigned int)len;
 2636   return p;
 2637 }
 2638 
 2639 void ma_int_hash_free(void *p)
 2640 {
 2641   free(p);
 2642 }
 2643 
 2644 int
 2645 mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
 2646 {
 2647   va_list ap;
 2648   void *arg1;
 2649   size_t stacksize;
 2650   struct mysql_async_context *ctxt;
 2651 
 2652   va_start(ap, option);
 2653 
 2654   arg1= va_arg(ap, void *);
 2655 
 2656   switch (option) {
 2657   case MYSQL_OPT_CONNECT_TIMEOUT:
 2658     mysql->options.connect_timeout= *(uint*) arg1;
 2659     break;
 2660   case MYSQL_OPT_COMPRESS:
 2661     mysql->options.compress= 1;         /* Remember for connect */
 2662     mysql->options.client_flag|= CLIENT_COMPRESS;
 2663     break;
 2664   case MYSQL_OPT_NAMED_PIPE:
 2665     mysql->options.named_pipe=1;        /* Force named pipe */
 2666     break;
 2667   case MYSQL_OPT_LOCAL_INFILE:          /* Allow LOAD DATA LOCAL ?*/
 2668     if (!arg1 || test(*(unsigned int*) arg1))
 2669       mysql->options.client_flag|= CLIENT_LOCAL_FILES;
 2670     else
 2671       mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
 2672     break;
 2673   case MYSQL_INIT_COMMAND:
 2674     options_add_initcommand(&mysql->options, (char *)arg1);
 2675     break;
 2676   case MYSQL_READ_DEFAULT_FILE:
 2677     OPT_SET_VALUE_STR(&mysql->options, my_cnf_file, (char *)arg1);
 2678     break;
 2679   case MYSQL_READ_DEFAULT_GROUP:
 2680     OPT_SET_VALUE_STR(&mysql->options, my_cnf_group, arg1 ? (char *)arg1 : "");
 2681     break;
 2682   case MYSQL_SET_CHARSET_DIR:
 2683     OPT_SET_VALUE_STR(&mysql->options, charset_dir, arg1);
 2684     break;
 2685   case MYSQL_SET_CHARSET_NAME:
 2686     OPT_SET_VALUE_STR(&mysql->options, charset_name, arg1);
 2687     break;
 2688   case MYSQL_OPT_RECONNECT:
 2689     mysql->options.reconnect= *(my_bool *)arg1;
 2690     break;
 2691   case MYSQL_OPT_PROTOCOL:
 2692     mysql->options.protocol= *((uint *)arg1);
 2693     break;
 2694 #ifdef _WIN32
 2695   case MYSQL_SHARED_MEMORY_BASE_NAME:
 2696     OPT_SET_VALUE_STR(&mysql->options, shared_memory_base_name, arg1);
 2697     break;
 2698 #endif
 2699   case MYSQL_OPT_READ_TIMEOUT:
 2700     mysql->options.read_timeout= *(uint *)arg1;
 2701     break;
 2702   case MYSQL_OPT_WRITE_TIMEOUT:
 2703     mysql->options.write_timeout= *(uint *)arg1;
 2704     break;
 2705   case MYSQL_REPORT_DATA_TRUNCATION:
 2706     mysql->options.report_data_truncation= *(my_bool *)arg1;
 2707     break;
 2708   case MYSQL_PROGRESS_CALLBACK:
 2709     CHECK_OPT_EXTENSION_SET(&mysql->options);
 2710     if (mysql->options.extension)
 2711       mysql->options.extension->report_progress=
 2712         (void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg1;
 2713     break;
 2714   case MYSQL_SERVER_PUBLIC_KEY:
 2715     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, server_public_key, (char *)arg1);
 2716     break;
 2717   case MYSQL_PLUGIN_DIR:
 2718     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, plugin_dir, (char *)arg1);
 2719     break;
 2720   case MYSQL_DEFAULT_AUTH:
 2721     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, default_auth, (char *)arg1);
 2722     break;
 2723   case MYSQL_OPT_NONBLOCK:
 2724     if (mysql->options.extension &&
 2725         (ctxt = mysql->options.extension->async_context) != 0)
 2726     {
 2727       /*
 2728         We must not allow changing the stack size while a non-blocking call is
 2729         suspended (as the stack is then in use).
 2730       */
 2731       if (ctxt->suspended)
 2732         goto end;
 2733       my_context_destroy(&ctxt->async_context);
 2734       free(ctxt);
 2735     }
 2736     if (!(ctxt= (struct mysql_async_context *)
 2737           calloc(1, sizeof(*ctxt))))
 2738     {
 2739       SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2740       goto end;
 2741     }
 2742     stacksize= 0;
 2743     if (arg1)
 2744       stacksize= *(const size_t *)arg1;
 2745     if (!stacksize)
 2746       stacksize= ASYNC_CONTEXT_DEFAULT_STACK_SIZE;
 2747     if (my_context_init(&ctxt->async_context, stacksize))
 2748     {
 2749       free(ctxt);
 2750       goto end;
 2751     }
 2752     if (!mysql->options.extension)
 2753       if(!(mysql->options.extension= (struct st_mysql_options_extension *)
 2754         calloc(1, sizeof(struct st_mysql_options_extension))))
 2755       {
 2756         free(ctxt);
 2757         SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2758         goto end;
 2759       }
 2760     mysql->options.extension->async_context= ctxt;
 2761     break;
 2762   case MYSQL_OPT_MAX_ALLOWED_PACKET:
 2763     if (mysql)
 2764       mysql->options.max_allowed_packet= (unsigned long)(*(size_t *)arg1);
 2765     else
 2766       max_allowed_packet= (unsigned long)(*(size_t *)arg1);
 2767     break;
 2768   case MYSQL_OPT_NET_BUFFER_LENGTH:
 2769     net_buffer_length= (unsigned long)(*(size_t *)arg1);
 2770     break;
 2771   case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
 2772     *((my_bool *)arg1)= test(mysql->options.client_flag & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS);
 2773     break;
 2774   case MYSQL_OPT_SSL_ENFORCE:
 2775     mysql->options.use_ssl= (*(my_bool *)arg1);
 2776     break;
 2777   case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
 2778     if (*(my_bool *)arg1)
 2779       mysql->options.client_flag |= CLIENT_SSL_VERIFY_SERVER_CERT;
 2780     else
 2781       mysql->options.client_flag &= ~CLIENT_SSL_VERIFY_SERVER_CERT;
 2782     break;
 2783   case MYSQL_OPT_SSL_KEY:
 2784     OPT_SET_VALUE_STR(&mysql->options, ssl_key, (char *)arg1);
 2785     break;
 2786   case MYSQL_OPT_SSL_CERT:
 2787     OPT_SET_VALUE_STR(&mysql->options, ssl_cert, (char *)arg1);
 2788     break;
 2789   case MYSQL_OPT_SSL_CA:
 2790     OPT_SET_VALUE_STR(&mysql->options, ssl_ca, (char *)arg1);
 2791     break;
 2792   case MYSQL_OPT_SSL_CAPATH:
 2793     OPT_SET_VALUE_STR(&mysql->options, ssl_capath, (char *)arg1);
 2794     break;
 2795   case MYSQL_OPT_SSL_CIPHER:
 2796     OPT_SET_VALUE_STR(&mysql->options, ssl_cipher, (char *)arg1);
 2797     break;
 2798   case MYSQL_OPT_SSL_CRL:
 2799     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crl, (char *)arg1);
 2800     break;
 2801   case MYSQL_OPT_SSL_CRLPATH:
 2802     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crlpath, (char *)arg1);
 2803     break;
 2804   case MYSQL_OPT_CONNECT_ATTR_DELETE:
 2805     {
 2806       uchar *h;
 2807       CHECK_OPT_EXTENSION_SET(&mysql->options);
 2808       if (hash_inited(&mysql->options.extension->connect_attrs) &&
 2809           (h= (uchar *)hash_search(&mysql->options.extension->connect_attrs, (uchar *)arg1,
 2810                       arg1 ? (uint)strlen((char *)arg1) : 0)))
 2811       {
 2812         uchar *p= h;
 2813         size_t key_len= strlen((char *)p);
 2814         mysql->options.extension->connect_attrs_len-= key_len + get_store_length(key_len);
 2815         p+= key_len + 1;
 2816         key_len= strlen((char *)p);
 2817         mysql->options.extension->connect_attrs_len-= key_len + get_store_length(key_len);
 2818         hash_delete(&mysql->options.extension->connect_attrs, h);
 2819       }
 2820 
 2821     }
 2822     break;
 2823   case MYSQL_OPT_CONNECT_ATTR_RESET:
 2824     CHECK_OPT_EXTENSION_SET(&mysql->options);
 2825     if (hash_inited(&mysql->options.extension->connect_attrs))
 2826     {
 2827       hash_free(&mysql->options.extension->connect_attrs);
 2828       mysql->options.extension->connect_attrs_len= 0;
 2829     }
 2830     break;
 2831   case MARIADB_OPT_CONNECTION_HANDLER:
 2832     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, connection_handler, (char *)arg1);
 2833     break;
 2834   case MARIADB_OPT_PORT:
 2835     OPT_SET_VALUE_INT(&mysql->options, port, *((uint *)arg1));
 2836     break;
 2837   case MARIADB_OPT_UNIXSOCKET:
 2838     OPT_SET_VALUE_STR(&mysql->options, unix_socket, arg1);
 2839     break;
 2840   case MARIADB_OPT_USER:
 2841     OPT_SET_VALUE_STR(&mysql->options, user, arg1);
 2842     break;
 2843   case MARIADB_OPT_HOST:
 2844     OPT_SET_VALUE_STR(&mysql->options, host, arg1);
 2845     break;
 2846   case MARIADB_OPT_SCHEMA:
 2847     OPT_SET_VALUE_STR(&mysql->options, db, arg1);
 2848     break;
 2849   case MARIADB_OPT_DEBUG:
 2850     break;
 2851   case MARIADB_OPT_FOUND_ROWS:
 2852     mysql->options.client_flag|= CLIENT_FOUND_ROWS;
 2853     break;
 2854   case MARIADB_OPT_INTERACTIVE:
 2855     mysql->options.client_flag|= CLIENT_INTERACTIVE;
 2856     break;
 2857   case MARIADB_OPT_MULTI_RESULTS:
 2858     mysql->options.client_flag|= CLIENT_MULTI_RESULTS;
 2859     break;
 2860   case MARIADB_OPT_MULTI_STATEMENTS:
 2861     mysql->options.client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
 2862     break;
 2863   case MARIADB_OPT_PASSWORD:
 2864     OPT_SET_VALUE_STR(&mysql->options, password, arg1);
 2865     break;
 2866   case MARIADB_OPT_USERDATA:
 2867     {
 2868       void *data= va_arg(ap, void *);
 2869       uchar *buffer, *p;
 2870       char *key= (char *)arg1;
 2871 
 2872       if (!key || !data)
 2873       {
 2874         SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
 2875         goto end;
 2876       }
 2877 
 2878       CHECK_OPT_EXTENSION_SET(&mysql->options);
 2879       if (!hash_inited(&mysql->options.extension->userdata))
 2880       {
 2881         if (_hash_init(&mysql->options.extension->userdata,
 2882                        0, 0, 0, ma_get_hash_keyval, ma_int_hash_free, 0))
 2883         {
 2884           SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2885           goto end;
 2886         }
 2887       }
 2888       /* check if key is already in buffer */
 2889       p= (uchar *)hash_search(&mysql->options.extension->userdata, 
 2890                               (uchar *)key,
 2891                               (uint)strlen(key));
 2892       if (p)
 2893       {
 2894         p+= strlen(key) + 1;
 2895         memcpy(p, &data, sizeof(void *));
 2896         break;
 2897       }
 2898 
 2899       if (!(buffer= (uchar *)malloc(strlen(key) + 1 + sizeof(void *))))
 2900       {
 2901         SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2902         goto end;
 2903       }
 2904 
 2905       p= buffer;
 2906       strcpy((char *)p, key);
 2907       p+= strlen(key) + 1;
 2908       memcpy(p, &data, sizeof(void *));
 2909 
 2910       if (hash_insert(&mysql->options.extension->userdata, buffer))
 2911       {
 2912         free(buffer);
 2913         SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
 2914         goto end;
 2915       }
 2916     }
 2917     break;
 2918   case MYSQL_OPT_CONNECT_ATTR_ADD:
 2919     {
 2920       uchar *buffer;
 2921       void *arg2= va_arg(ap, void *);
 2922       size_t storage_len, key_len= arg1 ? strlen((char *)arg1) : 0,
 2923              value_len= arg2 ? strlen((char *)arg2) : 0;
 2924       if (!key_len || !value_len)
 2925       {
 2926         SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
 2927         goto end;
 2928       }
 2929       storage_len= key_len + value_len +
 2930                    get_store_length(key_len) +
 2931                    get_store_length(value_len);
 2932 
 2933       /* since we store terminating zero character in hash, we need
 2934        * to increase lengths */
 2935       key_len++;
 2936       value_len++;
 2937 
 2938       CHECK_OPT_EXTENSION_SET(&mysql->options);
 2939       if (!key_len ||
 2940           storage_len + mysql->options.extension->connect_attrs_len > 0xFFFF)
 2941       {
 2942         SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
 2943         goto end;
 2944       }
 2945 
 2946       if (!hash_inited(&mysql->options.extension->connect_attrs))
 2947       {
 2948         if (_hash_init(&mysql->options.extension->connect_attrs,
 2949                        0, 0, 0, ma_get_hash_keyval, ma_int_hash_free, 0))
 2950         {
 2951           SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2952           goto end;
 2953         }
 2954       }
 2955       if ((buffer= (uchar *)malloc(key_len + value_len)))
 2956       {
 2957         uchar *p= buffer;
 2958         strcpy((char *)p, arg1);
 2959         p+= (strlen(arg1) + 1);
 2960         if (arg2)
 2961           strcpy((char *)p, arg2);
 2962 
 2963         if (hash_insert(&mysql->options.extension->connect_attrs, buffer))
 2964         {
 2965           free(buffer);
 2966           SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
 2967           goto end;
 2968         }
 2969         mysql->options.extension->connect_attrs_len+= storage_len;
 2970       }
 2971       else
 2972       {
 2973         SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
 2974         goto end;
 2975       }
 2976     }
 2977     break;
 2978   case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
 2979     break;
 2980   case MYSQL_SECURE_AUTH:
 2981     mysql->options.secure_auth= *(my_bool *)arg1;
 2982     break;
 2983   case MYSQL_OPT_BIND:
 2984     OPT_SET_VALUE_STR(&mysql->options, bind_address, arg1);
 2985     break;
 2986   case MARIADB_OPT_TLS_CIPHER_STRENGTH:
 2987     OPT_SET_EXTENDED_VALUE_INT(&mysql->options, tls_cipher_strength, *((unsigned int *)arg1));
 2988     break;
 2989   case MARIADB_OPT_SSL_FP:
 2990   case MARIADB_OPT_TLS_PEER_FP:
 2991     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_fp, (char *)arg1);
 2992     mysql->options.use_ssl= 1;
 2993     break;
 2994   case MARIADB_OPT_SSL_FP_LIST:
 2995   case MARIADB_OPT_TLS_PEER_FP_LIST:
 2996     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_fp_list, (char *)arg1);
 2997     mysql->options.use_ssl= 1;
 2998     break;
 2999   case MARIADB_OPT_TLS_PASSPHRASE:
 3000     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_pw, (char *)arg1);
 3001     break;
 3002   case MARIADB_OPT_CONNECTION_READ_ONLY:
 3003     OPT_SET_EXTENDED_VALUE_INT(&mysql->options, read_only, *(my_bool *)arg1);
 3004     break;
 3005   case MARIADB_OPT_PROXY_HEADER:
 3006     {
 3007     size_t arg2 = va_arg(ap, size_t);
 3008     OPT_SET_EXTENDED_VALUE(&mysql->options, proxy_header, (char *)arg1);
 3009     OPT_SET_EXTENDED_VALUE(&mysql->options, proxy_header_len, arg2);
 3010     }
 3011     break;
 3012   case MARIADB_OPT_TLS_VERSION:
 3013   case MYSQL_OPT_TLS_VERSION:
 3014     OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_version, (char *)arg1);
 3015     break;
 3016   default:
 3017     va_end(ap);
 3018     return(-1);
 3019   }
 3020   va_end(ap);
 3021   return(0);
 3022 end:
 3023   va_end(ap);
 3024   return(1);
 3025 }
 3026 
 3027 int
 3028 mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...)
 3029 {
 3030   va_list ap;
 3031 
 3032   va_start(ap, arg);
 3033 
 3034   switch(option) {
 3035   case MYSQL_OPT_CONNECT_TIMEOUT:
 3036     *((uint *)arg)= mysql->options.connect_timeout;
 3037     break;
 3038   case MYSQL_OPT_COMPRESS:
 3039     *((my_bool *)arg)= mysql->options.compress;
 3040     break;
 3041   case MYSQL_OPT_NAMED_PIPE:
 3042     *((my_bool *)arg)= mysql->options.named_pipe;
 3043     break;
 3044   case MYSQL_OPT_LOCAL_INFILE:          /* Allow LOAD DATA LOCAL ?*/
 3045     *((uint *)arg)= test(mysql->options.client_flag & CLIENT_LOCAL_FILES);
 3046     break;
 3047   case MYSQL_INIT_COMMAND:
 3048     /* mysql_get_optionsv(mysql, MYSQL_INIT_COMMAND, commands, elements) */
 3049     {
 3050       unsigned int *elements;
 3051       if (arg)
 3052         *((char **)arg)= mysql->options.init_command ? mysql->options.init_command->buffer : NULL;
 3053       if ((elements= va_arg(ap, unsigned int *)))
 3054         *elements= mysql->options.init_command ? mysql->options.init_command->elements : 0;
 3055     }
 3056     break;
 3057   case MYSQL_READ_DEFAULT_FILE:
 3058     *((char **)arg)= mysql->options.my_cnf_file;
 3059     break;
 3060   case MYSQL_READ_DEFAULT_GROUP:
 3061     *((char **)arg)= mysql->options.my_cnf_group;
 3062     break;
 3063   case MYSQL_SET_CHARSET_DIR:
 3064     /* not supported in this version. Since all character sets
 3065        are internally available, we don't throw an error */
 3066     *((char **)arg)= NULL;
 3067     break;
 3068   case MYSQL_SET_CHARSET_NAME:
 3069     if (mysql->charset)
 3070       *((const char **)arg)= mysql->charset->csname;
 3071     else
 3072       *((char **)arg)= mysql->options.charset_name;
 3073     break;
 3074   case MYSQL_OPT_RECONNECT:
 3075     *((my_bool *)arg)= mysql->options.reconnect;
 3076     break;
 3077   case MYSQL_OPT_PROTOCOL:
 3078     *((uint *)arg)= mysql->options.protocol;
 3079     break;
 3080   case MYSQL_OPT_READ_TIMEOUT:
 3081     *((uint *)arg)= mysql->options.read_timeout;
 3082     break;
 3083   case MYSQL_OPT_WRITE_TIMEOUT:
 3084     *((uint *)arg)= mysql->options.write_timeout;
 3085     break;
 3086   case MYSQL_REPORT_DATA_TRUNCATION:
 3087     *((my_bool *)arg)= mysql->options.report_data_truncation;
 3088     break;
 3089   case MYSQL_PROGRESS_CALLBACK:
 3090     *((void (**)(const MYSQL *, uint, uint, double, const char *, uint))arg)=
 3091        mysql->options.extension ?  mysql->options.extension->report_progress : NULL;
 3092     break;
 3093   case MYSQL_SERVER_PUBLIC_KEY:
 3094     *((char **)arg)= mysql->options.extension ?
 3095       mysql->options.extension->server_public_key : NULL;
 3096     break;
 3097   case MYSQL_PLUGIN_DIR:
 3098     *((char **)arg)= mysql->options.extension ? mysql->options.extension->plugin_dir : NULL;
 3099     break;
 3100   case MYSQL_DEFAULT_AUTH:
 3101     *((char **)arg)= mysql->options.extension ? mysql->options.extension->default_auth : NULL;
 3102     break;
 3103   case MYSQL_OPT_NONBLOCK:
 3104     *((my_bool *)arg)= test(mysql->options.extension && mysql->options.extension->async_context);
 3105     break;
 3106   case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
 3107     if (*(my_bool *)arg)
 3108       mysql->options.client_flag |= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
 3109     else
 3110       mysql->options.client_flag &= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
 3111     break;
 3112   case MYSQL_OPT_SSL_ENFORCE:
 3113     *((my_bool *)arg)= mysql->options.use_ssl;
 3114     break;
 3115   case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
 3116     *((my_bool *)arg)= test(mysql->options.client_flag & CLIENT_SSL_VERIFY_SERVER_CERT);
 3117     break;
 3118   case MYSQL_OPT_SSL_KEY:
 3119     *((char **)arg)= mysql->options.ssl_key;
 3120     break;
 3121   case MYSQL_OPT_SSL_CERT:
 3122     *((char **)arg)= mysql->options.ssl_cert;
 3123     break;
 3124   case MYSQL_OPT_SSL_CA:
 3125     *((char **)arg)= mysql->options.ssl_ca;
 3126     break;
 3127   case MYSQL_OPT_SSL_CAPATH:
 3128     *((char **)arg)= mysql->options.ssl_capath;
 3129     break;
 3130   case MYSQL_OPT_SSL_CIPHER:
 3131     *((char **)arg)= mysql->options.ssl_cipher;
 3132     break;
 3133   case MYSQL_OPT_SSL_CRL:
 3134     *((char **)arg)= mysql->options.extension ? mysql->options.ssl_cipher : NULL;
 3135     break;
 3136   case MYSQL_OPT_SSL_CRLPATH:
 3137     *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_crlpath : NULL;
 3138     break;
 3139   case MYSQL_OPT_CONNECT_ATTRS:
 3140     /* mysql_get_optionsv(mysql, MYSQL_OPT_CONNECT_ATTRS, keys, vals, elements) */
 3141     {
 3142       unsigned int i, *elements;
 3143       char **key= NULL;
 3144       void *arg1;
 3145       char **val= NULL;
 3146 
 3147       if (arg)
 3148         key= *(char ***)arg;
 3149 
 3150       arg1= va_arg(ap, char **);
 3151       if (arg1)
 3152         val= *(char ***)arg1;
 3153 
 3154       if (!(elements= va_arg(ap, unsigned int *)))
 3155         goto error;
 3156 
 3157       *elements= 0;
 3158 
 3159       if (!mysql->options.extension ||
 3160           !hash_inited(&mysql->options.extension->connect_attrs))
 3161         break;
 3162 
 3163       *elements= mysql->options.extension->connect_attrs.records;
 3164 
 3165       if (val || key)
 3166       {
 3167         for (i=0; i < *elements; i++)
 3168         {
 3169           uchar *p= hash_element(&mysql->options.extension->connect_attrs, i);
 3170           if (key)
 3171             key[i]= (char *)p;
 3172           p+= strlen((char *)p) + 1;
 3173           if (val)
 3174             val[i]= (char *)p;
 3175         }
 3176       }
 3177     }
 3178     break;
 3179   case MYSQL_OPT_MAX_ALLOWED_PACKET:
 3180     *((unsigned long *)arg)= (mysql) ? mysql->options.max_allowed_packet :
 3181                                        max_allowed_packet;
 3182     break;
 3183   case MYSQL_OPT_NET_BUFFER_LENGTH:
 3184     *((unsigned long *)arg)= net_buffer_length;
 3185     break;
 3186   case MYSQL_SECURE_AUTH:
 3187     *((my_bool *)arg)= mysql->options.secure_auth;
 3188     break;
 3189   case MYSQL_OPT_BIND:
 3190     *((char **)arg)= mysql->options.bind_address;
 3191     break;
 3192   case MARIADB_OPT_TLS_CIPHER_STRENGTH:
 3193     *((unsigned int *)arg) = mysql->options.extension ? mysql->options.extension->tls_cipher_strength : 0;
 3194     break;
 3195   case MARIADB_OPT_SSL_FP:
 3196   case MARIADB_OPT_TLS_PEER_FP:
 3197     *((char **)arg)= mysql->options.extension ? mysql->options.extension->tls_fp : NULL;
 3198     break;
 3199   case MARIADB_OPT_SSL_FP_LIST:
 3200   case MARIADB_OPT_TLS_PEER_FP_LIST:
 3201     *((char **)arg)= mysql->options.extension ? mysql->options.extension->tls_fp_list : NULL;
 3202     break;
 3203   case MARIADB_OPT_TLS_PASSPHRASE:
 3204     *((char **)arg)= mysql->options.extension ? mysql->options.extension->tls_pw : NULL;
 3205     break;
 3206   case MARIADB_OPT_CONNECTION_READ_ONLY:
 3207     *((my_bool *)arg)= mysql->options.extension ? mysql->options.extension->read_only : 0;
 3208     break;
 3209   case MARIADB_OPT_USERDATA:
 3210     /* nysql_get_optionv(mysql, MARIADB_OPT_USERDATA, key, value) */
 3211     {
 3212       uchar *p;
 3213       void *data= va_arg(ap, void *);
 3214       char *key= (char *)arg;
 3215       if (key && data && mysql->options.extension && hash_inited(&mysql->options.extension->userdata) &&
 3216           (p= (uchar *)hash_search(&mysql->options.extension->userdata, (uchar *)key,
 3217                       (uint)strlen((char *)key))))
 3218       {
 3219         p+= strlen(key) + 1;
 3220         *((void **)data)= *((void **)p);
 3221         break;
 3222       }
 3223       if (data)
 3224         *((void **)data)= NULL;
 3225     }
 3226     break;
 3227   case MARIADB_OPT_CONNECTION_HANDLER:
 3228     *((char **)arg)= mysql->options.extension ? mysql->options.extension->connection_handler : NULL;
 3229     break;
 3230   default:
 3231     va_end(ap);
 3232     return(-1);
 3233   }
 3234   va_end(ap);
 3235   return(0);
 3236 error:
 3237   va_end(ap);
 3238   return(-1);
 3239 }
 3240 
 3241 int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option, void *arg)
 3242 {
 3243   return mysql_get_optionv(mysql, option, arg);
 3244 }
 3245 
 3246 int STDCALL
 3247 mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
 3248 {
 3249   return mysql_optionsv(mysql, option, arg);
 3250 }
 3251 
 3252 int STDCALL
 3253 mysql_options4(MYSQL *mysql,enum mysql_option option, const void *arg1, const void *arg2)
 3254 {
 3255   return mysql_optionsv(mysql, option, arg1, arg2);
 3256 }
 3257 /****************************************************************************
 3258 ** Functions to get information from the MySQL structure
 3259 ** These are functions to make shared libraries more usable.
 3260 ****************************************************************************/
 3261 
 3262 /* MYSQL_RES */
 3263 my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
 3264 {
 3265   return res->row_count;
 3266 }
 3267 
 3268 unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
 3269 {
 3270   return res->field_count;
 3271 }
 3272 
 3273 /* deprecated */
 3274 my_bool STDCALL mysql_eof(MYSQL_RES *res)
 3275 {
 3276   return res->eof;
 3277 }
 3278 
 3279 MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
 3280 {
 3281   return &(res)->fields[fieldnr];
 3282 }
 3283 
 3284 MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
 3285 {
 3286   return (res)->fields;
 3287 }
 3288 
 3289 MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res)
 3290 {
 3291   return res->data_cursor;
 3292 }
 3293 
 3294 uint STDCALL mysql_field_tell(MYSQL_RES *res)
 3295 {
 3296   return (res)->current_field;
 3297 }
 3298 
 3299 /* MYSQL */
 3300 
 3301 unsigned int STDCALL mysql_field_count(MYSQL *mysql)
 3302 {
 3303   return mysql->field_count;
 3304 }
 3305 
 3306 my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
 3307 {
 3308   return (mysql)->affected_rows;
 3309 }
 3310 
 3311 my_bool STDCALL mysql_autocommit(MYSQL *mysql, my_bool mode)
 3312 {
 3313   return((my_bool) mysql_real_query(mysql, (mode) ? "SET autocommit=1" :
 3314                                          "SET autocommit=0", 16));
 3315 }
 3316 
 3317 my_bool STDCALL mysql_commit(MYSQL *mysql)
 3318 {
 3319   return((my_bool)mysql_real_query(mysql, "COMMIT", (unsigned long) sizeof("COMMIT")));
 3320 }
 3321 
 3322 my_bool STDCALL mysql_rollback(MYSQL *mysql)
 3323 {
 3324   return((my_bool)mysql_real_query(mysql, "ROLLBACK", (unsigned long)sizeof("ROLLBACK")));
 3325 }
 3326 
 3327 my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
 3328 {
 3329   return (mysql)->insert_id;
 3330 }
 3331 
 3332 uint STDCALL mysql_errno(MYSQL *mysql)
 3333 {
 3334   return mysql ? mysql->net.last_errno : 0;
 3335 }
 3336 
 3337 const char * STDCALL mysql_error(MYSQL *mysql)
 3338 {
 3339   return mysql ? (mysql)->net.last_error : (char *)"";
 3340 }
 3341 
 3342 const char *STDCALL mysql_info(MYSQL *mysql)
 3343 {
 3344   return (mysql)->info;
 3345 }
 3346 
 3347 my_bool STDCALL mysql_more_results(MYSQL *mysql)
 3348 {
 3349   return(test(mysql->server_status & SERVER_MORE_RESULTS_EXIST));
 3350 }
 3351 
 3352 int STDCALL mysql_next_result(MYSQL *mysql)
 3353 {
 3354 
 3355   /* make sure communication is not blocking */
 3356   if (mysql->status != MYSQL_STATUS_READY)
 3357   {
 3358     SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
 3359     return(1);
 3360   }
 3361 
 3362   /* clear error, and mysql status variables */
 3363   CLEAR_CLIENT_ERROR(mysql);
 3364   mysql->affected_rows = (ulonglong) ~0;
 3365 
 3366   if (mysql->server_status & SERVER_MORE_RESULTS_EXIST)
 3367   {
 3368      return(mysql->methods->db_read_query_result(mysql));
 3369   }
 3370 
 3371   return(-1);
 3372 }
 3373 
 3374 ulong STDCALL mysql_thread_id(MYSQL *mysql)
 3375 {
 3376   return (mysql)->thread_id;
 3377 }
 3378 
 3379 const char * STDCALL mysql_character_set_name(MYSQL *mysql)
 3380 {
 3381   return mysql->charset->csname;
 3382 }
 3383 
 3384 
 3385 uint STDCALL mysql_thread_safe(void)
 3386 {
 3387 #ifdef THREAD
 3388   return 1;
 3389 #else
 3390   return 0;
 3391 #endif
 3392 }
 3393 
 3394 /****************************************************************************
 3395 ** Some support functions
 3396 ****************************************************************************/
 3397 
 3398 /*
 3399 ** Add escape characters to a string (blob?) to make it suitable for a insert
 3400 ** to should at least have place for length*2+1 chars
 3401 ** Returns the length of the to string
 3402 */
 3403 
 3404 ulong STDCALL
 3405 mysql_escape_string(char *to,const char *from, ulong length)
 3406 {
 3407     return (ulong)mysql_cset_escape_slashes(ma_default_charset_info, to, from, length);
 3408 }
 3409 
 3410 ulong STDCALL
 3411 mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
 3412              ulong length)
 3413 {
 3414   if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
 3415     return (ulong)mysql_cset_escape_quotes(mysql->charset, to, from, length);
 3416   else
 3417     return (ulong)mysql_cset_escape_slashes(mysql->charset, to, from, length);
 3418 }
 3419 
 3420 static void mariadb_get_charset_info(MYSQL *mysql, MY_CHARSET_INFO *cs)
 3421 {
 3422   if (!cs)
 3423     return;
 3424 
 3425   cs->number= mysql->charset->nr;
 3426   cs->csname=  mysql->charset->csname;
 3427   cs->name= mysql->charset->name;
 3428   cs->state= 0;
 3429   cs->comment= NULL;
 3430   cs->dir= NULL;
 3431   cs->mbminlen= mysql->charset->char_minlen;
 3432   cs->mbmaxlen= mysql->charset->char_maxlen;
 3433 
 3434   return;
 3435 }
 3436 
 3437 void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs)
 3438 {
 3439   mariadb_get_charset_info(mysql, cs);
 3440 }
 3441 
 3442 int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname)
 3443 {
 3444   const MARIADB_CHARSET_INFO *cs;
 3445 
 3446   if (!csname)
 3447     goto error;
 3448 
 3449   if ((cs= mysql_find_charset_name(csname)))
 3450   {
 3451     char buff[64];
 3452 
 3453     snprintf(buff, 63, "SET NAMES %s", cs->csname);
 3454     if (!mysql_real_query(mysql, buff, (unsigned long)strlen(buff)))
 3455     {
 3456       mysql->charset= cs;
 3457       return(0);
 3458     }
 3459   }
 3460 
 3461 error:
 3462   my_set_error(mysql, CR_CANT_READ_CHARSET, SQLSTATE_UNKNOWN,
 3463                0, csname, "compiled_in");
 3464   return(mysql->net.last_errno);
 3465 }
 3466 
 3467 unsigned int STDCALL mysql_warning_count(MYSQL *mysql)
 3468 {
 3469   return mysql->warning_count;
 3470 }
 3471 
 3472 const char * STDCALL mysql_sqlstate(MYSQL *mysql)
 3473 {
 3474   return mysql->net.sqlstate;
 3475 }
 3476 
 3477 #ifndef _WIN32
 3478 #include <signal.h>
 3479 static void ignore_sigpipe()
 3480 {
 3481   signal(SIGPIPE, SIG_IGN);
 3482 }
 3483 #else
 3484 #define ignore_sigpipe()
 3485 #endif
 3486 
 3487 #ifdef _WIN32
 3488 static int mysql_once_init()
 3489 #else
 3490 static void mysql_once_init()
 3491 #endif
 3492 {
 3493   ma_init();                    /* Will init threads */
 3494   init_client_errs();
 3495   get_default_configuration_dirs();
 3496   set_default_charset_by_name(MARIADB_DEFAULT_CHARSET, 0);
 3497   if (mysql_client_plugin_init())
 3498   {
 3499 #ifdef _WIN32
 3500     return 1;
 3501 #else
 3502     return;
 3503 #endif
 3504   }
 3505   if (!mysql_port)
 3506   {
 3507     struct servent *serv_ptr;
 3508     char *env;
 3509 
 3510     mysql_port = MARIADB_PORT;
 3511     if ((serv_ptr = getservbyname("mysql", "tcp")))
 3512       mysql_port = (uint)ntohs((ushort)serv_ptr->s_port);
 3513     if ((env = getenv("MYSQL_TCP_PORT")))
 3514       mysql_port =(uint)atoi(env);
 3515   }
 3516   if (!mysql_unix_port)
 3517   {
 3518     char *env;
 3519 #ifdef _WIN32
 3520     mysql_unix_port = (char*)MARIADB_NAMEDPIPE;
 3521 #else
 3522     mysql_unix_port = (char*)MARIADB_UNIX_ADDR;
 3523 #endif
 3524     if ((env = getenv("MYSQL_UNIX_PORT")) ||
 3525       (env = getenv("MARIADB_UNIX_PORT")))
 3526       mysql_unix_port = env;
 3527   }
 3528   if (!mysql_ps_subsystem_initialized)
 3529     mysql_init_ps_subsystem();
 3530 #ifdef HAVE_TLS
 3531   ma_tls_start(0, 0);
 3532 #endif
 3533   ignore_sigpipe();
 3534   mysql_client_init = 1;
 3535 #ifdef _WIN32
 3536   return 0;
 3537 #endif
 3538 }
 3539 
 3540 #ifdef _WIN32
 3541 static INIT_ONCE init_once= INIT_ONCE_STATIC_INIT;
 3542 BOOL CALLBACK win_init_once(
 3543   PINIT_ONCE InitOnce,
 3544   PVOID Parameter,
 3545   PVOID *lpContext)
 3546 {
 3547   return !mysql_once_init();
 3548   return TRUE;
 3549 }
 3550 #else
 3551 static pthread_once_t init_once = PTHREAD_ONCE_INIT;
 3552 #endif
 3553 
 3554 int STDCALL mysql_server_init(int argc __attribute__((unused)),
 3555   char **argv __attribute__((unused)),
 3556   char **groups __attribute__((unused)))
 3557 {
 3558 #ifdef _WIN32
 3559   BOOL ret = InitOnceExecuteOnce(&init_once, win_init_once, NULL, NULL);
 3560   return ret? 0: 1;
 3561 #else
 3562   return pthread_once(&init_once, mysql_once_init);
 3563 #endif
 3564 }
 3565 
 3566 void STDCALL mysql_server_end(void)
 3567 {
 3568   if (!mysql_client_init)
 3569     return;
 3570 
 3571   release_configuration_dirs();
 3572   mysql_client_plugin_deinit();
 3573 
 3574   list_free(pvio_callback, 0);
 3575   if (ma_init_done)
 3576     ma_end(0);
 3577 #ifdef HAVE_TLS
 3578   ma_pvio_tls_end();
 3579 #endif
 3580   mysql_client_init= 0;
 3581   ma_init_done= 0;
 3582 #ifdef WIN32
 3583   init_once = (INIT_ONCE)INIT_ONCE_STATIC_INIT;
 3584 #else
 3585   init_once = (pthread_once_t)PTHREAD_ONCE_INIT;
 3586 #endif
 3587 }
 3588 
 3589 my_bool STDCALL mysql_thread_init(void)
 3590 {
 3591   return 0;
 3592 }
 3593 
 3594 void STDCALL mysql_thread_end(void)
 3595 {
 3596 }
 3597 
 3598 int STDCALL mysql_set_server_option(MYSQL *mysql,
 3599                                     enum enum_mysql_set_option option)
 3600 {
 3601   char buffer[2];
 3602   int2store(buffer, (uint)option);
 3603   return(ma_simple_command(mysql, COM_SET_OPTION, buffer, sizeof(buffer), 0, 0));
 3604 }
 3605 
 3606 ulong STDCALL mysql_get_client_version(void)
 3607 {
 3608   return MARIADB_VERSION_ID;
 3609 }
 3610 
 3611 ulong STDCALL mysql_hex_string(char *to, const char *from, unsigned long len)
 3612 {
 3613   char *start= to;
 3614   char hexdigits[]= "0123456789ABCDEF";
 3615 
 3616   while (len--)
 3617   {
 3618     *to++= hexdigits[((unsigned char)*from) >> 4];
 3619     *to++= hexdigits[((unsigned char)*from) & 0x0F];
 3620     from++;
 3621   }
 3622   *to= 0;
 3623   return (ulong)(to - start);
 3624 }
 3625 
 3626 my_bool STDCALL mariadb_connection(MYSQL *mysql)
 3627 {
 3628   return (strstr(mysql->server_version, "MariaDB") ||
 3629           strstr(mysql->server_version, "-maria-"));
 3630 }
 3631 
 3632 const char * STDCALL
 3633 mysql_get_server_name(MYSQL *mysql)
 3634 {
 3635   if (mysql->options.extension &&
 3636       mysql->options.extension->db_driver != NULL)
 3637     return mysql->options.extension->db_driver->name;
 3638   return mariadb_connection(mysql) ? "MariaDB" : "MySQL";
 3639 }
 3640 
 3641 static my_socket mariadb_get_socket(MYSQL *mysql)
 3642 {
 3643   my_socket sock= INVALID_SOCKET;
 3644   if (mysql->net.pvio)
 3645   {
 3646     ma_pvio_get_handle(mysql->net.pvio, &sock);
 3647 
 3648   }
 3649   /* if an asynchronous connect is in progress, we need to obtain
 3650      pvio handle from async_context until the connection was
 3651      successfully established.
 3652   */
 3653   else if (mysql->options.extension && mysql->options.extension->async_context &&
 3654            mysql->options.extension->async_context->pvio)
 3655   {
 3656     ma_pvio_get_handle(mysql->options.extension->async_context->pvio, &sock);
 3657   }
 3658   return sock;
 3659 }
 3660 
 3661 my_socket STDCALL
 3662 mysql_get_socket(MYSQL *mysql)
 3663 {
 3664   return mariadb_get_socket(mysql);
 3665 }
 3666 
 3667 MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname)
 3668 {
 3669   return (MARIADB_CHARSET_INFO *)mysql_find_charset_name(csname);
 3670 }
 3671 
 3672 MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr)
 3673 {
 3674   return (MARIADB_CHARSET_INFO *)mysql_find_charset_nr(csnr);
 3675 }
 3676 
 3677 my_bool mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ...)
 3678 {
 3679   va_list ap;
 3680 
 3681   va_start(ap, arg);
 3682 
 3683   switch(value) {
 3684   case MARIADB_MAX_ALLOWED_PACKET:
 3685     *((size_t *)arg)= (size_t)max_allowed_packet;
 3686     break;
 3687   case MARIADB_NET_BUFFER_LENGTH:
 3688     *((size_t *)arg)= (size_t)net_buffer_length;
 3689     break;
 3690   case MARIADB_CONNECTION_ERROR_ID:
 3691     if (!mysql)
 3692       goto error;
 3693     *((unsigned int *)arg)= mysql->net.last_errno;
 3694     break;
 3695   case MARIADB_CONNECTION_ERROR:
 3696     if (!mysql)
 3697       goto error;
 3698     *((char **)arg)= mysql->net.last_error;
 3699     break;
 3700   case MARIADB_CONNECTION_SQLSTATE:
 3701     if (!mysql)
 3702       goto error;
 3703     *((char **)arg)= mysql->net.sqlstate;
 3704     break;
 3705   case MARIADB_CONNECTION_TLS_VERSION:
 3706     #ifdef HAVE_TLS
 3707     if (mysql && mysql->net.pvio && mysql->net.pvio->ctls)
 3708       *((char **)arg)= (char *)ma_pvio_tls_get_protocol_version(mysql->net.pvio->ctls);
 3709     else
 3710     #endif
 3711       goto error;
 3712     break;
 3713   case MARIADB_CONNECTION_TLS_VERSION_ID:
 3714     #ifdef HAVE_TLS
 3715     if (mysql && mysql->net.pvio && mysql->net.pvio->ctls)
 3716       *((unsigned int *)arg)= ma_pvio_tls_get_protocol_version_id(mysql->net.pvio->ctls);
 3717     else
 3718     #endif
 3719       goto error;
 3720     break;
 3721   case MARIADB_TLS_LIBRARY:
 3722 #ifdef HAVE_TLS
 3723     *((const char **)arg)= tls_library_version;
 3724 #else
 3725     *((char **)arg)= "Off";
 3726 #endif
 3727     break;
 3728   case MARIADB_CLIENT_VERSION:
 3729     *((const char **)arg)= MARIADB_CLIENT_VERSION_STR;
 3730     break;
 3731   case MARIADB_CLIENT_VERSION_ID:
 3732     *((size_t *)arg)= MARIADB_VERSION_ID;
 3733     break;
 3734   case MARIADB_CONNECTION_SERVER_VERSION:
 3735     if (mysql)
 3736       *((char **)arg)= mysql->server_version;
 3737     else
 3738       goto error;
 3739     break;
 3740   case MARIADB_CONNECTION_SERVER_TYPE:
 3741     if (mysql)
 3742       *((const char **)arg)= mariadb_connection(mysql) ? "MariaDB" : "MySQL";
 3743     else
 3744       goto error;
 3745     break;
 3746   case MARIADB_CONNECTION_SERVER_VERSION_ID:
 3747     if (mysql)
 3748       *((size_t *)arg)= mariadb_server_version_id(mysql);
 3749     else
 3750       goto error;
 3751     break;
 3752   case MARIADB_CONNECTION_PROTOCOL_VERSION_ID:
 3753     if (mysql)
 3754       *((unsigned int *)arg)= mysql->protocol_version;
 3755     else
 3756       goto error;
 3757     break;
 3758   case MARIADB_CONNECTION_MARIADB_CHARSET_INFO:
 3759     if (mysql)
 3760       mariadb_get_charset_info(mysql, (MY_CHARSET_INFO *)arg);
 3761     else
 3762       goto error;
 3763     break;
 3764   case MARIADB_CONNECTION_SOCKET:
 3765     if (mysql)
 3766       *((my_socket *)arg)= mariadb_get_socket(mysql);
 3767     else
 3768       goto error;
 3769     break;
 3770   case MARIADB_CONNECTION_TYPE:
 3771     if (mysql  && mysql->net.pvio)
 3772       *((int *)arg)= (int)mysql->net.pvio->type;
 3773     else
 3774       goto error;
 3775     break;
 3776   case MARIADB_CONNECTION_ASYNC_TIMEOUT_MS:
 3777     if (mysql && mysql->options.extension && mysql->options.extension->async_context)
 3778       *((unsigned int *)arg)= mysql->options.extension->async_context->timeout_value;
 3779     break;
 3780   case MARIADB_CONNECTION_ASYNC_TIMEOUT:
 3781     if (mysql && mysql->options.extension && mysql->options.extension->async_context)
 3782     {
 3783       unsigned int timeout= mysql->options.extension->async_context->timeout_value;
 3784       if (timeout > UINT_MAX - 999)
 3785         *((unsigned int *)arg)= (timeout - 1)/1000 + 1;
 3786       else
 3787         *((unsigned int *)arg)= (timeout+999)/1000;
 3788     }
 3789     break;
 3790   case MARIADB_CHARSET_NAME:
 3791     {
 3792       char *name;
 3793       name= va_arg(ap, char *);
 3794       if (name)
 3795         *((MARIADB_CHARSET_INFO **)arg)= (MARIADB_CHARSET_INFO *)mysql_find_charset_name(name);
 3796       else
 3797         goto error;
 3798     }
 3799     break;
 3800   case MARIADB_CHARSET_ID:
 3801     {
 3802       unsigned int nr;
 3803       nr= va_arg(ap, unsigned int);
 3804       *((MARIADB_CHARSET_INFO **)arg)= (MARIADB_CHARSET_INFO *)mysql_find_charset_nr(nr);
 3805     }
 3806     break;
 3807   case MARIADB_CONNECTION_SSL_CIPHER:
 3808     #ifdef HAVE_TLS
 3809     if (mysql && mysql->net.pvio && mysql->net.pvio->ctls)
 3810       *((char **)arg)= (char *)ma_pvio_tls_cipher(mysql->net.pvio->ctls);
 3811     else
 3812     #endif
 3813       goto error;
 3814     break;
 3815   case MARIADB_CLIENT_ERRORS:
 3816     *((char ***)arg)= (char **)client_errors;
 3817     break;
 3818   case MARIADB_CONNECTION_INFO:
 3819     if (mysql)
 3820       *((char **)arg)= (char *)mysql->info;
 3821     else
 3822       goto error;
 3823     break;
 3824   case MARIADB_CONNECTION_PVIO_TYPE:
 3825     if (mysql && mysql->net.pvio)
 3826       *((unsigned int *)arg)= (unsigned int)mysql->net.pvio->type;
 3827     else
 3828       goto error;
 3829     break;
 3830   case MARIADB_CONNECTION_SCHEMA:
 3831     if (mysql)
 3832       *((char **)arg)= mysql->db;
 3833     else
 3834       goto error;
 3835     break;
 3836   case MARIADB_CONNECTION_USER:
 3837     if (mysql)
 3838       *((char **)arg)= mysql->user;
 3839     else
 3840       goto error;
 3841     break;
 3842   case MARIADB_CONNECTION_PORT:
 3843     if (mysql)
 3844       *((unsigned int *)arg)= mysql->port;
 3845     else
 3846       goto error;
 3847     break;
 3848   case MARIADB_CONNECTION_UNIX_SOCKET:
 3849     if (mysql)
 3850       *((char **)arg)= mysql->unix_socket;
 3851     else
 3852       goto error;
 3853     break;
 3854   case MARIADB_CONNECTION_HOST:
 3855     if (mysql)
 3856       *((char **)arg)= mysql->host;
 3857     else
 3858       goto error;
 3859     break;
 3860   case MARIADB_CONNECTION_SERVER_STATUS:
 3861     if (mysql)
 3862       *((unsigned int *)arg)= mysql->server_status;
 3863     else
 3864       goto error;
 3865     break;
 3866   case MARIADB_CONNECTION_SERVER_CAPABILITIES:
 3867     if (mysql)
 3868       *((unsigned long *)arg)= mysql->server_capabilities;
 3869     else
 3870       goto error;
 3871     break;
 3872   case MARIADB_CONNECTION_EXTENDED_SERVER_CAPABILITIES:
 3873     if (mysql)
 3874       *((unsigned long *)arg)= mysql->extension->mariadb_server_capabilities;
 3875     else
 3876       goto error;
 3877     break;
 3878   case MARIADB_CONNECTION_CLIENT_CAPABILITIES:
 3879     if (mysql)
 3880       *((unsigned long *)arg)= mysql->client_flag;
 3881     else
 3882       goto error;
 3883     break;
 3884   default:
 3885     va_end(ap);
 3886     return(-1);
 3887   }
 3888   va_end(ap);
 3889   return(0);
 3890 error:
 3891   va_end(ap);
 3892   return(-1);
 3893 }
 3894 
 3895 my_bool STDCALL mariadb_get_info(MYSQL *mysql, enum mariadb_value value, void *arg)
 3896 {
 3897   return mariadb_get_infov(mysql, value, arg);
 3898 }
 3899 
 3900 /*
 3901   Immediately aborts connection, making all subsequent read/write operations fail.
 3902   Does not invalidate memory used for mysql structure, nor closes any communication
 3903   channels - mysql_close is still needed.
 3904   Useful to break long query, in situation  sending KILL is not possible.
 3905 */
 3906 int STDCALL mariadb_cancel(MYSQL *mysql)
 3907 {
 3908   if (!mysql || !mysql->net.pvio || !mysql->net.pvio->methods || !mysql->net.pvio->methods->shutdown)
 3909   {
 3910     return 1;
 3911   }
 3912   else
 3913   {
 3914     MARIADB_PVIO *pvio = mysql->net.pvio;
 3915     return pvio->methods->shutdown(pvio);
 3916   }
 3917 }
 3918 
 3919 /* compatibility functions for MariaDB */
 3920 void STDCALL
 3921 mysql_debug(const char *debug __attribute__((unused)))
 3922 {
 3923   return;
 3924 }
 3925 
 3926 /********************************************************************
 3927   mysql_net_ functions - low-level API to MySQL protocol
 3928 *********************************************************************/
 3929 ulong STDCALL mysql_net_read_packet(MYSQL *mysql)
 3930 {
 3931   return ma_net_safe_read(mysql);
 3932 }
 3933 
 3934 ulong STDCALL mysql_net_field_length(uchar **packet)
 3935 {
 3936   return net_field_length(packet);
 3937 }
 3938 
 3939 my_bool STDCALL mysql_embedded(void)
 3940 {
 3941 #ifdef EMBEDDED_LIBRARY
 3942   return 1;
 3943 #else
 3944   return 0;
 3945 #endif
 3946 }
 3947 
 3948 MYSQL_PARAMETERS *STDCALL
 3949 mysql_get_parameters(void)
 3950 {
 3951   return &mariadb_internal_parameters;
 3952 }
 3953 
 3954 int STDCALL mysql_reset_connection(MYSQL *mysql)
 3955 {
 3956   int rc;
 3957 
 3958   /* check if connection handler is active */
 3959   if (IS_CONNHDLR_ACTIVE(mysql))
 3960   {
 3961     if (mysql->extension->conn_hdlr->plugin && mysql->extension->conn_hdlr->plugin->reset)
 3962       return(mysql->extension->conn_hdlr->plugin->reset(mysql));
 3963   }
 3964 
 3965   /* skip result sets */
 3966   if (mysql->status == MYSQL_STATUS_USE_RESULT ||
 3967       mysql->status == MYSQL_STATUS_GET_RESULT ||
 3968       mysql->status & SERVER_MORE_RESULTS_EXIST)
 3969   {
 3970     mthd_my_skip_result(mysql);
 3971     mysql->status= MYSQL_STATUS_READY;
 3972   }
 3973 
 3974   rc= ma_simple_command(mysql, COM_RESET_CONNECTION, 0, 0, 0, 0);
 3975   if (rc && mysql->options.reconnect)
 3976   {
 3977     /* There is no big sense in resetting but we need reconnect */
 3978     rc= ma_simple_command(mysql, COM_RESET_CONNECTION,0,0,0,0);
 3979   }
 3980   if (rc)
 3981     return 1;
 3982 
 3983   /* reset the connection in all active statements */
 3984   ma_invalidate_stmts(mysql, "mysql_reset_connection()");
 3985   free_old_query(mysql);
 3986   mysql->status= MYSQL_STATUS_READY;
 3987   mysql->affected_rows= ~(my_ulonglong)0;
 3988   mysql->insert_id= 0;
 3989   return 0;
 3990 }
 3991 
 3992 #undef STDCALL
 3993 /* API functions for usage in dynamic plugins */
 3994 struct st_mariadb_api MARIADB_API=
 3995 {
 3996   mysql_num_rows,
 3997   mysql_num_fields,
 3998   mysql_eof,
 3999   mysql_fetch_field_direct,
 4000   mysql_fetch_fields,
 4001   mysql_row_tell,
 4002   mysql_field_tell,
 4003   mysql_field_count,
 4004   mysql_more_results,
 4005   mysql_next_result,
 4006   mysql_affected_rows,
 4007   mysql_autocommit,
 4008   mysql_commit,
 4009   mysql_rollback,
 4010   mysql_insert_id,
 4011   mysql_errno,
 4012   mysql_error,
 4013   mysql_info,
 4014   mysql_thread_id,
 4015   mysql_character_set_name,
 4016   mysql_get_character_set_info,
 4017   mysql_set_character_set,
 4018   mariadb_get_infov,
 4019   mariadb_get_info,
 4020   mysql_init,
 4021   mysql_ssl_set,
 4022   mysql_get_ssl_cipher,
 4023   mysql_change_user,
 4024   mysql_real_connect,
 4025   mysql_close,
 4026   mysql_select_db,
 4027   mysql_query,
 4028   mysql_send_query,
 4029   mysql_read_query_result,
 4030   mysql_real_query,
 4031   mysql_shutdown,
 4032   mysql_dump_debug_info,
 4033   mysql_refresh,
 4034   mysql_kill,
 4035   mysql_ping,
 4036   mysql_stat,
 4037   mysql_get_server_info,
 4038   mysql_get_server_version,
 4039   mysql_get_host_info,
 4040   mysql_get_proto_info,
 4041   mysql_list_dbs,
 4042   mysql_list_tables,
 4043   mysql_list_fields,
 4044   mysql_list_processes,
 4045   mysql_store_result,
 4046   mysql_use_result,
 4047   mysql_options,
 4048   mysql_free_result,
 4049   mysql_data_seek,
 4050   mysql_row_seek,
 4051   mysql_field_seek,
 4052   mysql_fetch_row,
 4053   mysql_fetch_lengths,
 4054   mysql_fetch_field,
 4055   mysql_escape_string,
 4056   mysql_real_escape_string,
 4057   mysql_thread_safe,
 4058   mysql_warning_count,
 4059   mysql_sqlstate,
 4060   mysql_server_init,
 4061   mysql_server_end,
 4062   mysql_thread_end,
 4063   mysql_thread_init,
 4064   mysql_set_server_option,
 4065   mysql_get_client_info,
 4066   mysql_get_client_version,
 4067   mariadb_connection,
 4068   mysql_get_server_name,
 4069   mariadb_get_charset_by_name,
 4070   mariadb_get_charset_by_nr,
 4071   mariadb_convert_string,
 4072   mysql_optionsv,
 4073   mysql_get_optionv,
 4074   mysql_get_option,
 4075   mysql_hex_string,
 4076   mysql_get_socket,
 4077   mysql_get_timeout_value,
 4078   mysql_get_timeout_value_ms,
 4079   mariadb_reconnect,
 4080   mysql_stmt_init,
 4081   mysql_stmt_prepare,
 4082   mysql_stmt_execute,
 4083   mysql_stmt_fetch,
 4084   mysql_stmt_fetch_column,
 4085   mysql_stmt_store_result,
 4086   mysql_stmt_param_count,
 4087   mysql_stmt_attr_set,
 4088   mysql_stmt_attr_get,
 4089   mysql_stmt_bind_param,
 4090   mysql_stmt_bind_result,
 4091   mysql_stmt_close,
 4092   mysql_stmt_reset,
 4093   mysql_stmt_free_result,
 4094   mysql_stmt_send_long_data,
 4095   mysql_stmt_result_metadata,
 4096   mysql_stmt_param_metadata,
 4097   mysql_stmt_errno,
 4098   mysql_stmt_error,
 4099   mysql_stmt_sqlstate,
 4100   mysql_stmt_row_seek,
 4101   mysql_stmt_row_tell,
 4102   mysql_stmt_data_seek,
 4103   mysql_stmt_num_rows,
 4104   mysql_stmt_affected_rows,
 4105   mysql_stmt_insert_id,
 4106   mysql_stmt_field_count,
 4107   mysql_stmt_next_result,
 4108   mysql_stmt_more_results,
 4109   mariadb_stmt_execute_direct,
 4110   mysql_reset_connection
 4111 };
 4112 
 4113 /*
 4114  * Default methods for a connection. These methods are
 4115  * stored in mysql->methods and can be overwritten by
 4116  * a plugin, e.g. for using another database
 4117  */
 4118 struct st_mariadb_methods MARIADB_DEFAULT_METHODS = {
 4119   /* open a connection */
 4120   mthd_my_real_connect,
 4121   /* close connection */
 4122   mysql_close_slow_part,
 4123   /* send command to server */
 4124   mthd_my_send_cmd,
 4125   /* skip result set */
 4126   mthd_my_skip_result,
 4127   /* read response packet */
 4128   mthd_my_read_query_result,
 4129   /* read all rows from a result set */
 4130   mthd_my_read_rows,
 4131   /* read one/next row */
 4132   mthd_my_read_one_row,
 4133   /* check if datatype is supported */
 4134   mthd_supported_buffer_type,
 4135   /* read response packet from prepare */
 4136   mthd_stmt_read_prepare_response,
 4137   /* read response from stmt execute */
 4138   mthd_my_read_query_result,
 4139   /* get result set metadata for a prepared statement */
 4140   mthd_stmt_get_result_metadata,
 4141   /* get param metadata for a prepared statement */
 4142   mthd_stmt_get_param_metadata,
 4143   /* read all rows (buffered) */
 4144   mthd_stmt_read_all_rows,
 4145   /* fetch one row (unbuffered) */
 4146   mthd_stmt_fetch_row,
 4147   /* store values in bind buffer */
 4148   mthd_stmt_fetch_to_bind,
 4149   /* skip unbuffered stmt result */
 4150   mthd_stmt_flush_unbuffered,
 4151   /* set error */
 4152   my_set_error,
 4153   /* invalidate statements */
 4154   ma_invalidate_stmts,
 4155   /* API functions */
 4156   &MARIADB_API
 4157 };