[Commits] Rev 4609: merge 10.0-connect in lp:~maria-captains/maria/10.0

Sergei Golubchik serg at mariadb.org
Thu Feb 19 10:37:16 EET 2015


At lp:~maria-captains/maria/10.0

------------------------------------------------------------
revno: 4609 [merge]
revision-id: sergii at pisem.net-20150219083711-hx1b8420m9auiwxa
parent: sergii at pisem.net-20150218193140-aw25ak5ci4xiqscn
parent: bertrandop at gmail.com-20150219002531-3n1fxohzln6vv36f
committer: Sergei Golubchik <sergii at pisem.net>
branch nick: 10.0
timestamp: Thu 2015-02-19 09:37:11 +0100
message:
  merge 10.0-connect
added:
  storage/connect/jsonudf.cpp    jsonudf.cpp-20150211203816-gtd88lms33bcgfg4-1
modified:
  storage/connect/CMakeLists.txt cmakelists.txt-20130118152100-brop9nht76vm6epb-2
  storage/connect/array.h        array.h-20140310175720-4v9qh751lk6dt85v-2
  storage/connect/checklvl.h     checklvl.h-20130118152109-mmnrlp4ll8csqtqq-3
  storage/connect/connect.cc     connect.cc-20130118152127-2616haw0q36d4dmb-1
  storage/connect/ha_connect.cc  ha_connect.cc-20130118152127-2616haw0q36d4dmb-2
  storage/connect/json.cpp       json.cpp-20150115143630-dawznhps8fdj3qme-1
  storage/connect/json.h         json.h-20150117113449-oi0vg3wtfs4nippv-1
  storage/connect/myconn.cpp     myconn.cpp-20130118152118-8rznf4ulkgxm3gnq-13
  storage/connect/mysql-test/connect/r/json.result json.result-20150119174647-g7jmi77xzbi05g32-1
  storage/connect/mysql-test/connect/t/json.test json.test-20150119174647-g7jmi77xzbi05g32-7
  storage/connect/myutil.cpp     myutil.cpp-20130118152118-8rznf4ulkgxm3gnq-14
  storage/connect/odbccat.h      odbccat.h-20130211061514-fy4e6czzzvtjkl4o-1
  storage/connect/odbconn.cpp    odbconn.cpp-20130118152118-8rznf4ulkgxm3gnq-15
  storage/connect/odbconn.h      odbconn.h-20130118152109-mmnrlp4ll8csqtqq-26
  storage/connect/tabdos.h       tabdos.h-20130118152109-mmnrlp4ll8csqtqq-38
  storage/connect/tabjson.cpp    tabjson.cpp-20150115143639-v2h2q40gysdrmpk6-1
  storage/connect/tabjson.h      tabjson.h-20150115143647-cw6fyrcq5j6cz5oi-1
  storage/connect/tabmysql.cpp   tabmysql.cpp-20130118152118-8rznf4ulkgxm3gnq-26
  storage/connect/taboccur.cpp   taboccur.cpp-20130429115006-0ejhae6f11myj97c-1
  storage/connect/tabodbc.cpp    tabodbc.cpp-20130118152118-8rznf4ulkgxm3gnq-27
  storage/connect/tabodbc.h      tabodbc.h-20130118152109-mmnrlp4ll8csqtqq-44
  storage/connect/tabpivot.cpp   tabpivot.cpp-20130118152118-8rznf4ulkgxm3gnq-28
  storage/connect/tabpivot.h     tabpivot.h-20130118152109-mmnrlp4ll8csqtqq-45
  storage/connect/tabtbl.cpp     tabtbl.cpp-20130118152118-8rznf4ulkgxm3gnq-30
  storage/connect/tabutil.cpp    tabutil.cpp-20130429115006-0ejhae6f11myj97c-3
  storage/connect/tabutil.h      tabutil.h-20130429115006-0ejhae6f11myj97c-4
  storage/connect/tabxcl.cpp     tabxcl.cpp-20130429115006-0ejhae6f11myj97c-5
  storage/connect/tabxcl.h       tabxcl.h-20130429115006-0ejhae6f11myj97c-6
  storage/connect/valblk.h       valblk.h-20130118152109-mmnrlp4ll8csqtqq-52
  storage/connect/value.cpp      value.cpp-20130118152118-8rznf4ulkgxm3gnq-35
  storage/connect/xindex.h       xindex.h-20130118152109-mmnrlp4ll8csqtqq-54
  storage/connect/xobject.cpp    xobject.cpp-20130118152118-8rznf4ulkgxm3gnq-37
  storage/connect/xobject.h      xobject.h-20130118152109-mmnrlp4ll8csqtqq-55
=== modified file 'storage/connect/CMakeLists.txt'
--- a/storage/connect/CMakeLists.txt	2015-02-10 12:01:03 +0000
+++ b/storage/connect/CMakeLists.txt	2015-02-19 08:37:11 +0000
@@ -21,9 +21,9 @@ ha_connect.cc connect.cc user_connect.cc
 fmdlex.c osutil.c plugutil.c rcmsg.c rcmsg.h
 array.cpp blkfil.cpp colblk.cpp csort.cpp
 filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp filamzip.cpp
-filter.cpp json.cpp maputil.cpp myutil.cpp plgdbutl.cpp reldef.cpp tabcol.cpp
-tabdos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul.cpp taboccur.cpp
-tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvct.cpp tabvir.cpp
+filter.cpp json.cpp jsonudf.cpp maputil.cpp myutil.cpp plgdbutl.cpp reldef.cpp
+tabcol.cpp tabdos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul.cpp
+taboccur.cpp tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvct.cpp tabvir.cpp
 tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp
 
 array.h blkfil.h block.h catalog.h checklvl.h colblk.h connect.h csort.h
@@ -72,11 +72,6 @@ IF(UNIX)
     message(STATUS "CONNECT: GCC: Some warnings disabled")
   endif(WITH_WARNINGS)
 
-  # Avoid compilation failure in maintainer mode
-  IF(CMAKE_COMPILER_IS_GNUCXX)
-    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-overloaded-virtual -Wno-error=type-limits")
-  ENDIF(CMAKE_COMPILER_IS_GNUCXX)
-
   add_definitions( -DUNIX -DLINUX -DUBUNTU )
 
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -fexceptions -fPIC ")

=== modified file 'storage/connect/array.h'
--- a/storage/connect/array.h	2014-08-07 15:59:21 +0000
+++ b/storage/connect/array.h	2015-01-27 18:18:51 +0000
@@ -50,6 +50,7 @@ class DllExport ARRAY : public XOBJECT,
 //        void  SetCorrel(bool b) {Correlated = b;}
 
   // Methods
+  using XOBJECT::GetIntValue;
   virtual void  Reset(void) {Bot = -1;}
   virtual int   Qcompare(int *, int *);
   virtual bool  Compare(PXOB) {assert(FALSE); return FALSE;}

=== modified file 'storage/connect/checklvl.h'
--- a/storage/connect/checklvl.h	2014-08-22 15:30:22 +0000
+++ b/storage/connect/checklvl.h	2015-02-07 10:33:52 +0000
@@ -40,4 +40,11 @@ enum USETEMP {TMP_NO    =  0,         /*
               TMP_FORCE =  3,         /* Forced for MAP tables         */
               TMP_TEST  =  4};        /* Testing value                 */
 
+/***********************************************************************/
+/*  Following definitions indicate conversion of TEXT columns.         */
+/***********************************************************************/
+enum TYPCONV {TPC_NO   =  0,          /* Never                         */
+              TPC_YES  =  1,          /* Always                        */
+              TPC_SKIP =  2};         /* Skip TEXT columns             */
+
 #endif    // _CHKLVL_DEFINED_

=== modified file 'storage/connect/connect.cc'
--- a/storage/connect/connect.cc	2015-01-06 09:18:04 +0000
+++ b/storage/connect/connect.cc	2015-02-18 23:59:02 +0000
@@ -469,9 +469,12 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
 
     } while (rc == RC_NF);
 
+  if (rc == RC_OK)
+    rc= EvalColumns(g, tdbp, false);
+
  err:
   g->jump_level--;
-  return (rc != RC_OK) ? rc : EvalColumns(g, tdbp, false);
+  return rc;
   } // end of CntReadNext
 
 /***********************************************************************/

=== modified file 'storage/connect/ha_connect.cc'
--- a/storage/connect/ha_connect.cc	2015-01-20 00:21:56 +0000
+++ b/storage/connect/ha_connect.cc	2015-02-11 20:39:41 +0000
@@ -170,18 +170,18 @@
 #define SZWMIN 4194304             // Minimum work area size  4M
 
 extern "C" {
-       char  version[]= "Version 1.03.0006 January 13, 2015";
-       char  compver[]= "Version 1.03.0006 " __DATE__ " "  __TIME__;
+       char  version[]= "Version 1.03.0006 February 06, 2015";
 
 #if defined(WIN32)
+       char  compver[]= "Version 1.03.0006 " __DATE__ " "  __TIME__;
        char slash= '\\';
 #else   // !WIN32
        char slash= '/';
 #endif  // !WIN32
 
 //     int   trace= 0;             // The general trace value
-       ulong xconv= 0;             // The type conversion option
-       int   zconv= 0;             // The text conversion size
+//     ulong xconv= 0;             // The type conversion option
+//     int   zconv= 0;             // The text conversion size
 } // extern "C"
 
 #if defined(XMAP)
@@ -215,6 +215,8 @@ bool    CheckSelf(PGLOBAL g, TABLE_SHARE
                   const char *db, char *tab, const char *src, int port);
 bool    ExactInfo(void);
 USETEMP UseTemp(void);
+int     GetConvSize(void);
+TYPCONV GetTypeConv(void);
 uint    GetWorkSize(void);
 void    SetWorkSize(uint);
 extern "C" const char *msglang(void);
@@ -289,6 +291,38 @@ static MYSQL_THDVAR_UINT(work_size,
        "Size of the CONNECT work area.",
        NULL, NULL, SZWORK, SZWMIN, UINT_MAX, 1);
 
+// Size used when converting TEXT columns to VARCHAR
+static MYSQL_THDVAR_INT(conv_size,
+       PLUGIN_VAR_RQCMDARG,             // opt
+       "Size used when converting TEXT columns.",
+       NULL, NULL, SZCONV, 0, 65500, 1);
+
+/**
+  Type conversion:
+    no:   Unsupported types -> TYPE_ERROR
+    yes:  TEXT -> VARCHAR
+    skip: skip unsupported type columns in Discovery
+*/
+const char *xconv_names[]=
+{
+  "NO", "YES", "SKIP", NullS
+};
+
+TYPELIB xconv_typelib=
+{
+  array_elements(xconv_names) - 1, "xconv_typelib",
+  xconv_names, NULL
+};
+
+static MYSQL_THDVAR_ENUM(
+  type_conv,                       // name
+  PLUGIN_VAR_RQCMDARG,             // opt
+  "Unsupported types conversion.", // comment
+  NULL,                            // check
+  NULL,                            // update function
+  0,                               // def (no)
+  &xconv_typelib);                 // typelib
+
 #if defined(XMSG) || defined(NEWMSG)
 const char *language_names[]=
 {
@@ -317,6 +351,8 @@ static MYSQL_THDVAR_ENUM(
 extern "C" int GetTraceValue(void) {return THDVAR(current_thd, xtrace);}
 bool ExactInfo(void) {return THDVAR(current_thd, exact_info);}
 USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);}
+int GetConvSize(void) {return THDVAR(current_thd, conv_size);}
+TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);}
 uint GetWorkSize(void) {return THDVAR(current_thd, work_size);}
 void SetWorkSize(uint n) 
 {
@@ -598,7 +634,11 @@ static int connect_init_func(void *p)
   }
 #endif   // 0 (LINUX)
 
+#if defined(WIN32)
   sql_print_information("CONNECT: %s", compver);
+#else   // !WIN32
+  sql_print_information("CONNECT: %s", version);
+#endif  // !WIN32
 
 #ifdef LIBXML2_SUPPORT
   XmlInitParserLib();
