]> git.sven.stormbind.net Git - sven/mysqltcl.git/blobdiff - generic/mysqltcl.c
Imported Upstream version 3.05
[sven/mysqltcl.git] / generic / mysqltcl.c
diff --git a/generic/mysqltcl.c b/generic/mysqltcl.c
new file mode 100755 (executable)
index 0000000..cd79a07
--- /dev/null
@@ -0,0 +1,2757 @@
+/*\r
+ * $Eid: mysqltcl.c,v 1.2 2002/02/15 18:52:08 artur Exp $\r
+ *\r
+ * MYSQL interface to Tcl\r
+ *\r
+ * Hakan Soderstrom, hs@soderstrom.se\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 1994, 1995 Hakan Soderstrom and Tom Poindexter\r
+ * \r
+ * Permission to use, copy, modify, distribute, and sell this software\r
+ * and its documentation for any purpose is hereby granted without fee,\r
+ * provided that the above copyright notice and this permission notice\r
+ * appear in all copies of the software and related documentation.\r
+ * \r
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY\r
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * IN NO EVENT SHALL HAKAN SODERSTROM OR SODERSTROM PROGRAMVARUVERKSTAD\r
+ * AB BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL\r
+ * DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS\r
+ * OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY\r
+ * OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN\r
+ * CONNECTON WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+ */\r
+\r
+/*\r
+ Modified after version 2.0 by Artur Trzewik\r
+ see http://www.xdobry.de/mysqltcl\r
+ Patch for encoding option by Alexander Schoepe (version2.20)\r
+*/\r
+\r
+#ifdef _WINDOWS\r
+   #include <windows.h>\r
+   #define PACKAGE "mysqltcl"\r
+   #define PACKAGE_VERSION "3.04"\r
+#endif\r
+\r
+#include <tcl.h>\r
+#include <mysql.h>\r
+\r
+#include <errno.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <stdlib.h>\r
+\r
+#define MYSQL_SMALL_SIZE  TCL_RESULT_SIZE /* Smaller buffer size. */\r
+#define MYSQL_NAME_LEN     80    /* Max. database name length. */\r
+/* #define PREPARED_STATEMENT */\r
+\r
+enum MysqlHandleType {HT_CONNECTION=1,HT_QUERY=2,HT_STATEMENT=3};\r
+\r
+typedef struct MysqlTclHandle {\r
+  MYSQL * connection;         /* Connection handle, if connected; NULL otherwise. */\r
+  char database[MYSQL_NAME_LEN];  /* Db name, if selected; NULL otherwise. */\r
+  MYSQL_RES* result;              /* Stored result, if any; NULL otherwise. */\r
+  int res_count;                 /* Count of unfetched rows in result. */\r
+  int col_count;                 /* Column count in result, if any. */\r
+  int number;                    /* handle id */\r
+  enum MysqlHandleType type;                      /* handle type */\r
+  Tcl_Encoding encoding;         /* encoding for connection */\r
+#ifdef PREPARED_STATEMENT\r
+  MYSQL_STMT *statement;         /* used only by prepared statements*/\r
+  MYSQL_BIND *bindParam;\r
+  MYSQL_BIND *bindResult;\r
+  MYSQL_RES *resultMetadata;\r
+  MYSQL_RES *paramMetadata;\r
+#endif\r
+} MysqlTclHandle;\r
+\r
+typedef struct MysqltclState { \r
+  Tcl_HashTable hash;\r
+  int handleNum;\r
+  char *MysqlNullvalue;\r
+  // Tcl_Obj *nullObjPtr;\r
+} MysqltclState;\r
+\r
+static char *MysqlHandlePrefix = "mysql";\r
+/* Prefix string used to identify handles.\r
+ * The following must be strlen(MysqlHandlePrefix).\r
+ */\r
+#define MYSQL_HPREFIX_LEN 5\r
+\r
+/* Array for status info, and its elements. */\r
+#define MYSQL_STATUS_ARR "mysqlstatus"\r
+\r
+#define MYSQL_STATUS_CODE "code"\r
+#define MYSQL_STATUS_CMD  "command"\r
+#define MYSQL_STATUS_MSG  "message"\r
+#define MYSQL_STATUS_NULLV  "nullvalue"\r
+\r
+#define FUNCTION_NOT_AVAILABLE "function not available"\r
+\r
+/* C variable corresponding to mysqlstatus(nullvalue) */\r
+#define MYSQL_NULLV_INIT ""\r
+\r
+/* Check Level for mysql_prologue */\r
+enum CONNLEVEL {CL_PLAIN,CL_CONN,CL_DB,CL_RES};\r
+\r
+/* Prototypes for all functions. */\r
+\r
+static int Mysqltcl_Use(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Escape(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Sel(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Fetch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Seek(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Map(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Exec(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Close(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Info(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Result(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Col(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_State(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_InsertId(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Query(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int Mysqltcl_Receive(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);\r
+static int MysqlHandleSet _ANSI_ARGS_((Tcl_Interp *interp,Tcl_Obj *objPtr));\r
+static void MysqlHandleFree _ANSI_ARGS_((Tcl_Obj *objPtr));\r
+static int MysqlNullSet _ANSI_ARGS_((Tcl_Interp *interp,Tcl_Obj *objPtr));\r
+static Tcl_Obj *Mysqltcl_NewNullObj(MysqltclState *mysqltclState);\r
+static void UpdateStringOfNull _ANSI_ARGS_((Tcl_Obj *objPtr));\r
+\r
+/* handle object type \r
+ * This section defince funtions for Handling new Tcl_Obj type */\r
+  \r
+Tcl_ObjType mysqlHandleType = {\r
+    "mysqlhandle", \r
+    MysqlHandleFree,\r
+    (Tcl_DupInternalRepProc *) NULL,\r
+    NULL,\r
+    MysqlHandleSet\r
+};\r
+Tcl_ObjType mysqlNullType = {\r
+    "mysqlnull",\r
+    (Tcl_FreeInternalRepProc *) NULL,\r
+    (Tcl_DupInternalRepProc *) NULL,\r
+    UpdateStringOfNull,\r
+    MysqlNullSet\r
+};\r
+\r
+\r
+static MysqltclState *getMysqltclState(Tcl_Interp *interp) {\r
+  Tcl_CmdInfo cmdInfo;\r
+  if (Tcl_GetCommandInfo(interp,"mysqlconnect",&cmdInfo)==0) {\r
+    return NULL;\r
+  }\r
+  return (MysqltclState *)cmdInfo.objClientData;\r
+}\r
+\r
+static int MysqlHandleSet(Tcl_Interp *interp, register Tcl_Obj *objPtr)\r
+{\r
+    Tcl_ObjType *oldTypePtr = objPtr->typePtr;\r
+    char *string;\r
+    MysqlTclHandle *handle;\r
+    Tcl_HashEntry *entryPtr;\r
+    MysqltclState *statePtr;\r
+\r
+    string = Tcl_GetStringFromObj(objPtr, NULL);  \r
+    statePtr = getMysqltclState(interp);\r
+    if (statePtr==NULL) return TCL_ERROR;\r
+\r
+    entryPtr = Tcl_FindHashEntry(&statePtr->hash,string);\r
+    if (entryPtr == NULL) {\r
+\r
+      handle=0;\r
+    } else {\r
+      handle=(MysqlTclHandle *)Tcl_GetHashValue(entryPtr);\r
+    }\r
+    if (!handle) {\r
+        if (interp != NULL)\r
+         return TCL_ERROR;\r
+    }\r
+    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {\r
+        oldTypePtr->freeIntRepProc(objPtr);\r
+    }\r
+    \r
+    objPtr->internalRep.otherValuePtr = (MysqlTclHandle *) handle;\r
+    objPtr->typePtr = &mysqlHandleType;\r
+    Tcl_Preserve((char *)handle);\r
+    return TCL_OK;\r
+}\r
+static int MysqlNullSet(Tcl_Interp *interp, Tcl_Obj *objPtr)\r
+{\r
+    Tcl_ObjType *oldTypePtr = objPtr->typePtr;\r
+\r
+    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {\r
+        oldTypePtr->freeIntRepProc(objPtr);\r
+    }\r
+    objPtr->typePtr = &mysqlNullType;\r
+    return TCL_OK;\r
+}\r
+static void UpdateStringOfNull(Tcl_Obj *objPtr) {\r
+       int valueLen;\r
+       MysqltclState *state = (MysqltclState *)objPtr->internalRep.otherValuePtr;\r
+\r
+       valueLen = strlen(state->MysqlNullvalue);\r
+       objPtr->bytes = Tcl_Alloc(valueLen+1);\r
+       strcpy(objPtr->bytes,state->MysqlNullvalue);\r
+       objPtr->length = valueLen;\r
+}\r
+static void MysqlHandleFree(Tcl_Obj *obj)\r
+{\r
+  MysqlTclHandle *handle = (MysqlTclHandle *)obj->internalRep.otherValuePtr;\r
+  Tcl_Release((char *)handle);\r
+}\r
+\r
+static int GetHandleFromObj(Tcl_Interp *interp,Tcl_Obj *objPtr,MysqlTclHandle **handlePtr)\r
+{\r
+    if (Tcl_ConvertToType(interp, objPtr, &mysqlHandleType) != TCL_OK)\r
+        return TCL_ERROR;\r
+    *handlePtr = (MysqlTclHandle *)objPtr->internalRep.otherValuePtr;\r
+    return TCL_OK;\r
+}\r
+\r
+static Tcl_Obj *Tcl_NewHandleObj(MysqltclState *statePtr,MysqlTclHandle *handle)\r
+{\r
+    register Tcl_Obj *objPtr;\r
+    char buffer[MYSQL_HPREFIX_LEN+TCL_DOUBLE_SPACE+1];\r
+    register int len;\r
+    Tcl_HashEntry *entryPtr;\r
+    int newflag;\r
+\r
+    objPtr=Tcl_NewObj();\r
+    /* the string for "query" can not be longer as MysqlHandlePrefix see buf variable */\r
+    len=sprintf(buffer, "%s%d", (handle->type==HT_QUERY) ? "query" : MysqlHandlePrefix,handle->number);    \r
+    objPtr->bytes = Tcl_Alloc((unsigned) len + 1);\r
+    strcpy(objPtr->bytes, buffer);\r
+    objPtr->length = len;\r
+    \r
+    entryPtr=Tcl_CreateHashEntry(&statePtr->hash,buffer,&newflag);\r
+    Tcl_SetHashValue(entryPtr,handle);     \r
+  \r
+    objPtr->internalRep.otherValuePtr = handle;\r
+    objPtr->typePtr = &mysqlHandleType;\r
+\r
+    Tcl_Preserve((char *)handle);  \r
+\r
+    return objPtr;\r
+}\r
+\r
+\r
+\r
+\r
+/* CONFLICT HANDLING\r
+ *\r
+ * Every command begins by calling 'mysql_prologue'.\r
+ * This function resets mysqlstatus(code) to zero; the other array elements\r
+ * retain their previous values.\r
+ * The function also saves objc/objv in global variables.\r
+ * After this the command processing proper begins.\r
+ *\r
+ * If there is a conflict, the message is taken from one of the following\r
+ * sources,\r
+ * -- this code (mysql_prim_confl),\r
+ * -- the database server (mysql_server_confl),\r
+ * A complete message is put together from the above plus the name of the\r
+ * command where the conflict was detected.\r
+ * The complete message is returned as the Tcl result and is also stored in\r
+ * mysqlstatus(message).\r
+ * mysqlstatus(code) is set to "-1" for a primitive conflict or to mysql_errno\r
+ * for a server conflict\r
+ * In addition, the whole command where the conflict was detected is put\r
+ * together from the saved objc/objv and is copied into mysqlstatus(command).\r
+ */\r
+\r
+/*\r
+ *-----------------------------------------------------------\r
+ * set_statusArr\r
+ * Help procedure to set Tcl global array with mysqltcl internal\r
+ * informations\r
+ */\r
+\r
+static void set_statusArr(Tcl_Interp *interp,char *elem_name,Tcl_Obj *tobj)\r
+{\r
+  Tcl_SetVar2Ex (interp,MYSQL_STATUS_ARR,elem_name,tobj,TCL_GLOBAL_ONLY); \r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ * clear_msg\r
+ *\r
+ * Clears all error and message elements in the global array variable.\r
+ *\r
+ */\r
+\r
+static void\r
+clear_msg(Tcl_Interp *interp)\r
+{\r
+  set_statusArr(interp,MYSQL_STATUS_CODE,Tcl_NewIntObj(0));\r
+  set_statusArr(interp,MYSQL_STATUS_CMD,Tcl_NewObj());\r
+  set_statusArr(interp,MYSQL_STATUS_MSG,Tcl_NewObj());\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ * mysql_reassemble\r
+ * Reassembles the current command from the saved objv; copies it into\r
+ * mysqlstatus(command).\r
+ */\r
+\r
+static void mysql_reassemble(Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[])\r
+{\r
+   set_statusArr(interp,MYSQL_STATUS_CMD,Tcl_NewListObj(objc, objv));\r
+}\r
+\r
+/*\r
+ * free result from handle and consume left result of multresult statement \r
+ */\r
+static void freeResult(MysqlTclHandle *handle)\r
+{\r
+       MYSQL_RES* result;\r
+       if (handle->result != NULL) {\r
+               mysql_free_result(handle->result);\r
+               handle->result = NULL ;\r
+       }\r
+#if (MYSQL_VERSION_ID >= 50000)\r
+       while (!mysql_next_result(handle->connection)) {\r
+               result = mysql_store_result(handle->connection);\r
+               if (result) {\r
+                       mysql_free_result(result);\r
+               }\r
+       }\r
+#endif\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ * mysql_prim_confl\r
+ * Conflict handling after a primitive conflict.\r
+ *\r
+ */\r
+\r
+static int mysql_prim_confl(Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[],char *msg)\r
+{\r
+  set_statusArr(interp,MYSQL_STATUS_CODE,Tcl_NewIntObj(-1));\r
+\r
+  Tcl_ResetResult(interp) ;\r
+  Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),\r
+                          Tcl_GetString(objv[0]), ": ", msg, (char*)NULL);\r
+\r
+  set_statusArr(interp,MYSQL_STATUS_MSG,Tcl_GetObjResult(interp));\r
+\r
+  mysql_reassemble(interp,objc,objv) ;\r
+  return TCL_ERROR ;\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ * mysql_server_confl\r
+ * Conflict handling after an mySQL conflict.\r
+ * If error it set error message and return TCL_ERROR\r
+ * If no error occurs it returns TCL_OK\r
+ */\r
+\r
+static int mysql_server_confl(Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[],MYSQL * connection)\r
+{\r
+  const char* mysql_errorMsg;\r
+  if (mysql_errno(connection)) {\r
+    mysql_errorMsg = mysql_error(connection);\r
+\r
+    set_statusArr(interp,MYSQL_STATUS_CODE,Tcl_NewIntObj(mysql_errno(connection)));\r
+\r
+\r
+    Tcl_ResetResult(interp) ;\r
+    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),\r
+                          Tcl_GetString(objv[0]), "/db server: ",\r
+                         (mysql_errorMsg == NULL) ? "" : mysql_errorMsg,\r
+                          (char*)NULL) ;\r
+\r
+    set_statusArr(interp,MYSQL_STATUS_MSG,Tcl_GetObjResult(interp));\r
+\r
+    mysql_reassemble(interp,objc,objv);\r
+    return TCL_ERROR;\r
+  } else {\r
+    return TCL_OK;\r
+  }\r
+}\r
+\r
+static  MysqlTclHandle *get_handle(Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[],int check_level) \r
+{\r
+  MysqlTclHandle *handle;\r
+  if (GetHandleFromObj(interp, objv[1], &handle) != TCL_OK) {\r
+    mysql_prim_confl(interp,objc,objv,"not mysqltcl handle") ;\r
+    return NULL;\r
+  }\r
+  if (check_level==CL_PLAIN) return handle;\r
+  if (handle->connection == 0) {\r
+      mysql_prim_confl(interp,objc,objv,"handle already closed (dangling pointer)") ;\r
+      return NULL;\r
+  }\r
+  if (check_level==CL_CONN) return handle;\r
+  if (check_level!=CL_RES) {\r
+    if (handle->database[0] == '\0') {\r
+      mysql_prim_confl(interp,objc,objv,"no current database") ;\r
+      return NULL;\r
+    }\r
+    if (check_level==CL_DB) return handle;\r
+  }\r
+  if (handle->result == NULL) {\r
+      mysql_prim_confl(interp,objc,objv,"no result pending") ;\r
+      return NULL;\r
+  }\r
+  return handle;\r
+}\r
+\r
+/*----------------------------------------------------------------------\r
+\r
+ * mysql_QueryTclObj\r
+ * This to method control how tcl data is transfered to mysql and\r
+ * how data is imported into tcl from mysql\r
+ * Return value : Zero on success, Non-zero if an error occurred.\r
+ */\r
+static int mysql_QueryTclObj(MysqlTclHandle *handle,Tcl_Obj *obj)\r
+{\r
+  char *query;\r
+  int result,queryLen;\r
+\r
+  Tcl_DString queryDS;\r
+\r
+  query=Tcl_GetStringFromObj(obj, &queryLen);\r
+\r
+\r
+  if (handle->encoding==NULL) {\r
+    query = (char *) Tcl_GetByteArrayFromObj(obj, &queryLen);\r
+    result =  mysql_real_query(handle->connection,query,queryLen);\r
+  } else {\r
+    Tcl_UtfToExternalDString(handle->encoding, query, -1, &queryDS);\r
+    queryLen = Tcl_DStringLength(&queryDS); \r
+    result =  mysql_real_query(handle->connection,Tcl_DStringValue(&queryDS),queryLen);\r
+    Tcl_DStringFree(&queryDS);\r
+  }\r
+  return result;\r
+} \r
+static Tcl_Obj *getRowCellAsObject(MysqltclState *mysqltclState,MysqlTclHandle *handle,MYSQL_ROW row,int length) \r
+{\r
+  Tcl_Obj *obj;\r
+  Tcl_DString ds;\r
+\r
+  if (*row) {\r
+    if (handle->encoding!=NULL) {\r
+      Tcl_ExternalToUtfDString(handle->encoding, *row, length, &ds);\r
+      obj = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds));\r
+      Tcl_DStringFree(&ds);\r
+    } else {\r
+      obj = Tcl_NewByteArrayObj((unsigned char *)*row,length);\r
+    }\r
+  } else {\r
+    obj = Mysqltcl_NewNullObj(mysqltclState);\r
+  } \r
+  return obj;\r
+}\r
+\r
+static MysqlTclHandle *createMysqlHandle(MysqltclState *statePtr) \r
+{\r
+  MysqlTclHandle *handle;\r
+  handle=(MysqlTclHandle *)Tcl_Alloc(sizeof(MysqlTclHandle));\r
+  memset(handle,0,sizeof(MysqlTclHandle));\r
+  if (handle == 0) {\r
+    panic("no memory for handle");\r
+    return handle;\r
+  }\r
+  handle->type = HT_CONNECTION;\r
+\r
+  /* MT-safe, because every thread in tcl has own interpreter */\r
+  handle->number=statePtr->handleNum++;\r
+  return handle;\r
+}\r
+\r
+static MysqlTclHandle *createHandleFrom(MysqltclState *statePtr,MysqlTclHandle *handle,enum MysqlHandleType handleType)\r
+{\r
+  int number;\r
+  MysqlTclHandle *qhandle;\r
+  qhandle = createMysqlHandle(statePtr);\r
+  /* do not overwrite the number */\r
+  number = qhandle->number;\r
+  if (!qhandle) return qhandle;\r
+  memcpy(qhandle,handle,sizeof(MysqlTclHandle));\r
+  qhandle->type=handleType;\r
+  qhandle->number=number;\r
+  return qhandle;\r
+}\r
+static void closeHandle(MysqlTclHandle *handle)\r
+{\r
+  freeResult(handle);\r
+  if (handle->type==HT_CONNECTION) {\r
+    mysql_close(handle->connection);\r
+  }\r
+#ifdef PREPARED_STATEMENT\r
+  if (handle->type==HT_STATEMENT) {\r
+    if (handle->statement!=NULL)\r
+           mysql_stmt_close(handle->statement);\r
+       if (handle->bindResult!=NULL)\r
+               Tcl_Free((char *)handle->bindResult);\r
+    if (handle->bindParam!=NULL)\r
+       Tcl_Free((char *)handle->bindParam);\r
+    if (handle->resultMetadata!=NULL)\r
+           mysql_free_result(handle->resultMetadata);\r
+    if (handle->paramMetadata!=NULL)\r
+           mysql_free_result(handle->paramMetadata);\r
+  }\r
+#endif\r
+  handle->connection = (MYSQL *)NULL;\r
+  if (handle->encoding!=NULL && handle->type==HT_CONNECTION)\r
+  {\r
+    Tcl_FreeEncoding(handle->encoding);\r
+    handle->encoding = NULL;\r
+  }\r
+  Tcl_EventuallyFree((char *)handle,TCL_DYNAMIC);\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ * mysql_prologue\r
+ *\r
+ * Does most of standard command prologue; required for all commands\r
+ * having conflict handling.\r
+ * 'req_min_args' must be the minimum number of arguments for the command,\r
+ * including the command word.\r
+ * 'req_max_args' must be the maximum number of arguments for the command,\r
+ * including the command word.\r
+ * 'usage_msg' must be a usage message, leaving out the command name.\r
+ * Checks the handle assumed to be present in objv[1] if 'check' is not NULL.\r
+ * RETURNS: Handle index or -1 on failure.\r
+ * SIDE EFFECT: Sets the Tcl result on failure.\r
+ */\r
+\r
+static MysqlTclHandle *mysql_prologue(Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[],int req_min_args,int req_max_args,int check_level,char *usage_msg)\r
+{\r
+  /* Check number of args. */\r
+  if (objc < req_min_args || objc > req_max_args) {\r
+      Tcl_WrongNumArgs(interp, 1, objv, usage_msg);\r
+      return NULL;\r
+  }\r
+\r
+  /* Reset mysqlstatus(code). */\r
+  set_statusArr(interp,MYSQL_STATUS_CODE,Tcl_NewIntObj(0));\r
+\r
+  /* Check the handle.\r
+   * The function is assumed to set the status array on conflict.\r
+   */\r
+  return (get_handle(interp,objc,objv,check_level));\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ * mysql_colinfo\r
+ *\r
+ * Given an MYSQL_FIELD struct and a string keyword appends a piece of\r
+ * column info (one item) to the Tcl result.\r
+ * ASSUMES 'fld' is non-null.\r
+ * RETURNS 0 on success, 1 otherwise.\r
+ * SIDE EFFECT: Sets the result and status on failure.\r
+ */\r
+\r
+static Tcl_Obj *mysql_colinfo(Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[],MYSQL_FIELD* fld,Tcl_Obj * keyw)\r
+{\r
+  int idx ;\r
+\r
+  static CONST char* MysqlColkey[] =\r
+    {\r
+      "table", "name", "type", "length", "prim_key", "non_null", "numeric", "decimals", NULL\r
+    };\r
+  enum coloptions {\r
+    MYSQL_COL_TABLE_K, MYSQL_COL_NAME_K, MYSQL_COL_TYPE_K, MYSQL_COL_LENGTH_K, \r
+    MYSQL_COL_PRIMKEY_K, MYSQL_COL_NONNULL_K, MYSQL_COL_NUMERIC_K, MYSQL_COL_DECIMALS_K};\r
+\r
+  if (Tcl_GetIndexFromObj(interp, keyw, MysqlColkey, "option",\r
+                          TCL_EXACT, &idx) != TCL_OK)\r
+    return NULL;\r
+\r
+  switch (idx)\r
+    {\r
+    case MYSQL_COL_TABLE_K:\r
+      return Tcl_NewStringObj(fld->table, -1) ;\r
+    case MYSQL_COL_NAME_K:\r
+      return Tcl_NewStringObj(fld->name, -1) ;\r
+    case MYSQL_COL_TYPE_K:\r
+      switch (fld->type)\r
+       {\r
+\r
+\r
+       case FIELD_TYPE_DECIMAL:\r
+         return Tcl_NewStringObj("decimal", -1);\r
+       case FIELD_TYPE_TINY:\r
+         return Tcl_NewStringObj("tiny", -1);\r
+       case FIELD_TYPE_SHORT:\r
+         return Tcl_NewStringObj("short", -1);\r
+       case FIELD_TYPE_LONG:\r
+         return Tcl_NewStringObj("long", -1) ;\r
+       case FIELD_TYPE_FLOAT:\r
+         return Tcl_NewStringObj("float", -1);\r
+       case FIELD_TYPE_DOUBLE:\r
+         return Tcl_NewStringObj("double", -1);\r
+       case FIELD_TYPE_NULL:\r
+         return Tcl_NewStringObj("null", -1);\r
+       case FIELD_TYPE_TIMESTAMP:\r
+         return Tcl_NewStringObj("timestamp", -1);\r
+       case FIELD_TYPE_LONGLONG:\r
+         return Tcl_NewStringObj("long long", -1);\r
+       case FIELD_TYPE_INT24:\r
+         return Tcl_NewStringObj("int24", -1);\r
+       case FIELD_TYPE_DATE:\r
+         return Tcl_NewStringObj("date", -1);\r
+       case FIELD_TYPE_TIME:\r
+         return Tcl_NewStringObj("time", -1);\r
+       case FIELD_TYPE_DATETIME:\r
+         return Tcl_NewStringObj("date time", -1);\r
+       case FIELD_TYPE_YEAR:\r
+         return Tcl_NewStringObj("year", -1);\r
+       case FIELD_TYPE_NEWDATE:\r
+         return Tcl_NewStringObj("new date", -1);\r
+       case FIELD_TYPE_ENUM:\r
+         return Tcl_NewStringObj("enum", -1); \r
+       case FIELD_TYPE_SET:\r
+         return Tcl_NewStringObj("set", -1);\r
+       case FIELD_TYPE_TINY_BLOB:\r
+         return Tcl_NewStringObj("tiny blob", -1);\r
+       case FIELD_TYPE_MEDIUM_BLOB:\r
+         return Tcl_NewStringObj("medium blob", -1);\r
+       case FIELD_TYPE_LONG_BLOB:\r
+         return Tcl_NewStringObj("long blob", -1);\r
+       case FIELD_TYPE_BLOB:\r
+         return Tcl_NewStringObj("blob", -1);\r
+       case FIELD_TYPE_VAR_STRING:\r
+         return Tcl_NewStringObj("var string", -1);\r
+       case FIELD_TYPE_STRING:\r
+         return Tcl_NewStringObj("string", -1);\r
+#if MYSQL_VERSION_ID >= 50000\r
+       case MYSQL_TYPE_NEWDECIMAL:\r
+          return Tcl_NewStringObj("newdecimal", -1);\r
+       case MYSQL_TYPE_GEOMETRY:\r
+          return Tcl_NewStringObj("geometry", -1);\r
+       case MYSQL_TYPE_BIT:\r
+          return Tcl_NewStringObj("bit", -1);\r
+#endif\r
+       default:\r
+         return Tcl_NewStringObj("unknown", -1);\r
+       }\r
+      break ;\r
+    case MYSQL_COL_LENGTH_K:\r
+      return Tcl_NewIntObj(fld->length) ;\r
+    case MYSQL_COL_PRIMKEY_K:\r
+      return Tcl_NewBooleanObj(IS_PRI_KEY(fld->flags));\r
+    case MYSQL_COL_NONNULL_K:\r
+      return Tcl_NewBooleanObj(IS_NOT_NULL(fld->flags));\r
+    case MYSQL_COL_NUMERIC_K:\r
+      return Tcl_NewBooleanObj(IS_NUM(fld->type));\r
+    case MYSQL_COL_DECIMALS_K:\r
+      return IS_NUM(fld->type)? Tcl_NewIntObj(fld->decimals): Tcl_NewIntObj(-1);\r
+    default: /* should never happen */\r
+      mysql_prim_confl(interp,objc,objv,"weirdness in mysql_colinfo");\r
+      return NULL ;\r
+    }\r
+}\r
+\r
+/*\r
+ * Mysqltcl_CloseAll\r
+ * Close all connections.\r
+ */\r
+\r
+static void Mysqltcl_CloseAll(ClientData clientData)\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  Tcl_HashSearch search;\r
+  MysqlTclHandle *handle;\r
+  Tcl_HashEntry *entryPtr; \r
+  int wasdeleted=0;\r
+\r
+  for (entryPtr=Tcl_FirstHashEntry(&statePtr->hash,&search); \r
+       entryPtr!=NULL;\r
+       entryPtr=Tcl_NextHashEntry(&search)) {\r
+    wasdeleted=1;\r
+    handle=(MysqlTclHandle *)Tcl_GetHashValue(entryPtr);\r
+\r
+    if (handle->connection == 0) continue;\r
+    closeHandle(handle);\r
+  }\r
+  if (wasdeleted) {\r
+    Tcl_DeleteHashTable(&statePtr->hash);\r
+    Tcl_InitHashTable(&statePtr->hash, TCL_STRING_KEYS);\r
+  }\r
+}\r
+/*\r
+ * Invoked from Interpreter by removing mysqltcl command\r
+\r
+ * Warnign: This procedure can be called only once\r
+ */\r
+static void Mysqltcl_Kill(ClientData clientData) \r
+{ \r
+   MysqltclState *statePtr = (MysqltclState *)clientData; \r
+   Tcl_HashEntry *entryPtr; \r
+   MysqlTclHandle *handle;\r
+   Tcl_HashSearch search; \r
+\r
+   for (entryPtr=Tcl_FirstHashEntry(&statePtr->hash,&search); \r
+       entryPtr!=NULL;\r
+       entryPtr=Tcl_NextHashEntry(&search)) {\r
+     handle=(MysqlTclHandle *)Tcl_GetHashValue(entryPtr);\r
+     if (handle->connection == 0) continue;\r
+     closeHandle(handle);\r
+   } \r
+   Tcl_Free(statePtr->MysqlNullvalue);\r
+   Tcl_Free((char *)statePtr); \r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Connect\r
+ * Implements the mysqlconnect command:\r
+ * usage: mysqlconnect ?option value ...?\r
+ *                     \r
+ * Results:\r
+ *      handle - a character string of newly open handle\r
+ *      TCL_OK - connect successful\r
+ *      TCL_ERROR - connect not successful - error message returned\r
+ */\r
+\r
+static CONST char* MysqlConnectOpt[] =\r
+    {\r
+      "-host", "-user", "-password", "-db", "-port", "-socket","-encoding",\r
+      "-ssl", "-compress", "-noschema","-odbc",\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+      "-multistatement","-multiresult",\r
+#endif\r
+      "-localfiles","-ignorespace","-foundrows","-interactive","-sslkey","-sslcert",\r
+      "-sslca","-sslcapath","-sslciphers",NULL\r
+    };\r
+\r
+static int Mysqltcl_Connect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  int        i, idx;\r
+  char *hostname = NULL;\r
+  char *user = NULL;\r
+  char *password = NULL;\r
+  char *db = NULL;\r
+  int port = 0, flags = 0, booleanflag;\r
+  char *socket = NULL;\r
+  char *encodingname = NULL;\r
+\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+  int isSSL = 0;\r
+#endif\r
+  char *sslkey = NULL;\r
+  char *sslcert = NULL;\r
+  char *sslca = NULL;\r
+  char *sslcapath = NULL;\r
+  char *sslcipher = NULL;\r
+  \r
+  MysqlTclHandle *handle;\r
+  const char *groupname = "mysqltcl";\r
+\r
+  \r
+  enum connectoption {\r
+    MYSQL_CONNHOST_OPT, MYSQL_CONNUSER_OPT, MYSQL_CONNPASSWORD_OPT, \r
+    MYSQL_CONNDB_OPT, MYSQL_CONNPORT_OPT, MYSQL_CONNSOCKET_OPT, MYSQL_CONNENCODING_OPT,\r
+    MYSQL_CONNSSL_OPT, MYSQL_CONNCOMPRESS_OPT, MYSQL_CONNNOSCHEMA_OPT, MYSQL_CONNODBC_OPT,\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+    MYSQL_MULTISTATEMENT_OPT,MYSQL_MULTIRESULT_OPT,\r
+#endif\r
+    MYSQL_LOCALFILES_OPT,MYSQL_IGNORESPACE_OPT,\r
+    MYSQL_FOUNDROWS_OPT,MYSQL_INTERACTIVE_OPT,MYSQL_SSLKEY_OPT,MYSQL_SSLCERT_OPT,\r
+    MYSQL_SSLCA_OPT,MYSQL_SSLCAPATH_OPT,MYSQL_SSLCIPHERS_OPT\r
+  };\r
+\r
+  if (!(objc & 1) || \r
+    objc>(sizeof(MysqlConnectOpt)/sizeof(MysqlConnectOpt[0]-1)*2+1)) {\r
+    Tcl_WrongNumArgs(interp, 1, objv, "[-user xxx] [-db mysql] [-port 3306] [-host localhost] [-socket sock] [-password pass] [-encoding encoding] [-ssl boolean] [-compress boolean] [-odbc boolean] [-noschema boolean]"\r
+    );\r
+       return TCL_ERROR;\r
+  }\r
+              \r
+  for (i = 1; i < objc; i++) {\r
+    if (Tcl_GetIndexFromObj(interp, objv[i], MysqlConnectOpt, "option",\r
+                          0, &idx) != TCL_OK)\r
+      return TCL_ERROR;\r
+    \r
+    switch (idx) {\r
+    case MYSQL_CONNHOST_OPT:\r
+      hostname = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_CONNUSER_OPT:\r
+      user = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_CONNPASSWORD_OPT:\r
+      password = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_CONNDB_OPT:\r
+      db = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_CONNPORT_OPT:\r
+      if (Tcl_GetIntFromObj(interp, objv[++i], &port) != TCL_OK)\r
+       return TCL_ERROR;\r
+      break;\r
+    case MYSQL_CONNSOCKET_OPT:\r
+      socket = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_CONNENCODING_OPT:\r
+      encodingname = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_CONNSSL_OPT:\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&isSSL) != TCL_OK )\r
+       return TCL_ERROR;\r
+#else\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+        flags |= CLIENT_SSL;\r
+#endif\r
+      break;\r
+    case MYSQL_CONNCOMPRESS_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_COMPRESS;\r
+      break;\r
+    case MYSQL_CONNNOSCHEMA_OPT: \r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_NO_SCHEMA;\r
+      break;\r
+    case MYSQL_CONNODBC_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_ODBC;\r
+      break;\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+    case MYSQL_MULTISTATEMENT_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_MULTI_STATEMENTS;\r
+      break;\r
+    case MYSQL_MULTIRESULT_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_MULTI_RESULTS;\r
+      break;\r
+#endif\r
+    case MYSQL_LOCALFILES_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_LOCAL_FILES;\r
+      break;\r
+    case MYSQL_IGNORESPACE_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_IGNORE_SPACE;\r
+      break;\r
+    case MYSQL_FOUNDROWS_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_FOUND_ROWS;\r
+      break;\r
+    case MYSQL_INTERACTIVE_OPT:\r
+      if (Tcl_GetBooleanFromObj(interp,objv[++i],&booleanflag) != TCL_OK )\r
+       return TCL_ERROR;\r
+      if (booleanflag)\r
+       flags |= CLIENT_INTERACTIVE;\r
+      break;\r
+    case MYSQL_SSLKEY_OPT:\r
+      sslkey = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_SSLCERT_OPT:\r
+      sslcert = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_SSLCA_OPT:\r
+      sslca = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_SSLCAPATH_OPT:\r
+      sslcapath = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    case MYSQL_SSLCIPHERS_OPT:\r
+      sslcipher = Tcl_GetStringFromObj(objv[++i],NULL);\r
+      break;\r
+    default:\r
+      return mysql_prim_confl(interp,objc,objv,"Weirdness in options");            \r
+    }\r
+  }\r
+\r
+  handle = createMysqlHandle(statePtr);\r
+\r
+  if (handle == 0) {\r
+    panic("no memory for handle");\r
+    return TCL_ERROR;\r
+\r
+  }\r
+\r
+  handle->connection = mysql_init(NULL);\r
+\r
+  /* the function below caused in version pre 3.23.50 segmentation fault */\r
+#if (MYSQL_VERSION_ID>=32350)\r
+  mysql_options(handle->connection,MYSQL_READ_DEFAULT_GROUP,groupname);\r
+#endif\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+  if (isSSL) {\r
+      mysql_ssl_set(handle->connection,sslkey,sslcert, sslca, sslcapath, sslcipher);\r
+  }\r
+#endif\r
+\r
+  if (!mysql_real_connect(handle->connection, hostname, user,\r
+                                password, db, port, socket, flags)) {\r
+      mysql_server_confl(interp,objc,objv,handle->connection);\r
+      closeHandle(handle);\r
+      return TCL_ERROR;\r
+  }\r
+\r
+  if (db) {\r
+    strncpy(handle->database, db, MYSQL_NAME_LEN) ;\r
+    handle->database[MYSQL_NAME_LEN - 1] = '\0' ;\r
+  }\r
+\r
+  if (encodingname==NULL || (encodingname!=NULL &&  strcmp(encodingname, "binary") != 0)) {\r
+    if (encodingname==NULL)\r
+      encodingname = (char *)Tcl_GetEncodingName(NULL);\r
+    handle->encoding = Tcl_GetEncoding(interp, encodingname);\r
+    if (handle->encoding == NULL)\r
+      return TCL_ERROR;\r
+  }\r
+\r
+  Tcl_SetObjResult(interp, Tcl_NewHandleObj(statePtr,handle));\r
+\r
+  return TCL_OK;\r
+\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Use\r
+ *    Implements the mysqluse command:\r
+\r
+ *    usage: mysqluse handle dbname\r
+ *                     \r
+ *    results:\r
+ *     Sets current database to dbname.\r
+ */\r
+\r
+static int Mysqltcl_Use(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  int len;\r
+  char *db;\r
+  MysqlTclHandle *handle;  \r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "handle dbname")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  db=Tcl_GetStringFromObj(objv[2], &len);\r
+  if (len >= MYSQL_NAME_LEN) {\r
+     mysql_prim_confl(interp,objc,objv,"database name too long");\r
+     return TCL_ERROR;\r
+  }\r
+\r
+  if (mysql_select_db(handle->connection, db)!=0) {\r
+    return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  strcpy(handle->database, db);\r
+  return TCL_OK;\r
+}\r
+\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Escape\r
+ *    Implements the mysqlescape command:\r
+ *    usage: mysqlescape string\r
+ *                     \r
+ *    results:\r
+ *     Escaped string for use in queries.\r
+ */\r
+\r
+static int Mysqltcl_Escape(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  int len;\r
+  char *inString, *outString;\r
+  MysqlTclHandle *handle;\r
+  \r
+  if (objc <2 || objc>3) {\r
+      Tcl_WrongNumArgs(interp, 1, objv, "?handle? string");\r
+      return TCL_ERROR;\r
+  }\r
+  if (objc==2) {\r
+    inString=Tcl_GetStringFromObj(objv[1], &len);\r
+    outString=Tcl_Alloc((len<<1) + 1);\r
+    len=mysql_escape_string(outString, inString, len);\r
+    Tcl_SetStringObj(Tcl_GetObjResult(interp), outString, len);\r
+    Tcl_Free(outString);\r
+  } else { \r
+    if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "handle string")) == 0)\r
+      return TCL_ERROR;\r
+    inString=Tcl_GetStringFromObj(objv[2], &len);\r
+    outString=Tcl_Alloc((len<<1) + 1);\r
+    len=mysql_real_escape_string(handle->connection, outString, inString, len);\r
+    Tcl_SetStringObj(Tcl_GetObjResult(interp), outString, len);\r
+    Tcl_Free(outString);\r
+  }\r
+  return TCL_OK;\r
+}\r
+\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Sel\r
+ *    Implements the mysqlsel command:\r
+ *    usage: mysqlsel handle sel-query ?-list|-flatlist?\r
+ *                     \r
+ *    results:\r
+ *\r
+ *    SIDE EFFECT: Flushes any pending result, even in case of conflict.\r
+ *    Stores new results.\r
+ */\r
+\r
+static int Mysqltcl_Sel(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  Tcl_Obj *res, *resList;\r
+  MYSQL_ROW row;\r
+  MysqlTclHandle *handle;\r
+  unsigned long *lengths;\r
+\r
+\r
+  static CONST char* selOptions[] = {"-list", "-flatlist", NULL};\r
+  /* Warning !! no option number */\r
+  int i,selOption=2,colCount;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 4, CL_CONN,\r
+                           "handle sel-query ?-list|-flatlist?")) == 0)\r
+    return TCL_ERROR;\r
+\r
+\r
+  if (objc==4) {\r
+    if (Tcl_GetIndexFromObj(interp, objv[3], selOptions, "option",\r
+                           TCL_EXACT, &selOption) != TCL_OK)\r
+      return TCL_ERROR;\r
+  }\r
+\r
+  /* Flush any previous result. */\r
+  freeResult(handle);\r
+\r
+  if (mysql_QueryTclObj(handle,objv[2])) {\r
+    return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  if (selOption<2) {\r
+    /* If imadiatly result than do not store result in mysql client library cache */\r
+    handle->result = mysql_use_result(handle->connection);\r
+  } else {\r
+    handle->result = mysql_store_result(handle->connection);\r
+  }\r
+  \r
+  if (handle->result == NULL) {\r
+    if (selOption==2) Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));\r
+  } else {\r
+    colCount = handle->col_count = mysql_num_fields(handle->result);\r
+    res = Tcl_GetObjResult(interp);\r
+    handle->res_count = 0;\r
+    switch (selOption) {\r
+    case 0: /* -list */\r
+      while ((row = mysql_fetch_row(handle->result)) != NULL) {\r
+       resList = Tcl_NewListObj(0, NULL);\r
+       lengths = mysql_fetch_lengths(handle->result);\r
+       for (i=0; i< colCount; i++, row++) {\r
+         Tcl_ListObjAppendElement(interp, resList,getRowCellAsObject(statePtr,handle,row,lengths[i]));\r
+       }\r
+       Tcl_ListObjAppendElement(interp, res, resList);\r
+      }  \r
+      break;\r
+    case 1: /* -flatlist */\r
+      while ((row = mysql_fetch_row(handle->result)) != NULL) {\r
+       lengths = mysql_fetch_lengths(handle->result);\r
+       for (i=0; i< colCount; i++, row++) {\r
+         Tcl_ListObjAppendElement(interp, res,getRowCellAsObject(statePtr,handle,row,lengths[i]));\r
+       }\r
+      }  \r
+      break;\r
+    case 2: /* No option */\r
+      handle->res_count = mysql_num_rows(handle->result);\r
+      Tcl_SetIntObj(res, handle->res_count);\r
+      break;\r
+    }\r
+  }\r
+  return TCL_OK;\r
+}\r
+/*\r
+ * Mysqltcl_Query\r
+ * Works as mysqltclsel but return an $query handle that allow to build\r
+ * nested queries on simple handle\r
+ */\r
+\r
+static int Mysqltcl_Query(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  MYSQL_RES *result;\r
+  MysqlTclHandle *handle, *qhandle;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+\r
+                           "handle sqlstatement")) == 0)\r
+    return TCL_ERROR;\r
+       \r
+  if (mysql_QueryTclObj(handle,objv[2])) {\r
+    return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+\r
+  if ((result = mysql_store_result(handle->connection)) == NULL) {\r
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));\r
+    return TCL_OK;\r
+  } \r
+  if ((qhandle = createHandleFrom(statePtr,handle,HT_QUERY)) == NULL) return TCL_ERROR;\r
+  qhandle->result = result;\r
+  qhandle->col_count = mysql_num_fields(qhandle->result) ;\r
+\r
+\r
+  qhandle->res_count = mysql_num_rows(qhandle->result);\r
+  Tcl_SetObjResult(interp, Tcl_NewHandleObj(statePtr,qhandle));\r
+  return TCL_OK;\r
+}\r
+\r
+/*\r
+ * Mysqltcl_Enquery\r
+ * close and free a query handle\r
+ * if handle is not query than the result will be discarted\r
+ */\r
+\r
+static int Mysqltcl_EndQuery(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  Tcl_HashEntry *entryPtr;\r
+  MysqlTclHandle *handle;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "queryhandle")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  if (handle->type==HT_QUERY) {\r
+    entryPtr = Tcl_FindHashEntry(&statePtr->hash,Tcl_GetStringFromObj(objv[1],NULL));\r
+    if (entryPtr) {\r
+      Tcl_DeleteHashEntry(entryPtr);\r
+    }\r
+    closeHandle(handle);\r
+  } else {\r
+      freeResult(handle);\r
+  }\r
+  return TCL_OK;\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Exec\r
+ * Implements the mysqlexec command:\r
+ * usage: mysqlexec handle sql-statement\r
+ *                     \r
+ * Results:\r
+ * Number of affected rows on INSERT, UPDATE or DELETE, 0 otherwise.\r
+ *\r
+ * SIDE EFFECT: Flushes any pending result, even in case of conflict.\r
+ */\r
+\r
+\r
+\r
+static int Mysqltcl_Exec(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+       MysqlTclHandle *handle;\r
+       int affected;\r
+       Tcl_Obj *resList;\r
+    if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,"handle sql-statement")) == 0)\r
+       return TCL_ERROR;\r
+\r
+       /* Flush any previous result. */\r
+       freeResult(handle);\r
+\r
+       if (mysql_QueryTclObj(handle,objv[2]))\r
+       return mysql_server_confl(interp,objc,objv,handle->connection);\r
+\r
+       if ((affected=mysql_affected_rows(handle->connection)) < 0) affected=0;\r
+\r
+#if (MYSQL_VERSION_ID >= 50000)\r
+       if (!mysql_next_result(handle->connection)) {\r
+               resList = Tcl_GetObjResult(interp);\r
+               Tcl_ListObjAppendElement(interp, resList, Tcl_NewIntObj(affected));\r
+               do {\r
+                       if ((affected=mysql_affected_rows(handle->connection)) < 0) affected=0;\r
+               Tcl_ListObjAppendElement(interp, resList, Tcl_NewIntObj(affected));\r
+               } while (!mysql_next_result(handle->connection));\r
+               return TCL_OK;\r
+       }\r
+#endif\r
+       Tcl_SetIntObj(Tcl_GetObjResult(interp),affected);  \r
+       return TCL_OK ;\r
+}\r
+\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Fetch\r
+ *    Implements the mysqlnext command:\r
+\r
+ *    usage: mysql::fetch handle\r
+ *                     \r
+ *    results:\r
+ *     next row from pending results as tcl list, or null list.\r
+ */\r
+\r
+static int Mysqltcl_Fetch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  MysqlTclHandle *handle;\r
+  int idx ;\r
+  MYSQL_ROW row ;\r
+  Tcl_Obj *resList;\r
+  unsigned long *lengths;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_RES,"handle")) == 0)\r
+    return TCL_ERROR;\r
+\r
+\r
+  if (handle->res_count == 0)\r
+    return TCL_OK ;\r
+  else if ((row = mysql_fetch_row(handle->result)) == NULL) {\r
+    handle->res_count = 0 ;\r
+    return mysql_prim_confl(interp,objc,objv,"result counter out of sync") ;\r
+  } else\r
+    handle->res_count-- ;\r
+  \r
+  lengths = mysql_fetch_lengths(handle->result);\r
+\r
+\r
+  resList = Tcl_GetObjResult(interp);\r
+  for (idx = 0 ; idx < handle->col_count ; idx++, row++) {\r
+    Tcl_ListObjAppendElement(interp, resList,getRowCellAsObject(statePtr,handle,row,lengths[idx]));\r
+  }\r
+  return TCL_OK;\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Seek\r
+ *    Implements the mysqlseek command:\r
+ *    usage: mysqlseek handle rownumber\r
+ *                     \r
+ *    results:\r
+ *     number of remaining rows\r
+ */\r
+\r
+static int Mysqltcl_Seek(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+    MysqlTclHandle *handle;\r
+    int row;\r
+    int total;\r
+   \r
+    if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_RES,\r
+                              " handle row-index")) == 0)\r
+      return TCL_ERROR;\r
+\r
+    if (Tcl_GetIntFromObj(interp, objv[2], &row) != TCL_OK)\r
+      return TCL_ERROR;\r
+    \r
+    total = mysql_num_rows(handle->result);\r
+    \r
+    if (total + row < 0) {\r
+      mysql_data_seek(handle->result, 0);\r
+\r
+      handle->res_count = total;\r
+    } else if (row < 0) {\r
+      mysql_data_seek(handle->result, total + row);\r
+      handle->res_count = -row;\r
+    } else if (row >= total) {\r
+      mysql_data_seek(handle->result, row);\r
+      handle->res_count = 0;\r
+    } else {\r
+      mysql_data_seek(handle->result, row);\r
+      handle->res_count = total - row;\r
+    }\r
+\r
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(handle->res_count)) ;\r
+    return TCL_OK;\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Map\r
+ * Implements the mysqlmap command:\r
+ * usage: mysqlmap handle binding-list script\r
+ *                     \r
+ * Results:\r
+ * SIDE EFFECT: For each row the column values are bound to the variables\r
+ * in the binding list and the script is evaluated.\r
+ * The variables are created in the current context.\r
+ * NOTE: mysqlmap works very much like a 'foreach' construct.\r
+ * The 'continue' and 'break' commands may be used with their usual effect.\r
+ */\r
+\r
+static int Mysqltcl_Map(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  int code ;\r
+  int count ;\r
+\r
+  MysqlTclHandle *handle;\r
+  int idx;\r
+  int listObjc;\r
+  Tcl_Obj *tempObj,*varNameObj;\r
+  MYSQL_ROW row;\r
+  int *val;\r
+  unsigned long *lengths;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 4, 4, CL_RES,\r
+                           "handle binding-list script")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  if (Tcl_ListObjLength(interp, objv[2], &listObjc) != TCL_OK)\r
+        return TCL_ERROR ;\r
+  \r
+\r
+  if (listObjc > handle->col_count)\r
+    {\r
+      return mysql_prim_confl(interp,objc,objv,"too many variables in binding list") ;\r
+    }\r
+  else\r
+    count = (listObjc < handle->col_count)?listObjc\r
+      :handle->col_count ;\r
+  \r
+  val=(int*)Tcl_Alloc((count * sizeof(int)));\r
+\r
+  for (idx=0; idx<count; idx++) {\r
+    val[idx]=1;\r
+    if (Tcl_ListObjIndex(interp, objv[2], idx, &varNameObj)!=TCL_OK)\r
+        return TCL_ERROR;\r
+    if (Tcl_GetStringFromObj(varNameObj,0)[0] != '-')\r
+        val[idx]=1;\r
+    else\r
+        val[idx]=0;\r
+  }\r
+  \r
+  while (handle->res_count > 0) {\r
+    /* Get next row, decrement row counter. */\r
+    if ((row = mysql_fetch_row(handle->result)) == NULL) {\r
+      handle->res_count = 0 ;\r
+      Tcl_Free((char *)val);\r
+      return mysql_prim_confl(interp,objc,objv,"result counter out of sync") ;\r
+    } else\r
+      handle->res_count-- ;\r
+      \r
+    /* Bind variables to column values. */\r
+    for (idx = 0; idx < count; idx++, row++) {\r
+      lengths = mysql_fetch_lengths(handle->result);\r
+      if (val[idx]) {\r
+       tempObj = getRowCellAsObject(statePtr,handle,row,lengths[idx]);\r
+        if (Tcl_ListObjIndex(interp, objv[2], idx, &varNameObj) != TCL_OK)\r
+            goto error;\r
+       if (Tcl_ObjSetVar2 (interp,varNameObj,NULL,tempObj,0) == NULL)\r
+            goto error;\r
+      }\r
+    }\r
+\r
+    /* Evaluate the script. */\r
+    switch(code=Tcl_EvalObjEx(interp, objv[3],0)) {\r
+    case TCL_CONTINUE:\r
+    case TCL_OK:\r
+      break ;\r
+    case TCL_BREAK:\r
+      Tcl_Free((char *)val);\r
+      return TCL_OK ;\r
+    default:\r
+      Tcl_Free((char *)val);\r
+      return code ;\r
+    }\r
+  }\r
+  Tcl_Free((char *)val);\r
+  return TCL_OK ;\r
+error:\r
+  Tcl_Free((char *)val);\r
+  return TCL_ERROR;    \r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Receive\r
+ * Implements the mysqlmap command:\r
+ * usage: mysqlmap handle sqlquery binding-list script\r
+ * \r
+ * The method use internal mysql_use_result that no cache statment on client but\r
+ * receive it direct from server \r
+ *\r
+ * Results:\r
+ * SIDE EFFECT: For each row the column values are bound to the variables\r
+ * in the binding list and the script is evaluated.\r
+ * The variables are created in the current context.\r
+ * NOTE: mysqlmap works very much like a 'foreach' construct.\r
+ * The 'continue' and 'break' commands may be used with their usual effect.\r
+\r
+ */\r
+\r
+static int Mysqltcl_Receive(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  int code=0;\r
+  int count=0;\r
+\r
+  MysqlTclHandle *handle;\r
+  int idx;\r
+  int listObjc;\r
+  Tcl_Obj *tempObj,*varNameObj;\r
+  MYSQL_ROW row;\r
+  int *val = NULL;\r
+  int breakLoop = 0;\r
+  unsigned long *lengths;\r
+  \r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 5, 5, CL_CONN,\r
+                           "handle sqlquery binding-list script")) == 0)\r
+    return TCL_ERROR;\r
+  \r
+  if (Tcl_ListObjLength(interp, objv[3], &listObjc) != TCL_OK)\r
+        return TCL_ERROR;\r
+  \r
+  freeResult(handle);\r
+  \r
+  if (mysql_QueryTclObj(handle,objv[2])) {\r
+    return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+\r
+  if ((handle->result = mysql_use_result(handle->connection)) == NULL) {\r
+    return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  } else {\r
+    while ((row = mysql_fetch_row(handle->result))!= NULL) {\r
+      if (val==NULL) {\r
+       /* first row compute all data */\r
+       handle->col_count = mysql_num_fields(handle->result);\r
+       if (listObjc > handle->col_count) {\r
+          return mysql_prim_confl(interp,objc,objv,"too many variables in binding list") ;\r
+       } else {\r
+         count = (listObjc < handle->col_count)?listObjc:handle->col_count ;\r
+       }\r
+       val=(int*)Tcl_Alloc((count * sizeof(int)));\r
+       for (idx=0; idx<count; idx++) {\r
+          if (Tcl_ListObjIndex(interp, objv[3], idx, &varNameObj)!=TCL_OK)\r
+            return TCL_ERROR;\r
+         if (Tcl_GetStringFromObj(varNameObj,0)[0] != '-')\r
+           val[idx]=1;\r
+         else\r
+           val[idx]=0;\r
+       }       \r
+      }\r
+      for (idx = 0; idx < count; idx++, row++) {\r
+        lengths = mysql_fetch_lengths(handle->result);\r
+\r
+        if (val[idx]) {\r
+           if (Tcl_ListObjIndex(interp, objv[3], idx, &varNameObj)!=TCL_OK) {\r
+                Tcl_Free((char *)val);\r
+                return TCL_ERROR;\r
+            }\r
+            tempObj = getRowCellAsObject(statePtr,handle,row,lengths[idx]);\r
+            if (Tcl_ObjSetVar2 (interp,varNameObj,NULL,tempObj,TCL_LEAVE_ERR_MSG) == NULL) {\r
+              Tcl_Free((char *)val);\r
+              return TCL_ERROR ;\r
+           }\r
+        }\r
+      }\r
+      \r
+      /* Evaluate the script. */\r
+      switch(code=Tcl_EvalObjEx(interp, objv[4],0)) {\r
+      case TCL_CONTINUE:\r
+      case TCL_OK:\r
+       break ;\r
+      case TCL_BREAK:\r
+       breakLoop=1;\r
+       break;\r
+      default:\r
+       breakLoop=1;\r
+       break;\r
+      }\r
+      if (breakLoop==1) break;\r
+    }\r
+  }\r
+  if (val!=NULL) {\r
+    Tcl_Free((char *)val);\r
+  } \r
+  /*  Read all rest rows that leave in error or break case */\r
+  while ((row = mysql_fetch_row(handle->result))!= NULL);\r
+  if (code!=TCL_CONTINUE && code!=TCL_OK && code!=TCL_BREAK) {\r
+    return code;\r
+  } else {\r
+    return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  } \r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Info\r
+ * Implements the mysqlinfo command:\r
+ * usage: mysqlinfo handle option\r
+ *\r
+\r
+\r
+ */\r
+\r
+static int Mysqltcl_Info(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+\r
+  int count ;\r
+  MysqlTclHandle *handle;\r
+  int idx ;\r
+  MYSQL_RES* list ;\r
+  MYSQL_ROW row ;\r
+  const char* val ;\r
+  Tcl_Obj *resList;\r
+  static CONST char* MysqlDbOpt[] =\r
+    {\r
+      "dbname", "dbname?", "tables", "host", "host?", "databases",\r
+      "info","serverversion",\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+      "serverversionid","sqlstate",\r
+#endif\r
+      "state",NULL\r
+    };\r
+  enum dboption {\r
+    MYSQL_INFNAME_OPT, MYSQL_INFNAMEQ_OPT, MYSQL_INFTABLES_OPT,\r
+    MYSQL_INFHOST_OPT, MYSQL_INFHOSTQ_OPT, MYSQL_INFLIST_OPT, MYSQL_INFO,\r
+    MYSQL_INF_SERVERVERSION,MYSQL_INFO_SERVERVERSION_ID,MYSQL_INFO_SQLSTATE,MYSQL_INFO_STATE\r
+  };\r
+  \r
+  /* We can't fully check the handle at this stage. */\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_PLAIN,\r
+                           "handle option")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  if (Tcl_GetIndexFromObj(interp, objv[2], MysqlDbOpt, "option",\r
+                          TCL_EXACT, &idx) != TCL_OK)\r
+    return TCL_ERROR;\r
+\r
+  /* First check the handle. Checking depends on the option. */\r
+  switch (idx) {\r
+  case MYSQL_INFNAMEQ_OPT:\r
+    if ((handle = get_handle(interp,objc,objv,CL_CONN))!=NULL) {\r
+      if (handle->database[0] == '\0')\r
+       return TCL_OK ; /* Return empty string if no current db. */\r
+    }\r
+    break ;\r
+  case MYSQL_INFNAME_OPT:\r
+  case MYSQL_INFTABLES_OPT:\r
+  case MYSQL_INFHOST_OPT:\r
+  case MYSQL_INFLIST_OPT:\r
+    /* !!! */\r
+    handle = get_handle(interp,objc,objv,CL_CONN);\r
+    break;\r
+  case MYSQL_INFO:\r
+  case MYSQL_INF_SERVERVERSION:\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+  case MYSQL_INFO_SERVERVERSION_ID:\r
+  case MYSQL_INFO_SQLSTATE:\r
+#endif\r
+  case MYSQL_INFO_STATE:\r
+    break;\r
+\r
+  case MYSQL_INFHOSTQ_OPT:\r
+    if (handle->connection == 0)\r
+      return TCL_OK ; /* Return empty string if not connected. */\r
+    break;\r
+  default: /* should never happen */\r
+    return mysql_prim_confl(interp,objc,objv,"weirdness in Mysqltcl_Info") ;\r
+  }\r
+  \r
+  if (handle == 0) return TCL_ERROR ;\r
+\r
+  /* Handle OK, return the requested info. */\r
+  switch (idx) {\r
+  case MYSQL_INFNAME_OPT:\r
+  case MYSQL_INFNAMEQ_OPT:\r
+    Tcl_SetObjResult(interp, Tcl_NewStringObj(handle->database, -1));\r
+    break ;\r
+  case MYSQL_INFTABLES_OPT:\r
+    if ((list = mysql_list_tables(handle->connection,(char*)NULL)) == NULL)\r
+      return mysql_server_confl(interp,objc,objv,handle->connection);\r
+    \r
+    resList = Tcl_GetObjResult(interp);\r
+    for (count = mysql_num_rows(list); count > 0; count--) {\r
+      val = *(row = mysql_fetch_row(list)) ;\r
+      Tcl_ListObjAppendElement(interp, resList, Tcl_NewStringObj((val == NULL)?"":val,-1));\r
+    }\r
+    mysql_free_result(list) ;\r
+    break ;\r
+  case MYSQL_INFHOST_OPT:\r
+\r
+  case MYSQL_INFHOSTQ_OPT:\r
+    Tcl_SetObjResult(interp, Tcl_NewStringObj(mysql_get_host_info(handle->connection), -1));\r
+    break ;\r
+  case MYSQL_INFLIST_OPT:\r
+    if ((list = mysql_list_dbs(handle->connection,(char*)NULL)) == NULL)\r
+      return mysql_server_confl(interp,objc,objv,handle->connection);\r
+    \r
+    resList = Tcl_GetObjResult(interp);\r
+    for (count = mysql_num_rows(list); count > 0; count--) {\r
+      val = *(row = mysql_fetch_row(list)) ;\r
+      Tcl_ListObjAppendElement(interp, resList,\r
+                               Tcl_NewStringObj((val == NULL)?"":val,-1));\r
+    }\r
+    mysql_free_result(list) ;\r
+    break ;\r
+  case MYSQL_INFO:\r
+    val = mysql_info(handle->connection);\r
+    if (val!=NULL) {\r
+      Tcl_SetObjResult(interp, Tcl_NewStringObj(val,-1));      \r
+    }\r
+    break;\r
+  case MYSQL_INF_SERVERVERSION:\r
+     Tcl_SetObjResult(interp, Tcl_NewStringObj(mysql_get_server_info(handle->connection),-1));\r
+     break;\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+  case MYSQL_INFO_SERVERVERSION_ID:\r
+        Tcl_SetObjResult(interp, Tcl_NewIntObj(mysql_get_server_version(handle->connection)));\r
+        break;\r
+  case MYSQL_INFO_SQLSTATE:\r
+     Tcl_SetObjResult(interp, Tcl_NewStringObj(mysql_sqlstate(handle->connection),-1));\r
+     break;\r
+#endif\r
+  case MYSQL_INFO_STATE:\r
+     Tcl_SetObjResult(interp, Tcl_NewStringObj(mysql_stat(handle->connection),-1));\r
+     break;\r
+  default: /* should never happen */\r
+    return mysql_prim_confl(interp,objc,objv,"weirdness in Mysqltcl_Info") ;\r
+  }\r
+\r
+  return TCL_OK ;\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_BaseInfo\r
+ * Implements the mysqlinfo command:\r
+ * usage: mysqlbaseinfo option\r
+ *\r
+ */\r
+\r
+static int Mysqltcl_BaseInfo(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  int idx ;\r
+  Tcl_Obj *resList;\r
+  char **option;\r
+  static CONST char* MysqlInfoOpt[] =\r
+    {\r
+      "connectparameters", "clientversion",\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+      "clientversionid",\r
+#endif\r
+      NULL\r
+    };\r
+  enum baseoption {\r
+    MYSQL_BINFO_CONNECT, MYSQL_BINFO_CLIENTVERSION,MYSQL_BINFO_CLIENTVERSIONID\r
+  };\r
+\r
+  if (objc <2) {\r
+      Tcl_WrongNumArgs(interp, 1, objv, "connectparameters | clientversion");\r
+\r
+      return TCL_ERROR;\r
+  }  \r
+  if (Tcl_GetIndexFromObj(interp, objv[1], MysqlInfoOpt, "option",\r
+                          TCL_EXACT, &idx) != TCL_OK)\r
+    return TCL_ERROR;\r
+\r
+  /* First check the handle. Checking depends on the option. */\r
+  switch (idx) {\r
+  case MYSQL_BINFO_CONNECT:\r
+    option = (char **)MysqlConnectOpt;\r
+    resList = Tcl_NewListObj(0, NULL);\r
+\r
+    while (*option!=NULL) {\r
+      Tcl_ListObjAppendElement(interp, resList, Tcl_NewStringObj(*option,-1));\r
+      option++;\r
+    }\r
+    Tcl_SetObjResult(interp, resList);\r
+    break ;\r
+  case MYSQL_BINFO_CLIENTVERSION:\r
+    Tcl_SetObjResult(interp, Tcl_NewStringObj(mysql_get_client_info(),-1));\r
+    break;\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+  case MYSQL_BINFO_CLIENTVERSIONID:\r
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(mysql_get_client_version()));\r
+    break;\r
+#endif\r
+  }\r
+  return TCL_OK ;\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Result\r
+\r
+ * Implements the mysqlresult command:\r
+ * usage: mysqlresult handle option\r
+ *\r
+ */\r
+\r
+static int Mysqltcl_Result(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  int idx ;\r
+  MysqlTclHandle *handle;\r
+  static CONST char* MysqlResultOpt[] =\r
+    {\r
+     "rows", "rows?", "cols", "cols?", "current", "current?", NULL\r
+    };\r
+  enum resultoption {\r
+    MYSQL_RESROWS_OPT, MYSQL_RESROWSQ_OPT, MYSQL_RESCOLS_OPT, \r
+    MYSQL_RESCOLSQ_OPT, MYSQL_RESCUR_OPT, MYSQL_RESCURQ_OPT\r
+  };\r
+  /* We can't fully check the handle at this stage. */\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_PLAIN,\r
+                           " handle option")) == 0)\r
+\r
+    return TCL_ERROR;\r
+\r
+  if (Tcl_GetIndexFromObj(interp, objv[2], MysqlResultOpt, "option",\r
+                          TCL_EXACT, &idx) != TCL_OK)\r
+    return TCL_ERROR;\r
+\r
+  /* First check the handle. Checking depends on the option. */\r
+  switch (idx) {\r
+  case MYSQL_RESROWS_OPT:\r
+  case MYSQL_RESCOLS_OPT:\r
+  case MYSQL_RESCUR_OPT:\r
+    handle = get_handle(interp,objc,objv,CL_RES) ;\r
+    break ;\r
+  case MYSQL_RESROWSQ_OPT:\r
+  case MYSQL_RESCOLSQ_OPT:\r
+  case MYSQL_RESCURQ_OPT:\r
+    if ((handle = get_handle(interp,objc,objv,CL_RES))== NULL)\r
+      return TCL_OK ; /* Return empty string if no pending result. */\r
+    break ;\r
+  default: /* should never happen */\r
+    return mysql_prim_confl(interp,objc,objv,"weirdness in Mysqltcl_Result") ;\r
+  }\r
+  \r
+  \r
+  if (handle == 0)\r
+    return TCL_ERROR ;\r
+\r
+  /* Handle OK; return requested info. */\r
+  switch (idx) {\r
+  case MYSQL_RESROWS_OPT:\r
+  case MYSQL_RESROWSQ_OPT:\r
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(handle->res_count));\r
+    break ;\r
+  case MYSQL_RESCOLS_OPT:\r
+  case MYSQL_RESCOLSQ_OPT:\r
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(handle->col_count));\r
+    break ;\r
+  case MYSQL_RESCUR_OPT:\r
+  case MYSQL_RESCURQ_OPT:\r
+    Tcl_SetObjResult(interp,\r
+                       Tcl_NewIntObj(mysql_num_rows(handle->result)\r
+                                    - handle->res_count)) ;\r
+    break ;\r
+  default:\r
+    return mysql_prim_confl(interp,objc,objv,"weirdness in Mysqltcl_Result");\r
+  }\r
+  return TCL_OK ;\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Col\r
+\r
+ *    Implements the mysqlcol command:\r
+ *    usage: mysqlcol handle table-name option ?option ...?\r
+ *           mysqlcol handle -current option ?option ...?\r
+ * '-current' can only be used if there is a pending result.\r
+ *                     \r
+ *    results:\r
+ *     List of lists containing column attributes.\r
+ *      If a single attribute is requested the result is a simple list.\r
+ *\r
+ * SIDE EFFECT: '-current' disturbs the field position of the result.\r
+ */\r
+\r
+static int Mysqltcl_Col(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  int coln ;\r
+  int current_db ;\r
+  MysqlTclHandle *handle;\r
+  int idx ;\r
+  int listObjc ;\r
+  Tcl_Obj **listObjv, *colinfo, *resList, *resSubList;\r
+  MYSQL_FIELD* fld ;\r
+  MYSQL_RES* result ;\r
+  char *argv ;\r
+  \r
+  /* This check is enough only without '-current'. */\r
+  if ((handle = mysql_prologue(interp, objc, objv, 4, 99, CL_CONN,\r
+                           "handle table-name option ?option ...?")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  /* Fetch column info.\r
+   * Two ways: explicit database and table names, or current.\r
+   */\r
+  argv=Tcl_GetStringFromObj(objv[2],NULL);\r
+  current_db = strcmp(argv, "-current") == 0;\r
+  \r
+  if (current_db) {\r
+    if ((handle = get_handle(interp,objc,objv,CL_RES)) == 0)\r
+      return TCL_ERROR ;\r
+    else\r
+      result = handle->result ;\r
+  } else {\r
+    if ((result = mysql_list_fields(handle->connection, argv, (char*)NULL)) == NULL) {\r
+      return mysql_server_confl(interp,objc,objv,handle->connection) ;\r
+    }\r
+  }\r
+  /* Must examine the first specifier at this point. */\r
+  if (Tcl_ListObjGetElements(interp, objv[3], &listObjc, &listObjv) != TCL_OK)\r
+    return TCL_ERROR ;\r
+  resList = Tcl_GetObjResult(interp);\r
+  if (objc == 4 && listObjc == 1) {\r
+      mysql_field_seek(result, 0) ;\r
+      while ((fld = mysql_fetch_field(result)) != NULL)\r
+        if ((colinfo = mysql_colinfo(interp,objc,objv,fld, objv[3])) != NULL) {\r
+            Tcl_ListObjAppendElement(interp, resList, colinfo);\r
+        } else {\r
+            goto conflict;\r
+           }\r
+  } else if (objc == 4 && listObjc > 1) {\r
+      mysql_field_seek(result, 0) ;\r
+      while ((fld = mysql_fetch_field(result)) != NULL) {\r
+        resSubList = Tcl_NewListObj(0, NULL);\r
+        for (coln = 0; coln < listObjc; coln++)\r
+            if ((colinfo = mysql_colinfo(interp,objc,objv,fld, listObjv[coln])) != NULL) {\r
+                Tcl_ListObjAppendElement(interp, resSubList, colinfo);\r
+            } else {\r
+\r
+               goto conflict; \r
+            }\r
+        Tcl_ListObjAppendElement(interp, resList, resSubList);\r
+       }\r
+  } else {\r
+      for (idx = 3; idx < objc; idx++) {\r
+        resSubList = Tcl_NewListObj(0, NULL);\r
+        mysql_field_seek(result, 0) ;\r
+        while ((fld = mysql_fetch_field(result)) != NULL)\r
+        if ((colinfo = mysql_colinfo(interp,objc,objv,fld, objv[idx])) != NULL) {\r
+\r
+            Tcl_ListObjAppendElement(interp, resSubList, colinfo);\r
+        } else {\r
+            goto conflict; \r
+        }\r
+        Tcl_ListObjAppendElement(interp, resList, resSubList);\r
+      }\r
+  }\r
+  if (!current_db) mysql_free_result(result) ;\r
+  return TCL_OK;\r
+  \r
+  conflict:\r
+    if (!current_db) mysql_free_result(result) ;\r
+    return TCL_ERROR;\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_State\r
+ *    Implements the mysqlstate command:\r
+ *    usage: mysqlstate handle ?-numeric?\r
+\r
+ *                     \r
+ */\r
+\r
+static int Mysqltcl_State(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqlTclHandle *handle;\r
+  int numeric=0 ;\r
+  Tcl_Obj *res;\r
+\r
+  if (objc!=2 && objc!=3) {\r
+      Tcl_WrongNumArgs(interp, 1, objv, "handle ?-numeric");\r
+      return TCL_ERROR;\r
+  }\r
+\r
+  if (objc==3) {\r
+    if (strcmp(Tcl_GetStringFromObj(objv[2],NULL), "-numeric"))\r
+      return mysql_prim_confl(interp,objc,objv,"last parameter should be -numeric");\r
+    else\r
+\r
+      numeric=1;\r
+  }\r
+  \r
+  if (GetHandleFromObj(interp, objv[1], &handle) != TCL_OK)\r
+    res = (numeric)?Tcl_NewIntObj(0):Tcl_NewStringObj("NOT_A_HANDLE",-1);\r
+  else if (handle->connection == 0)\r
+    res = (numeric)?Tcl_NewIntObj(1):Tcl_NewStringObj("UNCONNECTED",-1);\r
+  else if (handle->database[0] == '\0')\r
+    res = (numeric)?Tcl_NewIntObj(2):Tcl_NewStringObj("CONNECTED",-1);\r
+  else if (handle->result == NULL)\r
+    res = (numeric)?Tcl_NewIntObj(3):Tcl_NewStringObj("IN_USE",-1);\r
+  else\r
+    res = (numeric)?Tcl_NewIntObj(4):Tcl_NewStringObj("RESULT_PENDING",-1);\r
+\r
+  Tcl_SetObjResult(interp, res);\r
+  return TCL_OK ;\r
+}\r
+\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_InsertId\r
+ *    Implements the mysqlstate command:\r
+ *    usage: mysqlinsertid handle \r
+ *    Returns the auto increment id of the last INSERT statement\r
+ *                     \r
+ */\r
+\r
+static int Mysqltcl_InsertId(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+\r
+  MysqlTclHandle *handle;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  Tcl_SetObjResult(interp, Tcl_NewIntObj(mysql_insert_id(handle->connection)));\r
+\r
+  return TCL_OK;\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Ping\r
+ *    usage: mysqlping handle\r
+ *    It can be used to check and refresh (reconnect after time out) the connection\r
+ *    Returns 0 if connection is OK\r
+ */\r
+\r
+\r
+static int Mysqltcl_Ping(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqlTclHandle *handle;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(mysql_ping(handle->connection)==0));\r
+\r
+  return TCL_OK;\r
+}\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_ChangeUser\r
+ *    usage: mysqlchangeuser handle user password database\r
+ *    return TCL_ERROR if operation failed\r
+ */\r
+\r
+static int Mysqltcl_ChangeUser(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqlTclHandle *handle;\r
+  int len;\r
+  char *user,*password,*database=NULL;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 4, 5, CL_CONN,\r
+                           "handle user password ?database?")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  user = Tcl_GetStringFromObj(objv[2],NULL);\r
+  password = Tcl_GetStringFromObj(objv[3],NULL);\r
+  if (objc==5) {\r
+    database = Tcl_GetStringFromObj(objv[4],&len);\r
+    if (len >= MYSQL_NAME_LEN) {\r
+       mysql_prim_confl(interp,objc,objv,"database name too long");\r
+       return TCL_ERROR;\r
+    }\r
+  }\r
+  if (mysql_change_user(handle->connection, user, password, database)!=0) {\r
+      mysql_server_confl(interp,objc,objv,handle->connection);\r
+      return TCL_ERROR;\r
+  }\r
+  if (database!=NULL) \r
+         strcpy(handle->database, database);\r
+  return TCL_OK;\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_AutoCommit\r
+ *    usage: mysql::autocommit bool\r
+ *    set autocommit mode\r
+ */\r
+\r
+static int Mysqltcl_AutoCommit(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+#if (MYSQL_VERSION_ID < 40107)\r
+  Tcl_AddErrorInfo(interp, FUNCTION_NOT_AVAILABLE);\r
+  return TCL_ERROR;\r
+#else\r
+  MysqlTclHandle *handle;\r
+  int isAutocommit = 0;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "handle bool")) == 0)\r
+       return TCL_ERROR;\r
+  if (Tcl_GetBooleanFromObj(interp,objv[2],&isAutocommit) != TCL_OK )\r
+       return TCL_ERROR;\r
+  if (mysql_autocommit(handle->connection, isAutocommit)!=0) {\r
+       mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  return TCL_OK;\r
+#endif\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Commit\r
+ *    usage: mysql::commit\r
+ *    \r
+ */\r
+\r
+static int Mysqltcl_Commit(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+#if (MYSQL_VERSION_ID < 40107)\r
+  Tcl_AddErrorInfo(interp, FUNCTION_NOT_AVAILABLE);\r
+  return TCL_ERROR;\r
+#else\r
+  MysqlTclHandle *handle;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+  if (mysql_commit(handle->connection)!=0) {\r
+       mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  return TCL_OK;\r
+#endif\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Rollback\r
+ *    usage: mysql::rollback\r
+ *\r
+ */\r
+\r
+static int Mysqltcl_Rollback(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+#if (MYSQL_VERSION_ID < 40107)\r
+  Tcl_AddErrorInfo(interp, FUNCTION_NOT_AVAILABLE);\r
+  return TCL_ERROR;\r
+#else\r
+  MysqlTclHandle *handle;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+  if (mysql_rollback(handle->connection)!=0) {\r
+      mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  return TCL_OK;\r
+#endif\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_MoreResult\r
+ *    usage: mysql::moreresult handle\r
+ *    return true if more results exists\r
+ */\r
+\r
+static int Mysqltcl_MoreResult(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+#if (MYSQL_VERSION_ID < 40107)\r
+  Tcl_AddErrorInfo(interp, FUNCTION_NOT_AVAILABLE);\r
+  return TCL_ERROR;\r
+#else\r
+  MysqlTclHandle *handle;\r
+  int boolResult = 0;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_RES,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+  boolResult =  mysql_more_results(handle->connection);\r
+  Tcl_SetObjResult(interp,Tcl_NewBooleanObj(boolResult));\r
+  return TCL_OK;\r
+#endif\r
+}\r
+/*\r
+\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_NextResult\r
+ *    usage: mysql::nextresult\r
+ *\r
+ *  return nummber of rows in result set. 0 if no next result\r
+ */\r
+\r
+static int Mysqltcl_NextResult(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+#if (MYSQL_VERSION_ID < 40107)\r
+  Tcl_AddErrorInfo(interp, FUNCTION_NOT_AVAILABLE);\r
+  return TCL_ERROR;\r
+#else\r
+  MysqlTclHandle *handle;\r
+  int result = 0;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_RES,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+  if (handle->result != NULL) {\r
+    mysql_free_result(handle->result) ;\r
+    handle->result = NULL ;\r
+  }\r
+  result = mysql_next_result(handle->connection);\r
+  if (result==-1) {\r
+      Tcl_SetObjResult(interp, Tcl_NewIntObj(0));\r
+      return TCL_OK;\r
+  }\r
+  if (result<0) {\r
+      return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  handle->result = mysql_store_result(handle->connection);\r
+  if (handle->result == NULL) {\r
+      Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));\r
+  } else {\r
+      handle->res_count = mysql_num_rows(handle->result);\r
+      Tcl_SetObjResult(interp, Tcl_NewIntObj(handle->res_count));\r
+  }\r
+  return TCL_OK;\r
+#endif\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_WarningCount\r
+ *    usage: mysql::warningcount\r
+ *\r
+ */\r
+\r
+static int Mysqltcl_WarningCount(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+#if (MYSQL_VERSION_ID < 40107)\r
+  Tcl_AddErrorInfo(interp, FUNCTION_NOT_AVAILABLE);\r
+  return TCL_ERROR;\r
+#else\r
+  MysqlTclHandle *handle;\r
+  int count = 0;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+  count = mysql_warning_count(handle->connection);\r
+  Tcl_SetObjResult(interp,Tcl_NewIntObj(count));\r
+  return TCL_OK;\r
+#endif\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_IsNull\r
+ *    usage: mysql::isnull value\r
+ *\r
+ */\r
+\r
+static int Mysqltcl_IsNull(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  int boolResult = 0;\r
+  if (objc != 2) {\r
+      Tcl_WrongNumArgs(interp, 1, objv, "value");\r
+      return TCL_ERROR;\r
+  }\r
+  boolResult = objv[1]->typePtr == &mysqlNullType;\r
+  Tcl_SetObjResult(interp,Tcl_NewBooleanObj(boolResult));\r
+  return TCL_OK;\r
+\r
+  return TCL_OK;\r
+}\r
+/*\r
+ * Create new Mysql NullObject\r
+ * (similar to Tcl API for example Tcl_NewIntObj)\r
+ */\r
+static Tcl_Obj *Mysqltcl_NewNullObj(MysqltclState *mysqltclState) {\r
+  Tcl_Obj *objPtr;\r
+  objPtr = Tcl_NewObj();\r
+  objPtr->bytes = NULL;\r
+  objPtr->typePtr = &mysqlNullType;\r
+  objPtr->internalRep.otherValuePtr = mysqltclState;\r
+  return objPtr;\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_NewNull\r
+ *    usage: mysql::newnull\r
+ *\r
+ */\r
+\r
+static int Mysqltcl_NewNull(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  if (objc != 1) {\r
+      Tcl_WrongNumArgs(interp, 1, objv, "");\r
+      return TCL_ERROR;\r
+  }\r
+  Tcl_SetObjResult(interp,Mysqltcl_NewNullObj((MysqltclState *)clientData));\r
+  return TCL_OK;\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_SetServerOption\r
+ *    usage: mysql::setserveroption (-\r
+ *\r
+ */\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+static CONST char* MysqlServerOpt[] =\r
+    {\r
+      "-multi_statment_on", "-multi_statment_off",NULL\r
+    };\r
+#endif\r
\r
+static int Mysqltcl_SetServerOption(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+#if (MYSQL_VERSION_ID < 40107)\r
+  Tcl_AddErrorInfo(interp, FUNCTION_NOT_AVAILABLE);\r
+  return TCL_ERROR;\r
+#else\r
+  MysqlTclHandle *handle;\r
+  int idx;\r
+  enum enum_mysql_set_option mysqlServerOption;\r
+  \r
+  enum serveroption {\r
+    MYSQL_MSTATMENT_ON_SOPT, MYSQL_MSTATMENT_OFF_SOPT\r
+  };\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "handle option")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  if (Tcl_GetIndexFromObj(interp, objv[2], MysqlServerOpt, "option",\r
+                          0, &idx) != TCL_OK)\r
+      return TCL_ERROR;\r
+\r
+  switch (idx) {\r
+    case MYSQL_MSTATMENT_ON_SOPT:\r
+      mysqlServerOption = MYSQL_OPTION_MULTI_STATEMENTS_ON;\r
+      break;\r
+    case MYSQL_MSTATMENT_OFF_SOPT:\r
+      mysqlServerOption = MYSQL_OPTION_MULTI_STATEMENTS_OFF;\r
+      break;\r
+    default:\r
+      return mysql_prim_confl(interp,objc,objv,"Weirdness in server options");\r
+  }\r
+  if (mysql_set_server_option(handle->connection,mysqlServerOption)!=0) {\r
+       mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  return TCL_OK;\r
+#endif\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_ShutDown\r
+ *    usage: mysql::shutdown handle\r
+ *\r
+ */\r
+static int Mysqltcl_ShutDown(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqlTclHandle *handle;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "handle")) == 0)\r
+    return TCL_ERROR;\r
+#if (MYSQL_VERSION_ID >= 40107)\r
+  if (mysql_shutdown(handle->connection,SHUTDOWN_DEFAULT)!=0) {\r
+#else\r
+  if (mysql_shutdown(handle->connection)!=0) {\r
+#endif\r
+       mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  return TCL_OK;\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Encoding\r
+ *    usage: mysql::encoding handle ?encoding|binary?\r
+ *\r
+ */\r
+static int Mysqltcl_Encoding(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData;\r
+  Tcl_HashSearch search;\r
+  Tcl_HashEntry *entryPtr;\r
+  MysqlTclHandle *handle,*qhandle;\r
+  char *encodingname;\r
+  Tcl_Encoding encoding;\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 3, CL_CONN,\r
+                           "handle")) == 0)\r
+        return TCL_ERROR;\r
+  if (objc==2) {\r
+      if (handle->encoding == NULL)\r
+         Tcl_SetObjResult(interp, Tcl_NewStringObj("binary",-1));\r
+      else \r
+         Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetEncodingName(handle->encoding),-1));\r
+  } else {\r
+      if (handle->type!=HT_CONNECTION) {\r
+            Tcl_SetObjResult(interp, Tcl_NewStringObj("encoding set can be used only on connection handle",-1));\r
+            return TCL_ERROR;\r
+      }\r
+      encodingname = Tcl_GetStringFromObj(objv[2],NULL);\r
+      if (strcmp(encodingname, "binary") == 0) {\r
+        encoding = NULL;       \r
+      } else {\r
+         encoding = Tcl_GetEncoding(interp, encodingname);\r
+        if (encoding == NULL)\r
+            return TCL_ERROR;\r
+      }\r
+      if (handle->encoding!=NULL)\r
+          Tcl_FreeEncoding(handle->encoding);\r
+      handle->encoding = encoding;\r
+\r
+      /* change encoding of all subqueries */\r
+      for (entryPtr=Tcl_FirstHashEntry(&statePtr->hash,&search);\r
+               entryPtr!=NULL;\r
+                entryPtr=Tcl_NextHashEntry(&search)) {\r
+            qhandle=(MysqlTclHandle *)Tcl_GetHashValue(entryPtr);\r
+            if (qhandle->type==HT_QUERY && handle->connection==qhandle->connection) {\r
+                qhandle->encoding = encoding;\r
+            }\r
+      }\r
+\r
+  }\r
+  return TCL_OK;\r
+}\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Close --\r
+ *    Implements the mysqlclose command:\r
+ *    usage: mysqlclose ?handle?\r
+ *                     \r
+ *    results:\r
+ *     null string\r
+ */\r
+\r
+static int Mysqltcl_Close(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData; \r
+  MysqlTclHandle *handle,*thandle;\r
+  Tcl_HashEntry *entryPtr;\r
+  Tcl_HashEntry *qentries[16];\r
+  Tcl_HashSearch search;\r
+\r
+  int i,qfound = 0;\r
+\r
+\r
+  /* If handle omitted, close all connections. */\r
+  if (objc == 1) {\r
+      Mysqltcl_CloseAll(clientData) ;\r
+      return TCL_OK ;\r
+  }\r
+  \r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "?handle?")) == 0)\r
+    return TCL_ERROR;\r
+\r
+\r
+  /* Search all queries and statements on this handle and close those */\r
+  if (handle->type==HT_CONNECTION)  {\r
+    while (1) {\r
+      for (entryPtr=Tcl_FirstHashEntry(&statePtr->hash,&search); \r
+          entryPtr!=NULL;\r
+          entryPtr=Tcl_NextHashEntry(&search)) {\r
+\r
+       thandle=(MysqlTclHandle *)Tcl_GetHashValue(entryPtr);\r
+       if (thandle->connection == handle->connection &&\r
+           thandle->type!=HT_CONNECTION) {\r
+         qentries[qfound++] = entryPtr;\r
+       }\r
+       if (qfound==16) break;\r
+      }\r
+      if (qfound>0) {\r
+       for(i=0;i<qfound;i++) {\r
+         entryPtr=qentries[i];\r
+         thandle=(MysqlTclHandle *)Tcl_GetHashValue(entryPtr);\r
+         Tcl_DeleteHashEntry(entryPtr);\r
+         closeHandle(thandle);\r
+       }\r
+      }\r
+      if (qfound!=16) break;\r
+      qfound = 0;\r
+    }\r
+  }\r
+  entryPtr = Tcl_FindHashEntry(&statePtr->hash,Tcl_GetStringFromObj(objv[1],NULL));\r
+  if (entryPtr) Tcl_DeleteHashEntry(entryPtr);\r
+  closeHandle(handle);\r
+  return TCL_OK;\r
+}\r
+\r
+#ifdef PREPARED_STATEMENT\r
+/*\r
+ *----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_Prepare --\r
+ *    Implements the mysql::prepare command:\r
+ *    usage: mysql::prepare handle statements\r
+ *\r
+ *    results:\r
+ *         prepared statment handle\r
+ */\r
+\r
+static int Mysqltcl_Prepare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData;\r
+\r
+  MysqlTclHandle *handle;\r
+  MysqlTclHandle *shandle;\r
+  MYSQL_STMT *statement;\r
+  char *query;\r
+  int queryLen;\r
+  int resultColumns;\r
+  int paramCount;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "handle sql-statement")) == 0)\r
+    return TCL_ERROR;\r
+\r
+  statement = mysql_stmt_init(handle->connection);\r
+  if (statement==NULL) {\r
+       return TCL_ERROR;\r
+  }\r
+  query = (char *)Tcl_GetByteArrayFromObj(objv[2], &queryLen);\r
+  if (mysql_stmt_prepare(statement,query,queryLen)) {\r
+\r
+       mysql_stmt_close(statement);\r
+    return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  if ((shandle = createHandleFrom(statePtr,handle,HT_STATEMENT)) == NULL) return TCL_ERROR;\r
+  shandle->statement=statement;\r
+  shandle->resultMetadata = mysql_stmt_result_metadata(statement);\r
+  shandle->paramMetadata = mysql_stmt_param_metadata(statement);\r
+  /* set result bind memory */\r
+  resultColumns = mysql_stmt_field_count(statement);\r
+  if (resultColumns>0) {\r
+       shandle->bindResult = (MYSQL_BIND *)Tcl_Alloc(sizeof(MYSQL_BIND)*resultColumns);\r
+    memset(shandle->bindResult,0,sizeof(MYSQL_BIND)*resultColumns);\r
+  }\r
+  paramCount = mysql_stmt_param_count(statement);\r
+  if (resultColumns>0) {\r
+       shandle->bindParam = (MYSQL_BIND *)Tcl_Alloc(sizeof(MYSQL_BIND)*paramCount);\r
+    memset(shandle->bindParam,0,sizeof(MYSQL_BIND)*paramCount);\r
+  }\r
+  Tcl_SetObjResult(interp, Tcl_NewHandleObj(statePtr,shandle));\r
+  return TCL_OK;\r
+}\r
+static int Mysqltcl_ParamMetaData(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData;\r
+  MysqlTclHandle *handle;\r
+  MYSQL_RES *res;\r
+  MYSQL_ROW row;\r
+  Tcl_Obj *colinfo,*resObj;\r
+  unsigned long *lengths;\r
+  int i;\r
+  int colCount;\r
+  MYSQL_FIELD* fld;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "statement-handle")) == 0)\r
+    return TCL_ERROR;\r
+  if(handle->type!=HT_STATEMENT)\r
+       return TCL_ERROR;\r
+\r
+  resObj = Tcl_GetObjResult(interp);\r
+  printf("statement %p count %d\n",handle->statement,mysql_stmt_param_count(handle->statement));\r
+  res = mysql_stmt_result_metadata(handle->statement);\r
+  printf("res %p\n",res);\r
+  if(res==NULL)\r
+       return TCL_ERROR;\r
+\r
+  mysql_field_seek(res, 0) ;\r
+  while ((fld = mysql_fetch_field(res)) != NULL) {\r
+        if ((colinfo = mysql_colinfo(interp,objc,objv,fld, objv[2])) != NULL) {\r
+            Tcl_ListObjAppendElement(interp, resObj, colinfo);\r
+        } else {\r
+            goto conflict;\r
+           }\r
+  }\r
+  conflict:\r
+\r
+  mysql_free_result(res);\r
+  return TCL_OK;\r
+}\r
+/*----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_PSelect --\r
+ *    Implements the mysql::pselect command:\r
+ *    usage: mysql::pselect $statement_handle ?arguments...?\r
+ *\r
+ *    results:\r
+ *         number of returned rows\r
+ */\r
+\r
+static int Mysqltcl_PSelect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData;\r
+  MysqlTclHandle *handle;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "handle sql-statement")) == 0)\r
+    return TCL_ERROR;\r
+  if (handle->type!=HT_STATEMENT) {\r
+       return TCL_ERROR;\r
+  }\r
+  mysql_stmt_reset(handle->statement);\r
+  if (mysql_stmt_execute(handle->statement)) {\r
+       return mysql_server_confl(interp,objc,objv,handle->connection);\r
+  }\r
+  mysql_stmt_bind_result(handle->statement, handle->bindResult);\r
+  mysql_stmt_store_result(handle->statement);\r
+  return TCL_OK;\r
+}\r
+/*----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_PFetch --\r
+ *    Implements the mysql::pfetch command:\r
+ *    usage: mysql::pfetch $statement_handle\r
+ *\r
+ *    results:\r
+ *         number of returned rows\r
+ */\r
+\r
+static int Mysqltcl_PFetch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData;\r
+  MysqlTclHandle *handle;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 2, 2, CL_CONN,\r
+                           "prep-stat-handle")) == 0)\r
+    return TCL_ERROR;\r
+  if (handle->type!=HT_STATEMENT) {\r
+       return TCL_ERROR;\r
+  }\r
+  \r
+  return TCL_OK;\r
+}\r
+/*----------------------------------------------------------------------\r
+ *\r
+ * Mysqltcl_PExecute --\r
+ *    Implements the mysql::pexecute command:\r
+ *    usage: mysql::pexecute statement-handle ?arguments...?\r
+ *\r
+ *    results:\r
+ *         number of effected rows\r
+ */\r
+\r
+static int Mysqltcl_PExecute(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])\r
+{\r
+  MysqltclState *statePtr = (MysqltclState *)clientData;\r
+  MysqlTclHandle *handle;\r
+\r
+  if ((handle = mysql_prologue(interp, objc, objv, 3, 3, CL_CONN,\r
+                           "handle sql-statement")) == 0)\r
+    return TCL_ERROR;\r
+  if (handle->type!=HT_STATEMENT) {\r
+       return TCL_ERROR;\r
+  }\r
+  mysql_stmt_reset(handle->statement);\r
+\r
+  if (mysql_stmt_param_count(handle->statement)!=0) {\r
+         Tcl_SetStringObj(Tcl_GetObjResult(interp),"works only for 0 params",-1);\r
+         return TCL_ERROR;\r
+  }\r
+  if (mysql_stmt_execute(handle->statement))\r
+  {\r
+       Tcl_SetStringObj(Tcl_GetObjResult(interp),mysql_stmt_error(handle->statement),-1);\r
+       return TCL_ERROR;\r
+  }\r
+  return TCL_OK;\r
+}\r
+#endif\r
+\r
+/*\r
+ *----------------------------------------------------------------------\r
+ * Mysqltcl_Init\r
+ * Perform all initialization for the MYSQL to Tcl interface.\r
+ * Adds additional commands to interp, creates message array, initializes\r
+ * all handles.\r
+ *\r
+ * A call to Mysqltcl_Init should exist in Tcl_CreateInterp or\r
+ * Tcl_CreateExtendedInterp.\r
+\r
+ */\r
+\r
+\r
+#ifdef _WINDOWS\r
+__declspec( dllexport )\r
+#endif\r
+int Mysqltcl_Init(interp)\r
+    Tcl_Interp *interp;\r
+{\r
+  char nbuf[MYSQL_SMALL_SIZE];\r
+  MysqltclState *statePtr;\r
\r
+  if (Tcl_InitStubs(interp, "8.1", 0) == NULL)\r
+    return TCL_ERROR;\r
+  if (Tcl_PkgRequire(interp, "Tcl", "8.1", 0) == NULL)\r
+    return TCL_ERROR;\r
+  if (Tcl_PkgProvide(interp, "mysqltcl" , PACKAGE_VERSION) != TCL_OK)\r
+    return TCL_ERROR;\r
+  /*\r
+\r
+   * Initialize the new Tcl commands.\r
+   * Deleting any command will close all connections.\r
+   */\r
+   statePtr = (MysqltclState*)Tcl_Alloc(sizeof(MysqltclState)); \r
+   Tcl_InitHashTable(&statePtr->hash, TCL_STRING_KEYS);\r
+   statePtr->handleNum = 0;\r
+\r
+   Tcl_CreateObjCommand(interp,"mysqlconnect",Mysqltcl_Connect,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqluse", Mysqltcl_Use,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlescape", Mysqltcl_Escape,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlsel", Mysqltcl_Sel,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlnext", Mysqltcl_Fetch,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlseek", Mysqltcl_Seek,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlmap", Mysqltcl_Map,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlexec", Mysqltcl_Exec,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlclose", Mysqltcl_Close,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlinfo", Mysqltcl_Info,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlresult", Mysqltcl_Result,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlcol", Mysqltcl_Col,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlstate", Mysqltcl_State,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlinsertid", Mysqltcl_InsertId,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlquery", Mysqltcl_Query,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlendquery", Mysqltcl_EndQuery,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlbaseinfo", Mysqltcl_BaseInfo,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlping", Mysqltcl_Ping,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlchangeuser", Mysqltcl_ChangeUser,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"mysqlreceive", Mysqltcl_Receive,(ClientData)statePtr, NULL);\r
+   \r
+   Tcl_CreateObjCommand(interp,"::mysql::connect",Mysqltcl_Connect,(ClientData)statePtr, Mysqltcl_Kill);\r
+   Tcl_CreateObjCommand(interp,"::mysql::use", Mysqltcl_Use,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::escape", Mysqltcl_Escape,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::sel", Mysqltcl_Sel,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::fetch", Mysqltcl_Fetch,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::seek", Mysqltcl_Seek,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::map", Mysqltcl_Map,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::exec", Mysqltcl_Exec,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::close", Mysqltcl_Close,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::info", Mysqltcl_Info,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::result", Mysqltcl_Result,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::col", Mysqltcl_Col,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::state", Mysqltcl_State,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::insertid", Mysqltcl_InsertId,(ClientData)statePtr, NULL);\r
+   /* new in mysqltcl 2.0 */\r
+   Tcl_CreateObjCommand(interp,"::mysql::query", Mysqltcl_Query,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::endquery", Mysqltcl_EndQuery,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::baseinfo", Mysqltcl_BaseInfo,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::ping", Mysqltcl_Ping,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::changeuser", Mysqltcl_ChangeUser,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::receive", Mysqltcl_Receive,(ClientData)statePtr, NULL);\r
+   /* new in mysqltcl 3.0 */\r
+   Tcl_CreateObjCommand(interp,"::mysql::autocommit", Mysqltcl_AutoCommit,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::commit", Mysqltcl_Commit,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::rollback", Mysqltcl_Rollback,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::nextresult", Mysqltcl_NextResult,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::moreresult", Mysqltcl_MoreResult,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::warningcount", Mysqltcl_WarningCount,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::isnull", Mysqltcl_IsNull,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::newnull", Mysqltcl_NewNull,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::setserveroption", Mysqltcl_SetServerOption,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::shutdown", Mysqltcl_ShutDown,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::encoding", Mysqltcl_Encoding,(ClientData)statePtr, NULL);\r
+   /* prepared statements */\r
+\r
+#ifdef PREPARED_STATEMENT\r
+   Tcl_CreateObjCommand(interp,"::mysql::prepare", Mysqltcl_Prepare,(ClientData)statePtr, NULL);\r
+   // Tcl_CreateObjCommand(interp,"::mysql::parammetadata", Mysqltcl_ParamMetaData,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::pselect", Mysqltcl_PSelect,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::pselect", Mysqltcl_PFetch,(ClientData)statePtr, NULL);\r
+   Tcl_CreateObjCommand(interp,"::mysql::pexecute", Mysqltcl_PExecute,(ClientData)statePtr, NULL);\r
+#endif\r
+   \r
+\r
+   \r
+   /* Initialize mysqlstatus global array. */\r
+   \r
+   clear_msg(interp);\r
+  \r
+   /* Link the null value element to the corresponding C variable. */\r
+   if ((statePtr->MysqlNullvalue = Tcl_Alloc (12)) == NULL) return TCL_ERROR;\r
+   strcpy (statePtr->MysqlNullvalue, MYSQL_NULLV_INIT);\r
+   sprintf (nbuf, "%s(%s)", MYSQL_STATUS_ARR, MYSQL_STATUS_NULLV);\r
+\r
+   /* set null object in mysqltcl state */\r
+   /* statePtr->nullObjPtr = Mysqltcl_NewNullObj(statePtr); */\r
+   \r
+   if (Tcl_LinkVar(interp,nbuf,(char *)&statePtr->MysqlNullvalue, TCL_LINK_STRING) != TCL_OK)\r
+     return TCL_ERROR;\r
+   \r
+   /* Register the handle object type */\r
+   Tcl_RegisterObjType(&mysqlHandleType);\r
+   /* Register own null type object */\r
+   Tcl_RegisterObjType(&mysqlNullType);\r
+   \r
+   /* A little sanity check.\r
+    * If this message appears you must change the source code and recompile.\r
+   */\r
+   if (strlen(MysqlHandlePrefix) == MYSQL_HPREFIX_LEN)\r
+     return TCL_OK;\r
+   else {\r
+     panic("*** mysqltcl (mysqltcl.c): handle prefix inconsistency!\n");\r
+     return TCL_ERROR ;\r
+   }\r
+}\r
+\r
+#ifdef _WINDOWS\r
+__declspec( dllexport )\r
+#endif\r
+int Mysqltcl_SafeInit(interp)\r
+    Tcl_Interp *interp;\r
+{\r
+  return Mysqltcl_Init(interp);\r
+}\r