/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.

The MySQL Connector/C is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
*/

#include <stdarg.h>

#define MYSQL_CLIENT_GENERIC_INTERFACE_VERSION  0x0100
#define MYSQL_CLIENT_TRACE_INTERFACE_VERSION  0x0103

/* known plugin types */
#define MYSQL_CLIENT_GENERIC_PLUGIN          0
#define MYSQL_CLIENT_TRACE_PLUGIN            1

#define MYSQL_CLIENT_MAX_PLUGINS             2

#define MYSQL_CLIENT_PLUGIN_LOG_ERROR       1
#define MYSQL_CLIENT_PLUGIN_LOG_WARNING     2
#define MYSQL_CLIENT_PLUGIN_LOG_INFO        3
#define MYSQL_CLIENT_PLUGIN_LOG_DEBUG       4

#define PLUGIN_DECLARATION_SYMBOL "_mysql_client_plugin_declaration_"

#define mysql_declare_client_plugin(X)          \
     struct st_mysql_client_plugin_ ## X        \
        _mysql_client_plugin_declaration_ = {   \
          MYSQL_CLIENT_ ## X ## _PLUGIN,        \
          MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION,
#define mysql_end_client_plugin             }

/* generic plugin header structure */
#define MYSQL_CLIENT_PLUGIN_HEADER \
  int type;\
  int interface_version;\
  const char *name;\
  const char *author;\
  const char *desc;\
  unsigned int version[3];\
  char *license;\
  struct st_mysql_api *mysql_api;\
  int (*init)(char *, size_t, int, va_list);\
  int (*deinit)();\
  int (*options)(const char *, const void *);
struct st_mysql_client_plugin
{
  MYSQL_CLIENT_PLUGIN_HEADER
};


extern struct st_mysql_client_plugin_list *client_plugin_list;

struct st_mysql; /* will be declared later in mysql.h */
struct st_mysql_stmt;
struct st_mysql_res;

/******** trace plugin specific declarations *********/
enum enum_cta_action
{
  MYSQL_TRACE_CMD_CONNECT, MYSQL_TRACE_CMD_QUERY, 
  MYSQL_TRACE_CMD_PREPARE, MYSQL_TRACE_CMD_EXECUTE, 
  MYSQL_TRACE_CMD_STORE_RESULT, MYSQL_TRACE_CMD_STMT_CLOSE, 
  MYSQL_TRACE_CMD_FREE_RESULT, MYSQL_TRACE_CMD_CLOSE
};

struct st_mysql_client_plugin_TRACE
{
  MYSQL_CLIENT_PLUGIN_HEADER
  /* trace plugin specific */
  int (*send)                                    /* plugin function which obtains trace data */
      (enum enum_cta_action,
       struct st_mysql *,
       struct st_mysql_stmt *,
       struct st_mysql_res *,
       const char *,
       ulong);
  void *userdata;                                 /* for plugin specific extra data */
};

struct st_plugin_trace_connection_data {
  my_ulonglong query_id;          /* unique query id per connection */
  my_ulonglong elapsed_time;      /* execution time of last statement */
  my_ulonglong bytes_sent;        /* bytes sent to server */
  my_ulonglong bytes_received;    /* bytes received from server */
  int (*validate) 
      (void *,
       ulong);
  void *cta;                      /* plugin specific private data */
};

#define MYSQL_TRACE_START(a)\
if((a) && (a)->trace_data)\
  (a)->trace_data->elapsed_time= my_micro_time();

/* macro for sending trace information to plugin:
   MYSQL_TRACE_SEND(command, MYSQL *, MYSQL_STMT *, MYSQL_RES *, query, query_len)
*/
#define MYSQL_TRACE_SEND(a,b,c,d,e,f)\
if((b) && (b)->trace_data)\
{\
  struct st_mysql_client_plugin *p= NULL;\
  while ((p= mysql_get_next_client_plugin(p, MYSQL_CLIENT_TRACE_PLUGIN)))\
  {\
    if(p->type == MYSQL_CLIENT_TRACE_PLUGIN)\
    {\
      if ((b)->trace_data)\
        (b)->trace_data->elapsed_time= my_micro_time() - (b)->trace_data->elapsed_time;\
      ((struct st_mysql_client_plugin_TRACE *)(p))->send((a),(b),(c),(d),(e),(f));\
    }\
  }\
}

#define MYSQL_TRACE_NEW_CONNECTION(a)\
if(a)\
{\
  struct st_mysql_client_plugin *p= NULL;\
  while ((p= mysql_get_next_client_plugin(p, MYSQL_CLIENT_TRACE_PLUGIN)))\
  {\
    if(p->type == MYSQL_CLIENT_TRACE_PLUGIN)\
    {\
      ((struct st_mysql_client_plugin_TRACE *)(p))->send(MYSQL_TRACE_CMD_CONNECT, (a), NULL, NULL, NULL, 0);\
    }\
  }\
}

#define MYSQL_TRACE_READ(a,b)\
if ((a) && (a)->trace_data)\
  (a)->trace_data->bytes_received+= (b);
#define MYSQL_TRACE_WRITE(a,b)\
if ((a) && (a)->trace_data)\
  (a)->trace_data->bytes_sent+= (b);
/*******************************************************/


int mysql_client_plugin_init();
void mysql_client_plugin_deinit();
struct st_mysql_client_plugin
*mysql_get_next_client_plugin(struct st_mysql_client_plugin *last_plugin, uint type);

struct st_mysql_client_plugin *
STDCALL mysql_load_client_plugin(MYSQL *mysql, const char *dlname, int argc, ...);
struct st_mysql_client_plugin *
STDCALL mysql_load_client_plugin_v(MYSQL *mysql, const char *dlname, int argc, va_list args);
struct st_mysql_client_plugin * STDCALL
mysql_register_client_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin);
int STDCALL mysql_plugin_options(struct st_mysql_client_plugin *plugin,
                                 const char *option, const void *value);