@@ -934,6 +974,9 @@ ulonglong ha_connect::table_flags() cons
 char *GetListOption(PGLOBAL g, const char *opname,
                                const char *oplist, const char *def)
 {
+  if (!oplist)
+    return (char*)def;
+
   char  key[16], val[256];
   char *pk, *pv, *pn;
   char *opval= (char*) def;
@@ -997,8 +1040,12 @@ char *ha_connect::GetRealString(const ch
   char *sv;
 
   if (IsPartitioned() && s) {
-    sv= (char*)PlugSubAlloc(xp->g, NULL, strlen(s) + strlen(partname));
+//  sv= (char*)PlugSubAlloc(xp->g, NULL, strlen(s) + strlen(partname));
+    // With wrong string pattern, the size of the constructed string
+    // can be more than strlen(s) + strlen(partname)
+    sv= (char*)PlugSubAlloc(xp->g, NULL, 0);
     sprintf(sv, s, partname);
+    PlugSubAlloc(xp->g, NULL, strlen(sv) + 1);
   } else
     sv= (char*)s;
 
@@ -1064,9 +1111,16 @@ char *ha_connect::GetStringOption(char *
 
   } // endif Table_charset
 
-  if (!opval && options && options->oplist)
+  if (!opval && options && options->oplist) {
     opval= GetListOption(xp->g, opname, options->oplist);
 
+    if (opval && (!stricmp(opname, "connect") 
+               || !stricmp(opname, "tabname") 
+               || !stricmp(opname, "filename")))
+      opval = GetRealString(opval);
+
+    } // endif opval
+
   if (!opval) {
     if (sdef && !strcmp(sdef, "*")) {
       // Return the handler default value
@@ -2467,6 +2521,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, P
   char *body= filp->Body;
   unsigned int i;
   bool  ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
+  bool  nonul= (tty == TYPE_AM_ODBC && (tdbp->GetMode() == MODE_INSERT ||
+                                        tdbp->GetMode() == MODE_DELETE));
   OPVAL vop= OP_XX;
 
   if (!cond)
@@ -2484,7 +2540,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, P
 
     if (trace)
       htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
-                                         cond_item->func_name());
+                                       cond_item->func_name());
 
     switch (cond_item->functype()) {
       case Item_func::COND_AND_FUNC: vop= OP_AND; break;
@@ -2503,7 +2559,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, P
     for (i= 0; i < arglist->elements; i++)
       if ((subitem= li++)) {
         if (!CheckCond(g, filp, tty, subitem)) {
-          if (vop == OP_OR)
+          if (vop == OP_OR || nonul)
             return NULL;
           else
             *p2= 0;
@@ -2599,6 +2655,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, P
         if (trace) {
           htrc("Field index=%d\n", pField->field->field_index);
           htrc("Field name=%s\n", pField->field->field_name);
+          htrc("Field type=%d\n", pField->field->type());
+          htrc("Field_type=%d\n", args[i]->field_type());
           } // endif trace
 
         // IN and BETWEEN clauses should be col VOP list
@@ -2618,8 +2676,9 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, P
         char    buff[256];
         String *res, tmp(buff, sizeof(buff), &my_charset_bin);
         Item_basic_constant *pval= (Item_basic_constant *)args[i];
+        Item::Type type= args[i]->real_type();
 
-        switch (args[i]->real_type()) {
+        switch (type) {
           case COND::STRING_ITEM:
           case COND::INT_ITEM:
           case COND::REAL_ITEM:
@@ -2644,10 +2703,64 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, P
 
         if (!x) {
           // Append the value to the filter
-          if (args[i]->field_type() == MYSQL_TYPE_VARCHAR)
-            strcat(strncat(strcat(body, "'"), res->ptr(), res->length()), "'");
-          else
-            strncat(body, res->ptr(), res->length());
+          switch (args[i]->field_type()) {
+            case MYSQL_TYPE_TIMESTAMP:
+            case MYSQL_TYPE_DATETIME:
+              if (tty == TYPE_AM_ODBC) {
+                strcat(body, "{ts '");
+                strcat(strncat(body, res->ptr(), res->length()), "'}");
+                break;
+                } // endif ODBC
+
+            case MYSQL_TYPE_DATE:
+              if (tty == TYPE_AM_ODBC) {
+                strcat(body, "{d '");
+                strcat(strncat(body, res->ptr(), res->length()), "'}");
+                break;
+                } // endif ODBC
+
+            case MYSQL_TYPE_TIME:
+              if (tty == TYPE_AM_ODBC) {
+                strcat(body, "{t '");
+                strcat(strncat(body, res->ptr(), res->length()), "'}");
+                break;
+                } // endif ODBC
+
+            case MYSQL_TYPE_VARCHAR:
+              if (tty == TYPE_AM_ODBC && i) {
+                switch (args[0]->field_type()) {
+                  case MYSQL_TYPE_TIMESTAMP:
+                  case MYSQL_TYPE_DATETIME:
+                    strcat(body, "{ts '");
+                    strncat(body, res->ptr(), res->length());
+                    strcat(body, "'}");
+                    break;
+                  case MYSQL_TYPE_DATE:
+                    strcat(body, "{d '");
+                    strncat(body, res->ptr(), res->length());
+                    strcat(body, "'}");
+                    break;
+                  case MYSQL_TYPE_TIME:
+                    strcat(body, "{t '");
+                    strncat(body, res->ptr(), res->length());
+                    strcat(body, "'}");
+                    break;
+                  default:
+                    strcat(body, "'");
+                    strncat(body, res->ptr(), res->length());
+                    strcat(body, "'");
+                  } // endswitch field type
+
+              } else {
+                strcat(body, "'");
+                strncat(body, res->ptr(), res->length());
+                strcat(body, "'");
+              } // endif tty
+
+              break;
+            default:
+              strncat(body, res->ptr(), res->length());
+            } // endswitch field type
 
         } else {
           if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) {
@@ -2753,7 +2866,7 @@ const COND *ha_connect::cond_push(const
       } else if (x && cond)
         tdbp->SetCondFil(filp);   // Wrong filter
 
-    } else
+    } else if (tty != TYPE_AM_JSN && tty != TYPE_AM_JSON)
       tdbp->SetFilter(CondFilter(g, (Item *)cond));
 
    fin:
@@ -4620,7 +4733,7 @@ static bool add_field(String *sql, const
                       char *dft, char *xtra, int flag, bool dbf, char v)
 {
   char var = (len > 255) ? 'V' : v;
-  bool error= false;
+  bool q, error= false;
   const char *type= PLGtoMYSQLtype(typ, dbf, var);
 
   error|= sql->append('`');
@@ -4661,7 +4774,12 @@ static bool add_field(String *sql, const
   if (dft && *dft) {
     error|= sql->append(" DEFAULT ");
 
-    if (!IsTypeNum(typ)) {
+    if (typ == TYPE_DATE)
+      q = (strspn(dft, "0123456789 -:/") == strlen(dft));
+    else
+      q = !IsTypeNum(typ);
+
+    if (q) {
       error|= sql->append("'");
       error|= sql->append_for_single_quote(dft, strlen(dft));
       error|= sql->append("'");
@@ -4831,6 +4949,9 @@ static int connect_assisted_discovery(ha
   int         port= 0, hdr= 0, mxr __attribute__((unused))= 0, mxe= 0, rc= 0;
   int         cop __attribute__((unused)) = 0;
 #if defined(ODBC_SUPPORT)
+  POPARM      sop = NULL;
+  char       *ucnc = NULL;
+  bool        cnc= false;
   int         cto= -1, qto= -1;
 #endif   // ODBC_SUPPORT
   uint        tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
@@ -4875,7 +4996,8 @@ static int connect_assisted_discovery(ha
 
   if (topt->oplist) {
     host= GetListOption(g, "host", topt->oplist, "localhost");
-    user= GetListOption(g, "user", topt->oplist, "root");
+    user= GetListOption(g, "user", topt->oplist, 
+                       (ttp == TAB_ODBC ? NULL : "root"));
     // Default value db can come from the DBNAME=xxx option.
     db= GetListOption(g, "database", topt->oplist, db);
     col= GetListOption(g, "colist", topt->oplist, col);
@@ -4894,6 +5016,9 @@ static int connect_assisted_discovery(ha
     mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
     cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1"));
     qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1"));
+    
+    if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
+      cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
 #endif
     mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
 #if defined(PROMPT_OK)
@@ -4901,7 +5026,7 @@ static int connect_assisted_discovery(ha
 #endif   // PROMPT_OK
   } else {
     host= "localhost";
-    user= "root";
+    user= (ttp == TAB_ODBC ? NULL : "root");
   } // endif option_list
 
   if (!(shm= (char*)db))
@@ -4978,10 +5103,18 @@ static int connect_assisted_discovery(ha
           } // endif dsn
 #endif   // PROMPT_OK
 
-      } else if (!dsn)
+      } else if (!dsn) {
         sprintf(g->Message, "Missing %s connection string", topt->type);
-      else
+      } else {
+        // Store ODBC additional parameters
+        sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
+        sop->User= (char*)user;
+        sop->Pwd= (char*)pwd;
+        sop->Cto= cto;
+        sop->Qto= qto;
+        sop->UseCnc= cnc;
         ok= true;
+      } // endif's
 
       supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
       break;
@@ -5112,15 +5245,15 @@ static int connect_assisted_discovery(ha
           case FNC_NO:
           case FNC_COL:
             if (src) {
-              qrp= ODBCSrcCols(g, dsn, (char*)src, cto, qto);
+              qrp= ODBCSrcCols(g, dsn, (char*)src, sop); 
               src= NULL;     // for next tests
             } else
-              qrp= ODBCColumns(g, dsn, shm, tab, NULL,
-                               mxr, cto, qto, fnc == FNC_COL);
+              qrp= ODBCColumns(g, dsn, shm, tab, NULL, 
+                               mxr, fnc == FNC_COL, sop);
 
             break;
           case FNC_TABLE:
-            qrp= ODBCTables(g, dsn, shm, tab, mxr, cto, qto, true);
+            qrp= ODBCTables(g, dsn, shm, tab, mxr, true, sop);
             break;
           case FNC_DSN:
             qrp= ODBCDataSources(g, mxr, true);
@@ -5237,9 +5370,10 @@ static int connect_assisted_discovery(ha
         for (crp= qrp->Colresp; crp; crp= crp->Next)
           switch (crp->Fld) {
             case FLD_NAME:
-              if (ttp == TAB_CSV && topt->data_charset &&
+              if (ttp == TAB_PRX || 
+                 (ttp == TAB_CSV && topt->data_charset &&
                  (!stricmp(topt->data_charset, "UTF8") ||
-                  !stricmp(topt->data_charset, "UTF-8")))
+                  !stricmp(topt->data_charset, "UTF-8"))))
                 cnm= crp->Kdata->GetCharValue(i);
               else
                 cnm= encode(g, crp->Kdata->GetCharValue(i));
@@ -5299,9 +5433,18 @@ static int connect_assisted_discovery(ha
 
           // typ must be PLG type, not SQL type
           if (!(plgtyp= TranslateSQLType(typ, dec, prec, v))) {
-            sprintf(g->Message, "Unsupported SQL type %d", typ);
-            my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
-            goto err;
+            if (GetTypeConv() == TPC_SKIP) {
+              // Skip this column
+              sprintf(g->Message, "Column %s skipped (unsupported type %d)",
+                      cnm, typ);
+              push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+              continue;
+            } else {
+              sprintf(g->Message, "Unsupported SQL type %d", typ);
+              my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+              goto err;
+            } // endif type_conv
+
           } else
             typ= plgtyp;
 
@@ -6341,58 +6484,6 @@ struct st_mysql_storage_engine connect_s
 /***********************************************************************/
 /*  CONNECT global variables definitions.                              */
 /***********************************************************************/
-// Size used when converting TEXT columns to VARCHAR
-#if defined(_DEBUG)
-static MYSQL_SYSVAR_INT(conv_size, zconv,
-       PLUGIN_VAR_RQCMDARG,             // opt
-       "Size used when converting TEXT columns.",
-       NULL, NULL, SZCONV, 0, 65500, 1);
-#else
-static MYSQL_SYSVAR_INT(conv_size, zconv,
-       PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,  // opt
-       "Size used when converting TEXT columns.",
-       NULL, NULL, SZCONV, 0, 65500, 1);
-#endif
-
-/**
-  Type conversion:
-    no:   Unsupported types -> TYPE_ERROR
-    yes:  TEXT -> VARCHAR
-    skip: skip unsupported type columns in Discovery
-*/
-const char *xconv_names[]=
-{
-  "NO", "YES", "SKIP", NullS
-};
-
-TYPELIB xconv_typelib=
-{
-  array_elements(xconv_names) - 1, "xconv_typelib",
-  xconv_names, NULL
-};
-
-#if defined(_DEBUG)
-static MYSQL_SYSVAR_ENUM(
-  type_conv,                       // name
-  xconv,                           // varname
-  PLUGIN_VAR_RQCMDARG,             // opt
-  "Unsupported types conversion.", // comment
-  NULL,                            // check
-  NULL,                            // update function
-  0,                               // def (no)
-  &xconv_typelib);                 // typelib
-#else
-static MYSQL_SYSVAR_ENUM(
-  type_conv,                       // name
-  xconv,                           // varname
-  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
-  "Unsupported types conversion.", // comment
-  NULL,                            // check
-  NULL,                            // update function
-  0,                               // def (no)
-  &xconv_typelib);                 // typelib
-#endif
-
 #if defined(XMAP)
 // Using file mapping for indexes if true
 static MYSQL_SYSVAR_BOOL(indx_map, xmap, PLUGIN_VAR_RQCMDARG,

=== modified file 'storage/connect/json.cpp'
--- a/storage/connect/json.cpp	2015-01-20 00:21:56 +0000
+++ b/storage/connect/json.cpp	2015-02-18 23:59:02 +0000
@@ -1,1055 +1,1106 @@
-/*************** json CPP Declares Source Code File (.H) ***************/
-/*  Name: json.cpp   Version 1.0                                       */
-/*                                                                     */
-/*  (C) Copyright to the author Olivier BERTRAND          2014 - 2015  */
-/*                                                                     */
-/*  This file contains the JSON classes functions.                     */
-/***********************************************************************/
-
-/***********************************************************************/
-/*  Include relevant sections of the MariaDB header file.              */
-/***********************************************************************/
-#include <my_global.h>
-
-/***********************************************************************/
-/*  Include application header files:                                  */
-/*  global.h    is header containing all global declarations.          */
-/*  plgdbsem.h  is header containing the DB application declarations.  */
-/*  xjson.h     is header containing the JSON classes declarations.    */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "json.h"
-
-#define ARGS       MY_MIN(24,len-i),s+MY_MAX(i-3,0)
-
-#if defined(WIN32)
-#define EL  "\r\n"
-#else
-#define EL  "\n"
-#endif
-
-/***********************************************************************/
-/* Parse a json string.                                                */
-/***********************************************************************/
-PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
-{
-  int   i;
-  bool  b = false;
-  PJSON jsp = NULL;
-  STRG  src;
-
-  if (!s || !len) {
-    strcpy(g->Message, "Void JSON object");
-    return NULL;
-  } else if (comma)
-    *comma = false;
-
-  src.str = s;
-  src.len = len;
-
-  for (i = 0; i < len; i++)
-    switch (s[i]) {
-      case '[':
-        if (jsp) {
-          strcpy(g->Message, "More than one item in file");
-          return NULL;
-        } else if (!(jsp = ParseArray(g, ++i, src)))
-          return NULL;
-
-        break;
-      case '{':
-        if (jsp) {
-          strcpy(g->Message, "More than one item in file");
-          return NULL;
-        } else if (!(jsp = ParseObject(g, ++i, src)))
-          return NULL;
-        break;
-      case ' ':
-      case '\t':
-      case '\n':
-      case '\r':
-        break;
-      case ',':
-        if (jsp && pretty == 1) {
-          if (comma)
-            *comma = true;
-
-          break;
-          } // endif pretty
-
-        sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
-        return NULL;
-      case '(':
-        b = true;
-        break;
-      case ')':
-        if (b) {
-          b = false;
-          break;
-          } // endif b
-
-      default:
-        sprintf(g->Message, "Bad '%c' character near %.*s",
-                s[i], ARGS);
-        return NULL;
-    }; // endswitch s[i]
-
-  if (!jsp)
-    sprintf(g->Message, "Invalid Json string '%.*s'", 50, s);
-
-  return jsp;
-} // end of ParseJson
-
-/***********************************************************************/
-/* Parse a JSON Array.                                                 */
-/***********************************************************************/
-PJAR ParseArray(PGLOBAL g, int& i, STRG& src)
-{
-  char  *s = src.str;
-  int    len = src.len;
-  int    level = 0;
-  PJAR   jarp = new(g) JARRAY;
-  PJVAL  jvp = NULL;
-
-  for (; i < len; i++)
-    switch (s[i]) {
-      case ',':
-        if (level < 2) {
-          sprintf(g->Message, "Unexpected ',' near %.*s",ARGS);
-          return NULL;
-        } else
-          level = 1;
-
-        break;
-      case ']':
-        if (level == 1) {
-          sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
-          return NULL;
-          } // endif level
-
-        jarp->InitArray(g);
-        return jarp;
-      case ' ':
-      case '\t':
-      case '\n':
-      case '\r':
-        break;
-      default:
-        if (level == 2) {
-          sprintf(g->Message, "Unexpected value near %.*s", ARGS);
-          return NULL;
-        } else if ((jvp = ParseValue(g, i, src))) {
-          jarp->AddValue(g, jvp);
-          level = 2;
-        } else
-          return NULL;
-
-        level = 2;
-        break;
-    }; // endswitch s[i]
-
-  strcpy(g->Message, "Unexpected EOF in array");
-  return NULL;
-} // end of ParseArray
-
-/***********************************************************************/
-/* Parse a JSON Object.                                                */
-/***********************************************************************/
-PJOB ParseObject(PGLOBAL g, int& i, STRG& src)
-{
-  PSZ   key;
-  char *s = src.str;
-  int   len = src.len;
-  int   level = 0;
-  PJOB  jobp = new(g) JOBJECT;
-  PJPR  jpp = NULL;
-
-  for (; i < len; i++)
-    switch (s[i]) {
-      case '"':
-        if (level < 2) {
-          if ((key = ParseString(g, ++i, src))) {
-            jpp = jobp->AddPair(g, key);
-            level = 1;
-          } else
-            return NULL;
-
-        } else {
-          sprintf(g->Message, "misplaced string near %.*s", ARGS);
-          return NULL;
-        } // endif level
-
-        break;
-      case ':':
-        if (level == 1) {
-          if (!(jpp->Val = ParseValue(g, ++i, src)))
-            return NULL;
-
-          level = 2;
-        } else {
-          sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
-          return NULL;
-        } // endif level
-
-        break;
-      case ',':
-        if (level < 2) {
-          sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
-          return NULL;
-        } else
-          level = 1;
-
-        break;
-      case '}':
-        if (level == 1) {
-          sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
-          return NULL;
-          } // endif level
-
-        return jobp;
-      case ' ':
-      case '\t':
-      case '\n':
-      case '\r':
-        break;
-      default:
-        sprintf(g->Message, "Unexpected character '%c' near %.*s",
-                s[i], ARGS);
-        return NULL;
-    }; // endswitch s[i]
-
-  strcpy(g->Message, "Unexpected EOF in Object");
-  return NULL;
-} // end of ParseObject
-
-/***********************************************************************/
-/* Parse a JSON Value.                                                 */
-/***********************************************************************/
-PJVAL ParseValue(PGLOBAL g, int& i, STRG& src)
-{
-  char *strval, *s = src.str;
-  int   n, len = src.len;
-  PJVAL jvp = new(g) JVALUE;
-
-  for (; i < len; i++)
-    switch (s[i]) {
-      case ' ':
-      case '\t':
-      case '\n':
-      case '\r':
-        break;
-      default:
-        goto suite;
-    } // endswitch
-
- suite:
-  switch (s[i]) {
-    case '[':
-      if (!(jvp->Jsp = ParseArray(g, ++i, src)))
-        return NULL;
-
-      break;
-    case '{':
-      if (!(jvp->Jsp = ParseObject(g, ++i, src)))
-        return NULL;
-
-      break;
-    case '"':
-      if ((strval = ParseString(g, ++i, src)))
-        jvp->Value = AllocateValue(g, strval, TYPE_STRING);
-      else
-        return NULL;
-
-      break;
-    case 't':
-      if (!strncmp(s + i, "true", 4)) {
-        n = 1;
-        jvp->Value = AllocateValue(g, &n, TYPE_TINY);
-        i += 3;
-      } else
-        goto err;
-
-      break;
-    case 'f':
-      if (!strncmp(s + i, "false", 5)) {
-        n = 0;
-        jvp->Value = AllocateValue(g, &n, TYPE_TINY);
-        i += 4;
-      } else
-        goto err;
-
-      break;
-    case 'n':
-      if (!strncmp(s + i, "null", 4))
-        i += 3;
-      else
-        goto err;
-
-      break;
-    case '-':
-    default:
-      if (s[i] == '-' || isdigit(s[i])) {
-        if (!(jvp->Value = ParseNumeric(g, i, src)))
-          goto err;
-
-      } else
-        goto err;
-
-    }; // endswitch s[i]
-
-  jvp->Size = 1;
-  return jvp;
-
-err:
-  sprintf(g->Message, "Unexpected character '%c' near %.*s",
-          s[i], ARGS);
-  return NULL;
-} // end of ParseValue
-
-/***********************************************************************/
-/*  Unescape and parse a JSON string.                                  */
-/***********************************************************************/
-char *ParseString(PGLOBAL g, int& i, STRG& src)
-{
-  char *p, *s = src.str;
-  int   n = 0, len = src.len;
-
-  // The size to allocate is not known yet
-  p = (char*)PlugSubAlloc(g, NULL, 0);
-
-  for (; i < len; i++)
-    switch (s[i]) {
-      case '"':
-        p[n++] = 0;
-        PlugSubAlloc(g, NULL, n);
-        return p;
-      case '\\':
-        if (++i < len) {
-          if (s[i] == 'u') {
-            if (len - i > 5) {
-//            if (charset == utf8) {
-                char xs[5];
-                uint hex;
-            
-                xs[0] = s[++i];
-                xs[1] = s[++i];
-                xs[2] = s[++i];
-                xs[3] = s[++i];
-                xs[4] = 0;
-                hex = strtoul(xs, NULL, 16);
-            
-                if (hex < 0x80) {
-                  p[n] = (uchar)hex;
-                } else if (hex < 0x800) {
-                  p[n++] = (uchar)(0xC0 | (hex >> 6));
-                  p[n]   = (uchar)(0x80 | (hex & 0x3F));
-                } else if (hex < 0x10000) {
-                  p[n++] = (uchar)(0xE0 | (hex >> 12));
-                  p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
-                  p[n]   = (uchar)(0x80 | (hex & 0x3f));
-                } else
-                  p[n] = '?';
-
-#if 0
-              } else {
-                char xs[3];
-                UINT hex;
-            
-                i += 2;
-                xs[0] = s[++i];
-                xs[1] = s[++i];
-                xs[2] = 0;
-                hex = strtoul(xs, NULL, 16);
-                p[n] = (char)hex;
-              } // endif charset
-#endif // 0
-            } else
-              goto err;
-
-          } else switch(s[i]) {
-            case 't': p[n] = '\t'; break;
-            case 'n': p[n] = '\n'; break;
-            case 'r': p[n] = '\r'; break;
-            case 'b': p[n] = '\b'; break;
-            case 'f': p[n] = '\f'; break;
-            default:  p[n] = s[i]; break;
-            } // endswitch
-
-          n++;
-        } else
-          goto err;
-
-        break;
-      default:
-        p[n++] = s[i];
-        break;
-      }; // endswitch s[i]
-
- err:
-  strcpy(g->Message, "Unexpected EOF in String");
-  return NULL;
-} // end of ParseString
-
-/***********************************************************************/
-/* Parse a JSON numeric value.                                         */
-/***********************************************************************/
-PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src)
-{
-  char *s = src.str, buf[50];
-  int   n = 0, len = src.len;
-  short nd = 0;
-	bool  has_dot = false;
-	bool  has_e = false;
-	bool  found_digit = false;
-  PVAL  valp = NULL;
-
-  for (; i < len; i++) {
-    switch (s[i]) {
-      case '.':
-        if (!found_digit || has_dot || has_e)
-          goto err;
-        
-        has_dot = true;
-        break;
-      case 'e':
-      case 'E':
-        if (!found_digit || has_e)
-          goto err;
-
-        has_e = true;
-        found_digit = false;
-        break;
-      case '+':
-        if (!has_e)
-          goto err;
-
-        // passthru
-      case '-':
-        if (found_digit)
-          goto err;
-
-        break;
-      default:
-        if (isdigit(s[i])) {
-          if (has_dot && !has_e)
-            nd++;       // Number of decimals
-
-          found_digit = true;
-        } else
-          goto fin;
-
-      }; // endswitch s[i]
-
-    buf[n++] = s[i];
-    } // endfor i
-
- fin:
-  if (found_digit) {
-    buf[n] = 0;
-
-    if (has_dot || has_e) {
-      double dv = strtod(buf, NULL);
-
-      valp = AllocateValue(g, &dv, TYPE_DOUBLE, nd);
-    } else {
-      int iv = strtol(buf, NULL, 10);
-
-      valp = AllocateValue(g, &iv, TYPE_INT);
-    } // endif has
-
-    i--;  // Unstack  following character
-    return valp;
-  } else {
-    strcpy(g->Message, "No digit found");
-    return NULL;
-  } // endif found_digit
-
- err:
-  strcpy(g->Message, "Unexpected EOF in number");
-  return NULL;
-} // end of ParseNumeric
-
-/***********************************************************************/
-/* Serialize a JSON tree:                                              */
-/***********************************************************************/
-PSZ Serialize(PGLOBAL g, PJSON jsp, FILE *fs, int pretty)
-{
-  bool  b = false, err = true;
-  JOUT *jp;
-
-  g->Message[0] = 0;
-
-  if (!jsp) {
-    strcpy(g->Message, "Null json tree");
-    return NULL;
-  } else if (!fs) {
-    // Serialize to a string
-    jp = new(g) JOUTSTR(g);
-    b = pretty == 1;
-  } else if (pretty == 2) {
-    // Serialize to a pretty file
-    jp = new(g) JOUTPRT(g, fs);
-  } else {
-    // Serialize to a flat file
-    jp = new(g) JOUTFILE(g, fs);
-    b = pretty == 1;
-  } // endif's
-
-  switch (jsp->GetType()) {
-    case TYPE_JAR:
-      err = SerializeArray(jp, (PJAR)jsp, b);
-      break;
-    case TYPE_JOB:
-      err = (b && jp->WriteChr('\t'));
-      err |= SerializeObject(jp, (PJOB)jsp);
-      break;
-    default:
-      strcpy(g->Message, "json tree is not an Array or an Object");
-    } // endswitch Type
-
-  if (fs) {
-    fputc('\n', fs);
-    fclose(fs);
-    return (err) ? g->Message : NULL;
-  } else if (!err) {
-    PSZ str = ((JOUTSTR*)jp)->Strp;
-
-    jp->WriteChr('\0');
-    PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
-    return str;
-  } else {
-    if (!g->Message[0])
-      strcpy(g->Message, "Error in Serialize");
-
-    return NULL;
-  } // endif's
-
-} // end of Serialize
-
-/***********************************************************************/
-/* Serialize a JSON Array.                                             */
-/***********************************************************************/
-bool SerializeArray(JOUT *js, PJAR jarp, bool b)
-{
-  bool first = true;
-
-
-  if (js->WriteChr('['))
-    return true;
-  else if (b && (js->WriteStr(EL) || js->WriteChr('\t')))
-    return true;
-
-  for (int i = 0; i < jarp->size(); i++) {
-    if (first)
-      first = false;
-    else if (js->WriteChr(','))
-      return true;
-    else if (b && (js->WriteStr(EL) || js->WriteChr('\t')))
-      return true;
-
-    if (SerializeValue(js, jarp->GetValue(i)))
-      return true;
-
-    } // endfor i
-
-  if (b && js->WriteStr(EL))
-    return true;
-
-  return js->WriteChr(']');
-} // end of SerializeArray
-
-/***********************************************************************/
-/* Serialize a JSON Object.                                            */
-/***********************************************************************/
-bool SerializeObject(JOUT *js, PJOB jobp)
-{
-  bool first = true;
-
-  if (js->WriteChr('{'))
-    return true;
-
-  for (PJPR pair = jobp->First; pair; pair = pair->Next) {
-    if (first)
-      first = false;
-    else if (js->WriteChr(','))
-      return true;
-
-    if (js->WriteChr('\"') ||
-        js->WriteStr(pair->Key) ||
-        js->WriteChr('\"') ||
-        js->WriteChr(':') ||
-        SerializeValue(js, pair->Val))
-      return true;
-
-    } // endfor i
-
-  return js->WriteChr('}');
-} // end of SerializeObject
-
-/***********************************************************************/
-/* Serialize a JSON Value.                                             */
-/***********************************************************************/
-bool SerializeValue(JOUT *js, PJVAL jvp)
-{
-  PJAR jap;
-  PJOB jop;
-  PVAL valp;
-
-  if ((jap = jvp->GetArray()))
-    return SerializeArray(js, jap, false);
-  else if ((jop = jvp->GetObject()))
-    return SerializeObject(js, jop);
-  else if (!(valp = jvp->Value) || valp->IsNull())
-    return js->WriteStr("null");
-  else switch (valp->GetType()) {
-    case TYPE_TINY:
-      return js->WriteStr(valp->GetTinyValue() ? "true" : "false");
-    case TYPE_STRING:
-      return js->Escape(valp->GetCharValue());
-    default:
-      if (valp->IsTypeNum()) {
-        char buf[32];
-
-        return js->WriteStr(valp->GetCharString(buf));
-        } // endif valp
-
-    } // endswitch Type
-
-strcpy(js->g->Message, "Unrecognized value");
-return true;
-} // end of SerializeValue
-
-/* -------------------------- Class JOUTSTR -------------------------- */
-
-/***********************************************************************/
-/* JOUTSTR constructor.                                                */
-/***********************************************************************/
-JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g)
-{
-  PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
-
-  N = 0;
-  Max = pph->FreeBlk;
-  Max = (Max > 512) ? Max - 512 : Max;
-  Strp = (char*)PlugSubAlloc(g, NULL, 0);  // Size not know yet
-} // end of JOUTSTR constructor
-
-/***********************************************************************/
-/* Concatenate a string to the Serialize string.                       */
-/***********************************************************************/
-bool JOUTSTR::WriteStr(const char *s)
-{
-  if (s) {
-    size_t len = strlen(s);
-
-    if (N + len > Max)
-      return true;
-
-    memcpy(Strp + N, s, len);
-    N += len;
-    return false;
-  } else
-    return true;
-
-} // end of WriteStr
-
-/***********************************************************************/
-/* Concatenate a character to the Serialize string.                    */
-/***********************************************************************/
-bool JOUTSTR::WriteChr(const char c)
-{
-  if (N + 1 > Max)
-    return true;
-
-  Strp[N++] = c;
-  return false;
-} // end of WriteChr
-
-/***********************************************************************/
-/* Escape and Concatenate a string to the Serialize string.            */
-/***********************************************************************/
-bool JOUTSTR::Escape(const char *s)
-{
-  WriteChr('"');
-
-  for (unsigned int i = 0; i < strlen(s); i++)
-    switch (s[i]) {
-      case '\t':
-      case '\n':
-      case '\r':
-      case '\b':
-      case '\f':
-      case '"':  WriteChr('\\');
-        // passthru
-      default:
-        WriteChr(s[i]);
-        break;
-      } // endswitch s[i]
-
-  WriteChr('"');
-  return false;
-} // end of Escape
-
-/* ------------------------- Class JOUTFILE -------------------------- */
-
-/***********************************************************************/
-/* Write a string to the Serialize file.                               */
-/***********************************************************************/
-bool JOUTFILE::WriteStr(const char *s)
-{
-  // This is temporary
-  fputs(s, Stream);
-  return false;
-} // end of WriteStr
-
-/***********************************************************************/
-/* Write a character to the Serialize file.                            */
-/***********************************************************************/
-bool JOUTFILE::WriteChr(const char c)
-{
-  // This is temporary
-  fputc(c, Stream);
-  return false;
-} // end of WriteChr
-
-/***********************************************************************/
-/* Escape and Concatenate a string to the Serialize string.            */
-/***********************************************************************/
-bool JOUTFILE::Escape(const char *s)
-{
-  // This is temporary
-  fputc('"', Stream);
-
-  for (unsigned int i = 0; i < strlen(s); i++)
-    switch (s[i]) {
-      case '\t': fputs("\\t", Stream); break;
-      case '\n': fputs("\\n", Stream); break;
-      case '\r': fputs("\\r", Stream); break;
-      case '\b': fputs("\\b", Stream); break;
-      case '\f': fputs("\\f", Stream); break;
-      case '"': fputs("\\\"", Stream); break;
-      default:
-        fputc(s[i], Stream);
-        break;
-      } // endswitch s[i]
-
-  fputc('"', Stream);
-  return false;
-} // end of Escape
-
-/* ------------------------- Class JOUTPRT --------------------------- */
-
-/***********************************************************************/
-/* Write a string to the Serialize pretty file.                        */
-/***********************************************************************/
-bool JOUTPRT::WriteStr(const char *s)
-{
-  // This is temporary
-  if (B) {
-    fputs(EL, Stream);
-    M--;
-
-    for (int i = 0; i < M; i++)
-      fputc('\t', Stream);
-
-    B = false;
-    } // endif B
-
-  fputs(s, Stream);
-  return false;
-} // end of WriteStr
-
-/***********************************************************************/
-/* Write a character to the Serialize pretty file.                     */
-/***********************************************************************/
-bool JOUTPRT::WriteChr(const char c)
-{
-  switch (c) {
-    case ':':
-      fputs(": ", Stream);
-      break;
-    case '{':
-    case '[':
-#if 0
-      if (M)
-        fputs(EL, Stream);
-
-      for (int i = 0; i < M; i++)
-        fputc('\t', Stream);
-#endif // 0
-
-      fputc(c, Stream);
-      fputs(EL, Stream);
-      M++;
-
-      for (int i = 0; i < M; i++)
-        fputc('\t', Stream);
-
-      break;
-    case '}':
-    case ']':
-      M--;
-      fputs(EL, Stream);
-
-      for (int i = 0; i < M; i++)
-        fputc('\t', Stream);
-
-      fputc(c, Stream);
-      B = true;
-      break;
-    case ',':
-      fputc(c, Stream);
-      fputs(EL, Stream);
-
-      for (int i = 0; i < M; i++)
-        fputc('\t', Stream);
-
-      B = false;
-      break;
-    default:
-      fputc(c, Stream);
-    } // endswitch c
-
-return false;
-} // end of WriteChr
-
-/* -------------------------- Class JOBJECT -------------------------- */
-
-/***********************************************************************/
-/* Add a new pair to an Object.                                        */
-/***********************************************************************/
-PJPR JOBJECT::AddPair(PGLOBAL g, PSZ key)
-{
-  PJPR jpp = new(g) JPAIR(key);
-
-  if (Last)
-    Last->Next = jpp;
-  else
-    First = jpp;
-
-  Last = jpp;
-  Size++;
-  return jpp;
-} // end of AddPair
-
-/***********************************************************************/
-/* Get the value corresponding to the given key.                       */
-/***********************************************************************/
-PJVAL JOBJECT::GetValue(const char* key)
-{
-  for (PJPR jp = First; jp; jp = jp->Next)
-    if (!strcmp(jp->Key, key))
-      return jp->Val;
-
-  return NULL;
-} // end of GetValue;
-
-/***********************************************************************/
-/* Return the text corresponding to all keys (XML like).               */
-/***********************************************************************/
-PSZ JOBJECT::GetText(PGLOBAL g)
-{
-  char *p, *text = (char*)PlugSubAlloc(g, NULL, 0);
-  bool  b = true;
-
-  if (!First)
-    return NULL;
-  else for (PJPR jp = First; jp; jp = jp->Next) {
-    if (!(p = jp->Val->GetString()))
-      p = "???";
-
-    if (b) {
-      strcpy(text, p); 
-      b = false;
-    } else
-      strcat(strcat(text, " "), p);
-
-    } // endfor jp
-
-  PlugSubAlloc(g, NULL, strlen(text) + 1);
-  return text;
-} // end of GetValue;
-
-/***********************************************************************/
-/* Set or add a value corresponding to the given key.                  */
-/***********************************************************************/
-void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PSZ key)
-{
-  PJPR jp;
-
-  for (jp = First; jp; jp = jp->Next)
-    if (!strcmp(jp->Key, key)) {
-      jp->Val = jvp;
-      break;
-      } // endif key
-
-  if (!jp) {
-    jp = AddPair(g, key);
-    jp->Val = jvp;
-    } // endif jp
-
-} // end of SetValue
-
-/* -------------------------- Class JARRAY --------------------------- */
-
-/***********************************************************************/
-/* Make the array of values from the values list.                      */
-/***********************************************************************/
-void JARRAY::InitArray(PGLOBAL g)
-{
-  int   i;
-  PJVAL jvp;
-
-  for (Size = 0, jvp = First; jvp; jvp = jvp->Next) 
-    if (!jvp->Del)
-      Size++;
-
-  if (!Size) {
-    return;
-  } else if (Size > Alloc) {
-    // No need to realloc after deleting values
-    Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
-    Alloc = Size;
-  } // endif Size
-
-  for (i = 0, jvp = First; jvp; jvp = jvp->Next)
-    if (!jvp->Del)
-      Mvals[i++] = jvp;
-
-} // end of InitArray
-
-/***********************************************************************/
-/* Get the Nth value of an Array.                                      */
-/***********************************************************************/
-PJVAL JARRAY::GetValue(int i)
-{
-  if (Mvals && i >= 0 && i < Size)
-    return Mvals[i];
-  else
-    return NULL;
-} // end of GetValue
-
-/***********************************************************************/
-/* Add a Value to the Arrays Value list.                               */
-/***********************************************************************/
-PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp)
-{
-  if (!jvp)
-    jvp = new(g) JVALUE;
-
-  if (Last)
-    Last->Next = jvp;
-  else
-    First = jvp;
-
-  Last = jvp;
-  return jvp;
-} // end of AddValue
-
-/***********************************************************************/
-/* Add a Value to the Arrays Value list.                               */
-/***********************************************************************/
-bool JARRAY::SetValue(PGLOBAL g, PJVAL jvp, int n)
-{
-  int   i = 0;
-  PJVAL jp, *jpp = &First;
-
-  for (i = 0, jp = First; i < n; i++, jp = *(jpp = &jp->Next))
-    if (!jp)
-      *jpp = jp = new(g) JVALUE;
-
-  *jpp = jvp;
-  jvp->Next = (jp ? jp->Next : NULL);
-  return false;
-} // end of SetValue
-
-/***********************************************************************/
-/* Delete a Value from the Arrays Value list.                          */
-/***********************************************************************/
-bool JARRAY::DeleteValue(int n)
-{
-  PJVAL jvp = GetValue(n);
-
-  if (jvp) {
-    jvp->Del = true;
-    return false;
-  } else
-    return true;
-
-} // end of DeleteValue
-
-/* -------------------------- Class JVALUE- -------------------------- */
-
-/***********************************************************************/
-/* Constructor for a Value with a given string or numeric value.       */
-/***********************************************************************/
-JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON()
-{
-  Jsp = NULL; 
-  Value = AllocateValue(g, valp); 
-  Next = NULL;
-  Del = false;
-} // end of JVALUE constructor
-
-/***********************************************************************/
-/* Returns the type of the Value's value.                              */
-/***********************************************************************/
-JTYP JVALUE::GetValType(void)
-{
-  if (Jsp)
-    return Jsp->GetType();
-  else if (Value)
-    return (JTYP)Value->GetType();
-  else
-    return (JTYP)TYPE_VOID;
-
-} // end of GetValType
-
-/***********************************************************************/
-/* Return the Value's Object value.                                    */
-/***********************************************************************/
-PJOB JVALUE::GetObject(void)
-{
-  if (Jsp && Jsp->GetType() == TYPE_JOB)
-    return (PJOB)Jsp;
-
-  return NULL;
-} // end of GetObject
-
-/***********************************************************************/
-/* Return the Value's Array value.                                     */
-/***********************************************************************/
-PJAR JVALUE::GetArray(void)
-{
-  if (Jsp && Jsp->GetType() == TYPE_JAR)
-    return (PJAR)Jsp;
-
-  return NULL;
-} // end of GetArray
-
-/***********************************************************************/
-/* Return the Value's Integer value.                                   */
-/***********************************************************************/
-int JVALUE::GetInteger(void)
-{
-  return (Value) ? Value->GetIntValue() : 0;
-} // end of GetInteger
-
-/***********************************************************************/
-/* Return the Value's Double value.                                    */
-/***********************************************************************/
-double JVALUE::GetFloat(void)
-{
-  return (Value) ? Value->GetFloatValue() : 0.0;
-} // end of GetFloat
-
-/***********************************************************************/
-/* Return the Value's String value.                                    */
-/***********************************************************************/
-PSZ JVALUE::GetString(void)
-{
-  char buf[32];
-  return (Value) ? Value->GetCharString(buf) : NULL;
-} // end of GetString
-
+/*************** json CPP Declares Source Code File (.H) ***************/
+/*  Name: json.cpp   Version 1.0                                       */
+/*                                                                     */
+/*  (C) Copyright to the author Olivier BERTRAND          2014 - 2015  */
+/*                                                                     */
+/*  This file contains the JSON classes functions.                     */
+/***********************************************************************/
+
+/***********************************************************************/
+/*  Include relevant sections of the MariaDB header file.              */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/*  Include application header files:                                  */
+/*  global.h    is header containing all global declarations.          */
+/*  plgdbsem.h  is header containing the DB application declarations.  */
+/*  xjson.h     is header containing the JSON classes declarations.    */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "json.h"
+
+#define ARGS       MY_MIN(24,len-i),s+MY_MAX(i-3,0)
+
+#if defined(WIN32)
+#define EL  "\r\n"
+#else
+#define EL  "\n"
+#endif
+
+/***********************************************************************/
+/* Parse a json string.                                                */
+/***********************************************************************/
+PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
+{
+  int   i, rc;
+  bool  b = false;
+  PJSON jsp = NULL;
+  STRG  src;
+
+  if (!s || !len) {
+    strcpy(g->Message, "Void JSON object");
+    return NULL;
+  } else if (comma)
+    *comma = false;
+
+  src.str = s;
+  src.len = len;
+
+  // Save stack and allocation environment and prepare error return
+  if (g->jump_level == MAX_JUMP) {
+    strcpy(g->Message, MSG(TOO_MANY_JUMPS));
+    return NULL;
+    } // endif jump_level
+
+  if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) {
+    goto err;
+    } // endif rc
+
+  for (i = 0; i < len; i++)
+    switch (s[i]) {
+      case '[':
+        if (jsp) {
+          strcpy(g->Message, "More than one item in file");
+          goto err;
+        } else if (!(jsp = ParseArray(g, ++i, src)))
+          goto err;
+
+        break;
+      case '{':
+        if (jsp) {
+          strcpy(g->Message, "More than one item in file");
+          goto err;
+        } else if (!(jsp = ParseObject(g, ++i, src)))
+          goto err;
+        break;
+      case ' ':
+      case '\t':
+      case '\n':
+      case '\r':
+        break;
+      case ',':
+        if (jsp && pretty == 1) {
+          if (comma)
+            *comma = true;
+
+          break;
+          } // endif pretty
+
+        sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
+        goto err;
+      case '(':
+        b = true;
+        break;
+      case ')':
+        if (b) {
+          b = false;
+          break;
+          } // endif b
+
+      default:
+        sprintf(g->Message, "Bad '%c' character near %.*s",
+                s[i], ARGS);
+        goto err;
+    }; // endswitch s[i]
+
+  if (!jsp)
+    sprintf(g->Message, "Invalid Json string '%.*s'", 50, s);
+
+  g->jump_level--;
+  return jsp;
+
+ err:
+  g->jump_level--;
+  return NULL;
+} // end of ParseJson
+
+/***********************************************************************/
+/* Parse a JSON Array.                                                 */
+/***********************************************************************/
+PJAR ParseArray(PGLOBAL g, int& i, STRG& src)
+{
+  char  *s = src.str;
+  int    len = src.len;
+  int    level = 0;
+  PJAR   jarp = new(g) JARRAY;
+  PJVAL  jvp = NULL;
+
+  for (; i < len; i++)
+    switch (s[i]) {
+      case ',':
+        if (level < 2) {
+          sprintf(g->Message, "Unexpected ',' near %.*s",ARGS);
+          return NULL;
+        } else
+          level = 1;
+
+        break;
+      case ']':
+        if (level == 1) {
+          sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
+          return NULL;
+          } // endif level
+
+        jarp->InitArray(g);
+        return jarp;
+      case ' ':
+      case '\t':
+      case '\n':
+      case '\r':
+        break;
+      default:
+        if (level == 2) {
+          sprintf(g->Message, "Unexpected value near %.*s", ARGS);
+          return NULL;
+        } else if ((jvp = ParseValue(g, i, src))) {
+          jarp->AddValue(g, jvp);
+          level = 2;
+        } else
+          return NULL;
+
+        level = 2;
+        break;
+    }; // endswitch s[i]
+
+  strcpy(g->Message, "Unexpected EOF in array");
+  return NULL;
+} // end of ParseArray
+
+/***********************************************************************/
+/* Parse a JSON Object.                                                */
+/***********************************************************************/
+PJOB ParseObject(PGLOBAL g, int& i, STRG& src)
+{
+  PSZ   key;
+  char *s = src.str;
+  int   len = src.len;
+  int   level = 0;
+  PJOB  jobp = new(g) JOBJECT;
+  PJPR  jpp = NULL;
+
+  for (; i < len; i++)
+    switch (s[i]) {
+      case '"':
+        if (level < 2) {
+          if ((key = ParseString(g, ++i, src))) {
+            jpp = jobp->AddPair(g, key);
+            level = 1;
+          } else
+            return NULL;
+
+        } else {
+          sprintf(g->Message, "misplaced string near %.*s", ARGS);
+          return NULL;
+        } // endif level
+
+        break;
+      case ':':
+        if (level == 1) {
+          if (!(jpp->Val = ParseValue(g, ++i, src)))
+            return NULL;
+
+          level = 2;
+        } else {
+          sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
+          return NULL;
+        } // endif level
+
+        break;
+      case ',':
+        if (level < 2) {
+          sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
+          return NULL;
+        } else
+          level = 1;
+
+        break;
+      case '}':
+        if (level == 1) {
+          sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
+          return NULL;
+          } // endif level
+
+        return jobp;
+      case ' ':
+      case '\t':
+      case '\n':
+      case '\r':
+        break;
+      default:
+        sprintf(g->Message, "Unexpected character '%c' near %.*s",
+                s[i], ARGS);
+        return NULL;
+    }; // endswitch s[i]
+
+  strcpy(g->Message, "Unexpected EOF in Object");
+  return NULL;
+} // end of ParseObject
+
+/***********************************************************************/
+/* Parse a JSON Value.                                                 */
+/***********************************************************************/
+PJVAL ParseValue(PGLOBAL g, int& i, STRG& src)
+{
+  char *strval, *s = src.str;
+  int   n, len = src.len;
+  PJVAL jvp = new(g) JVALUE;
+
+  for (; i < len; i++)
+    switch (s[i]) {
+      case ' ':
+      case '\t':
+      case '\n':
+      case '\r':
+        break;
+      default:
+        goto suite;
+    } // endswitch
+
+ suite:
+  switch (s[i]) {
+    case '[':
+      if (!(jvp->Jsp = ParseArray(g, ++i, src)))
+        return NULL;
+
+      break;
+    case '{':
+      if (!(jvp->Jsp = ParseObject(g, ++i, src)))
+        return NULL;
+
+      break;
+    case '"':
+      if ((strval = ParseString(g, ++i, src)))
+        jvp->Value = AllocateValue(g, strval, TYPE_STRING);
+      else
+        return NULL;
+
+      break;
+    case 't':
+      if (!strncmp(s + i, "true", 4)) {
+        n = 1;
+        jvp->Value = AllocateValue(g, &n, TYPE_TINY);
+        i += 3;
+      } else
+        goto err;
+
+      break;
+    case 'f':
+      if (!strncmp(s + i, "false", 5)) {
+        n = 0;
+        jvp->Value = AllocateValue(g, &n, TYPE_TINY);
+        i += 4;
+      } else
+        goto err;
+
+      break;
+    case 'n':
+      if (!strncmp(s + i, "null", 4))
+        i += 3;
+      else
+        goto err;
+
+      break;
+    case '-':
+    default:
+      if (s[i] == '-' || isdigit(s[i])) {
+        if (!(jvp->Value = ParseNumeric(g, i, src)))
+          goto err;
+
+      } else
+        goto err;
+
+    }; // endswitch s[i]
+
+  jvp->Size = 1;
+  return jvp;
+
+err:
+  sprintf(g->Message, "Unexpected character '%c' near %.*s",
+          s[i], ARGS);
+  return NULL;
+} // end of ParseValue
+
+/***********************************************************************/
+/*  Unescape and parse a JSON string.                                  */
+/***********************************************************************/
+char *ParseString(PGLOBAL g, int& i, STRG& src)
+{
+  char  *s = src.str;
+  uchar *p;
+  int    n = 0, len = src.len;
+
+  // Be sure of memory availability
+  if (len + 1 - i > (signed)((PPOOLHEADER)g->Sarea)->FreeBlk) {
+    strcpy(g->Message, "ParseString: Out of memory");
+    return NULL;
+    } // endif len
+
+  // The size to allocate is not known yet
+  p = (uchar*)PlugSubAlloc(g, NULL, 0);
+
+  for (; i < len; i++)
+    switch (s[i]) {
+      case '"':
+        p[n++] = 0;
+        PlugSubAlloc(g, NULL, n);
+        return (char*)p;
+      case '\\':
+        if (++i < len) {
+          if (s[i] == 'u') {
+            if (len - i > 5) {
+//            if (charset == utf8) {
+                char xs[5];
+                uint hex;
+            
+                xs[0] = s[++i];
+                xs[1] = s[++i];
+                xs[2] = s[++i];
+                xs[3] = s[++i];
+                xs[4] = 0;
+                hex = strtoul(xs, NULL, 16);
+            
+                if (hex < 0x80) {
+                  p[n] = (uchar)hex;
+                } else if (hex < 0x800) {
+                  p[n++] = (uchar)(0xC0 | (hex >> 6));
+                  p[n]   = (uchar)(0x80 | (hex & 0x3F));
+                } else if (hex < 0x10000) {
+                  p[n++] = (uchar)(0xE0 | (hex >> 12));
+                  p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
+                  p[n]   = (uchar)(0x80 | (hex & 0x3f));
+                } else
+                  p[n] = '?';
+
+#if 0
+              } else {
+                char xs[3];
+                UINT hex;
+            
+                i += 2;
+                xs[0] = s[++i];
+                xs[1] = s[++i];
+                xs[2] = 0;
+                hex = strtoul(xs, NULL, 16);
+                p[n] = (char)hex;
+              } // endif charset
+#endif // 0
+            } else
+              goto err;
+
+          } else switch(s[i]) {
+            case 't': p[n] = '\t'; break;
+            case 'n': p[n] = '\n'; break;
+            case 'r': p[n] = '\r'; break;
+            case 'b': p[n] = '\b'; break;
+            case 'f': p[n] = '\f'; break;
+            default:  p[n] = s[i]; break;
+            } // endswitch
+
+          n++;
+        } else
+          goto err;
+
+        break;
+      default:
+        p[n++] = s[i];
+        break;
+      }; // endswitch s[i]
+
+ err:
+  strcpy(g->Message, "Unexpected EOF in String");
+  return NULL;
+} // end of ParseString
+
+/***********************************************************************/
+/* Parse a JSON numeric value.                                         */
+/***********************************************************************/
+PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src)
+{
+  char *s = src.str, buf[50];
+  int   n = 0, len = src.len;
+  short nd = 0;
+	bool  has_dot = false;
+	bool  has_e = false;
+	bool  found_digit = false;
+  PVAL  valp = NULL;
+
+  for (; i < len; i++) {
+    switch (s[i]) {
+      case '.':
+        if (!found_digit || has_dot || has_e)
+          goto err;
+        
+        has_dot = true;
+        break;
+      case 'e':
+      case 'E':
+        if (!found_digit || has_e)
+          goto err;
+
+        has_e = true;
+        found_digit = false;
+        break;
+      case '+':
+        if (!has_e)
+          goto err;
+
+        // passthru
+      case '-':
+        if (found_digit)
+          goto err;
+
+        break;
+      default:
+        if (isdigit(s[i])) {
+          if (has_dot && !has_e)
+            nd++;       // Number of decimals
+
+          found_digit = true;
+        } else
+          goto fin;
+
+      }; // endswitch s[i]
+
+    buf[n++] = s[i];
+    } // endfor i
+
+ fin:
+  if (found_digit) {
+    buf[n] = 0;
+
+    if (has_dot || has_e) {
+      double dv = strtod(buf, NULL);
+
+      valp = AllocateValue(g, &dv, TYPE_DOUBLE, nd);
+    } else {
+      int iv = strtol(buf, NULL, 10);
+
+      valp = AllocateValue(g, &iv, TYPE_INT);
+    } // endif has
+
+    i--;  // Unstack  following character
+    return valp;
+  } else {
+    strcpy(g->Message, "No digit found");
+    return NULL;
+  } // endif found_digit
+
+ err:
+  strcpy(g->Message, "Unexpected EOF in number");
+  return NULL;
+} // end of ParseNumeric
+
+/***********************************************************************/
+/* Serialize a JSON tree:                                              */
+/***********************************************************************/
+PSZ Serialize(PGLOBAL g, PJSON jsp, FILE *fs, int pretty)
+{
+  bool  b = false, err = true;
+  JOUT *jp;
+
+  g->Message[0] = 0;
+
+  if (!jsp) {
+    strcpy(g->Message, "Null json tree");
+    return NULL;
+  } else if (!fs) {
+    // Serialize to a string
+    jp = new(g) JOUTSTR(g);
+    b = pretty == 1;
+  } else if (pretty == 2) {
+    // Serialize to a pretty file
+    jp = new(g) JOUTPRT(g, fs);
+  } else {
+    // Serialize to a flat file
+    jp = new(g) JOUTFILE(g, fs);
+    b = pretty == 1;
+  } // endif's
+
+  switch (jsp->GetType()) {
+    case TYPE_JAR:
+      err = SerializeArray(jp, (PJAR)jsp, b);
+      break;
+    case TYPE_JOB:
+      err = (b && jp->WriteChr('\t'));
+      err |= SerializeObject(jp, (PJOB)jsp);
+      break;
+    case TYPE_JVAL:
+      err = SerializeValue(jp, (PJVAL)jsp);
+      break;
+    default:
+      strcpy(g->Message, "Invalid json tree");
+    } // endswitch Type
+
+  if (fs) {
+    fputc('\n', fs);
+    fclose(fs);
+    return (err) ? g->Message : NULL;
+  } else if (!err) {
+    PSZ str = ((JOUTSTR*)jp)->Strp;
+
+    jp->WriteChr('\0');
+    PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
+    return str;
+  } else {
+    if (!g->Message[0])
+      strcpy(g->Message, "Error in Serialize");
+
+    return NULL;
+  } // endif's
+
+} // end of Serialize
+
+/***********************************************************************/
+/* Serialize a JSON Array.                                             */
+/***********************************************************************/
+bool SerializeArray(JOUT *js, PJAR jarp, bool b)
+{
+  bool first = true;
+
+
+  if (js->WriteChr('['))
+    return true;
+  else if (b && (js->WriteStr(EL) || js->WriteChr('\t')))
+    return true;
+
+  for (int i = 0; i < jarp->size(); i++) {
+    if (first)
+      first = false;
+    else if (js->WriteChr(','))
+      return true;
+    else if (b && (js->WriteStr(EL) || js->WriteChr('\t')))
+      return true;
+
+    if (SerializeValue(js, jarp->GetValue(i)))
+      return true;
+
+    } // endfor i
+
+  if (b && js->WriteStr(EL))
+    return true;
+
+  return js->WriteChr(']');
+} // end of SerializeArray
+
+/***********************************************************************/
+/* Serialize a JSON Object.                                            */
+/***********************************************************************/
+bool SerializeObject(JOUT *js, PJOB jobp)
+{
+  bool first = true;
+
+  if (js->WriteChr('{'))
+    return true;
+
+  for (PJPR pair = jobp->First; pair; pair = pair->Next) {
+    if (first)
+      first = false;
+    else if (js->WriteChr(','))
+      return true;
+
+    if (js->WriteChr('"') ||
+        js->WriteStr(pair->Key) ||
+        js->WriteChr('"') ||
+        js->WriteChr(':') ||
+        SerializeValue(js, pair->Val))
+      return true;
+
+    } // endfor i
+
+  return js->WriteChr('}');
+} // end of SerializeObject
+
+/***********************************************************************/
+/* Serialize a JSON Value.                                             */
+/***********************************************************************/
+bool SerializeValue(JOUT *js, PJVAL jvp)
+{
+  PJAR jap;
+  PJOB jop;
+  PVAL valp;
+
+  if ((jap = jvp->GetArray()))
+    return SerializeArray(js, jap, false);
+  else if ((jop = jvp->GetObject()))
+    return SerializeObject(js, jop);
+  else if (!(valp = jvp->Value) || valp->IsNull())
+    return js->WriteStr("null");
+  else switch (valp->GetType()) {
+    case TYPE_TINY:
+      return js->WriteStr(valp->GetTinyValue() ? "true" : "false");
+    case TYPE_STRING:
+      return js->Escape(valp->GetCharValue());
+    default:
+      if (valp->IsTypeNum()) {
+        char buf[32];
+
+        return js->WriteStr(valp->GetCharString(buf));
+        } // endif valp
+
+    } // endswitch Type
+
+strcpy(js->g->Message, "Unrecognized value");
+return true;
+} // end of SerializeValue
+
+/* -------------------------- Class JOUTSTR -------------------------- */
+
+/***********************************************************************/
+/* JOUTSTR constructor.                                                */
+/***********************************************************************/
+JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g)
+{
+  PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
+
+  N = 0;
+  Max = pph->FreeBlk;
+  Max = (Max > 512) ? Max - 512 : Max;
+  Strp = (char*)PlugSubAlloc(g, NULL, 0);  // Size not know yet
+} // end of JOUTSTR constructor
+
+/***********************************************************************/
+/* Concatenate a string to the Serialize string.                       */
+/***********************************************************************/
+bool JOUTSTR::WriteStr(const char *s)
+{
+  if (s) {
+    size_t len = strlen(s);
+
+    if (N + len > Max)
+      return true;
+
+    memcpy(Strp + N, s, len);
+    N += len;
+    return false;
+  } else
+    return true;
+
+} // end of WriteStr
+
+/***********************************************************************/
+/* Concatenate a character to the Serialize string.                    */
+/***********************************************************************/
+bool JOUTSTR::WriteChr(const char c)
+{
+  if (N + 1 > Max)
+    return true;
+
+  Strp[N++] = c;
+  return false;
+} // end of WriteChr
+
+/***********************************************************************/
+/* Escape and Concatenate a string to the Serialize string.            */
+/***********************************************************************/
+bool JOUTSTR::Escape(const char *s)
+{
+  WriteChr('"');
+
+  for (unsigned int i = 0; i < strlen(s); i++)
+    switch (s[i]) {
+      case '"':  
+      case '\\':
+      case '\t':
+      case '\n':
+      case '\r':
+      case '\b':
+      case '\f': WriteChr('\\');
+        // passthru
+      default:
+        WriteChr(s[i]);
+        break;
+      } // endswitch s[i]
+
+  WriteChr('"');
+  return false;
+} // end of Escape
+
+/* ------------------------- Class JOUTFILE -------------------------- */
+
+/***********************************************************************/
+/* Write a string to the Serialize file.                               */
+/***********************************************************************/
+bool JOUTFILE::WriteStr(const char *s)
+{
+  // This is temporary
+  fputs(s, Stream);
+  return false;
+} // end of WriteStr
+
+/***********************************************************************/
+/* Write a character to the Serialize file.                            */
+/***********************************************************************/
+bool JOUTFILE::WriteChr(const char c)
+{
+  // This is temporary
+  fputc(c, Stream);
+  return false;
+} // end of WriteChr
+
+/***********************************************************************/
+/* Escape and Concatenate a string to the Serialize string.            */
+/***********************************************************************/
+bool JOUTFILE::Escape(const char *s)
+{
+  // This is temporary
+  fputc('"', Stream);
+
+  for (unsigned int i = 0; i < strlen(s); i++)
+    switch (s[i]) {
+      case '"':  fputs("\\\"", Stream); break;
+      case '\\': fputs("\\\\", Stream); break;
+      case '\t': fputs("\\t",  Stream); break;
+      case '\n': fputs("\\n",  Stream); break;
+      case '\r': fputs("\\r",  Stream); break;
+      case '\b': fputs("\\b",  Stream); break;
+      case '\f': fputs("\\f",  Stream); break;
+      default:
+        fputc(s[i], Stream);
+        break;
+      } // endswitch s[i]
+
+  fputc('"', Stream);
+  return false;
+} // end of Escape
+
+/* ------------------------- Class JOUTPRT --------------------------- */
+
+/***********************************************************************/
+/* Write a string to the Serialize pretty file.                        */
+/***********************************************************************/
+bool JOUTPRT::WriteStr(const char *s)
+{
+  // This is temporary
+  if (B) {
+    fputs(EL, Stream);
+    M--;
+
+    for (int i = 0; i < M; i++)
+      fputc('\t', Stream);
+
+    B = false;
+    } // endif B
+
+  fputs(s, Stream);
+  return false;
+} // end of WriteStr
+
+/***********************************************************************/
+/* Write a character to the Serialize pretty file.                     */
+/***********************************************************************/
+bool JOUTPRT::WriteChr(const char c)
+{
+  switch (c) {
+    case ':':
+      fputs(": ", Stream);
+      break;
+    case '{':
+    case '[':
+#if 0
+      if (M)
+        fputs(EL, Stream);
+
+      for (int i = 0; i < M; i++)
+        fputc('\t', Stream);
+#endif // 0
+
+      fputc(c, Stream);
+      fputs(EL, Stream);
+      M++;
+
+      for (int i = 0; i < M; i++)
+        fputc('\t', Stream);
+
+      break;
+    case '}':
+    case ']':
+      M--;
+      fputs(EL, Stream);
+
+      for (int i = 0; i < M; i++)
+        fputc('\t', Stream);
+
+      fputc(c, Stream);
+      B = true;
+      break;
+    case ',':
+      fputc(c, Stream);
+      fputs(EL, Stream);
+
+      for (int i = 0; i < M; i++)
+        fputc('\t', Stream);
+
+      B = false;
+      break;
+    default:
+      fputc(c, Stream);
+    } // endswitch c
+
+return false;
+} // end of WriteChr
+
+/* -------------------------- Class JOBJECT -------------------------- */
+
+/***********************************************************************/
+/* Add a new pair to an Object.                                        */
+/***********************************************************************/
+PJPR JOBJECT::AddPair(PGLOBAL g, PSZ key)
+{
+  PJPR jpp = new(g) JPAIR(key);
+
+  if (Last)
+    Last->Next = jpp;
+  else
+    First = jpp;
+
+  Last = jpp;
+  Size++;
+  return jpp;
+} // end of AddPair
+
+/***********************************************************************/
+/* Get the value corresponding to the given key.                       */
+/***********************************************************************/
+PJVAL JOBJECT::GetValue(const char* key)
+{
+  for (PJPR jp = First; jp; jp = jp->Next)
+    if (!strcmp(jp->Key, key))
+      return jp->Val;
+
+  return NULL;
+} // end of GetValue;
+
+/***********************************************************************/
+/* Return the text corresponding to all keys (XML like).               */
+/***********************************************************************/
+PSZ JOBJECT::GetText(PGLOBAL g)
+{
+  char *p, *text = (char*)PlugSubAlloc(g, NULL, 0);
+  bool  b = true;
+
+  if (!First)
+    return NULL;
+  else for (PJPR jp = First; jp; jp = jp->Next) {
+    if (!(p = jp->Val->GetString()))
+      p = "???";
+
+    if (b) {
+      strcpy(text, p); 
+      b = false;
+    } else
+      strcat(strcat(text, " "), p);
+
+    } // endfor jp
+
+  PlugSubAlloc(g, NULL, strlen(text) + 1);
+  return text;
+} // end of GetValue;
+
+/***********************************************************************/
+/* Set or add a value corresponding to the given key.                  */
+/***********************************************************************/
+void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PSZ key)
+{
+  PJPR jp;
+
+  for (jp = First; jp; jp = jp->Next)
+    if (!strcmp(jp->Key, key)) {
+      jp->Val = jvp;
+      break;
+      } // endif key
+
+  if (!jp) {
+    jp = AddPair(g, key);
+    jp->Val = jvp;
+    } // endif jp
+
+} // end of SetValue
+
+/* -------------------------- Class JARRAY --------------------------- */
+
+/***********************************************************************/
+/* Make the array of values from the values list.                      */
+/***********************************************************************/
+void JARRAY::InitArray(PGLOBAL g)
+{
+  int   i;
+  PJVAL jvp;
+
+  for (Size = 0, jvp = First; jvp; jvp = jvp->Next) 
+    if (!jvp->Del)
+      Size++;
+
+  if (!Size) {
+    return;
+  } else if (Size > Alloc) {
+    // No need to realloc after deleting values
+    Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
+    Alloc = Size;
+  } // endif Size
+
+  for (i = 0, jvp = First; jvp; jvp = jvp->Next)
+    if (!jvp->Del)
+      Mvals[i++] = jvp;
+
+} // end of InitArray
+
+/***********************************************************************/
+/* Get the Nth value of an Array.                                      */
+/***********************************************************************/
+PJVAL JARRAY::GetValue(int i)
+{
+  if (Mvals && i >= 0 && i < Size)
+    return Mvals[i];
+  else
+    return NULL;
+} // end of GetValue
+
+/***********************************************************************/
+/* Add a Value to the Arrays Value list.                               */
+/***********************************************************************/
+PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp)
+{
+  if (!jvp)
+    jvp = new(g) JVALUE;
+
+  if (Last)
+    Last->Next = jvp;
+  else
+    First = jvp;
+
+  Last = jvp;
+  return jvp;
+} // end of AddValue
+
+/***********************************************************************/
+/* Add a Value to the Arrays Value list.                               */
+/***********************************************************************/
+bool JARRAY::SetValue(PGLOBAL g, PJVAL jvp, int n)
+{
+  int   i = 0;
+  PJVAL jp, *jpp = &First;
+
+  for (i = 0, jp = First; i < n; i++, jp = *(jpp = &jp->Next))
+    if (!jp)
+      *jpp = jp = new(g) JVALUE;
+
+  *jpp = jvp;
+  jvp->Next = (jp ? jp->Next : NULL);
+  return false;
+} // end of SetValue
+
+/***********************************************************************/
+/* Delete a Value from the Arrays Value list.                          */
+/***********************************************************************/
+bool JARRAY::DeleteValue(int n)
+{
+  PJVAL jvp = GetValue(n);
+
+  if (jvp) {
+    jvp->Del = true;
+    return false;
+  } else
+    return true;
+
+} // end of DeleteValue
+
+/* -------------------------- Class JVALUE- -------------------------- */
+
+/***********************************************************************/
+/* Constructor for a Value with a given string or numeric value.       */
+/***********************************************************************/
+JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON()
+{
+  Jsp = NULL; 
+  Value = AllocateValue(g, valp); 
+  Next = NULL;
+  Del = false;
+} // end of JVALUE constructor
+
+/***********************************************************************/
+/* Returns the type of the Value's value.                              */
+/***********************************************************************/
+JTYP JVALUE::GetValType(void)
+{
+  if (Jsp)
+    return Jsp->GetType();
+  else if (Value)
+    return (JTYP)Value->GetType();
+  else
+    return (JTYP)TYPE_VOID;
+
+} // end of GetValType
+
+/***********************************************************************/
+/* Return the Value's Object value.                                    */
+/***********************************************************************/
+PJOB JVALUE::GetObject(void)
+{
+  if (Jsp && Jsp->GetType() == TYPE_JOB)
+    return (PJOB)Jsp;
+
+  return NULL;
+} // end of GetObject
+
+/***********************************************************************/
+/* Return the Value's Array value.                                     */
+/***********************************************************************/
+PJAR JVALUE::GetArray(void)
+{
+  if (Jsp && Jsp->GetType() == TYPE_JAR)
+    return (PJAR)Jsp;
+
+  return NULL;
+} // end of GetArray
+
+/***********************************************************************/
+/* Return the Value's Integer value.                                   */
+/***********************************************************************/
+int JVALUE::GetInteger(void)
+{
+  return (Value) ? Value->GetIntValue() : 0;
+} // end of GetInteger
+
+/***********************************************************************/
+/* Return the Value's Double value.                                    */
+/***********************************************************************/
+double JVALUE::GetFloat(void)
+{
+  return (Value) ? Value->GetFloatValue() : 0.0;
+} // end of GetFloat
+
+/***********************************************************************/
+/* Return the Value's String value.                                    */
+/***********************************************************************/
+PSZ JVALUE::GetString(void)
+{
+  char buf[32];
+  return (Value) ? Value->GetCharString(buf) : NULL;
+} // end of GetString
+
+/***********************************************************************/
+/* Set the Value's value as the given integer.                         */
+/***********************************************************************/
+void JVALUE::SetInteger(PGLOBAL g, int n)
+{
+  Value = AllocateValue(g, &n, TYPE_INT);
+} // end of AddInteger
+
+/***********************************************************************/
+/* Set the Value's value as the given DOUBLE.                          */
+/***********************************************************************/
+void JVALUE::SetFloat(PGLOBAL g, double f)
+{
+  Value = AllocateValue(g, &f, TYPE_DOUBLE, 6);
+} // end of AddFloat
+
+/***********************************************************************/
+/* Set the Value's value as the given string.                          */
+/***********************************************************************/
+void JVALUE::SetString(PGLOBAL g, PSZ s)
+{
+  Value = AllocateValue(g, s, TYPE_STRING);
+} // end of AddFloat
+

=== modified file 'storage/connect/json.h'
--- a/storage/connect/json.h	2015-01-20 00:21:56 +0000
+++ b/storage/connect/json.h	2015-02-11 20:39:41 +0000
@@ -18,7 +18,8 @@ enum JTYP {TYPE_STRG = 1,
            TYPE_BOOL = 4,
            TYPE_INTG = 7, 
            TYPE_JSON = 12, 
-           TYPE_JAR, TYPE_JOB, 
+           TYPE_JAR, 
+           TYPE_JOB, 
            TYPE_JVAL};
 
 class JOUT;
@@ -156,6 +157,9 @@ class JSON : public BLOCK {
   virtual void   SetValue(PGLOBAL g, PJVAL jvp, PSZ key) {X}
   virtual void   SetValue(PVAL valp) {X}
   virtual void   SetValue(PJSON jsp) {X}
+  virtual void   SetString(PGLOBAL g, PSZ s) {X}
+  virtual void   SetInteger(PGLOBAL g, int n) {X}
+  virtual void   SetFloat(PGLOBAL g, double f) {X}
   virtual bool   DeleteValue(int i) {X return true;}
 
  protected:
@@ -171,6 +175,8 @@ class JOBJECT : public JSON {
  public:
   JOBJECT(void) : JSON() {First = Last = NULL;}
 
+  using JSON::GetValue;
+  using JSON::SetValue;
   virtual void  Clear(void) {First = Last = NULL; Size = 0;}
   virtual JTYP  GetType(void) {return TYPE_JOB;}
   virtual PJPR  AddPair(PGLOBAL g, PSZ key);
@@ -192,6 +198,8 @@ class JARRAY : public JSON {
  public:
   JARRAY(void) : JSON() {Alloc = 0; First = Last = NULL; Mvals = NULL;}
 
+  using JSON::GetValue;
+  using JSON::SetValue;
   virtual void  Clear(void) {First = Last = NULL; Size = 0;}
   virtual JTYP  GetType(void) {return TYPE_JAR;}
   virtual PJAR  GetArray(void) {return this;}
@@ -223,6 +231,8 @@ class JVALUE : public JSON {
                 {Jsp = jsp; Value = NULL; Next = NULL; Del = false;}
   JVALUE(PGLOBAL g, PVAL valp);
 
+  using JSON::GetValue;
+  using JSON::SetValue;
   virtual void   Clear(void)
           {Jsp = NULL; Value = NULL; Next = NULL; Del = false; Size = 0;}
   virtual JTYP   GetType(void) {return TYPE_JVAL;}
@@ -236,6 +246,9 @@ class JVALUE : public JSON {
   virtual PSZ    GetString(void);
   virtual void   SetValue(PVAL valp) {Value = valp;}
   virtual void   SetValue(PJSON jsp) {Jsp = jsp;}
+  virtual void   SetString(PGLOBAL g, PSZ s);
+  virtual void   SetInteger(PGLOBAL g, int n);
+  virtual void   SetFloat(PGLOBAL g, double f);
 
  protected:
   PJSON Jsp;      // To the json value

=== added file 'storage/connect/jsonudf.cpp'
--- a/storage/connect/jsonudf.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/connect/jsonudf.cpp	2015-02-19 00:25:31 +0000
@@ -0,0 +1,494 @@
+/************* jsonudf C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: jsonudf     Version 1.0                               */
+/*  (C) Copyright to the author Olivier BERTRAND          2015         */
+/*  This program are the JSON User Defined Functions     .             */
+/***********************************************************************/
+
+/***********************************************************************/
+/*  Include relevant sections of the MariaDB header file.              */
+/***********************************************************************/
+#include <my_global.h>
+#include <mysql.h>
+
+#include "global.h"
+#include "plgdbsem.h"
+#include "json.h"
+
+extern "C" {
+DllExport my_bool Json_Value_init(UDF_INIT*, UDF_ARGS*, char*);
+DllExport char *Json_Value(UDF_INIT*, UDF_ARGS*, char*,
+                         unsigned long*, char *, char *);
+DllExport void Json_Value_deinit(UDF_INIT*);
+DllExport my_bool Json_Array_init(UDF_INIT*, UDF_ARGS*, char*);
+DllExport char *Json_Array(UDF_INIT*, UDF_ARGS*, char*,
+                         unsigned long*, char *, char *);
+DllExport void Json_Array_deinit(UDF_INIT*);
+DllExport my_bool Json_Object_init(UDF_INIT*, UDF_ARGS*, char*);
+DllExport char *Json_Object(UDF_INIT*, UDF_ARGS*, char*,
+                         unsigned long*, char *, char *);
+DllExport void Json_Object_deinit(UDF_INIT*);
+DllExport my_bool Json_Array_Grp_init(UDF_INIT*, UDF_ARGS*, char*);
+DllExport void Json_Array_Grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+DllExport char *Json_Array_Grp(UDF_INIT*, UDF_ARGS*, char*,
+                         unsigned long*, char *, char *);
+DllExport void Json_Array_Grp_clear(UDF_INIT *, char *, char *);
+DllExport void Json_Array_Grp_deinit(UDF_INIT*);
+DllExport my_bool Json_Object_Grp_init(UDF_INIT*, UDF_ARGS*, char*);
+DllExport void Json_Object_Grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+DllExport char *Json_Object_Grp(UDF_INIT*, UDF_ARGS*, char*,
+                         unsigned long*, char *, char *);
+DllExport void Json_Object_Grp_clear(UDF_INIT *, char *, char *);
+DllExport void Json_Object_Grp_deinit(UDF_INIT*);
+} // extern "C"
+
+/***********************************************************************/
+/*  Allocate and initialise the memory area.                           */
+/***********************************************************************/
+static my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long reslen,
+                                                  unsigned long memlen)
+{
+  PGLOBAL g = PlugInit(NULL, memlen);
+
+  if (!g) {
+    strcpy(message, "Allocation error");
+    return true;
+  } else if (g->Sarea_Size == 0) {
+    strcpy(message, g->Message);
+    PlugExit(g);
+    return true;
+  } else
+    initid->ptr = (char*)g;
+
+  initid->maybe_null = false;
+  initid->max_length = reslen;
+  return false;
+} // end of Json_Object_init
+
+/***********************************************************************/
+/*  Returns true if the argument is a JSON string.                     */
+/***********************************************************************/
+static my_bool IsJson(UDF_ARGS *args, int i)
+{
+  return (args->arg_type[i] == STRING_RESULT &&
+          !strnicmp(args->attributes[i], "Json_", 5));
+} // end of IsJson
+
+/***********************************************************************/
+/*  Calculate the reslen and memlen needed by a function.              */
+/***********************************************************************/
+static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
+                       unsigned long& reslen, unsigned long& memlen)
+{
+  unsigned long i, k;
+  reslen = args->arg_count + 2;
+
+  // Calculate the result max length
+  for (i = 0; i < args->arg_count; i++) {
+    if (obj) {
+      if (!(k = args->attribute_lengths[i]))
+        k = strlen(args->attributes[i]);
+
+      reslen += (k + 3);     // For quotes and :
+      } // endif obj
+
+    switch (args->arg_type[i]) {
+      case STRING_RESULT:
+        if (IsJson(args, i))
+          reslen += args->lengths[i];
+        else
+          reslen += (args->lengths[i] + 1) * 2;   // Pessimistic !
+  
+        break;
+      case INT_RESULT:
+        reslen += 20;
+        break;
+      case REAL_RESULT:
+        reslen += 31;
+        break;
+      case DECIMAL_RESULT:
+        reslen += (args->lengths[i] + 7);   // 6 decimals
+        break;
+      case TIME_RESULT:
+      case ROW_RESULT:
+      case IMPOSSIBLE_RESULT:
+      default:
+        // What should we do here ?
+        break;
+      } // endswitch arg_type
+
+    } // endfor i
+
+  // Calculate the amount of memory needed
+  memlen = 1024 + sizeof(JOUTSTR) + reslen;
+
+  for (i = 0; i < args->arg_count; i++) {
+    memlen += (args->lengths[i] + sizeof(JVALUE));
+
+    if (obj) {
+      if (!(k = args->attribute_lengths[i]))
+        k = strlen(args->attributes[i]);
+
+      memlen += (k + sizeof(JOBJECT) + sizeof(JPAIR));
+    } else
+      memlen += sizeof(JARRAY);
+
+    switch (args->arg_type[i]) {
+      case STRING_RESULT:
+        if (IsJson(args, i))
+          memlen += args->lengths[i] * 5;  // Estimate parse memory
+  
+        memlen += sizeof(TYPVAL<PSZ>);
+        break;
+      case INT_RESULT:
+        memlen += sizeof(TYPVAL<int>);
+        break;
+      case REAL_RESULT:
+      case DECIMAL_RESULT:
+        memlen += sizeof(TYPVAL<double>);
+        break;
+      case TIME_RESULT:
+      case ROW_RESULT:
+      case IMPOSSIBLE_RESULT:
+      default:
+        // What should we do here ?
+        break;
+      } // endswitch arg_type
+
+    } // endfor i
+
+  return false;
+} // end of CalcLen
+
+/***********************************************************************/
+/*  Make a zero terminated string from the passed argument.            */
+/***********************************************************************/
+static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i)
+{
+  if (args->args[i]) {
+    int n = args->lengths[i];
+    PSZ s = (PSZ)PlugSubAlloc(g, NULL, n + 1);
+
+    memcpy(s, args->args[i], n);
+    s[n] = 0;
+    return s;
+  } else
+    return NULL;
+
+} // end of MakePSZ
+
+/***********************************************************************/
+/*  Make a valid key from the passed argument.                         */
+/***********************************************************************/
+static PSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
+{
+  int  n = args->attribute_lengths[i];
+  bool b;  // true if attribute is zero terminated
+  PSZ  p, s = args->attributes[i];
+
+  if (s && *s && (n || *s == '\'')) {
+    if ((b = (!n || !s[n])))
+      n = strlen(s);
+
+    if (n > 5 && IsJson(args, i)) {
+      s += 5;
+      n -= 5;
+    } else if (*s == '\'' && s[n-1] == '\'') {
+      s++;
+      n -= 2;
+      b = false;
+      } // endif *s
+
+    if (n < 1)
+      return "Key";
+
+    if (!b) {
+      p = (PSZ)PlugSubAlloc(g, NULL, n + 1);
+      memcpy(p, s, n);
+      p[n] = 0;
+      s = p;
+      } // endif b
+
+    } // endif s
+
+  return s;
+} // end of MakeKey
+
+/***********************************************************************/
+/*  Make a JSON value from the passed argument.                        */
+/***********************************************************************/
+static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
+{
+  char *sap = args->args[i];
+  PJVAL jvp = new(g) JVALUE;
+
+  if (sap) switch (args->arg_type[i]) {
+    case STRING_RESULT:
+      if (args->lengths[i]) {
+        if (IsJson(args, i))
+          jvp->SetValue(ParseJson(g, sap, args->lengths[i], 0));
+        else
+          jvp->SetString(g, MakePSZ(g, args, i));
+
+        } // endif str
+
+      break;
+    case INT_RESULT:
+      jvp->SetInteger(g, *(int*)sap);
+      break;
+    case REAL_RESULT:
+      jvp->SetFloat(g, *(double*)sap);
+      break;
+    case DECIMAL_RESULT:
+      jvp->SetFloat(g, atof(MakePSZ(g, args, i)));
+      break;
+    case TIME_RESULT:
+    case ROW_RESULT:
+    case IMPOSSIBLE_RESULT:
+    default:
+      break;
+    } // endswitch arg_type
+
+  return jvp;
+} // end of MakeValue
+
+/***********************************************************************/
+/*  Make a Json value containing the parameter.                        */
+/***********************************************************************/
+my_bool Json_Value_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+  unsigned long reslen, memlen;
+
+  if (args->arg_count > 1) {
+    strcpy(message, "Json_Value cannot accept more than 1 argument");
+    return true;
+  } else
+    CalcLen(args, false, reslen, memlen);
+
+  return JsonInit(initid, message, reslen, memlen);
+} // end of Json_Value_init
+
+char *Json_Value(UDF_INIT *initid, UDF_ARGS *args, char *result, 
+                unsigned long *res_length, char *is_null, char *error)
+{
+  char   *str;
+  PJVAL   jvp;
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+
+  PlugSubSet(g, g->Sarea, g->Sarea_Size);
+  jvp = MakeValue(g, args, 0);
+
+  if (!(str = Serialize(g, jvp, NULL, 0)))
+    str = strcpy(result, g->Message);
+
+  *res_length = strlen(str);
+  return str;
+} // end of Json_Value
+
+void Json_Value_deinit(UDF_INIT* initid)
+{
+  PlugExit((PGLOBAL)initid->ptr);
+} // end of Json_Value_deinit
+
+/***********************************************************************/
+/*  Make a Json array containing all the parameters.                   */
+/***********************************************************************/
+my_bool Json_Array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+  unsigned long reslen, memlen;
+
+  CalcLen(args, false, reslen, memlen);
+  return JsonInit(initid, message, reslen, memlen);
+} // end of Json_Array_init
+
+char *Json_Array(UDF_INIT *initid, UDF_ARGS *args, char *result, 
+                unsigned long *res_length, char *is_null, char *error)
+{
+  char   *str;
+  uint    i;
+  PJAR    arp;
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+
+  PlugSubSet(g, g->Sarea, g->Sarea_Size);
+  arp = new(g) JARRAY;
+
+  for (i = 0; i < args->arg_count; i++)
+    arp->AddValue(g, MakeValue(g, args, i));
+
+  arp->InitArray(g);
+
+  if (!(str = Serialize(g, arp, NULL, 0)))
+    str = strcpy(result, g->Message);
+
+  *res_length = strlen(str);
+  return str;
+} // end of Json_Array
+
+void Json_Array_deinit(UDF_INIT* initid)
+{
+  PlugExit((PGLOBAL)initid->ptr);
+} // end of Json_Array_deinit
+
+/***********************************************************************/
+/*  Make a Json Oject containing all the parameters.                   */
+/***********************************************************************/
+my_bool Json_Object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+  unsigned long reslen, memlen;
+
+  CalcLen(args, true, reslen, memlen);
+  return JsonInit(initid, message, reslen, memlen);
+} // end of Json_Object_init
+
+char *Json_Object(UDF_INIT *initid, UDF_ARGS *args, char *result, 
+                  unsigned long *res_length, char *is_null, char *error)
+{
+  char   *str;
+  uint    i;
+  PJOB    objp;
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+
+  PlugSubSet(g, g->Sarea, g->Sarea_Size);
+  objp = new(g) JOBJECT;
+
+  for (i = 0; i < args->arg_count; i++)
+    objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
+
+  if (!(str = Serialize(g, objp, NULL, 0)))
+    str = strcpy(result, g->Message);
+
+  *res_length = strlen(str);
+  return str;
+} // end of Json_Object
+
+void Json_Object_deinit(UDF_INIT* initid)
+{
+  PlugExit((PGLOBAL)initid->ptr);
+} // end of Json_Object_deinit
+
+/***********************************************************************/
+/*  Make a Json array from values comming from rows.                   */
+/***********************************************************************/
+my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+  unsigned long reslen, memlen, n = 10;
+
+  if (args->arg_count != 1) {
+    strcpy(message, "Json_Array_Grp can only accept 1 argument");
+    return true;
+  } else 
+    CalcLen(args, false, reslen, memlen);
+  
+  reslen *= n;
+  memlen *= n;
+
+  if (JsonInit(initid, message, reslen, memlen))
+    return true;
+
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+
+  PlugSubSet(g, g->Sarea, g->Sarea_Size);
+  g->Activityp = (PACTIVITY)new(g) JARRAY;
+  return false;
+} // end of Json_Array_Grp_init
+
+void Json_Array_Grp_add(UDF_INIT *initid, UDF_ARGS *args, 
+                      char *is_null, char *error)
+{
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+  PJAR    arp = (PJAR)g->Activityp;
+
+  arp->AddValue(g, MakeValue(g, args, 0));
+} // end of Json_Array_Grp_add
+
+char *Json_Array_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result, 
+                unsigned long *res_length, char *is_null, char *error)
+{
+  char   *str;
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+  PJAR    arp = (PJAR)g->Activityp;
+
+  arp->InitArray(g);
+
+  if (!(str = Serialize(g, arp, NULL, 0)))
+    str = strcpy(result, g->Message);
+
+  *res_length = strlen(str);
+  return str;
+} // end of Json_Array_Grp
+
+void Json_Array_Grp_clear(UDF_INIT *initid, char *is_null, char *error)
+{
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+
+  PlugSubSet(g, g->Sarea, g->Sarea_Size);
+  g->Activityp = (PACTIVITY)new(g) JARRAY;
+} // end of Json_Array_Grp_clear
+
+void Json_Array_Grp_deinit(UDF_INIT* initid)
+{
+  PlugExit((PGLOBAL)initid->ptr);
+} // end of Json_Array_Grp_deinit
+
+/***********************************************************************/
+/*  Make a Json object from values comming from rows.                  */
+/***********************************************************************/
+my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+  unsigned long reslen, memlen, n = 10;
+
+  if (args->arg_count != 2) {
+    strcpy(message, "Json_Array_Grp can only accept 2 argument");
+    return true;
+  } else 
+    CalcLen(args, true, reslen, memlen);
+  
+  reslen *= n;
+  memlen *= n;
+
+  if (JsonInit(initid, message, reslen, memlen))
+    return true;
+
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+
+  PlugSubSet(g, g->Sarea, g->Sarea_Size);
+  g->Activityp = (PACTIVITY)new(g) JOBJECT;
+  return false;
+} // end of Json_Object_Grp_init
+
+void Json_Object_Grp_add(UDF_INIT *initid, UDF_ARGS *args, 
+                      char *is_null, char *error)
+{
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+  PJOB    objp = (PJOB)g->Activityp;
+
+  objp->SetValue(g, MakeValue(g, args, 0), MakePSZ(g, args, 1)); 
+} // end of Json_Object_Grp_add
+
+char *Json_Object_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result, 
+                unsigned long *res_length, char *is_null, char *error)
+{
+  char   *str;
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+  PJOB    objp = (PJOB)g->Activityp;
+
+  if (!(str = Serialize(g, objp, NULL, 0)))
+    str = strcpy(result, g->Message);
+
+  *res_length = strlen(str);
+  return str;
+} // end of Json_Object_Grp
+
+void Json_Object_Grp_clear(UDF_INIT *initid, char *is_null, char *error)
+{
+  PGLOBAL g = (PGLOBAL)initid->ptr;
+
+  PlugSubSet(g, g->Sarea, g->Sarea_Size);
+  g->Activityp = (PACTIVITY)new(g) JOBJECT;
+} // end of Json_Object_Grp_clear
+
+void Json_Object_Grp_deinit(UDF_INIT* initid)
+{
+  PlugExit((PGLOBAL)initid->ptr);
+} // end of Json_Object_Grp_deinit
+
+

=== modified file 'storage/connect/myconn.cpp'
--- a/storage/connect/myconn.cpp	2015-01-06 09:18:04 +0000
+++ b/storage/connect/myconn.cpp	2015-02-07 10:33:52 +0000
@@ -51,7 +51,8 @@
 #define  DLL_EXPORT            // Items are exported from this DLL
 #include "myconn.h"
 
-extern "C" int   zconv;
+//extern "C" int   zconv;
+int GetConvSize(void);
 extern MYSQL_PLUGIN_IMPORT uint  mysqld_port;
 extern MYSQL_PLUGIN_IMPORT char *mysqld_unix_port;
 
@@ -265,7 +266,7 @@ PQRYRES MyColumns(PGLOBAL g, THD *thd, c
       return NULL;
     } else if (type == TYPE_STRING) {
       if (v == 'X') {
-        len = zconv;
+        len = GetConvSize();
         sprintf(g->Message, "Column %s converted to varchar(%d)",
                 colname, len);
         PushWarning(g, thd);

=== modified file 'storage/connect/mysql-test/connect/r/json.result'
--- a/storage/connect/mysql-test/connect/r/json.result	2015-01-20 10:26:03 +0000
+++ b/storage/connect/mysql-test/connect/r/json.result	2015-01-30 09:57:00 +0000
@@ -89,8 +89,8 @@ ISBN	Language	Subject	AuthorFN	AuthorLN
 UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab';
 SELECT * FROM t1 WHERE ISBN = '9782212090819';
 ISBN	Language	Subject	AuthorFN	AuthorLN	Title	Translation	Translator	Publisher	Location	Year
-9782212090819	fr	applications	Jean-Christophe	Bernadac	Construire une application XML			Eyrolles	Paris	1999
-9782212090819	fr	applications	Philippe	Knab	Construire une application XML			Eyrolles	Paris	1999
+9782212090819	fr	applications	Philippe	Bernadac	Construire une application XML			Eyrolles	Paris	1999
+9782212090819	fr	applications	François	Knab	Construire une application XML			Eyrolles	Paris	1999
 #
 # To add an author a new table must be created
 #
@@ -104,8 +104,8 @@ William J.	Pardi
 INSERT INTO t2 VALUES('Charles','Dickens');
 SELECT * FROM t1;
 ISBN	Language	Subject	AuthorFN	AuthorLN	Title	Translation	Translator	Publisher	Location	Year
-9782212090819	fr	applications	Jean-Christophe	Bernadac	Construire une application XML			Eyrolles	Paris	1999
-9782212090819	fr	applications	Philippe	Knab	Construire une application XML			Eyrolles	Paris	1999
+9782212090819	fr	applications	Philippe	Bernadac	Construire une application XML			Eyrolles	Paris	1999
+9782212090819	fr	applications	François	Knab	Construire une application XML			Eyrolles	Paris	1999
 9782840825685	fr	applications	William J.	Pardi	XML en Action	adapté de l'anglais par	James Guerin	Microsoft Press	Paris	1999
 9782840825685	fr	applications	Charles	Dickens	XML en Action	adapté de l'anglais par	James Guerin	Microsoft Press	Paris	1999
 DROP TABLE t1;
@@ -127,11 +127,11 @@ line
 		"SUBJECT": "applications",
 		"AUTHOR": [
 			{
-				"FIRSTNAME": "Jean-Christophe",
+				"FIRSTNAME": "Philippe",
 				"LASTNAME": "Bernadac"
 			},
 			{
-				"FIRSTNAME": "Philippe",
+				"FIRSTNAME": "François",
 				"LASTNAME": "Knab"
 			}
 		],
@@ -192,7 +192,7 @@ Janet	4	Car	17.00
 Janet	5	Beer+Car+Beer+Food	57.00
 DROP TABLE t1;
 #
-# Cannot be fully expanded
+# Now it can be fully expanded
 #
 CREATE TABLE t1 (
 WHO CHAR(12),
@@ -201,7 +201,31 @@ WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXP
 AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT')
 ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.jsn';
 SELECT * FROM t1;
-ERROR HY000: Got error 174 'Cannot expand more than one array' from CONNECT
+WHO	WEEK	WHAT	AMOUNT
+Joe	3	Beer	18.00
+Joe	3	Food	12.00
+Joe	3	Food	19.00
+Joe	3	Car	20.00
+Joe	4	Beer	19.00
+Joe	4	Beer	16.00
+Joe	4	Food	17.00
+Joe	4	Food	17.00
+Joe	4	Beer	14.00
+Joe	5	Beer	14.00
+Joe	5	Food	12.00
+Beth	3	Beer	16.00
+Beth	4	Food	17.00
+Beth	4	Beer	15.00
+Beth	5	Food	12.00
+Beth	5	Beer	20.00
+Janet	3	Car	19.00
+Janet	3	Food	18.00
+Janet	3	Beer	18.00
+Janet	4	Car	17.00
+Janet	5	Beer	14.00
+Janet	5	Car	12.00
+Janet	5	Beer	19.00
+Janet	5	Food	12.00
 DROP TABLE t1;
 #
 # Expand expense in 3 one week tables

=== modified file 'storage/connect/mysql-test/connect/t/json.test'
--- a/storage/connect/mysql-test/connect/t/json.test	2015-01-20 10:26:03 +0000
+++ b/storage/connect/mysql-test/connect/t/json.test	2015-01-30 09:57:00 +0000
@@ -128,7 +128,7 @@ SELECT * FROM t1;
 DROP TABLE t1;
 
 --echo #
---echo # Cannot be fully expanded
+--echo # Now it can be fully expanded
 --echo #
 CREATE TABLE t1 (
 WHO CHAR(12),
@@ -136,7 +136,7 @@ WEEK INT(2) FIELD_FORMAT='WEEK:[X]:NUMBE
 WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:WHAT',
 AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT')
 ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.jsn';
---error ER_GET_ERRMSG
+#--error ER_GET_ERRMSG
 SELECT * FROM t1;
 DROP TABLE t1;
 

=== modified file 'storage/connect/myutil.cpp'
--- a/storage/connect/myutil.cpp	2014-03-30 20:52:54 +0000
+++ b/storage/connect/myutil.cpp	2015-02-07 10:33:52 +0000
@@ -26,14 +26,16 @@
 #include "myutil.h"
 #define  DLL_EXPORT            // Items are exported from this DLL
 
-extern "C" int xconv;
+//extern "C" int xconv;
+TYPCONV GetTypeConv(void);
 
 /************************************************************************/
 /*  Convert from MySQL type name to PlugDB type number                  */
 /************************************************************************/
 int MYSQLtoPLG(char *typname, char *var)
   {
-  int type;
+  int     type;
+  TYPCONV xconv = GetTypeConv();
 
   if (!stricmp(typname, "int") || !stricmp(typname, "mediumint") ||
       !stricmp(typname, "integer"))
@@ -57,13 +59,13 @@ int MYSQLtoPLG(char *typname, char *var)
     type = TYPE_TINY;
   else if (!stricmp(typname, "text") && var) {
     switch (xconv) {
-      case 1:
+      case TPC_YES:
         type = TYPE_STRING;
         *var = 'X';
         break;
-      case 2:
+      case TPC_SKIP:
         *var = 'K';
-      default:
+      default: // TPC_NO
         type = TYPE_ERROR;
       } // endswitch xconv
 
@@ -88,7 +90,7 @@ int MYSQLtoPLG(char *typname, char *var)
     } else if (type == TYPE_STRING && !stricmp(typname, "varchar"))
       // This is to make the difference between CHAR and VARCHAR 
       *var = 'V';
-    else if (type == TYPE_ERROR && xconv == 2)
+    else if (type == TYPE_ERROR && xconv == TPC_SKIP)
       *var = 'K';
     else
       *var = 0;
@@ -174,7 +176,7 @@ const char *PLGtoMYSQLtype(int type, boo
 /************************************************************************/
 int MYSQLtoPLG(int mytype, char *var)
   {
-  int type;
+  int type, xconv = GetTypeConv();
 
   switch (mytype) {
     case MYSQL_TYPE_SHORT:
@@ -221,7 +223,7 @@ int MYSQLtoPLG(int mytype, char *var)
     case MYSQL_TYPE_LONG_BLOB:
       if (var) {
         switch (xconv) {
-          case 1:
+          case TPC_YES:
             if (*var != 'B') {
               // This is a TEXT column
               type = TYPE_STRING;
@@ -230,9 +232,9 @@ int MYSQLtoPLG(int mytype, char *var)
               type = TYPE_ERROR;
  
             break;
-          case 2:
+          case TPC_SKIP:
             *var = 'K';       // Skip
-          default:
+          default:            // TPC_NO
             type = TYPE_ERROR;
           } // endswitch xconv
 

=== modified file 'storage/connect/odbccat.h'
--- a/storage/connect/odbccat.h	2015-01-13 16:24:31 +0000
+++ b/storage/connect/odbccat.h	2015-01-31 14:05:43 +0000
@@ -2,6 +2,14 @@
 #define DEFAULT_LOGIN_TIMEOUT -1                  // means do not set
 #define DEFAULT_QUERY_TIMEOUT -1                  // means do not set
 
+typedef struct odbc_parms {
+  char *User;                 // User connect info
+  char *Pwd;                  // Password connect info
+  int   Cto;                  // Connect timeout
+  int   Qto;                  // Query timeout
+  bool  UseCnc;               // Use SQLConnect (!SQLDriverConnect)
+  } ODBCPARM, *POPARM;
+
 /***********************************************************************/
 /*  ODBC catalog function prototypes.                                  */
 /***********************************************************************/
@@ -10,8 +18,8 @@ char   *ODBCCheckConnection(PGLOBAL g, c
 #endif   // PROMPT_OK
 PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info);
 PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
-                    char *colpat, int maxres, int cto, int qto, bool info);
-PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, int cto, int qto);
+                    char *colpat, int maxres, bool info, POPARM sop);
+PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop); 
 PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
-                              int maxres, int cto, int qto, bool info);
+                   int maxres, bool info, POPARM sop);
 PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info);

=== modified file 'storage/connect/odbconn.cpp'
--- a/storage/connect/odbconn.cpp	2015-01-13 16:24:31 +0000
+++ b/storage/connect/odbconn.cpp	2015-02-08 17:17:29 +0000
@@ -37,8 +37,8 @@
 #include "xobject.h"
 //#include "kindex.h"
 #include "xtable.h"
-#include "tabodbc.h"
 #include "odbccat.h"
+#include "tabodbc.h"
 #include "plgcnx.h"                       // For DB types
 #include "resource.h"
 #include "valblk.h"
@@ -53,6 +53,8 @@
 extern "C" HINSTANCE s_hModule;           // Saved module handle
 #endif // WIN32
 
+int GetConvSize();
+
 /***********************************************************************/
 /*  Some macro's (should be defined elsewhere to be more accessible)   */
 /***********************************************************************/
@@ -122,7 +124,7 @@ int TranslateSQLType(int stp, int prec,
     case SQL_LONGVARCHAR:                   //  (-1)
       v = 'V';
       type = TYPE_STRING;
-      len = MY_MIN(abs(len), 256);
+      len = MY_MIN(abs(len), GetConvSize());
       break;
     case SQL_NUMERIC:                       //    2
     case SQL_DECIMAL:                       //    3
@@ -291,7 +293,7 @@ static void ResetNullValues(CATPARM *cap
 /*  of an ODBC table that will be retrieved by GetData commands.       */
 /***********************************************************************/
 PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
-                    char *colpat, int maxres, int cto, int qto, bool info)
+                    char *colpat, int maxres, bool info, POPARM sop)
   {
   int  buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
                    TYPE_SHORT,  TYPE_STRING, TYPE_INT,    TYPE_INT,
@@ -310,10 +312,8 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn
   /************************************************************************/
   if (!info) {
     ocp = new(g) ODBConn(g, NULL);
-    ocp->SetLoginTimeout((DWORD)cto);
-    ocp->SetQueryTimeout((DWORD)qto);
 
-    if (ocp->Open(dsn, 10) < 1)  // openReadOnly + noODBCdialog
+    if (ocp->Open(dsn, sop, 10) < 1)  // openReadOnly + noODBCdialog
       return NULL;
 
     if (table && !strchr(table, '%')) {
@@ -342,7 +342,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn
   } // endif ocp
 
   if (trace)
-    htrc("ODBCColumns: max=%d len=%d,%d,%d\n",
+    htrc("ODBCColumns: max=%d len=%d,%d,%d,%d\n",
          maxres, length[0], length[1], length[2], length[3]);
 
   /************************************************************************/
@@ -388,12 +388,13 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn
 /*  ODBCSrcCols: constructs the result blocks containing the              */
 /*  description of all the columns of a Srcdef option.                    */
 /**************************************************************************/
-PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, int cto, int qto)
+PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop)
   {
   ODBConn *ocp = new(g) ODBConn(g, NULL);
 
-  ocp->SetLoginTimeout((DWORD)cto);
-  ocp->SetQueryTimeout((DWORD)qto);
+  if (ocp->Open(dsn, sop, 10) < 1)   // openReadOnly + noOdbcDialog
+    return NULL;
+
   return ocp->GetMetaData(g, dsn, src);
   } // end of ODBCSrcCols
 
@@ -574,7 +575,7 @@ PQRYRES ODBCDataSources(PGLOBAL g, int m
 /*  an ODBC database that will be retrieved by GetData commands.          */
 /**************************************************************************/
 PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
-                              int maxres, int cto, int qto, bool info)
+                   int maxres, bool info, POPARM sop)
   {
   int      buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
                        TYPE_STRING, TYPE_STRING};
@@ -594,10 +595,8 @@ PQRYRES ODBCTables(PGLOBAL g, char *dsn,
     /*  Open the connection with the ODBC data source.                    */
     /**********************************************************************/
     ocp = new(g) ODBConn(g, NULL);
-    ocp->SetLoginTimeout((DWORD)cto);
-    ocp->SetQueryTimeout((DWORD)qto);
 
-    if (ocp->Open(dsn, 2) < 1)        // 2 is openReadOnly
+    if (ocp->Open(dsn, sop, 2) < 1)        // 2 is openReadOnly
       return NULL;
 
     if (!maxres)
@@ -925,11 +924,14 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdb
   m_Catver = (tdbp) ? tdbp->Catver : 0;
   m_Rows = 0;
   m_Connect = NULL;
+  m_User = NULL;
+  m_Pwd = NULL;
   m_Updatable = true;
   m_Transact = false;
   m_Scrollable = (tdbp) ? tdbp->Scrollable : false;
   m_First = true;
   m_Full = false;
+  m_UseCnc = false;
   m_IDQuoteChar[0] = '"';
   m_IDQuoteChar[1] = 0;
 //*m_ErrMsg = '\0';
@@ -1061,7 +1063,7 @@ void ODBConn::OnSetOptions(HSTMT hstmt)
 /***********************************************************************/
 /*  Open: connect to a data source.                                    */
 /***********************************************************************/
-int ODBConn::Open(PSZ ConnectString, DWORD options)
+int ODBConn::Open(PSZ ConnectString, POPARM sop, DWORD options)
   {
   PGLOBAL& g = m_G;
 //ASSERT_VALID(this);
@@ -1070,6 +1072,11 @@ int ODBConn::Open(PSZ ConnectString, DWO
 
   m_Updatable = !(options & openReadOnly);
   m_Connect = ConnectString;
+  m_User = sop->User;
+  m_Pwd = sop->Pwd;
+  m_LoginTimeout = sop->Cto;
+  m_QueryTimeout = sop->Qto;
+  m_UseCnc = sop->UseCnc;
 
   // Allocate the HDBC and make connection
   try {
@@ -1078,10 +1085,14 @@ int ODBConn::Open(PSZ ConnectString, DWO
     AllocConnect(options);
     /*ver = GetStringInfo(SQL_ODBC_VER);*/
 
-    if (Connect(options)) {
-      strcpy(g->Message, MSG(CONNECT_CANCEL));
-      return 0;
-      } // endif
+    if (!m_UseCnc) {
+      if (DriverConnect(options)) {
+        strcpy(g->Message, MSG(CONNECT_CANCEL));
+        return 0;
+        } // endif
+
+    } else           // Connect using SQLConnect
+      Connect();
 
     /*ver = GetStringInfo(SQL_DRIVER_ODBC_VER);*/
     // Verify support for required functionality and cache info
@@ -1164,9 +1175,26 @@ void ODBConn::AllocConnect(DWORD Options
   } // end of AllocConnect
 
 /***********************************************************************/
+/*  Connect to data source using SQLConnect.                           */
+/***********************************************************************/
+void ODBConn::Connect(void)
+  {
+  SQLRETURN   rc;
+  SQLSMALLINT ul = (m_User ? SQL_NTS : 0); 
+  SQLSMALLINT pl = (m_Pwd ? SQL_NTS : 0);
+
+  rc = SQLConnect(m_hdbc, (SQLCHAR*)m_Connect, SQL_NTS, 
+                          (SQLCHAR*)m_User, ul, (SQLCHAR*)m_Pwd, pl);
+                  
+  if (!Check(rc))
+    ThrowDBX(rc, "SQLConnect");
+
+  } // end of Connect
+
+/***********************************************************************/
 /*  Connect to data source using SQLDriverConnect.                     */
 /***********************************************************************/
-bool ODBConn::Connect(DWORD Options)
+bool ODBConn::DriverConnect(DWORD Options)
   {
   RETCODE rc;
   SWORD   nResult;
@@ -1213,7 +1241,7 @@ bool ODBConn::Connect(DWORD Options)
 
   // All done
   return false;
-  } // end of Connect
+  } // end of DriverConnect
 
 void ODBConn::VerifyConnect()
   {
@@ -1712,6 +1740,8 @@ bool ODBConn::BindParam(ODBCCOL *colp)
     strcpy(m_G->Message, x->GetErrorMessage(0));
     colsize = colp->GetPrecision();
     sqlt = GetSQLType(buftype);
+    dec = IsTypeChar(buftype) ? 0 : colp->GetScale();
+    nul = SQL_NULLABLE_UNKNOWN;
   } // end try/catch
 
   buf = colp->GetBuffer(0);
@@ -1865,9 +1895,6 @@ PQRYRES ODBConn::GetMetaData(PGLOBAL g,
   RETCODE rc;
   HSTMT   hstmt;
 
-  if (Open(dsn, 10) < 1)   // openReadOnly + noOdbcDialog
-    return NULL;
-
   try {
     rc = SQLAllocStmt(m_hdbc, &hstmt);
 

=== modified file 'storage/connect/odbconn.h'
--- a/storage/connect/odbconn.h	2015-01-13 16:24:31 +0000
+++ b/storage/connect/odbconn.h	2015-01-31 14:05:43 +0000
@@ -119,7 +119,7 @@ class ODBConn : public BLOCK {
     noOdbcDialog =    0x0008,     // Don't display ODBC Connect dialog
     forceOdbcDialog = 0x0010};    // Always display ODBC connect dialog
 
-  int  Open(PSZ ConnectString, DWORD Options = 0);
+  int  Open(PSZ ConnectString, POPARM sop, DWORD Options = 0);
   int  Rewind(char *sql, ODBCCOL *tocols);
   void Close(void);
   PQRYRES AllocateResult(PGLOBAL g);
@@ -135,8 +135,10 @@ class ODBConn : public BLOCK {
 
  public:
   // Operations
-  void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
-  void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
+//void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
+//void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
+//void SetUserName(PSZ user) {m_User = user;}
+//void SetUserPwd(PSZ pwd) {m_Pwd = pwd;}
   int  GetResultSize(char *sql, ODBCCOL *colp);
   int  ExecDirectSQL(char *sql, ODBCCOL *tocols);
   int  Fetch(void);
@@ -155,7 +157,7 @@ class ODBConn : public BLOCK {
 
   // Implementation
  public:
-//  virtual ~ODBConn();
+//virtual ~ODBConn();
 
   // ODBC operations
  protected:
@@ -163,7 +165,8 @@ class ODBConn : public BLOCK {
   void ThrowDBX(RETCODE rc, PSZ msg, HSTMT hstmt = SQL_NULL_HSTMT);
   void ThrowDBX(PSZ msg);
   void AllocConnect(DWORD dwOptions);
-  bool Connect(DWORD Options);
+  void Connect(void);
+  bool DriverConnect(DWORD Options);
   void VerifyConnect(void);
   void GetConnectInfo(void);
   void Free(void);
@@ -185,11 +188,14 @@ class ODBConn : public BLOCK {
   DWORD    m_RowsetSize;
   char     m_IDQuoteChar[2];
   PSZ      m_Connect;
+  PSZ      m_User;
+  PSZ      m_Pwd;
   int      m_Catver;
   int      m_Rows;
   bool     m_Updatable;
   bool     m_Transact;
   bool     m_Scrollable;
+  bool     m_UseCnc;
   bool     m_First;
   bool     m_Full;
   }; // end of ODBConn class definition

=== modified file 'storage/connect/tabdos.h'
--- a/storage/connect/tabdos.h	2014-10-09 15:23:37 +0000
+++ b/storage/connect/tabdos.h	2015-01-27 18:18:51 +0000
@@ -222,6 +222,7 @@ class DllExport DOSCOL : public COLBLK {
   virtual PVBLK  GetDval(void) {return Dval;}
 
   // Methods
+  using COLBLK::Print;
   virtual bool   VarSize(void);
   virtual bool   SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
   virtual void   ReadColumn(PGLOBAL g);

=== modified file 'storage/connect/tabjson.cpp'
--- a/storage/connect/tabjson.cpp	2015-01-20 00:21:56 +0000
+++ b/storage/connect/tabjson.cpp	2015-02-18 23:59:02 +0000
@@ -1,5 +1,5 @@
 /************* tabjson C++ Program Source Code File (.CPP) *************/
-/* PROGRAM NAME: tabxjson     Version 1.0                              */
+/* PROGRAM NAME: tabjson     Version 1.0                               */
 /*  (C) Copyright to the author Olivier BERTRAND          2014 - 2015  */
 /*  This program are the JSON class DB execution routines.             */
 /***********************************************************************/
@@ -119,12 +119,12 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : T
   Fpos = -1;
   Spos = N = 0;
   Limit = tdp->Limit;
+  NextSame = 0;
+  SameRow = 0;
+  Xval = -1;
   Pretty = tdp->Pretty;
   Strict = tdp->Strict;
-  NextSame = false;
   Comma = false;
-  SameRow = 0;
-  Xval = -1;
   } // end of TDBJSN standard constructor
 
 TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
@@ -137,12 +137,12 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NU
   Spos = tdbp->Spos;
   N = tdbp->N;
   Limit = tdbp->Limit;
-  Pretty = tdbp->Pretty;
-  Strict = tdbp->Strict;
   NextSame = tdbp->NextSame;
-  Comma = tdbp->Comma;
   SameRow = tdbp->SameRow;
   Xval = tdbp->Xval;
+  Pretty = tdbp->Pretty;
+  Strict = tdbp->Strict;
+  Comma = tdbp->Comma;
   } // end of TDBJSN copy constructor
 
 // Used for update
@@ -221,14 +221,9 @@ bool TDBJSN::OpenDB(PGLOBAL g)
     /*******************************************************************/
     /*  Table already open replace it at its beginning.                */
     /*******************************************************************/
-    for (PJCOL cp = (PJCOL)Columns; cp; cp = (PJCOL)cp->GetNext()) {
-      cp->Nx = 0;
-      cp->Arp = NULL;
-      } // endfor cp
-
     Fpos= -1;
     Spos = 0;
-    NextSame = false;
+    NextSame = 0;
     SameRow = 0;
   } else {
     /*******************************************************************/
@@ -292,7 +287,8 @@ int TDBJSN::ReadDB(PGLOBAL g)
   N++;
 
   if (NextSame) {
-    SameRow++;
+    SameRow = NextSame;
+    NextSame = 0;
     return RC_OK;
   } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK)
     if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK)) {
@@ -333,21 +329,20 @@ int TDBJSN::ReadDB(PGLOBAL g)
 
   } // end of PrepareWriting
 
-/* ----------------------------- JSNCOL ------------------------------- */
+/* ---------------------------- JSONCOL ------------------------------ */
 
 /***********************************************************************/
-/*  JSNCOL public constructor.                                         */
+/*  JSONCOL public constructor.                                        */
 /***********************************************************************/
 JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
        : DOSCOL(g, cdp, tdbp, cprec, i, "DOS")
   {
   Tjp = (TDBJSN *)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
-  Arp = NULL;
   Jpath = cdp->GetFmt();
   MulVal = NULL;
   Nodes = NULL;
-  Nod = Nx =0;
-  Ival = -1;
+  Nod = 0;
+  Xnod = -1;
   Xpd = false;
   Parsed = false;
   } // end of JSONCOL constructor
@@ -359,13 +354,11 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp,
 JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
   {
   Tjp = col1->Tjp;
-  Arp = col1->Arp;
   Jpath = col1->Jpath;
   MulVal = col1->MulVal;
   Nodes = col1->Nodes;
   Nod = col1->Nod;
-  Ival = col1->Ival;
-  Nx = col1->Nx;
+  Xnod = col1->Xnod;
   Xpd = col1->Xpd;
   Parsed = col1->Parsed;
   } // end of JSONCOL copy constructor
@@ -387,17 +380,16 @@ bool JSONCOL::SetBuffer(PGLOBAL g, PVAL
   } // end of SetBuffer
 
 /***********************************************************************/
-/*  Analyse array processing options.                                  */
+/*  Check whether this object is expanded.                             */
 /***********************************************************************/
 bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b)
   {
-  if (Tjp->Xcol && nm && !strcmp(nm, Tjp->Xcol) &&
-     (Tjp->Xval < 0 || Tjp->Xval == i)) {
+  if ((Tjp->Xcol && nm && !strcmp(nm, Tjp->Xcol) &&
+      (Tjp->Xval < 0 || Tjp->Xval == i)) || Xpd) {
     Xpd = true;              // Expandable object
-    Nodes[i].Op = OP_XX;
-    Tjp->Xval = i;
+    Nodes[i].Op = OP_EXP;
   } else if (b) {
-    strcpy(g->Message, "Cannot expand more than one array");
+    strcpy(g->Message, "Cannot expand more than one branch");
     return true;
   } // endif Xcol
 
@@ -434,7 +426,7 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g,
     // Default specifications
     if (CheckExpand(g, i, nm, false))
       return true;
-    else if (jnp->Op != OP_XX)
+    else if (jnp->Op != OP_EXP)
       if (!Value->IsTypeNum()) {
         jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING);
         jnp->Op = OP_CNC;
@@ -456,13 +448,13 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g,
       case '*': jnp->Op = OP_MULT; break;
       case '>': jnp->Op = OP_MAX;  break;
       case '<': jnp->Op = OP_MIN;  break;
-      case '#': jnp->Op = OP_NUM;  break;
       case '!': jnp->Op = OP_SEP;  break; // Average
+      case '#': jnp->Op = OP_NUM;  break;
       case 'x':
       case 'X': // Expand this array
         if (!Tjp->Xcol && nm) {  
           Xpd = true;
-          jnp->Op = OP_XX;
+          jnp->Op = OP_EXP;
           Tjp->Xval = i;
           Tjp->Xcol = nm;
         } else if (CheckExpand(g, i, nm, true))
@@ -490,6 +482,38 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g,
     return true;
   } // endif's
 
+  // For calculated arrays, a local Value must be used
+  switch (jnp->Op) {
+    case OP_NUM:
+      jnp->Valp = AllocateValue(g, TYPE_INT);
+      break;
+    case OP_ADD:
+    case OP_MULT:
+    case OP_SEP:
+      if (!IsTypeChar(Buf_Type))
+        jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
+      else
+        jnp->Valp = AllocateValue(g, TYPE_DOUBLE);
+
+      break;
+    case OP_MIN:
+    case OP_MAX:
+      jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
+      break;
+    case OP_CNC:
+      if (IsTypeChar(Buf_Type))
+        jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
+      else
+        jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
+
+      break;
+    default:
+      break;
+  } // endswitch Op
+
+  if (jnp->Valp)
+    MulVal = AllocateValue(g, jnp->Valp);
+
   return false;
   } // end of SetArrayOptions
 
@@ -533,6 +557,9 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
       if (SetArrayOptions(g, p, i, Nodes[i-1].Key))
         return true;
 
+    } else if (*p == '*') {
+      // Return JSON
+      Nodes[i].Op = OP_XX;
     } else {
       Nodes[i].Key = p;
       Nodes[i].Op = OP_EXIST;
@@ -546,42 +573,50 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
   } // end of ParseJpath
 
 /***********************************************************************/
+/*  MakeJson: Serialize the json item and set value to it.             */
+/***********************************************************************/
+PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
+  {
+  if (Value->IsTypeNum()) {
+    strcpy(g->Message, "Cannot make Json for a numeric column");
+    Value->Reset();
+  } else
+    Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
+
+  return Value;
+  } // end of MakeJson
+
+/***********************************************************************/
 /*  SetValue: Set a value from a JVALUE contains.                      */
 /***********************************************************************/
 void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
   {
   if (val) {
-    if (Nodes[n].Op == OP_NUM)
-      vp->SetValue(1);
-    else {
- again:
-      switch (val->GetValType()) {
-        case TYPE_STRG:
-        case TYPE_INTG:
-        case TYPE_DBL:
-          vp->SetValue_pval(val->GetValue());
-          break;
-        case TYPE_BOOL:
-          if (vp->IsTypeNum())
-            vp->SetValue(val->GetInteger() ? 1 : 0);
-          else
-            vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
-     
+    switch (val->GetValType()) {
+      case TYPE_STRG:
+      case TYPE_INTG:
+      case TYPE_DBL:
+        vp->SetValue_pval(val->GetValue());
+        break;
+      case TYPE_BOOL:
+        if (vp->IsTypeNum())
+          vp->SetValue(val->GetInteger() ? 1 : 0);
+        else
+          vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
+    
+        break;
+      case TYPE_JAR:
+        SetJsonValue(g, vp, val->GetArray()->GetValue(0), n);
+        break;
+      case TYPE_JOB:
+//      if (!vp->IsTypeNum() || !Strict) {
+          vp->SetValue_psz(val->GetObject()->GetText(g));
           break;
-        case TYPE_JAR:
-          val = val->GetArray()->GetValue(0);
-          goto again;
-        case TYPE_JOB:
-          if (!vp->IsTypeNum()) {
-            vp->SetValue_psz(val->GetObject()->GetText(g));
-            break;
-            } // endif Type
+//        } // endif Type
      
-        default:
-          vp->Reset();
-        } // endswitch Type
-
-      } // endelse
+      default:
+        vp->Reset();
+      } // endswitch Type
 
   } else
     vp->Reset();
@@ -589,16 +624,210 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PV
   } // end of SetJsonValue
 
 /***********************************************************************/
+/*  ReadColumn:                                                        */
+/***********************************************************************/
+void JSONCOL::ReadColumn(PGLOBAL g)
+  {
+  if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
+    Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
+
+  } // end of ReadColumn
+
+/***********************************************************************/
+/*  GetColumnValue:                                                    */
+/***********************************************************************/
+PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
+  {
+  int   n = Nod - 1;
+  bool  expd = false;
+  PJAR  arp;
+  PJVAL val = NULL;
+
+  for (; i < Nod && row; i++) {
+    if (Nodes[i].Op == OP_NUM) {
+      Value->SetValue(row->GetType() == TYPE_JAR ? row->size() : 1);
+      return(Value);
+    } else if (Nodes[i].Op == OP_XX) {
+      return MakeJson(g, row);
+    } else switch (row->GetType()) {
+      case TYPE_JOB:
+        if (!Nodes[i].Key) {
+          // Expected Array was not there
+          if (i < Nod-1)
+            continue;
+          else
+            val = new(g) JVALUE(row);
+
+        } else
+          val = ((PJOB)row)->GetValue(Nodes[i].Key);
+
+        break;
+      case TYPE_JAR:
+        arp = (PJAR)row;
+
+        if (!Nodes[i].Key) {
+          if (Nodes[i].Op != OP_NULL) {
+            if (Nodes[i].Rank) {
+              val = arp->GetValue(Nodes[i].Rank - 1);
+            } else if (Nodes[i].Op == OP_EXP) {
+              return ExpandArray(g, arp, i);
+            } else
+              return CalculateArray(g, arp, i);
+
+          } else
+            val = NULL;
+
+        } else if (i < Nod-1) {
+          strcpy(g->Message, "Unexpected array");
+          val = NULL;          // Not an expected array
+        } else
+          val = arp->GetValue(0);
+
+        break;
+      case TYPE_JVAL:
+        val = (PJVAL)row;
+        break;
+      default:
+        sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+        val = NULL;
+      } // endswitch Type
+
+    if (i < Nod-1)
+      row = (val) ? val->GetJson() : NULL;
+
+    } // endfor i
+
+  SetJsonValue(g, Value, val, n);
+  return Value;
+  } // end of GetColumnValue
+
+/***********************************************************************/
+/*  ExpandArray:                                                       */
+/***********************************************************************/
+PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
+  {
+  int    ars;
+  PJVAL  jvp;
+  JVALUE jval;
+
+  ars = MY_MIN(Tjp->Limit, arp->size());
+
+  if (!(jvp = arp->GetValue(Nodes[n].Nx))) {
+    strcpy(g->Message, "Logical error expanding array");
+    longjmp(g->jumper[g->jump_level], 666);
+    } // endif jvp
+
+  if (n < Nod - 1 && jvp->GetJson()) {
+    jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
+    jvp = &jval;
+    } // endif n
+
+  if (n >= Tjp->NextSame) {
+    if (++Nodes[n].Nx == ars) {
+      Nodes[n].Nx = 0;
+      Xnod = 0;
+    } else
+      Xnod = n;
+
+    Tjp->NextSame = Xnod;
+    } // endif NextSame 
+
+  SetJsonValue(g, Value, jvp, n);
+  return Value;
+  } // end of ExpandArray
+
+/***********************************************************************/
+/*  CalculateArray:                                                    */
+/***********************************************************************/
+PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
+  {
+  int    i, ars, nv = 0, nextsame = Tjp->NextSame;
+  bool   err;
+  OPVAL  op = Nodes[n].Op;
+  PVAL   val[2], vp = Nodes[n].Valp;
+  PJVAL  jvrp, jvp;
+  JVALUE jval;
+
+  vp->Reset();
+  ars = MY_MIN(Tjp->Limit, arp->size());
+
+  for (i = 0; i < ars; i++) {
+    jvrp = arp->GetValue(i);
+
+    do {
+      if (n < Nod - 1 && jvrp->GetJson()) {
+        Tjp->NextSame = nextsame;
+        jval.SetValue(GetColumnValue(g, jvrp->GetJson(), n + 1));
+        jvp = &jval;
+      } else
+        jvp = jvrp;
+  
+      if (!nv++) {
+        SetJsonValue(g, vp, jvp, n);
+        continue;
+      } else
+        SetJsonValue(g, MulVal, jvp, n);
+  
+      if (!MulVal->IsZero()) {
+        switch (op) {
+          case OP_CNC:
+            if (Nodes[n].CncVal) {
+              val[0] = Nodes[n].CncVal;
+              err = vp->Compute(g, val, 1, op);
+              } // endif CncVal
+  
+            val[0] = MulVal;
+            err = vp->Compute(g, val, 1, op);
+            break;
+//        case OP_NUM:
+          case OP_SEP:
+            val[0] = Nodes[n].Valp;
+            val[1] = MulVal;
+            err = vp->Compute(g, val, 2, OP_ADD);
+            break;
+          default:
+            val[0] = Nodes[n].Valp;
+            val[1] = MulVal;
+            err = vp->Compute(g, val, 2, op);
+          } // endswitch Op
+
+        if (err)
+          vp->Reset();
+    
+        } // endif Zero
+
+      } while (Tjp->NextSame > nextsame);
+
+    } // endfor i
+
+  if (op == OP_SEP) {
+    // Calculate average
+    MulVal->SetValue(nv);
+    val[0] = vp;
+    val[1] = MulVal;
+
+    if (vp->Compute(g, val, 2, OP_DIV))
+      vp->Reset();
+
+    } // endif Op
+
+  Tjp->NextSame = nextsame;
+  return vp;
+  } // end of CalculateArray
+
+/***********************************************************************/
 /*  GetRow: Get the object containing this column.                     */
 /***********************************************************************/
-PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
+PJSON JSONCOL::GetRow(PGLOBAL g)
   {
   PJVAL val;
   PJAR  arp;
   PJSON nwr, row = Tjp->Row;
 
   for (int i = 0; i < Nod-1 && row; i++) {
-    switch (row->GetType()) {
+    if (Nodes[i+1].Op == OP_XX)
+      break;
+    else switch (row->GetType()) {
       case TYPE_JOB:
         if (!Nodes[i].Key)
           // Expected Array was not there
@@ -609,21 +838,13 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mod
       case TYPE_JAR:
         if (!Nodes[i].Key) {
           if (Nodes[i].Op != OP_NULL) {
-            Ival = i;
             arp = (PJAR)row;
 
-            if (mode < 2)     // First pass
-              Arp = arp;
-
-            if (Nodes[i].Op != OP_XX) {
-              if (Nodes[i].Rank)
-                val = arp->GetValue(Nodes[i].Rank - 1);
-              else
-                val = arp->GetValue(arp == Arp ? Nx : 0);
+            if (Nodes[i].Rank)
+              val = arp->GetValue(Nodes[i].Rank - 1);
+            else
+              val = arp->GetValue(Nodes[i].Nx);
 
-            } else
-              val = arp->GetValue(Tjp->SameRow);
-                       
           } else
             val = NULL;
 
@@ -643,15 +864,16 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mod
 
     if (val) {
       row = val->GetJson();
-    } else if (mode == 1) {          // mode write
+    } else {
       // Construct missing objects
       for (i++; row && i < Nod; i++) {
-        if (!Nodes[i].Key) {
+        if (Nodes[i].Op == OP_XX)
+          break;
+        else if (!Nodes[i].Key)
           // Construct intermediate array
           nwr = new(g) JARRAY;
-        } else {
+        else
           nwr = new(g) JOBJECT;
-        } // endif Nodes
 
         if (row->GetType() == TYPE_JOB) {
           ((PJOB)row)->SetValue(g, new(g) JVALUE(nwr), Nodes[i-1].Key);
@@ -667,8 +889,7 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mod
         } // endfor i
 
       break;
-    } else
-      row = NULL;
+    } // endelse
 
     } // endfor i
 
@@ -676,131 +897,6 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mod
   } // end of GetRow
 
 /***********************************************************************/
-/*  ReadColumn:                                                        */
-/***********************************************************************/
-void JSONCOL::ReadColumn(PGLOBAL g)
-  {
-  int   mode = 0, n = Nod - 1;
-  PJSON row;
-  PJVAL val = NULL;
-
- evenmore:
-  row = GetRow(g, mode);
-
- more:
-  if (row) switch (row->GetType()) {
-    case TYPE_JOB:
-      if (Nodes[n].Key)
-        val = row->GetValue(Nodes[n].Key);
-      else
-        val = new(g) JVALUE(row);
-
-      break;
-    case TYPE_JAR:
-      // Multiple column ?
-      if (Nodes[n].Op != OP_NULL) {
-        Arp = (PJAR)row;
-        val = Arp->GetValue(Nodes[n].Rank > 0 ?
-                            Nodes[n].Rank - 1 : 
-                            Nodes[n].Op == OP_XX ? Tjp->SameRow : Nx);
-        Ival = n;
-      } else
-        val = NULL;
-
-      break;
-    case TYPE_JVAL:
-      val = (PJVAL)row;
-      break;
-    default:
-      sprintf(g->Message, "Wrong return value type %d", row->GetType());
-      Value->Reset();
-      return;
-    } // endswitch Type
-
-  if (!Nx /*|| (Xpd)*/)
-    SetJsonValue(g, Value, val, n);
-
-  if (Arp) {
-    // Multiple column
-    int ars = (Nodes[Ival].Rank > 0) ? 1 : MY_MIN(Tjp->Limit, Arp->size());
-
-    if (Nodes[Ival].Op == OP_XX) {
-      if (ars > Tjp->SameRow + 1)
-        Tjp->NextSame = true;      // More to come
-      else {
-        Tjp->NextSame = false;
-        Arp = NULL;
-      } // endelse
-
-    } else {
-      if (Nx && val) {
-        SetJsonValue(g, MulVal, val, Ival);
-
-        if (!MulVal->IsZero()) {
-          PVAL val[2];
-          bool err;
-
-          switch (Nodes[Ival].Op) {
-            case OP_CNC:
-              if (Nodes[Ival].CncVal) {
-                val[0] = Nodes[Ival].CncVal;
-                err = Value->Compute(g, val, 1, Nodes[Ival].Op);
-                } // endif CncVal
-
-              val[0] = MulVal;
-              err = Value->Compute(g, val, 1, Nodes[Ival].Op);
-              break;
-            case OP_NUM:
-            case OP_SEP:
-              val[0] = Value;
-              val[1] = MulVal;
-              err = Value->Compute(g, val, 2, OP_ADD);
-              break;
-            default:
-              val[0] = Value;
-              val[1] = MulVal;
-              err = Value->Compute(g, val, 2, Nodes[Ival].Op);
-            } // endswitch Op
-
-          if (err)
-            Value->Reset();
-
-          } // endif Zero
-
-        } // endif Nx
-
-      if (ars > ++Nx) {
-        if (Ival != n) {
-          mode = 2;
-          goto evenmore;
-        } else
-          goto more;
-
-      } else {
-        if (Nodes[Ival].Op == OP_SEP) {
-          // Calculate average
-          PVAL val[2];
-
-          MulVal->SetValue(ars);
-          val[0] = Value;
-          val[1] = MulVal;
-
-          if (Value->Compute(g, val, 2, OP_DIV))
-            Value->Reset();
-
-          } // endif Op
-
-        Arp = NULL;
-        Nx = 0;
-      } // endif ars
-
-    } // endif Op
-
-    } // endif Arp
-
-  } // end of ReadColumn
-
-/***********************************************************************/
 /*  WriteColumn:                                                       */
 /***********************************************************************/
 void JSONCOL::WriteColumn(PGLOBAL g)
@@ -817,10 +913,11 @@ void JSONCOL::WriteColumn(PGLOBAL g)
   if (Value->IsNull() && Tjp->Mode == MODE_INSERT)
     return;
 
+  char *s;
   PJOB  objp = NULL;
   PJAR  arp = NULL;
   PJVAL jvp = NULL;
-  PJSON row = GetRow(g, 1);
+  PJSON jsp, row = GetRow(g);
   JTYP  type = row->GetType();
 
   switch (row->GetType()) {
@@ -832,6 +929,28 @@ void JSONCOL::WriteColumn(PGLOBAL g)
 
   if (row) switch (Buf_Type) {
     case TYPE_STRING:
+      if (Nodes[Nod-1].Op == OP_XX) {
+        s = Value->GetCharValue();
+        jsp = ParseJson(g, s, (int)strlen(s), 0);
+
+        if (arp) {
+          if (Nod > 1 && Nodes[Nod-2].Rank)
+            arp->SetValue(g, new(g) JVALUE(jsp), Nodes[Nod-2].Rank-1);
+          else
+            arp->AddValue(g, new(g) JVALUE(jsp));
+
+          arp->InitArray(g);
+        } else if (objp) {
+          if (Nod > 1 && Nodes[Nod-2].Key)
+            objp->SetValue(g, new(g) JVALUE(jsp), Nodes[Nod-2].Key);
+
+        } else if (jvp)
+          jvp->SetValue(jsp);
+
+        break;
+        } // endif Op
+
+      // Passthru
     case TYPE_DATE:
     case TYPE_INT:
     case TYPE_DOUBLE:
@@ -1175,11 +1294,6 @@ bool TDBJSON::OpenDB(PGLOBAL g)
     /*******************************************************************/
     /*  Table already open replace it at its beginning.                */
     /*******************************************************************/
-    for (PJCOL cp = (PJCOL)Columns; cp; cp = (PJCOL)cp->GetNext()) {
-      cp->Nx = 0;
-      cp->Arp = NULL;
-      } // endfor cp
-
     Fpos= -1;
     Spos = 0;
     NextSame = false;
@@ -1217,7 +1331,8 @@ int TDBJSON::ReadDB(PGLOBAL g)
   N++;
 
   if (NextSame) {
-    SameRow++;
+    SameRow = NextSame;
+    NextSame = false;
     rc = RC_OK;
   } else if (++Fpos < (signed)Doc->size()) {
     Row = Doc->GetValue(Fpos);
@@ -1257,9 +1372,10 @@ int TDBJSON::WriteDB(PGLOBAL g)
       return RC_FX;
 
   } else { // if (Jmode == MODE_VALUE)
-    if (Mode == MODE_INSERT)
+    if (Mode == MODE_INSERT) {
       Doc->AddValue(g, (PJVAL)Row);
-    else if (Doc->SetValue(g, (PJVAL)Row, Fpos))
+      Row = new(g) JVALUE;
+    } else if (Doc->SetValue(g, (PJVAL)Row, Fpos))
       return RC_FX;
 
   } // endif Jmode

=== modified file 'storage/connect/tabjson.h'
--- a/storage/connect/tabjson.h	2015-01-19 17:55:25 +0000
+++ b/storage/connect/tabjson.h	2015-02-11 20:39:41 +0000
@@ -16,8 +16,6 @@ typedef class JSONDEF *PJDEF;
 typedef class TDBJSON *PJTDB;
 typedef class JSONCOL *PJCOL;
 
-class TDBJSN;
-
 /***********************************************************************/
 /*  The JSON tree node. Can be an Object or an Array.           	  	 */
 /***********************************************************************/
@@ -25,7 +23,9 @@ typedef struct _jnode {
   PSZ   Key;                    // The key used for object
   OPVAL Op;                     // Operator used for this node
   PVAL  CncVal;                 // To cont value used for OP_CNC
+  PVAL  Valp;                   // The internal array VALUE
   int   Rank;                   // The rank in array
+  int   Nx;                     // Same row number
 } JNODE, *PJNODE;
 
 /***********************************************************************/
@@ -77,7 +77,7 @@ class TDBJSN : public TDBDOS {
   virtual PTDB CopyOne(PTABS t);
   virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
   virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL colp);
-  virtual int  RowNumber(PGLOBAL g, BOOL b = FALSE)
+  virtual int  RowNumber(PGLOBAL g, bool b = FALSE)
                 {return (b) ? N : Fpos + 1;}
 
   // Database routines
@@ -98,11 +98,11 @@ class TDBJSN : public TDBDOS {
   int   N;                         // The current Rownum
 	int   Limit;		    				     // Limit of multiple values
   int   Pretty;                    // Depends on file structure
-  bool  Strict;                    // Strict syntax checking
-  bool  NextSame;                  // Same next row
-  bool  Comma;                     // Row has final comma
+  int   NextSame;                  // Same next row
   int   SameRow;                   // Same row nb
   int   Xval;                      // Index of expandable array
+  bool  Strict;                    // Strict syntax checking
+  bool  Comma;                     // Row has final comma
   }; // end of class TDBJSN
 
 /* -------------------------- JSONCOL class -------------------------- */
@@ -130,8 +130,12 @@ class JSONCOL : public DOSCOL {
  protected:
   bool    CheckExpand(PGLOBAL g, int i, PSZ nm, bool b);
   bool    SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm);
-  PJSON   GetRow(PGLOBAL g, int mode);
+  PVAL    GetColumnValue(PGLOBAL g, PJSON row, int i);
+  PVAL    ExpandArray(PGLOBAL g, PJAR arp, int n);
+  PVAL    CalculateArray(PGLOBAL g, PJAR arp, int n);
+  PVAL    MakeJson(PGLOBAL g, PJSON jsp);
   void    SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n);
+  PJSON   GetRow(PGLOBAL g);
 
   // Default constructor not to be used
   JSONCOL(void) {}
@@ -139,12 +143,10 @@ class JSONCOL : public DOSCOL {
   // Members
   TDBJSN *Tjp;                  // To the JSN table block
   PVAL    MulVal;               // To value used by multiple column
-  PJAR    Arp;                  // The intermediate array
   char   *Jpath;                // The json path
-  JNODE  *Nodes  ;              // The intermediate objects
+  JNODE  *Nodes;                // The intermediate objects
   int     Nod;                  // The number of intermediate objects
-  int     Ival;                 // Index of multiple values
-  int     Nx;                   // The last read sub-row
+  int     Xnod;                 // Index of multiple values
   bool    Xpd;                  // True for expandable column
   bool    Parsed;               // True when parsed
   }; // end of class JSONCOL

=== modified file 'storage/connect/tabmysql.cpp'
--- a/storage/connect/tabmysql.cpp	2015-01-06 09:18:04 +0000
+++ b/storage/connect/tabmysql.cpp	2015-01-23 16:54:53 +0000
@@ -1141,19 +1141,16 @@ int TDBMYSQL::WriteDB(PGLOBAL g)
   int  rc;
   uint len = Query->GetLength();
   char buf[64];
-  bool b, oom = false;
+  bool oom = false;
 
   // Make the Insert command value list
   for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
     if (!colp->GetValue()->IsNull()) {
-      if ((b = colp->GetResultType() == TYPE_STRING ||
-               colp->GetResultType() == TYPE_DATE))
-        oom |= Query->Append('\'');
-  
-      oom |= Query->Append(colp->GetValue()->GetCharString(buf));
-  
-      if (b)
-        oom |= Query->Append('\'');
+      if (colp->GetResultType() == TYPE_STRING ||
+          colp->GetResultType() == TYPE_DATE)
+        oom |= Query->Append_quoted(colp->GetValue()->GetCharString(buf));
+      else
+        oom |= Query->Append(colp->GetValue()->GetCharString(buf));
   
     } else
       oom |= Query->Append("NULL");

=== modified file 'storage/connect/taboccur.cpp'
--- a/storage/connect/taboccur.cpp	2014-10-21 15:29:51 +0000
+++ b/storage/connect/taboccur.cpp	2015-01-27 18:18:51 +0000
@@ -355,7 +355,7 @@ bool TDBOCCUR::MakeColumnList(PGLOBAL g)
 
   for (colp = Columns; colp; colp = colp->GetNext())
     if (colp->GetAmType() == TYPE_AM_PRX)
-		  if (((PPRXCOL)colp)->Init(g))
+		  if (((PPRXCOL)colp)->Init(g, NULL))
   			return true;
 
 	Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL));

=== modified file 'storage/connect/tabodbc.cpp'
--- a/storage/connect/tabodbc.cpp	2015-01-13 16:24:31 +0000
+++ b/storage/connect/tabodbc.cpp	2015-02-08 17:17:29 +0000
@@ -66,8 +66,8 @@
 #include "plgdbsem.h"
 #include "mycat.h"
 #include "xtable.h"
-#include "tabodbc.h"
 #include "odbccat.h"
+#include "tabodbc.h"
 #include "tabmul.h"
 #include "reldef.h"
 #include "tabcol.h"
@@ -93,9 +93,10 @@ bool ExactInfo(void);
 /***********************************************************************/
 ODBCDEF::ODBCDEF(void)
   {
-  Connect= Tabname= Tabschema= Tabcat= Srcdef= Qchar= Qrystr= Sep= NULL;
+  Connect = Tabname = Tabschema = Username = Password = NULL;
+  Tabcat = Srcdef = Qchar = Qrystr = Sep = NULL;
   Catver = Options = Cto = Qto = Quoted = Maxerr = Maxres = 0;
-  Scrollable = Memory = Xsrc = false;
+  Scrollable = Memory = Xsrc = UseCnc = false;
   }  // end of ODBCDEF constructor
 
 /***********************************************************************/
@@ -117,6 +118,8 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR
   Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
   Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
   Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
+  Username = GetStringCatInfo(g, "User", NULL);
+  Password = GetStringCatInfo(g, "Password", NULL);
 
   if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL)))
     Read_Only = true;
@@ -133,6 +136,7 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR
   Cto= GetIntCatInfo("ConnectTimeout", DEFAULT_LOGIN_TIMEOUT);
   Qto= GetIntCatInfo("QueryTimeout", DEFAULT_QUERY_TIMEOUT);
   Scrollable = GetBoolCatInfo("Scrollable", false);
+  UseCnc = GetBoolCatInfo("UseDSN", false);
   Memory = GetBoolCatInfo("Memory", false);
   Pseudo = 2;    // FILID is Ok but not ROWID
   return false;
@@ -190,34 +194,40 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp
     Connect = tdp->Connect;
     TableName = tdp->Tabname;
     Schema = tdp->Tabschema;
+    Ops.User = tdp->Username;
+    Ops.Pwd = tdp->Password;
     Catalog = tdp->Tabcat;
     Srcdef = tdp->Srcdef;
     Qrystr = tdp->Qrystr;
     Sep = tdp->GetSep();
     Options = tdp->Options;
-    Cto = tdp->Cto;
-    Qto = tdp->Qto;
+    Ops.Cto = tdp->Cto;
+    Ops.Qto = tdp->Qto;
     Quoted = MY_MAX(0, tdp->GetQuoted());
     Rows = tdp->GetElemt();
     Catver = tdp->Catver;
     Memory = (tdp->Memory) ? 1 : 0;
     Scrollable = tdp->Scrollable;
+    Ops.UseCnc = tdp->UseCnc;
   } else {
     Connect = NULL;
     TableName = NULL;
     Schema = NULL;
+    Ops.User = NULL;
+    Ops.Pwd = NULL;
     Catalog = NULL;
     Srcdef = NULL;
     Qrystr = NULL;
     Sep = 0;
     Options = 0;
-    Cto = DEFAULT_LOGIN_TIMEOUT;
-    Qto = DEFAULT_QUERY_TIMEOUT;
+    Ops.Cto = DEFAULT_LOGIN_TIMEOUT;
+    Ops.Qto = DEFAULT_QUERY_TIMEOUT;
     Quoted = 0;
     Rows = 0;
     Catver = 0;
     Memory = 0;
     Scrollable = false;
+    Ops.UseCnc = false;
   } // endif tdp
 
   Quote = NULL;
@@ -242,6 +252,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE
   Connect = tdbp->Connect;
   TableName = tdbp->TableName;
   Schema = tdbp->Schema;
+  Ops = tdbp->Ops;
   Catalog = tdbp->Catalog;
   Srcdef = tdbp->Srcdef;
   Qrystr = tdbp->Qrystr;
@@ -254,8 +265,6 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE
   MulConn = tdbp->MulConn;
   DBQ = tdbp->DBQ;
   Options = tdbp->Options;
-  Cto = tdbp->Cto;
-  Qto = tdbp->Qto;
   Quoted = tdbp->Quoted;
   Rows = tdbp->Rows;
   Fpos = tdbp->Fpos;
@@ -370,7 +379,7 @@ int TDBODBC::Decode(char *txt, char *buf
 /***********************************************************************/
 char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
   {
-  char   *colist, *tabname, *sql, buf[64];
+  char   *colist, *tabname, *sql, buf[NAM_LEN * 3];
   LPCSTR  schmp = NULL, catp = NULL;
   int     len, ncol = 0;
   bool    first = true;
@@ -474,6 +483,9 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool c
 
   if (To_CondFil)
     strcat(strcat(sql, " WHERE "), To_CondFil->Body);
+    
+  if (trace)
+    htrc("sql: '%s'\n", sql); 
 
   return sql;
   } // end of MakeSQL
@@ -483,7 +495,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool c
 /***********************************************************************/
 char *TDBODBC::MakeInsert(PGLOBAL g)
   {
-  char *stmt, *colist, *valist;
+  char *stmt, *colist, *valist, buf[NAM_LEN * 3];
 //  char *tk = "`";
   int   len = 0;
   bool  b = FALSE;
@@ -510,10 +522,13 @@ char *TDBODBC::MakeInsert(PGLOBAL g)
     } else
       b = true;
 
+    // Column name can be in UTF-8 encoding
+    Decode(colp->GetName(), buf, sizeof(buf));
+
     if (Quote)
-      strcat(strcat(strcat(colist, Quote), colp->GetName()), Quote);
+      strcat(strcat(strcat(colist, Quote), buf), Quote);
     else
-      strcat(colist, colp->GetName());
+      strcat(colist, buf);
 
     strcat(valist, "?");        // Parameter marker
     } // endfor colp
@@ -558,8 +573,7 @@ bool TDBODBC::BindParameters(PGLOBAL g)
 /***********************************************************************/
 char *TDBODBC::MakeCommand(PGLOBAL g)
   {
-  char *p, name[68], *qc = Ocp->GetQuoteChar();
-  char *stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+  char *p, *stmt, name[68], *body = NULL, *qc = Ocp->GetQuoteChar();
   char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
   bool  qtd = Quoted > 0;
   int   i = 0, k = 0;
@@ -570,6 +584,15 @@ char *TDBODBC::MakeCommand(PGLOBAL g)
     qrystr[i] = (Qrystr[i] == '`') ? *qc : tolower(Qrystr[i]);
     } while (Qrystr[i++]);
 
+  if (To_CondFil && (p = strstr(qrystr, " where "))) {
+    p[7] = 0;           // Remove where clause
+    Qrystr[(p - qrystr) + 7] = 0;
+    body = To_CondFil->Body;
+    stmt = (char*)PlugSubAlloc(g, NULL, strlen(qrystr) 
+                                      + strlen(body) + 64);
+  } else
+    stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+
   // Check whether the table name is equal to a keyword
   // If so, it must be quoted in the original query
   strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
@@ -597,6 +620,9 @@ char *TDBODBC::MakeCommand(PGLOBAL g)
       stmt[i++] = (Qrystr[k] == '`') ? *qc : Qrystr[k];
       } while (Qrystr[k++]);
 
+    if (body)
+      strcat(stmt, body);
+
   } else {
     sprintf(g->Message, "Cannot use this %s command",
                  (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
@@ -698,10 +724,7 @@ int TDBODBC::Cardinality(PGLOBAL g)
     char     qry[96], tbn[64];
     ODBConn *ocp = new(g) ODBConn(g, this);
 
-    ocp->SetLoginTimeout((DWORD)Cto);
-    ocp->SetQueryTimeout((DWORD)Qto);
-
-    if (ocp->Open(Connect, Options) < 1)
+    if (ocp->Open(Connect, &Ops, Options) < 1)
       return -1;
 
     // Table name can be encoded in UTF-8
@@ -762,7 +785,7 @@ int TDBODBC::GetProgMax(PGLOBAL g)
 /***********************************************************************/
 bool TDBODBC::OpenDB(PGLOBAL g)
   {
-  bool rc = false;
+  bool rc = true;
 
   if (g->Trace)
     htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
@@ -802,14 +825,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
   /*  and if so to allocate just a new result set. But this only for   */
   /*  drivers allowing concurency in getting results ???               */
   /*********************************************************************/
-  if (!Ocp) {
+  if (!Ocp)
     Ocp = new(g) ODBConn(g, this);
-    Ocp->SetLoginTimeout((DWORD)Cto);
-    Ocp->SetQueryTimeout((DWORD)Qto);
-  } else if (Ocp->IsOpen())
+  else if (Ocp->IsOpen())
     Ocp->Close();
 
-  if (Ocp->Open(Connect, Options) < 1)
+  if (Ocp->Open(Connect, &Ops, Options) < 1)
     return true;
   else if (Quoted)
     Quote = Ocp->GetQuoteChar();
@@ -839,12 +860,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
 
       } // endif Query
 
-  } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
-    Query = MakeCommand(g);
-  else
+  } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+    rc = false;  // wait for CheckCond before calling MakeCommand(g);
+  } else
     sprintf(g->Message, "Invalid mode %d", Mode);
 
-  if (!Query || rc) {
+  if (rc) {
     Ocp->Close();
     return true;
     } // endif rc
@@ -876,6 +897,9 @@ int TDBODBC::ReadDB(PGLOBAL g)
       GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
 
   if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+    if (!Query && !(Query = MakeCommand(g)))
+      return RC_FX;
+
     // Send the UPDATE/DELETE command to the remote table
     if (!Ocp->ExecSQLcommand(Query)) {
       sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
@@ -945,6 +969,9 @@ int TDBODBC::WriteDB(PGLOBAL g)
 int TDBODBC::DeleteDB(PGLOBAL g, int irc)
   {
   if (irc == RC_FX) {
+    if (!Query && !(Query = MakeCommand(g)))
+      return RC_FX;
+
     // Send the DELETE (all) command to the remote table
     if (!Ocp->ExecSQLcommand(Query)) {
       sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
@@ -1415,12 +1442,10 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
   /*********************************************************************/
   if (!Ocp) {
     Ocp = new(g) ODBConn(g, this);
-    Ocp->SetLoginTimeout((DWORD)Cto);
-    Ocp->SetQueryTimeout((DWORD)Qto);
   } else if (Ocp->IsOpen())
     Ocp->Close();
 
-  if (Ocp->Open(Connect, Options) < 1)
+  if (Ocp->Open(Connect, &Ops, Options) < 1)
     return true;
 
   Use = USE_OPEN;       // Do it now in case we are recursively called
@@ -1554,8 +1579,11 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
   Dsn = tdp->GetConnect();
   Schema = tdp->GetTabschema();
   Tab = tdp->GetTabname();
-  Cto = tdp->Cto;
-  Qto = tdp->Qto;
+  Ops.User = tdp->Username;
+  Ops.Pwd = tdp->Password;
+  Ops.Cto = tdp->Cto;
+  Ops.Qto = tdp->Qto;
+  Ops.UseCnc = tdp->UseCnc;
   } // end of TDBOTB constructor
 
 /***********************************************************************/
@@ -1563,7 +1591,7 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
 /***********************************************************************/
 PQRYRES TDBOTB::GetResult(PGLOBAL g)
   {
-  return ODBCTables(g, Dsn, Schema, Tab, Maxres, Cto, Qto, false);
+  return ODBCTables(g, Dsn, Schema, Tab, Maxres, false, &Ops);
 	} // end of GetResult
 
 /* ---------------------------TDBOCL class --------------------------- */
@@ -1573,7 +1601,7 @@ PQRYRES TDBOTB::GetResult(PGLOBAL g)
 /***********************************************************************/
 PQRYRES TDBOCL::GetResult(PGLOBAL g)
   {
-  return ODBCColumns(g, Dsn, Schema, Tab, NULL, Maxres, Cto, Qto, false);
+  return ODBCColumns(g, Dsn, Schema, Tab, NULL, Maxres, false, &Ops);
 	} // end of GetResult
 
 /* ------------------------ End of Tabodbc --------------------------- */

=== modified file 'storage/connect/tabodbc.h'
--- a/storage/connect/tabodbc.h	2015-01-13 16:24:31 +0000
+++ b/storage/connect/tabodbc.h	2015-01-31 14:05:43 +0000
@@ -50,6 +50,8 @@ class DllExport ODBCDEF : public TABDEF
   PSZ     Connect;            /* ODBC connection string                */
   PSZ     Tabname;            /* External table name                   */
   PSZ     Tabschema;          /* External table schema                 */
+  PSZ     Username;           /* User connect name                     */
+  PSZ     Password;           /* Password connect info                 */
   PSZ     Tabcat;             /* External table catalog                */
   PSZ     Srcdef;             /* The source table SQL definition       */
   PSZ     Qchar;              /* Identifier quoting character          */
@@ -65,6 +67,7 @@ class DllExport ODBCDEF : public TABDEF
   bool    Scrollable;         /* Use scrollable cursor                 */
   bool    Memory;             /* Put result set in memory              */
   bool    Xsrc;               /* Execution type                        */
+  bool    UseCnc;             /* Use SQLConnect (!SQLDriverConnect)    */
   }; // end of ODBCDEF
 
 #if !defined(NODBC)
@@ -124,9 +127,12 @@ class TDBODBC : public TDBASE {
   // Members
   ODBConn *Ocp;               // Points to an ODBC connection class
   ODBCCOL *Cnp;               // Points to count(*) column
+  ODBCPARM Ops;               // Additional parameters
   char    *Connect;           // Points to connection string
   char    *TableName;         // Points to ODBC table name
   char    *Schema;            // Points to ODBC table Schema
+  char    *User;              // User connect info
+  char    *Pwd;               // Password connect info
   char    *Catalog;           // Points to ODBC table Catalog
   char    *Srcdef;            // The source table SQL definition
   char    *Query;             // Points to SQL statement
@@ -151,6 +157,7 @@ class TDBODBC : public TDBASE {
   int      Nparm;             // The number of statement parameters
   int      Memory;            // 0: No 1: Alloc 2: Put 3: Get
   bool     Scrollable;        // Use scrollable cursor
+  bool     UseCnc;            // Use SQLConnect (!SQLDriverConnect)
   PQRYRES  Qrp;               // Points to storage result
   }; // end of class TDBODBC
 
@@ -316,8 +323,7 @@ class TDBOTB : public TDBDRV {
   char    *Dsn;               // Points to connection string
   char    *Schema;            // Points to schema name or NULL
   char    *Tab;               // Points to ODBC table name or pattern
-  int      Cto;               // Connect timeout
-  int      Qto;               // Query timeout
+  ODBCPARM Ops;               // Additional parameters
   }; // end of class TDBOTB
 
 /***********************************************************************/

=== modified file 'storage/connect/tabpivot.cpp'
--- a/storage/connect/tabpivot.cpp	2014-10-21 15:29:51 +0000
+++ b/storage/connect/tabpivot.cpp	2015-01-27 23:19:39 +0000
@@ -558,7 +558,7 @@ bool TDBPIVOT::MakePivotColumns(PGLOBAL
     //  Check and initialize the subtable columns
     for (PCOL cp = Columns; cp; cp = cp->GetNext())
       if (cp->GetAmType() == TYPE_AM_SRC) {
-        if (((PSRCCOL)cp)->Init(g))
+        if (((PSRCCOL)cp)->Init(g, NULL))
           return TRUE;
 
       } else if (cp->GetAmType() == TYPE_AM_FNC)
@@ -874,9 +874,9 @@ SRCCOL::SRCCOL(PCOLDEF cdp, PTDB tdbp, P
 /***********************************************************************/
 /*  Initialize the column as pointing to the source column.            */
 /***********************************************************************/
-bool SRCCOL::Init(PGLOBAL g)
+bool SRCCOL::Init(PGLOBAL g, PTDBASE tp)
   {
-  if (PRXCOL::Init(g))
+  if (PRXCOL::Init(g, tp))
     return true;
 
   AddStatus(BUF_READ);     // All is done here

=== modified file 'storage/connect/tabpivot.h'
--- a/storage/connect/tabpivot.h	2014-08-07 15:59:21 +0000
+++ b/storage/connect/tabpivot.h	2015-01-27 23:19:39 +0000
@@ -180,9 +180,10 @@ class SRCCOL : public PRXCOL {
   virtual int  GetAmType(void) {return TYPE_AM_SRC;}
 
   // Methods
+  using PRXCOL::Init;
   virtual void Reset(void) {}
           void SetColumn(void);
-          bool Init(PGLOBAL g);
+  virtual bool Init(PGLOBAL g, PTDBASE tp);
           bool CompareLast(void);
 
  protected:

=== modified file 'storage/connect/tabtbl.cpp'
--- a/storage/connect/tabtbl.cpp	2014-10-21 15:29:51 +0000
+++ b/storage/connect/tabtbl.cpp	2015-01-31 14:05:43 +0000
@@ -266,7 +266,7 @@ bool TDBTBL::InitTableList(PGLOBAL g)
       // Real initialization will be done later.
       for (colp = Columns; colp; colp = colp->GetNext())
         if (!colp->IsSpecial())
-          if (((PPRXCOL)colp)->Init(g) && !Accept)
+          if (((PPRXCOL)colp)->Init(g, NULL) && !Accept)
             return TRUE;
 
       if (Tablist)
@@ -352,7 +352,9 @@ bool TDBTBL::TestFil(PGLOBAL g, PCFIL fi
 /***********************************************************************/
 int TDBTBL::Cardinality(PGLOBAL g)
   {
-  if (Cardinal < 0) {
+  if (!g)
+    return 0;                 // Cannot make the table list
+  else if (Cardinal < 0) {
     int tsz;
 
     if (!Tablist && InitTableList(g))
@@ -468,7 +470,7 @@ bool TDBTBL::OpenDB(PGLOBAL g)
     for (PCOL cp = Columns; cp; cp = cp->GetNext())
       if (cp->GetAmType() == TYPE_AM_TABID)
         cp->COLBLK::Reset();
-      else if (((PPRXCOL)cp)->Init(g) && !Accept)
+      else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
         return TRUE;
         
     if (trace)
@@ -523,7 +525,7 @@ int TDBTBL::ReadDB(PGLOBAL g)
           if (cp->GetAmType() == TYPE_AM_TABID ||
               cp->GetAmType() == TYPE_AM_SRVID)
             cp->COLBLK::Reset();
-          else if (((PPRXCOL)cp)->Init(g) && !Accept)
+          else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
             return RC_FX;
 
         if (trace)
@@ -716,7 +718,7 @@ bool TDBTBM::OpenDB(PGLOBAL g)
     for (PCOL cp = Columns; cp; cp = cp->GetNext())
       if (cp->GetAmType() == TYPE_AM_TABID)
         cp->COLBLK::Reset();
-      else if (((PPRXCOL)cp)->Init(g) && !Accept)
+      else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
         return TRUE;
         
     if (trace)
@@ -807,7 +809,7 @@ int TDBTBM::ReadNextRemote(PGLOBAL g)
   for (PCOL cp = Columns; cp; cp = cp->GetNext())
     if (cp->GetAmType() == TYPE_AM_TABID)
       cp->COLBLK::Reset();
-    else if (((PPRXCOL)cp)->Init(g) && !Accept)
+    else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
       return RC_FX;
 
   if (trace)

=== modified file 'storage/connect/tabutil.cpp'
--- a/storage/connect/tabutil.cpp	2014-10-21 15:29:51 +0000
+++ b/storage/connect/tabutil.cpp	2015-02-11 20:39:41 +0000
@@ -54,7 +54,8 @@
 #include "tabutil.h"
 #include "ha_connect.h"
 
-extern "C" int zconv;
+//extern "C" int zconv;
+int GetConvSize(void);
 
 /************************************************************************/
 /*  Used by MYSQL tables to get MySQL parameters from the calling proxy */
@@ -132,6 +133,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd,
   char        *fld, *colname, *chset, *fmt, v;
   int          i, n, ncol = sizeof(buftyp) / sizeof(int);
   int          prec, len, type, scale;
+  int          zconv = GetConvSize();
   bool         mysql;
   TABLE_SHARE *s = NULL;
   Field*      *field;
@@ -669,6 +671,22 @@ PRXCOL::PRXCOL(PRXCOL *col1, PTDB tdbp)
   } // end of PRXCOL copy constructor
 
 /***********************************************************************/
+/*  Convert an UTF-8 name to latin characters.                         */
+/***********************************************************************/
+char *PRXCOL::Decode(PGLOBAL g, const char *cnm)
+  {
+  char  *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) + 1);
+  uint   dummy_errors;
+  uint32 len= copy_and_convert(buf, strlen(cnm) + 1,
+                               &my_charset_latin1,
+                               cnm, strlen(cnm),
+                               &my_charset_utf8_general_ci,
+                               &dummy_errors);
+  buf[len]= '\0';
+  return buf;
+  } // end of Decode
+
+/***********************************************************************/
 /*  PRXCOL initialization routine.                                     */
 /*  Look for the matching column in the object table.                  */
 /***********************************************************************/
@@ -683,6 +701,9 @@ bool PRXCOL::Init(PGLOBAL g, PTDBASE tp)
   if (Colp) {
     MODE mode = To_Tdb->GetMode();
 
+    // Needed for MYSQL subtables
+    ((XCOLBLK*)Colp)->Name = Decode(g, Colp->GetName());
+
     // May not have been done elsewhere
     Colp->InitValue(g);        
     To_Val = Colp->GetValue();

=== modified file 'storage/connect/tabutil.h'
--- a/storage/connect/tabutil.h	2014-09-27 10:09:37 +0000
+++ b/storage/connect/tabutil.h	2015-02-19 00:25:31 +0000
@@ -108,15 +108,18 @@ class DllExport PRXCOL : public COLBLK {
   virtual int  GetAmType(void) {return TYPE_AM_PRX;}
 
   // Methods
+  using COLBLK::Init;
   virtual void Reset(void);
   virtual bool IsSpecial(void) {return Pseudo;}
   virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
                 {return false;}
   virtual void ReadColumn(PGLOBAL g);
   virtual void WriteColumn(PGLOBAL g);
-  virtual bool Init(PGLOBAL g, PTDBASE tp = NULL);
+  virtual bool Init(PGLOBAL g, PTDBASE tp);
 
  protected:
+          char *Decode(PGLOBAL g, const char *cnm);
+
   // Default constructor not to be used
   PRXCOL(void) {}
 
@@ -144,4 +147,8 @@ class TDBTBC : public TDBCAT {
   PSZ     Tab;                   // Table name            
   }; // end of class TDBMCL
 
+class XCOLBLK : public COLBLK {
+  friend class PRXCOL;
+}; // end of class XCOLBLK
+
 #endif // TABUTIL

=== modified file 'storage/connect/tabxcl.cpp'
--- a/storage/connect/tabxcl.cpp	2014-10-31 11:28:07 +0000
+++ b/storage/connect/tabxcl.cpp	2015-01-27 23:19:39 +0000
@@ -183,7 +183,7 @@ bool TDBXCL::OpenDB(PGLOBAL g)
   /*********************************************************************/
   for (PCOL cp = Columns; cp; cp = cp->GetNext())
     if (!cp->IsSpecial())
-      if (((PPRXCOL)cp)->Init(g))
+      if (((PPRXCOL)cp)->Init(g, NULL))
         return TRUE;
 
   /*********************************************************************/

=== modified file 'storage/connect/tabxcl.h'
--- a/storage/connect/tabxcl.h	2014-10-31 11:28:07 +0000
+++ b/storage/connect/tabxcl.h	2015-01-27 18:18:51 +0000
@@ -88,6 +88,7 @@ class XCLCOL : public PRXCOL {
   XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
 
   // Methods
+  using PRXCOL::Init;
   virtual void Reset(void) {}	  // Evaluated only by TDBXCL
   virtual void ReadColumn(PGLOBAL g);
   virtual bool Init(PGLOBAL g, PTDBASE tp = NULL);

=== modified file 'storage/connect/valblk.h'
--- a/storage/connect/valblk.h	2014-08-07 15:59:21 +0000
+++ b/storage/connect/valblk.h	2015-01-27 18:18:51 +0000
@@ -163,6 +163,7 @@ class TYPBLK : public VALBLK {
   virtual void   Reset(int n) {Typp[n] = 0;}
 
   // Methods
+  using VALBLK::SetValue;
   virtual void   SetValue(PSZ sp, int n);
   virtual void   SetValue(char *sp, uint len, int n);
   virtual void   SetValue(short sval, int n)
@@ -233,6 +234,7 @@ class CHRBLK : public VALBLK {
   virtual bool   IsCi(void) {return Ci;}
 
   // Methods
+  using VALBLK::SetValue;
   virtual void   SetValue(PSZ sp, int n);
   virtual void   SetValue(char *sp, uint len, int n);
   virtual void   SetValue(PVAL valp, int n);
@@ -286,6 +288,7 @@ class STRBLK : public VALBLK {
   virtual void   Reset(int n) {Strp[n] = NULL;}
 
   // Methods
+  using VALBLK::SetValue;
   virtual void   SetValue(PSZ sp, int n);
   virtual void   SetValue(char *sp, uint len, int n);
   virtual void   SetValue(PVAL valp, int n);
@@ -322,6 +325,7 @@ class DATBLK : public TYPBLK<int> {
   virtual char *GetCharString(char *p, int n);
 
   // Methods
+  using TYPBLK<int>::SetValue;
   virtual void  SetValue(PSZ sp, int n);
 
  protected:
@@ -345,6 +349,8 @@ class PTRBLK : public STRBLK {
   // Implementation
 
   // Methods
+  using STRBLK::SetValue;
+  using STRBLK::CompVal;
   virtual void   SetValue(PSZ p, int n) {Strp[n] = p;}
   virtual int    CompVal(int i1, int i2);
 

=== modified file 'storage/connect/value.cpp'
--- a/storage/connect/value.cpp	2015-01-20 00:21:56 +0000
+++ b/storage/connect/value.cpp	2015-01-24 11:17:03 +0000
@@ -436,6 +436,9 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp,
   bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned();
   PVAL vp;
 
+  if (!valp)
+    return NULL;
+    
   if (newtype == TYPE_VOID)  // Means allocate a value of the same type
     newtype = valp->GetType();
 
@@ -443,8 +446,8 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp,
     case TYPE_STRING:
       p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen());
 
-      if ((sp = valp->GetCharString(p)) != p)
-        strcpy (p, sp);
+      if ((sp = valp->GetCharString(p)) != p && sp)
+        strcpy(p, sp);
 
       vp = new(g) TYPVAL<PSZ>(g, p, valp->GetValLen(), valp->GetValPrec());
       break;
@@ -1216,12 +1219,12 @@ TYPVAL<PSZ>::TYPVAL(PSZ s) : VALUE(TYPE_
 TYPVAL<PSZ>::TYPVAL(PGLOBAL g, PSZ s, int n, int c)
            : VALUE(TYPE_STRING)
   {
-  Len = (g) ? n : strlen(s);
+  Len = (g) ? n : (s) ? strlen(s) : 0;
 
   if (!s) {
     if (g) {
       if ((Strp = (char *)PlgDBSubAlloc(g, NULL, Len + 1)))
-        Strp[Len] = '\0';
+        memset(Strp, 0, Len + 1);
       else
         Len = 0;
 

=== modified file 'storage/connect/xindex.h'
--- a/storage/connect/xindex.h	2014-08-16 14:46:35 +0000
+++ b/storage/connect/xindex.h	2015-01-27 18:18:51 +0000
@@ -391,6 +391,7 @@ class DllExport XHUGE : public XLOAD {
   XHUGE(void) : XLOAD() {}
 
   // Methods
+  using XLOAD::Close;
   virtual bool  Open(PGLOBAL g, char *filename, int id, MODE mode);
   virtual bool  Seek(PGLOBAL g, int low, int high, int origin);
   virtual bool  Read(PGLOBAL g, void *buf, int n, int size);

=== modified file 'storage/connect/xobject.cpp'
--- a/storage/connect/xobject.cpp	2014-11-08 12:35:03 +0000
+++ b/storage/connect/xobject.cpp	2015-01-23 22:14:34 +0000
@@ -347,6 +347,31 @@ bool STRING::Append(char c)
 } // end of Append
 
 /***********************************************************************/
+/*  Append a quoted PSZ to a STRING.                                   */
+/***********************************************************************/
+bool STRING::Append_quoted(PSZ s)
+{
+  bool b = Append('\'');
+
+  if (s) for (char *p = s; !b && *p; p++)
+    switch (*p) {
+      case '\'':
+      case '\\':
+      case '\t':
+      case '\n':
+      case '\r':
+      case '\b':
+      case '\f': b |= Append('\\');
+        // passthru
+      default:
+        b |= Append(*p);
+        break;
+      } // endswitch *p
+
+  return (b |= Append('\''));
+} // end of Append_quoted
+
+/***********************************************************************/
 /*  Resize to given length but only when last suballocated.            */
 /*  New size should be greater than string length.                     */
 /***********************************************************************/

=== modified file 'storage/connect/xobject.h'
--- a/storage/connect/xobject.h	2014-10-22 10:02:46 +0000
+++ b/storage/connect/xobject.h	2015-01-23 16:54:53 +0000
@@ -138,6 +138,7 @@ class DllExport STRING : public BLOCK {
          bool   Append(STRING &str);
          bool   Append(char c);
          bool   Resize(uint n);
+         bool   Append_quoted(PSZ s);
   inline void   Trim(void) {(void)Resize(Length + 1);}
   inline void   Chop(void) {if (Length) Strp[--Length] = 0;}
   inline void   RepLast(char c) {if (Length) Strp[Length-1] = c;}



More information about the commits mailing list