[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