diff --git a/.gitignore b/.gitignore index 1a93c78b0e24a..c4109b63dc22d 100644 --- a/.gitignore +++ b/.gitignore @@ -131,6 +131,8 @@ scripts/wsrep_sst_xtrabackup scripts/wsrep_sst_xtrabackup-v2 scripts/maria_add_gis_sp.sql scripts/maria_add_gis_sp_bootstrap.sql +scripts/galera_new_cluster +scripts/galera_recovery sql-bench/bench-count-distinct sql-bench/bench-init.pl sql-bench/compare-results @@ -224,6 +226,7 @@ support-files/config.medium.ini support-files/config.small.ini support-files/mariadb.pc support-files/mariadb@.service +support-files/mariadb.service support-files/my-huge.cnf support-files/my-innodb-heavy-4G.cnf support-files/my-large.cnf @@ -237,6 +240,7 @@ support-files/mysqld_multi.server support-files/wsrep.cnf support-files/wsrep_notify support-files/policy/selinux/mysqld-safe.pp +support-files/mariadb.pp tags tests/async_queries tests/bug25714 diff --git a/debian/control b/debian/control index eba7022477335..50b07e73537c6 100644 --- a/debian/control +++ b/debian/control @@ -21,7 +21,7 @@ Build-Depends: bison, libpam0g-dev, libpcre3-dev (>= 2:8.35-3.2~), libreadline-gplv2-dev, - libssl-dev, + libssl-dev | libssl1.0-dev, libsnappy-dev, libsystemd-dev, libxml2-dev, diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index 5cf63ea94c1a3..35e838e83d313 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -724,7 +724,7 @@ have_queries_to_wait_for(MYSQL *connection, uint threshold) all_queries = (opt_lock_wait_query_type == QUERY_TYPE_ALL); while ((row = mysql_fetch_row(result)) != NULL) { const char *info = row[7]; - int duration = atoi(row[5]); + int duration = row[5] ? atoi(row[5]) : 0; char *id = row[0]; if (info != NULL @@ -754,7 +754,7 @@ kill_long_queries(MYSQL *connection, time_t timeout) all_queries = (opt_kill_long_query_type == QUERY_TYPE_ALL); while ((row = mysql_fetch_row(result)) != NULL) { const char *info = row[7]; - long long duration = atoll(row[5]); + long long duration = row[5]? atoll(row[5]) : 0; char *id = row[0]; if (info != NULL && diff --git a/mysql-test/suite/mariabackup/incremental_backup.test b/mysql-test/suite/mariabackup/incremental_backup.test index dde0aa3b7cb6c..b60b151563f0d 100644 --- a/mysql-test/suite/mariabackup/incremental_backup.test +++ b/mysql-test/suite/mariabackup/incremental_backup.test @@ -14,7 +14,7 @@ exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir --enable_result_log INSERT INTO t VALUES(2); SELECT * FROM t; -exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir; +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --ftwrl-wait-timeout=5 --ftwrl-wait-threshold=300 --ftwrl-wait-query-type=all --target-dir=$incremental_dir --incremental-basedir=$basedir; --disable_result_log echo # Prepare full backup, apply incremental one; diff --git a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c index 31d29fb06d908..34f4d629ba603 100644 --- a/mysys_ssl/openssl.c +++ b/mysys_ssl/openssl.c @@ -34,7 +34,8 @@ int check_openssl_compatibility() static uint testing, alloc_size, alloc_count; -static void *coc_malloc(size_t size, const char *, int) +static void *coc_malloc(size_t size, const char *f __attribute__((unused)), + int l __attribute__((unused))) { if (unlikely(testing)) { diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 81441892215fd..99037b7384352 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -38,7 +38,7 @@ user_connect.h valblk.h value.h xindex.h xobject.h xtable.h) # Definitions that are shared for all OSes # add_definitions( -DMARIADB -DFORCE_INIT_OF_VARS -Dconnect_EXPORTS) -add_definitions( -DHUGE_SUPPORT -DGZ_SUPPORT -DPIVOT_SUPPORT -DUSE_TRY ) +add_definitions( -DHUGE_SUPPORT -DGZ_SUPPORT -DPIVOT_SUPPORT ) # @@ -245,7 +245,7 @@ int main() { ENDIF(CONNECT_WITH_ODBC) # -# JDBC +# JDBC and MongoDB Java Driver # IF(APPLE) OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine without JDBC support" OFF) @@ -262,9 +262,13 @@ IF(CONNECT_WITH_JDBC) INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH2}) # SET(JDBC_LIBRARY ${JAVA_JVM_LIBRARY}) will be dynamically linked SET(CONNECT_SOURCES ${CONNECT_SOURCES} - jdbconn.cpp tabjdbc.cpp jdbconn.h tabjdbc.h jdbccat.h + javaconn.cpp jdbconn.cpp tabjdbc.cpp + jmgoconn.cpp jmgfam.cpp mongo.cpp tabjmg.cpp + jdbccat.h javaconn.h jdbconn.h tabjdbc.h + jmgoconn.h jmgfam.h mongo.h tabjmg.h JdbcInterface.java ApacheInterface.java MariadbInterface.java MysqlInterface.java OracleInterface.java PostgresqlInterface.java + Mongo2Interface.java Mongo3Interface.java JavaWrappers.jar) # TODO: Find how to compile and install the java wrapper classes # Find required libraries and include directories @@ -291,6 +295,36 @@ IF(CONNECT_WITH_ZIP) add_definitions(-DZIP_SUPPORT -DNOCRYPT) ENDIF(CONNECT_WITH_ZIP) +# +# MONGO C Driver (CMAKE NOT YET WORKING) +# + +#OPTION(CONNECT_WITH_MONGO "Compile CONNECT storage engine with MONGO support" ON) + +#IF(CONNECT_WITH_MONGO) +# IF(WIN32) +# # Adding some typical places to search in +# SET(PC_MONGO_INCLUDE_DIRS +# C:/mongo-c-driver/include +# D:/mongo-c-driver/include) +# SET(PC_MONGO_LIBRARY_DIRS +# C:/mongo-c-driver/lib +# D:/mongo-c-driver/lib) +# ENDIF(WIN32) +# FIND_PACKAGE(libmongoc) +# IF (MONGO_FOUND) +# INCLUDE_DIRECTORIES(${MONGO_INCLUDE_DIR}) +# SET(MONGO_LIBRARY ${MONGO_LIBRARIES}) +# SET(CONNECT_SOURCES ${CONNECT_SOURCES} +# cmgoconn.cpp mongofam.cpp tabmgo.cpp +# cmgoconn.h mongofam.h tabmgo.h) +# IF (NOT JAVA_FOUND AND JNI_FOUND) +# SET(CONNECT_SOURCES ${CONNECT_SOURCES} mongo.cpp mongo.h) +# ENDIF (NOT JAVA_FOUND AND JNI_FOUND) +# add_definitions(-DMONGO_SUPPORT) +# ENDIF(MONGO_FOUND) +#ENDIF(CONNECT_WITH_MONGO) + # # XMAP @@ -310,6 +344,8 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES} STORAGE_ENGINE COMPONENT connect-engine RECOMPILE_FOR_EMBEDDED +# LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY} $(MONGO_LIBRARY) LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY} ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${IPHLPAPI_LIBRARY}) + diff --git a/storage/connect/JavaWrappers.jar b/storage/connect/JavaWrappers.jar index 8c01c364a3f4d..dec9096703909 100644 Binary files a/storage/connect/JavaWrappers.jar and b/storage/connect/JavaWrappers.jar differ diff --git a/storage/connect/Mongo2Interface.java b/storage/connect/Mongo2Interface.java new file mode 100644 index 0000000000000..106dd4a4d6396 --- /dev/null +++ b/storage/connect/Mongo2Interface.java @@ -0,0 +1,437 @@ +package wrappers; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.mongodb.AggregationOptions; +import com.mongodb.BasicDBList; +import com.mongodb.BasicDBObject; +import com.mongodb.Cursor; +import com.mongodb.DB; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; +import com.mongodb.MongoClient; +import com.mongodb.MongoClientURI; +import com.mongodb.MongoException; +import com.mongodb.WriteConcernException; +import com.mongodb.WriteResult; +import com.mongodb.util.JSON; + +public class Mongo2Interface { + boolean DEBUG = false; + String Errmsg = "No error"; + Set Colnames = null; + Cursor cursor = null; + MongoClient client = null; + DB db = null; + DBCollection coll = null; + BasicDBObject doc = null; + BasicDBObject dbq = null; + BasicDBObject dbf = null; + List pip = null; + AggregationOptions aop = null; + + // === Constructors/finalize ========================================= + public Mongo2Interface() { + this(false); + } // end of default constructor + + public Mongo2Interface(boolean b) { + DEBUG = b; + } // end of constructor + + protected void SetErrmsg(String str) { + if (DEBUG) + System.out.println(str); + + Errmsg = str; + } // end of SetErrmsg + + protected void SetErrmsg(Exception e) { + if (DEBUG) + System.out.println(e.getMessage()); + + Errmsg = e.toString(); + } // end of SetErrmsg + + public String GetErrmsg() { + String err = Errmsg; + + Errmsg = "No error"; + return err; + } // end of GetErrmsg + + public int MongoConnect(String[] parms) { + int rc = 0; + + if (DEBUG) + System.out.println("Mongo2: URI=" + parms[0] + " DB=" + parms[1]); + + try { + MongoClientURI uri = new MongoClientURI(parms[0]); + + client = new MongoClient(uri); + + if (DEBUG) + System.out.println("Connection " + client.toString() + " established"); + + // Now connect to your databases + db = client.getDB(parms[1]); + + if (parms[2] != null && !parms[2].isEmpty()) { + if (DEBUG) + System.out.println("user=" + parms[2] + " pwd=" + parms[3]); + + @SuppressWarnings("deprecation") + boolean auth = db.authenticate(parms[2], parms[3].toCharArray()); + + if (DEBUG) + System.out.println("Authentication: " + auth); + + } // endif user + + } catch (MongoException me) { + SetErrmsg(me); + rc = -1; + } catch (Exception e) { + SetErrmsg(e); + rc = -3; + } // end try/catch + + return rc; + } // end of MongoConnect + + public int MongoDisconnect() { + int rc = 0; + + try { + if (cursor != null) { + if (DEBUG) + System.out.println("Closing cursor"); + + cursor.close(); + cursor = null; + } // endif client + + if (client != null) { + if (DEBUG) + System.out.println("Closing connection"); + + client.close(); + client = null; + } // endif client + + } catch (MongoException se) { + SetErrmsg(se); + rc += 8; + } // end try/catch + + return rc; + } // end of MongoDisconnect + + public boolean GetCollection(String name) { + if (DEBUG) + System.out.println("GetCollection: name=" + name); + + try { + coll = db.getCollection(name); + } catch (Exception e) { + SetErrmsg(e); + return true; + } // end try/catch + + return false; + } // end of GetCollection + + public long GetCollSize() { + return (coll != null) ? coll.count() : 0; + } // end of GetCollSize + + public boolean FindColl(String query, String fields) { + if (DEBUG) + System.out.println("FindColl: query=" + query + " fields=" + fields); + + try { + if (query != null || fields != null) { + dbq = (BasicDBObject) JSON.parse((query != null) ? query : "{}"); + + if (fields != null) { + dbf = (BasicDBObject) JSON.parse(fields); + cursor = coll.find(dbq, dbf); + } else + cursor = coll.find(dbq); + + } else + cursor = coll.find(); + + } catch (Exception e) { + SetErrmsg(e); + return true; + } // end try/catch + + return false; + } // end of FindColl + + @SuppressWarnings("unchecked") + public boolean AggregateColl(String pipeline) { + if (DEBUG) + System.out.println("AggregateColl: pipeline=" + pipeline); + + try { + DBObject pipe = (DBObject) JSON.parse(pipeline); + + pip = (List) pipe.get("pipeline"); + aop = AggregationOptions.builder().batchSize(0).allowDiskUse(true) + .outputMode(AggregationOptions.OutputMode.CURSOR).build(); + cursor = coll.aggregate(pip, aop); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } // end try/catch + + return false; + } // end of AggregateColl + + public boolean Rewind() { + if (cursor != null) + cursor.close(); + + if (pip == null) { + if (dbf != null) + cursor = coll.find(dbq, dbf); + else if (dbq != null) + cursor = coll.find(dbq); + else + cursor = coll.find(); + + } else + cursor = coll.aggregate(pip, aop); + + return (cursor == null); + } // end of Rewind + + public int ReadNext() { + try { + if (cursor.hasNext()) { + doc = (BasicDBObject) cursor.next(); + + if (DEBUG) + System.out.println("Class doc = " + doc.getClass()); + + Colnames = doc.keySet(); + return 1; + } else + return 0; + + } catch (MongoException me) { + SetErrmsg(me); + return -1; + } // end try/catch + + } // end of ReadNext + + public boolean Fetch(int row) { + if (cursor.hasNext()) { + doc = (BasicDBObject) cursor.next(); + Colnames = doc.keySet(); + return true; + } else + return false; + + } // end of Fetch + + public String GetDoc() { + return (doc != null) ? doc.toString() : null; + } // end of GetDoc + + public Set GetColumns() { + if (doc != null) + return doc.keySet(); + else + return null; + + } // end of GetColumns + + public String ColumnDesc(int n, int[] val) { + // if (rsmd == null) { + // System.out.println("No result metadata"); + // return null; + // } else try { + // val[0] = rsmd.getColumnType(n); + // val[1] = rsmd.getPrecision(n); + // val[2] = rsmd.getScale(n); + // val[3] = rsmd.isNullable(n); + // return rsmd.getColumnLabel(n); + // } catch (SQLException se) { + // SetErrmsg(se); + // } //end try/catch + + return null; + } // end of ColumnDesc + + protected Object GetFieldObject(String path) { + Object o = null; + BasicDBObject dob = null; + BasicDBList lst = null; + String[] names = null; + + if (path == null || path.equals("*")) + return doc; + else if (doc instanceof BasicDBObject) + dob = doc; + // else if (o instanceof BasicDBList) + // lst = (BasicDBList) doc; + else + return doc; + + try { + names = path.split("\\."); + + for (String name : names) { + if (lst != null) { + o = lst.get(Integer.parseInt(name)); + } else + o = dob.get(name); + + if (o == null) + break; + + if (DEBUG) + System.out.println("Class o = " + o.getClass()); + + if (o instanceof BasicDBObject) { + dob = (BasicDBObject) o; + lst = null; + } else if (o instanceof BasicDBList) { + lst = (BasicDBList) o; + } else + break; + + } // endfor name + + } catch (IndexOutOfBoundsException x) { + o = null; + } catch (MongoException se) { + SetErrmsg(se); + o = null; + } // end try/catch + + return o; + } // end of GetFieldObject + + public String GetField(String path) { + Object o = GetFieldObject(path); + + if (o != null) { + if (o instanceof Date) { + Integer TS = (int) (((Date) o).getTime() / 1000); + return TS.toString(); + } // endif Date + + return o.toString(); + } else + return null; + + } // end of GetField + + public Object MakeDocument() { + return new BasicDBObject(); + } // end of MakeDocument + + public boolean DocAdd(Object bdc, String key, Object val) { + try { + ((BasicDBObject) bdc).append(key, val); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } // end try/catch + + return false; + } // end of DocAdd + + public Object MakeArray() { + return new BasicDBList(); + } // end of MakeArray + + public boolean ArrayAdd(Object bar, int n, Object val) { + try { + ((BasicDBList) bar).put(n, val); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } catch (Exception ex) { + SetErrmsg(ex); + return true; + } // end try/catch + + return false; + } // end of ArrayAdd + + public boolean CollInsert(Object dob) { + try { + coll.insert((BasicDBObject) dob); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } catch (Exception ex) { + SetErrmsg(ex); + return true; + } // end try/catch + + return false; + } // end of CollInsert + + public long CollUpdate(Object upd) { + long n = -1; + + if (DEBUG) + System.out.println("upd: " + upd.toString()); + + try { + DBObject qry = new BasicDBObject("_id", doc.get("_id")); + + WriteResult res = coll.update(qry, (DBObject) upd); + + if (DEBUG) + System.out.println("CollUpdate: " + res.toString()); + + n = res.getN(); + } catch (MongoException me) { + SetErrmsg(me); + } catch (Exception ex) { + SetErrmsg(ex); + } // end try/catch + + return n; + } // end of CollUpdate + + public long CollDelete(boolean all) { + long n = -1; + + try { + WriteResult res; + BasicDBObject qry = new BasicDBObject(); + + if (!all) + qry.append("_id", doc.get("_id")); + + res = coll.remove(qry); + + if (DEBUG) + System.out.println("CollDelete: " + res.toString()); + + n = res.getN(); + } catch (WriteConcernException wx) { + SetErrmsg(wx); + } catch (MongoException me) { + SetErrmsg(me); + } catch (UnsupportedOperationException ux) { + SetErrmsg(ux); + n = 0; + } // end try/catch + + return n; + } // end of CollDelete + +} // end of class MongoInterface diff --git a/storage/connect/Mongo3Interface.java b/storage/connect/Mongo3Interface.java new file mode 100644 index 0000000000000..f587c01b39122 --- /dev/null +++ b/storage/connect/Mongo3Interface.java @@ -0,0 +1,504 @@ +package wrappers; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.bson.BsonArray; +import org.bson.BsonBoolean; +import org.bson.BsonDateTime; +import org.bson.BsonDocument; +import org.bson.BsonDouble; +import org.bson.BsonInt32; +import org.bson.BsonInt64; +import org.bson.BsonNull; +import org.bson.BsonString; +import org.bson.BsonValue; +import org.bson.Document; +import org.bson.conversions.Bson; + +import com.mongodb.MongoClient; +import com.mongodb.MongoClientURI; +import com.mongodb.MongoException; +import com.mongodb.client.AggregateIterable; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; + +public class Mongo3Interface { + boolean DEBUG = false; + String Errmsg = "No error"; + Set Colnames = null; + MongoClient client = null; + MongoDatabase db = null; + MongoCollection coll = null; + FindIterable finditer = null; + AggregateIterable aggiter = null; + MongoCursor cursor = null; + BsonDocument doc = null; + BsonDocument util = null; + BsonNull bsonull = new BsonNull(); + + // === Constructors/finalize ========================================= + public Mongo3Interface() { + this(false); + } // end of default constructor + + public Mongo3Interface(boolean b) { + DEBUG = b; + } // end of constructor + + protected void SetErrmsg(String str) { + if (DEBUG) + System.out.println(str); + + Errmsg = str; + } // end of SetErrmsg + + protected void SetErrmsg(Exception e) { + if (DEBUG) + System.out.println(e.getMessage()); + + Errmsg = e.toString(); + } // end of SetErrmsg + + public String GetErrmsg() { + String err = Errmsg; + + Errmsg = "No error"; + return err; + } // end of GetErrmsg + + public int MongoConnect(String[] parms) { + int rc = 0; + + if (DEBUG) + System.out.println("Mongo3: URI=" + parms[0] + " DB=" + parms[1]); + + try { + MongoClientURI uri = new MongoClientURI(parms[0]); + + client = new MongoClient(uri); + + if (DEBUG) + System.out.println("Connection " + client.toString() + " established"); + + // Now connect to your databases + db = client.getDatabase(parms[1]); + + // if (parms[2] != null && !parms[2].isEmpty()) { + // if (DEBUG) + // System.out.println("user=" + parms[2] + " pwd=" + parms[3]); + + // @SuppressWarnings("deprecation") + // boolean auth = db.authenticate(parms[2], parms[3].toCharArray()); + + // if (DEBUG) + // System.out.println("Authentication: " + auth); + + // } // endif user + + } catch (MongoException me) { + SetErrmsg(me); + rc = -1; + } catch (Exception e) { + SetErrmsg(e); + rc = -3; + } // end try/catch + + return rc; + } // end of MongoConnect + + public int MongoDisconnect() { + int rc = 0; + + try { + if (cursor != null) { + if (DEBUG) + System.out.println("Closing cursor"); + + cursor.close(); + cursor = null; + } // endif client + + if (client != null) { + if (DEBUG) + System.out.println("Closing connection"); + + client.close(); + client = null; + } // endif client + + } catch (MongoException se) { + SetErrmsg(se); + rc += 8; + } // end try/catch + + return rc; + } // end of MongoDisconnect + + public boolean GetCollection(String name) { + if (DEBUG) + System.out.println("GetCollection: name=" + name); + + try { + coll = db.getCollection(name).withDocumentClass(BsonDocument.class); + } catch (Exception e) { + SetErrmsg(e); + return true; + } // end try/catch + + return false; + } // end of GetCollection + + public long GetCollSize() { + return (coll != null) ? coll.count() : 0; + } // end of GetCollSize + + public boolean FindColl(String query, String fields) { + if (DEBUG) + System.out.println("FindColl: query=" + query + " fields=" + fields); + + try { + if (query != null) { + Bson dbq = Document.parse((query != null) ? query : "{}"); + finditer = coll.find(dbq); + } else + finditer = coll.find(); + + if (fields != null) { + Bson dbf = BsonDocument.parse(fields); + finditer = finditer.projection(dbf); + } // endif fields + + cursor = finditer.iterator(); + } catch (Exception e) { + SetErrmsg(e); + return true; + } // end try/catch + + return false; + } // end of FindColl + + @SuppressWarnings("unchecked") + public boolean AggregateColl(String pipeline) { + if (DEBUG) + System.out.println("AggregateColl: pipeline=" + pipeline); + + try { + Document pipe = Document.parse(pipeline); + ArrayList pip = (ArrayList) pipe.get("pipeline"); + + aggiter = coll.aggregate((List) pip); + cursor = aggiter.iterator(); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } // end try/catch + + return false; + } // end of AggregateColl + + public boolean Rewind() { + if (cursor != null) + cursor.close(); + + if (finditer != null) + cursor = finditer.iterator(); + else if (aggiter != null) + cursor = aggiter.iterator(); + + return (cursor == null); + } // end of Rewind + + public int ReadNext() { + if (cursor.hasNext()) { + doc = cursor.next(); + + if (DEBUG) + System.out.println("Class doc = " + doc.getClass()); + + Colnames = doc.keySet(); + return 1; + } else + return 0; + + } // end of ReadNext + + public boolean Fetch(int row) { + if (cursor.hasNext()) { + doc = cursor.next(); + Colnames = doc.keySet(); + return true; + } else + return false; + + } // end of Fetch + + public String GetDoc() { + return (doc != null) ? doc.toJson() : null; + } // end of GetDoc + + public Set GetColumns() { + if (doc != null) + return doc.keySet(); + else + return null; + + } // end of GetColumns + + public String ColumnName(int n) { + int i = 1; + + for (String name : Colnames) + if (i++ == n) + return name; + + return null; + } // end of ColumnName + + public int ColumnType(int n, String name) { + // if (rsmd == null) { + // System.out.println("No result metadata"); + // } else try { + // if (n == 0) + // n = rs.findColumn(name); + + // return rsmd.getColumnType(n); + // } catch (SQLException se) { + // SetErrmsg(se); + // } //end try/catch + + return 666; // Not a type + } // end of ColumnType + + public String ColumnDesc(int n, int[] val) { + // if (rsmd == null) { + // System.out.println("No result metadata"); + // return null; + // } else try { + // val[0] = rsmd.getColumnType(n); + // val[1] = rsmd.getPrecision(n); + // val[2] = rsmd.getScale(n); + // val[3] = rsmd.isNullable(n); + // return rsmd.getColumnLabel(n); + // } catch (SQLException se) { + // SetErrmsg(se); + // } //end try/catch + + return null; + } // end of ColumnDesc + + protected BsonValue GetFieldObject(String path) { + BsonValue o = doc; + BsonDocument dob = null; + BsonArray ary = null; + String[] names = null; + + if (path == null || path.equals("*")) + return doc; + else if (o instanceof BsonDocument) + dob = doc; + else if (o instanceof BsonArray) + ary = (BsonArray) o; + else + return doc; + + try { + names = path.split("\\."); + + for (String name : names) { + if (ary != null) { + o = ary.get(Integer.parseInt(name)); + } else + o = dob.get(name); + + if (o == null) + break; + + if (DEBUG) + System.out.println("Class o = " + o.getClass()); + + if (o instanceof BsonDocument) { + dob = (BsonDocument) o; + ary = null; + } else if (o instanceof BsonArray) { + ary = (BsonArray) o; + } else + break; + + } // endfor name + + } catch (IndexOutOfBoundsException x) { + o = null; + } catch (MongoException me) { + SetErrmsg(me); + o = null; + } // end try/catch + + return o; + } // end of GetFieldObject + + public String GetField(String path) { + BsonValue o = GetFieldObject(path); + + if (o != null) { + if (o.isString()) { + return o.asString().getValue(); + } else if (o.isInt32()) { + return Integer.toString(o.asInt32().getValue()); + } else if (o.isInt64()) { + return Long.toString(o.asInt64().getValue()); + } else if (o.isObjectId()) { + return o.asObjectId().getValue().toString(); + } else if (o.isDateTime()) { + Integer TS = (int) (o.asDateTime().getValue() / 1000); + return TS.toString(); + } else if (o.isDouble()) { + return Double.toString(o.asDouble().getValue()); + } else if (o.isDocument()) { + return o.asDocument().toJson(); + } else if (o.isArray()) { + util = new BsonDocument("arr", o.asArray()); + String s = util.toJson(); + int i1 = s.indexOf('['); + int i2 = s.lastIndexOf(']'); + return s.substring(i1, i2 + 1); + } else if (o.isNull()) { + return null; + } else + return o.toString(); + + } else + return null; + + } // end of GetField + + protected BsonValue ObjToBson(Object val) { + BsonValue bval = null; + + if (val == null) + bval = bsonull; + else if (val.getClass() == String.class) + bval = new BsonString((String) val); + else if (val.getClass() == Integer.class) + bval = new BsonInt32((int) val); + else if (val.getClass() == Double.class) + bval = new BsonDouble((double) val); + else if (val.getClass() == BigInteger.class) + bval = new BsonInt64((long) val); + else if (val.getClass() == Boolean.class) + bval = new BsonBoolean((Boolean) val); + else if (val.getClass() == Date.class) + bval = new BsonDateTime(((Date) val).getTime() * 1000); + else if (val.getClass() == BsonDocument.class) + bval = (BsonDocument) val; + else if (val.getClass() == BsonArray.class) + bval = (BsonArray) val; + + return bval; + } // end of ObjToBson + + public Object MakeDocument() { + return new BsonDocument(); + } // end of MakeDocument + + public boolean DocAdd(Object bdc, String key, Object val) { + try { + ((BsonDocument) bdc).append(key, ObjToBson(val)); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } // end try/catch + + return false; + } // end of DocAdd + + public Object MakeArray() { + return new BsonArray(); + } // end of MakeArray + + public boolean ArrayAdd(Object bar, int n, Object val) { + try { + for (int i = ((BsonArray) bar).size(); i < n; i++) + ((BsonArray) bar).add(bsonull); + + ((BsonArray) bar).add(ObjToBson(val)); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } catch (Exception ex) { + SetErrmsg(ex); + return true; + } // end try/catch + + return false; + } // end of ArrayAdd + + public boolean CollInsert(Object dob) { + try { + coll.insertOne((BsonDocument) dob); + } catch (MongoException me) { + SetErrmsg(me); + return true; + } catch (Exception ex) { + SetErrmsg(ex); + return true; + } // end try/catch + + return false; + } // end of CollInsert + + public long CollUpdate(Object upd) { + long n = -1; + + if (DEBUG) + System.out.println("upd: " + upd.toString()); + + try { + UpdateResult res = coll.updateOne(Filters.eq("_id", doc.get("_id")), (Bson) upd); + + if (DEBUG) + System.out.println("CollUpdate: " + res.toString()); + + n = res.getModifiedCount(); + } catch (MongoException me) { + SetErrmsg(me); + } catch (Exception ex) { + SetErrmsg(ex); + } // end try/catch + + return n; + } // end of CollUpdate + + public long CollDelete(boolean all) { + long n = -1; + + try { + DeleteResult res; + + if (all) + res = coll.deleteMany(new Document()); + else + res = coll.deleteOne(Filters.eq("_id", doc.get("_id"))); + + if (DEBUG) + System.out.println("CollDelete: " + res.toString()); + + n = res.getDeletedCount(); + } catch (MongoException me) { + SetErrmsg(me); + } catch (Exception ex) { + SetErrmsg(ex); + } // end try/catch + + return n; + } // end of CollDelete + +} // end of class MongoInterface diff --git a/storage/connect/array.cpp b/storage/connect/array.cpp index 6e0da312ca3c6..639edf63a1a9f 100644 --- a/storage/connect/array.cpp +++ b/storage/connect/array.cpp @@ -520,7 +520,7 @@ bool ARRAY::FilTest(PGLOBAL g, PVAL valp, OPVAL opc, int opm) } else if (opc != OP_EXIST) { sprintf(g->Message, MSG(MISSING_ARG), opc); - throw TYPE_ARRAY; + throw (int)TYPE_ARRAY; } else // OP_EXIST return Nval > 0; @@ -683,14 +683,14 @@ void ARRAY::SetPrecision(PGLOBAL g, int p) { if (Vblp == NULL) { strcpy(g->Message, MSG(PREC_VBLP_NULL)); - throw TYPE_ARRAY; + throw (int)TYPE_ARRAY; } // endif Vblp bool was = Vblp->IsCi(); if (was && !p) { strcpy(g->Message, MSG(BAD_SET_CASE)); - throw TYPE_ARRAY; + throw (int)TYPE_ARRAY; } // endif Vblp if (was || !p) @@ -701,7 +701,7 @@ void ARRAY::SetPrecision(PGLOBAL g, int p) if (!was && Type == TYPE_STRING) // Must be resorted to eliminate duplicate strings if (Sort(g)) - throw TYPE_ARRAY; + throw (int)TYPE_ARRAY; } // end of SetPrecision @@ -975,7 +975,7 @@ int ARRAY::BlockTest(PGLOBAL, int opc, int opm, PSZ ARRAY::MakeArrayList(PGLOBAL g) { char *p, *tp; - int i; + int i; size_t z, len = 2; if (Type == TYPE_LIST) @@ -1035,7 +1035,7 @@ void ARRAY::Printf(PGLOBAL g, FILE *f, uint n) } else fprintf(f, "%sVALLST: numval=%d\n", m, Nval); - } // end of Print + } // end of Printf /***********************************************************************/ /* Make string output of ARRAY contents. */ @@ -1047,7 +1047,7 @@ void ARRAY::Prints(PGLOBAL, char *ps, uint z) sprintf(ps, "ARRAY: type=%d\n", Type); // More to be implemented later - } // end of Print + } // end of Prints /* -------------------------- Class MULAR ---------------------------- */ diff --git a/storage/connect/blkfil.cpp b/storage/connect/blkfil.cpp index 3a0292481be6b..802095f2f82f3 100644 --- a/storage/connect/blkfil.cpp +++ b/storage/connect/blkfil.cpp @@ -65,7 +65,7 @@ void BLOCKFILTER::Printf(PGLOBAL, FILE *f, uint n) fprintf(f, "%sBLOCKFILTER: at %p opc=%d opm=%d result=%d\n", m, this, Opc, Opm, Result); - } // end of Print + } // end of Printf /***********************************************************************/ /* Make string output of BLOCKFILTER contents. */ @@ -73,7 +73,7 @@ void BLOCKFILTER::Printf(PGLOBAL, FILE *f, uint n) void BLOCKFILTER::Prints(PGLOBAL, char *ps, uint z) { strncat(ps, "BlockFilter(s)", z); - } // end of Print + } // end of Prints /* ---------------------- Class BLKFILLOG ---------------------------- */ @@ -412,7 +412,7 @@ void BLKFILMR2::MakeValueBitmap(void) Void = !Bmp[N]; // There are no good values in the file for (i = 0; i < N; i++) { - Bxp[i] = ~0U; + Bxp[i] = ~0; if (noteq) Bmp[i] = Bxp[i]; @@ -708,7 +708,7 @@ void BLKFILIN2::MakeValueBitmap(void) Void = !Bmp[N]; // There are no good values in the file for (i = 0; i < N; i++) { - Bxp[i] = ~0U; + Bxp[i] = ~0; if (noteq) { Bmp[i] = Bxp[i]; @@ -828,7 +828,7 @@ BLKFILIN2::BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp) Bxp[i] |= btp; for (N = i--; i >= 0; i--) - Bxp[i] = ~0U; + Bxp[i] = ~0; break; } // endif Bmp @@ -1006,9 +1006,9 @@ void BLOCKINDEX::Printf(PGLOBAL g, FILE *f, UINT n) m, this, Next, (Colp) ? Colp->GetName() : "Rowid", Kxp, Result); if (Next) - Next->Print(g, f, n); + Next->Printf(g, f, n); - } // end of Print + } // end of Printf /***********************************************************************/ /* Make string output of BLOCKINDEX contents. */ @@ -1016,7 +1016,7 @@ void BLOCKINDEX::Printf(PGLOBAL g, FILE *f, UINT n) void BLOCKINDEX::Prints(PGLOBAL g, char *ps, UINT z) { strncat(ps, "BlockIndex(es)", z); - } // end of Print + } // end of Prints /* ------------------------------------------------------------------- */ diff --git a/storage/connect/cmgoconn.cpp b/storage/connect/cmgoconn.cpp new file mode 100644 index 0000000000000..8367708d4ac43 --- /dev/null +++ b/storage/connect/cmgoconn.cpp @@ -0,0 +1,888 @@ +/************ CMgoConn C++ Functions Source Code File (.CPP) ***********/ +/* Name: CMgoConn.CPP Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the MongoDB C connection classes functions. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant MariaDB header file. */ +/***********************************************************************/ +#include + +/***********************************************************************/ +/* Required objects includes. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "colblk.h" +#include "xobject.h" +#include "xtable.h" +#include "filter.h" +#include "cmgoconn.h" + +bool IsNum(PSZ s); + +// Required to initialize libmongoc's internals +void mongo_init(bool init) +{ + if (init) + mongoc_init(); + else + mongoc_cleanup(); + +} // end of mongo_init + +/* --------------------------- Class INCOL --------------------------- */ + +/***********************************************************************/ +/* Add a column in the column list. */ +/***********************************************************************/ +void INCOL::AddCol(PGLOBAL g, PCOL colp, char *jp) +{ + char *p; + PKC kp, kcp; + + if ((p = strchr(jp, '.'))) { + PINCOL icp; + + *p++ = 0; + + for (kp = Klist; kp; kp = kp->Next) + if (kp->Incolp && !strcmp(jp, kp->Key)) + break; + + if (!kp) { + icp = new(g) INCOL(IsNum(p)); + kcp = (PKC)PlugSubAlloc(g, NULL, sizeof(KEYCOL)); + kcp->Next = NULL; + kcp->Incolp = icp; + kcp->Colp = NULL; + kcp->Key = PlugDup(g, jp); + + if (Klist) { + for (kp = Klist; kp->Next; kp = kp->Next); + + kp->Next = kcp; + } else + Klist = kcp; + + } else + icp = kp->Incolp; + + *(p - 1) = '.'; + icp->AddCol(g, colp, p); + } else { + kcp = (PKC)PlugSubAlloc(g, NULL, sizeof(KEYCOL)); + + kcp->Next = NULL; + kcp->Incolp = NULL; + kcp->Colp = colp; + kcp->Key = jp; + + if (Klist) { + for (kp = Klist; kp->Next; kp = kp->Next); + + kp->Next = kcp; + } else + Klist = kcp; + + } // endif jp + +} // end of AddCol + +/* -------------------------- Class CMgoConn ------------------------- */ + +/***********************************************************************/ +/* Implementation of the CMgoConn class. */ +/***********************************************************************/ +CMgoConn::CMgoConn(PGLOBAL g, PCPARM pcg) +{ + Pcg = pcg; + Uri = NULL; + Pool = NULL; + Client = NULL; + Database = NULL; + Collection = NULL; + Cursor = NULL; + Query = NULL; + Opts = NULL; + Fpc = NULL; + m_Connected = false; +} // end of CMgoConn standard constructor + +/***********************************************************************/ +/* Connect to the MongoDB server and get the collection. */ +/***********************************************************************/ +bool CMgoConn::Connect(PGLOBAL g) +{ + Uri = mongoc_uri_new(Pcg->Uristr); + + if (!Uri) { + sprintf(g->Message, "Failed to parse URI: \"%s\"", Pcg->Uristr); + return true; + } // endif Uri + + // Create a new client pool instance + Pool = mongoc_client_pool_new(Uri); + mongoc_client_pool_set_error_api(Pool, 2); + + // Register the application name so we can track it in the profile logs + // on the server. This can also be done from the URI. + mongoc_client_pool_set_appname(Pool, "Connect"); + + // Create a new client instance + Client = mongoc_client_pool_pop(Pool); + + if (!Client) { + sprintf(g->Message, "Failed to get Client"); + return true; + } // endif Client + + // Get a handle on the collection Coll_name + Collection = mongoc_client_get_collection(Client, Pcg->Db_name, Pcg->Coll_name); + + if (!Collection) { + sprintf(g->Message, "Failed to get Collection %s.%s", + Pcg->Db_name, Pcg->Coll_name); + return true; + } // endif Collection + + m_Connected = true; + return false; +} // end of Connect + +/***********************************************************************/ +/* CollSize: returns the number of documents in the collection. */ +/***********************************************************************/ +int CMgoConn::CollSize(PGLOBAL g) +{ + int cnt; + bson_t *query; + const char *jf = NULL; + + if (Pcg->Pipe) + return 10; + else if (Pcg->Filter) + jf = Pcg->Filter; + + if (jf) { + query = bson_new_from_json((const uint8_t *)jf, -1, &Error); + + if (!query) { + htrc("Wrong filter: %s", Error.message); + return 10; + } // endif Query + + } else + query = bson_new(); + + cnt = (int)mongoc_collection_count(Collection, + MONGOC_QUERY_NONE, query, 0, 0, NULL, &Error); + + if (cnt < 0) { + htrc("Collection count: %s", Error.message); + cnt = 2; + } // endif Cardinal + + bson_destroy(query); + return cnt; +} // end of CollSize + +/***********************************************************************/ +/* OpenDB: Data Base open routine for MONGO access method. */ +/***********************************************************************/ +bool CMgoConn::MakeCursor(PGLOBAL g) +{ + const char *p; + bool id, b = false, all = false; + PCSZ options = Pcg->Options; + PTDB tp = Pcg->Tdbp; + PCOL cp; + PSTRG s = NULL; + + id = (tp->GetMode() != MODE_READ); + + if (options && !stricmp(options, "all")) { + options = NULL; + all = true; + } // endif Options + + for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) + if (!strcmp(cp->GetName(), "_id")) + id = true; + else if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && !options) + all = true; + + if (Pcg->Pipe) { + if (trace) + htrc("Pipeline: %s\n", options); + + p = strrchr(options, ']'); + + if (!p) { + strcpy(g->Message, "Missing ] in pipeline"); + return true; + } else + *(char*)p = 0; + + s = new(g) STRING(g, 1023, (PSZ)options); + + if (tp->GetFilter()) { + s->Append(",{\"$match\":"); + + if (tp->GetFilter()->MakeSelector(g, s)) { + strcpy(g->Message, "Failed making selector"); + return true; + } else + s->Append('}'); + + tp->SetFilter(NULL); // Not needed anymore + } // endif To_Filter + + if (!all && tp->GetColumns()) { + // Project list + s->Append(",{\"$project\":{\""); + + if (!id) + s->Append("_id\":0,\""); + + for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) { + if (b) + s->Append(",\""); + else + b = true; + + s->Append(cp->GetJpath(g, true)); + s->Append("\":1"); + } // endfor cp + + s->Append("}}"); + } // endif all + + s->Append("]}"); + s->Resize(s->GetLength() + 1); + *(char*)p = ']'; // Restore Colist for discovery + p = s->GetStr(); + + if (trace) + htrc("New Pipeline: %s\n", p); + + Query = bson_new_from_json((const uint8_t *)p, -1, &Error); + + if (!Query) { + sprintf(g->Message, "Wrong pipeline: %s", Error.message); + return true; + } // endif Query + + Cursor = mongoc_collection_aggregate(Collection, MONGOC_QUERY_NONE, + Query, NULL, NULL); + + if (mongoc_cursor_error(Cursor, &Error)) { + sprintf(g->Message, "Mongo aggregate Failure: %s", Error.message); + return true; + } // endif error + + } else { + if (Pcg->Filter || tp->GetFilter()) { + if (trace) { + if (Pcg->Filter) + htrc("Filter: %s\n", Pcg->Filter); + + if (tp->GetFilter()) { + char buf[512]; + + tp->GetFilter()->Prints(g, buf, 511); + htrc("To_Filter: %s\n", buf); + } // endif To_Filter + + } // endif trace + + s = new(g) STRING(g, 1023, (PSZ)Pcg->Filter); + + if (tp->GetFilter()) { + if (Pcg->Filter) + s->Append(','); + + if (tp->GetFilter()->MakeSelector(g, s)) { + strcpy(g->Message, "Failed making selector"); + return NULL; + } // endif Selector + + tp->SetFilter(NULL); // Not needed anymore + } // endif To_Filter + + if (trace) + htrc("selector: %s\n", s->GetStr()); + + s->Resize(s->GetLength() + 1); + Query = bson_new_from_json((const uint8_t *)s->GetStr(), -1, &Error); + + if (!Query) { + sprintf(g->Message, "Wrong filter: %s", Error.message); + return NULL; + } // endif Query + + } else + Query = bson_new(); + + if (!all) { + if (options && *options) { + if (trace) + htrc("options=%s\n", options); + + p = options; + } else if (tp->GetColumns()) { + // Projection list + if (s) + s->Set("{\"projection\":{\""); + else + s = new(g) STRING(g, 511, "{\"projection\":{\""); + + if (!id) + s->Append("_id\":0,\""); + + for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) { + if (b) + s->Append(",\""); + else + b = true; + + s->Append(cp->GetJpath(g, true)); + s->Append("\":1"); + } // endfor cp + + s->Append("}}"); + s->Resize(s->GetLength() + 1); + p = s->GetStr(); + } else { + // count(*) ? + p = "{\"projection\":{\"_id\":1}}"; + } // endif Options + + Opts = bson_new_from_json((const uint8_t *)p, -1, &Error); + + if (!Opts) { + sprintf(g->Message, "Wrong options: %s", Error.message); + return NULL; + } // endif Opts + + } // endif all + + Cursor = mongoc_collection_find_with_opts(Collection, Query, Opts, NULL); + } // endif Pipe + + return false; +} // end of MakeCursor + +/***********************************************************************/ +/* Fetch next document. */ +/***********************************************************************/ +int CMgoConn::ReadNext(PGLOBAL g) +{ + int rc = RC_OK; + + if (!Cursor && MakeCursor(g)) { + rc = RC_FX; + } else if (mongoc_cursor_next(Cursor, &Document)) { + if (trace > 1) { + bson_iter_t iter; + ShowDocument(&iter, Document, ""); + } else if (trace == 1) + htrc("%s\n", GetDocument(g)); + + } else if (mongoc_cursor_error(Cursor, &Error)) { + sprintf(g->Message, "Mongo Cursor Failure: %s", Error.message); + rc = RC_FX; + } else + rc = RC_EF; + + return rc; +} // end of Fetch + +/***********************************************************************/ +/* Get the Json string of the current document. */ +/***********************************************************************/ +PSZ CMgoConn::GetDocument(PGLOBAL g) +{ + char *str = bson_as_json(Document, NULL); + PSZ doc = PlugDup(g, str); + + bson_free(str); + return doc; +} // end of GetDocument + +/***********************************************************************/ +/* Use to trace restaurants document contains. */ +/***********************************************************************/ +void CMgoConn::ShowDocument(bson_iter_t *iter, const bson_t *doc, const char *k) +{ + if (!doc || bson_iter_init(iter, doc)) { + const char *key; + + while (bson_iter_next(iter)) { + key = bson_iter_key(iter); + htrc("Found element key: \"%s\"\n", key); + + if (BSON_ITER_HOLDS_UTF8(iter)) + htrc("%s.%s=\"%s\"\n", k, key, bson_iter_utf8(iter, NULL)); + else if (BSON_ITER_HOLDS_INT32(iter)) + htrc("%s.%s=%d\n", k, key, bson_iter_int32(iter)); + else if (BSON_ITER_HOLDS_INT64(iter)) + htrc("%s.%s=%lld\n", k, key, bson_iter_int64(iter)); + else if (BSON_ITER_HOLDS_DOUBLE(iter)) + htrc("%s.%s=%g\n", k, key, bson_iter_double(iter)); + else if (BSON_ITER_HOLDS_DATE_TIME(iter)) + htrc("%s.%s=date(%lld)\n", k, key, bson_iter_date_time(iter)); + else if (BSON_ITER_HOLDS_OID(iter)) { + char str[25]; + + bson_oid_to_string(bson_iter_oid(iter), str); + htrc("%s.%s=%s\n", k, key, str); + } else if (BSON_ITER_HOLDS_DECIMAL128(iter)) { + char *str = NULL; + bson_decimal128_t dec; + + bson_iter_decimal128(iter, &dec); + bson_decimal128_to_string(&dec, str); + htrc("%s.%s=%s\n", k, key, str); + } else if (BSON_ITER_HOLDS_DOCUMENT(iter)) { + bson_iter_t child; + + if (bson_iter_recurse(iter, &child)) + ShowDocument(&child, NULL, key); + + } else if (BSON_ITER_HOLDS_ARRAY(iter)) { + bson_t *arr; + bson_iter_t itar; + const uint8_t *data = NULL; + uint32_t len = 0; + + bson_iter_array(iter, &len, &data); + arr = bson_new_from_data(data, len); + ShowDocument(&itar, arr, key); + } // endif's + + } // endwhile bson_iter_next + + } // endif bson_iter_init + +} // end of ShowDocument + +/***********************************************************************/ +/* Group columns for inserting or updating. */ +/***********************************************************************/ +void CMgoConn::MakeColumnGroups(PGLOBAL g) +{ + Fpc = new(g) INCOL(false); + + for (PCOL colp = Pcg->Tdbp->GetColumns(); colp; colp = colp->GetNext()) + if (!colp->IsSpecial()) + Fpc->AddCol(g, colp, colp->GetJpath(g, false)); + +} // end of MakeColumnGroups + +/***********************************************************************/ +/* DocWrite. */ +/***********************************************************************/ +bool CMgoConn::DocWrite(PGLOBAL g, PINCOL icp) +{ + for (PKC kp = icp->Klist; kp; kp = kp->Next) + if (kp->Incolp) { + bool isdoc = !kp->Incolp->Array; + + if (isdoc) + BSON_APPEND_DOCUMENT_BEGIN(&icp->Child, kp->Key, &kp->Incolp->Child); + else + BSON_APPEND_ARRAY_BEGIN(&icp->Child, kp->Key, &kp->Incolp->Child); + + if (DocWrite(g, kp->Incolp)) + return true; + + if (isdoc) + bson_append_document_end(&icp->Child, &kp->Incolp->Child); + else + bson_append_array_end(&icp->Child, &kp->Incolp->Child); + + } else if (AddValue(g, kp->Colp, &icp->Child, kp->Key, false)) + return true; + + return false; +} // end of DocWrite + +/***********************************************************************/ +/* WriteDB: Data Base write routine for DOS access method. */ +/***********************************************************************/ +int CMgoConn::Write(PGLOBAL g) +{ + int rc = RC_OK; + PTDB tp = Pcg->Tdbp; + + if (tp->GetMode() == MODE_INSERT) { + bson_init(&Fpc->Child); + + if (DocWrite(g, Fpc)) + return RC_FX; + + if (trace) { + char *str = bson_as_json(&Fpc->Child, NULL); + htrc("Inserting: %s\n", str); + bson_free(str); + } // endif trace + + if (!mongoc_collection_insert(Collection, MONGOC_INSERT_NONE, + &Fpc->Child, NULL, &Error)) { + sprintf(g->Message, "Mongo insert: %s", Error.message); + rc = RC_FX; + } // endif insert + + } else { + bool b = false; + bson_iter_t iter; + bson_t *query = bson_new(); + + bson_iter_init(&iter, Document); + + if (bson_iter_find(&iter, "_id")) { + if (BSON_ITER_HOLDS_OID(&iter)) + b = BSON_APPEND_OID(query, "_id", bson_iter_oid(&iter)); + else if (BSON_ITER_HOLDS_INT32(&iter)) + b = BSON_APPEND_INT32(query, "_id", bson_iter_int32(&iter)); + else if (BSON_ITER_HOLDS_INT64(&iter)) + b = BSON_APPEND_INT64(query, "_id", bson_iter_int64(&iter)); + else if (BSON_ITER_HOLDS_DOUBLE(&iter)) + b = BSON_APPEND_DOUBLE(query, "_id", bson_iter_double(&iter)); + else if (BSON_ITER_HOLDS_UTF8(&iter)) + b = BSON_APPEND_UTF8(query, "_id", bson_iter_utf8(&iter, NULL)); + + } // endif iter + + if (b) { + if (trace) { + char *str = bson_as_json(query, NULL); + htrc("update query: %s\n", str); + bson_free(str); + } // endif trace + + if (tp->GetMode() == MODE_UPDATE) { + bson_t child; + bson_t *update = bson_new(); + + BSON_APPEND_DOCUMENT_BEGIN(update, "$set", &child); + + for (PCOL colp = tp->GetSetCols(); colp; colp = colp->GetNext()) + if (AddValue(g, colp, &child, colp->GetJpath(g, false), true)) + rc = RC_FX; + + bson_append_document_end(update, &child); + + if (rc == RC_OK) + if (!mongoc_collection_update(Collection, MONGOC_UPDATE_NONE, + query, update, NULL, &Error)) { + sprintf(g->Message, "Mongo update: %s", Error.message); + rc = RC_FX; + } // endif update + + bson_destroy(update); + } else if (!mongoc_collection_remove(Collection, + MONGOC_REMOVE_SINGLE_REMOVE, query, NULL, &Error)) { + sprintf(g->Message, "Mongo delete: %s", Error.message); + rc = RC_FX; + } // endif remove + + } else { + strcpy(g->Message, "Mongo update: cannot find _id"); + rc = RC_FX; + } // endif b + + bson_destroy(query); + } // endif Mode + + return rc; +} // end of Write + +/***********************************************************************/ +/* Remove all documents from the collection. */ +/***********************************************************************/ +bool CMgoConn::DocDelete(PGLOBAL g) +{ + Query = bson_new(); + + if (!mongoc_collection_remove(Collection, MONGOC_REMOVE_NONE, + Query, NULL, &Error)) { + sprintf(g->Message, "Mongo remove all: %s", Error.message); + return true; + } // endif remove + + return false; +} // end of DocDelete + +/***********************************************************************/ +/* Rewind the collection. */ +/***********************************************************************/ +void CMgoConn::Rewind(void) +{ + mongoc_cursor_t *cursor = mongoc_cursor_clone(Cursor); + + mongoc_cursor_destroy(Cursor); + Cursor = cursor; +} // end of Rewind + +/***********************************************************************/ +/* Table close routine for MONGO tables. */ +/***********************************************************************/ +void CMgoConn::Close(void) +{ + if (Query) bson_destroy(Query); + if (Opts) bson_destroy(Opts); + if (Cursor) mongoc_cursor_destroy(Cursor); + if (Collection) mongoc_collection_destroy(Collection); + if (Client) mongoc_client_pool_push(Pool, Client); + if (Pool) mongoc_client_pool_destroy(Pool); + if (Uri) mongoc_uri_destroy(Uri); +} // end of Close + +/***********************************************************************/ +/* Mini: used to suppress blanks to json strings. */ +/***********************************************************************/ +char *CMgoConn::Mini(PGLOBAL g, PCOL colp, const bson_t *bson, bool b) +{ + char *s, *str = NULL; + char *Mbuf = (char*)PlugSubAlloc(g, NULL, colp->GetLength() + 1); + int i, k = 0; + bool ok = true; + + if (b) + s = str = bson_array_as_json(bson, NULL); + else + s = str = bson_as_json(bson, NULL); + + for (i = 0; i < colp->GetLength() && s[i]; i++) { + switch (s[i]) { + case ' ': + if (ok) continue; + case '"': + ok = !ok; + default: + break; + } // endswitch s[i] + + Mbuf[k++] = s[i]; + } // endfor i + + bson_free(str); + + if (i >= colp->GetLength()) { + sprintf(g->Message, "Value too long for column %s", colp->GetName()); + throw (int)TYPE_AM_MGO; + } // endif i + + Mbuf[k] = 0; + return Mbuf; +} // end of Mini + +/***********************************************************************/ +/* Retrieve the column value from the document. */ +/***********************************************************************/ +void CMgoConn::GetColumnValue(PGLOBAL g, PCOL colp) +{ + char *jpath = colp->GetJpath(g, false); + PVAL value = colp->GetValue(); + + if (!strcmp(jpath, "*")) { + value->SetValue_psz(Mini(g, colp, Document, false)); + } else if (bson_iter_init(&Iter, Document) && + bson_iter_find_descendant(&Iter, jpath, &Desc)) { + if (BSON_ITER_HOLDS_UTF8(&Desc)) + value->SetValue_psz((PSZ)bson_iter_utf8(&Desc, NULL)); + else if (BSON_ITER_HOLDS_INT32(&Desc)) + value->SetValue(bson_iter_int32(&Desc)); + else if (BSON_ITER_HOLDS_INT64(&Desc)) + value->SetValue(bson_iter_int64(&Desc)); + else if (BSON_ITER_HOLDS_DOUBLE(&Desc)) + value->SetValue(bson_iter_double(&Desc)); + else if (BSON_ITER_HOLDS_DATE_TIME(&Desc)) + value->SetValue(bson_iter_date_time(&Desc) / 1000); + else if (BSON_ITER_HOLDS_BOOL(&Desc)) { + bool b = bson_iter_bool(&Desc); + + if (value->IsTypeNum()) + value->SetValue(b ? 1 : 0); + else + value->SetValue_psz(b ? "true" : "false"); + + } else if (BSON_ITER_HOLDS_OID(&Desc)) { + char str[25]; + + bson_oid_to_string(bson_iter_oid(&Desc), str); + value->SetValue_psz(str); + } else if (BSON_ITER_HOLDS_NULL(&Iter)) { + // Apparently this does not work... + value->Reset(); + value->SetNull(true); + } else if (BSON_ITER_HOLDS_DECIMAL128(&Desc)) { + char *str = NULL; + bson_decimal128_t dec; + + bson_iter_decimal128(&Desc, &dec); + bson_decimal128_to_string(&dec, str); + value->SetValue_psz(str); + bson_free(str); + } else if (BSON_ITER_HOLDS_DOCUMENT(&Iter)) { + bson_t *doc; + const uint8_t *data = NULL; + uint32_t len = 0; + + bson_iter_document(&Desc, &len, &data); + + if (data) { + doc = bson_new_from_data(data, len); + value->SetValue_psz(Mini(g, colp, doc, false)); + bson_destroy(doc); + } else { + // ... but we can come here in case of NULL! + value->Reset(); + value->SetNull(true); + } // endif data + + } else if (BSON_ITER_HOLDS_ARRAY(&Iter)) { + bson_t *arr; + const uint8_t *data = NULL; + uint32_t len = 0; + + bson_iter_array(&Desc, &len, &data); + + if (data) { + arr = bson_new_from_data(data, len); + value->SetValue_psz(Mini(g, colp, arr, true)); + bson_destroy(arr); + } else { + // This is a bug in returning the wrong type + // This fix is only for document items + bson_t *doc; + + bson_iter_document(&Desc, &len, &data); + + if (data) { + doc = bson_new_from_data(data, len); + value->SetValue_psz(Mini(g, colp, doc, false)); + bson_destroy(doc); + } else { + // ... or we can also come here in case of NULL! + value->Reset(); + value->SetNull(true); + } // endif data + + } // endif data + + } else + value->Reset(); + + } else { + // Field does not exist + value->Reset(); + value->SetNull(true); + } // endif Iter + +} // end of GetColumnValue + +/***********************************************************************/ +/* AddValue: Add column value to the document to insert or update. */ +/***********************************************************************/ +bool CMgoConn::AddValue(PGLOBAL g, PCOL colp, bson_t *doc, char *key, bool upd) +{ + bool rc = false; + PVAL value = colp->GetValue(); + + if (value->IsNull()) { + if (upd) + rc = BSON_APPEND_NULL(doc, key); + else + return false; + + } else switch (colp->GetResultType()) { + case TYPE_STRING: + rc = BSON_APPEND_UTF8(doc, key, value->GetCharValue()); + break; + case TYPE_INT: + case TYPE_SHORT: + rc = BSON_APPEND_INT32(doc, key, value->GetIntValue()); + break; + case TYPE_TINY: + rc = BSON_APPEND_BOOL(doc, key, value->GetIntValue()); + break; + case TYPE_BIGINT: + rc = BSON_APPEND_INT64(doc, key, value->GetBigintValue()); + break; + case TYPE_DOUBLE: + rc = BSON_APPEND_DOUBLE(doc, key, value->GetFloatValue()); + break; + case TYPE_DECIM: + {bson_decimal128_t dec; + + if (bson_decimal128_from_string(value->GetCharValue(), &dec)) + rc = BSON_APPEND_DECIMAL128(doc, key, &dec); + + } break; + case TYPE_DATE: + rc = BSON_APPEND_DATE_TIME(doc, key, value->GetBigintValue() * 1000); + break; + default: + sprintf(g->Message, "Type %d not supported yet", colp->GetResultType()); + return true; + } // endswitch Buf_Type + + if (!rc) { + strcpy(g->Message, "Adding value failed"); + return true; + } else + return false; + +} // end of AddValue + +#if 0 +void *CMgoConn::mgo_alloc(size_t n) +{ + char *mst = (char*)PlgDBSubAlloc(G, NULL, n + sizeof(size_t)); + + if (mst) { + *(size_t*)mst = n; + return mst + sizeof(size_t); + } // endif mst + + return NULL; +} // end of mgo_alloc + +void *CMgoConn::mgo_calloc(size_t n, size_t sz) +{ + void *m = mgo_alloc(n * sz); + + if (m) + memset(m, 0, n * sz); + + return m; +} // end of mgo_calloc + +void *CMgoConn::mgo_realloc(void *m, size_t n) +{ + if (!m) + return n ? mgo_alloc(n) : NULL; + + size_t *osz = (size_t*)((char*)m - sizeof(size_t)); + + if (n > *osz) { + void *nwm = mgo_alloc(n); + + if (nwm) + memcpy(nwm, m, *osz); + + return nwm; + } else { + *osz = n; + return m; + } // endif n + +} // end of mgo_realloc +#endif // 0 + diff --git a/storage/connect/cmgoconn.h b/storage/connect/cmgoconn.h new file mode 100644 index 0000000000000..9e1361039ab07 --- /dev/null +++ b/storage/connect/cmgoconn.h @@ -0,0 +1,112 @@ +/***********************************************************************/ +/* CMgoConn.h : header file for the MongoDB connection classes. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include MongoDB library header files. */ +/***********************************************************************/ +#include +#include +#include + +// C connection to a MongoDB data source +class TDBMGO; +class MGOCOL; + +/***********************************************************************/ +/* Include MongoDB library header files. */ +/***********************************************************************/ +typedef class INCOL *PINCOL; +typedef class MGODEF *PMGODEF; +typedef class TDBMGO *PTDBMGO; +typedef class MGOCOL *PMGOCOL; + +typedef struct mongo_parms { + PTDB Tdbp; + PCSZ Uristr; // Driver URI + PCSZ Db_name; + PCSZ Coll_name; + PCSZ Options; + PCSZ Filter; + bool Pipe; +//PCSZ User; // User connect info +//PCSZ Pwd; // Password connect info +//int Fsize; // Fetch size +//bool Scrollable; // Scrollable cursor +} CMGOPARM, *PCPARM; + +typedef struct KEYCOL { + KEYCOL *Next; + PINCOL Incolp; + PCOL Colp; + char *Key; +} *PKC; + +/***********************************************************************/ +/* Used when inserting values in a MongoDB collection. */ +/***********************************************************************/ +class INCOL : public BLOCK { +public: + // Constructor + INCOL(bool ar) { Klist = NULL; Array = ar; } + + // Methods + void AddCol(PGLOBAL g, PCOL colp, char *jp); + + //Members + bson_t Child; + PKC Klist; + bool Array; +}; // end of INCOL; + +/***********************************************************************/ +/* CMgoConn class. */ +/***********************************************************************/ +class CMgoConn : public BLOCK { + friend class TDBMGO; + friend class MGODISC; +public: + // Constructor + CMgoConn(PGLOBAL g, PCPARM pcg); + + //static void *mgo_alloc(size_t n); + //static void *mgo_calloc(size_t n, size_t sz); + //static void *mgo_realloc(void *m, size_t n); + //static void mgo_free(void *) {} + + // Implementation + bool IsConnected(void) { return m_Connected; } + bool Connect(PGLOBAL g); + int CollSize(PGLOBAL g); + bool MakeCursor(PGLOBAL g); + int ReadNext(PGLOBAL g); + PSZ GetDocument(PGLOBAL g); + void ShowDocument(bson_iter_t *iter, const bson_t *doc, const char *k); + void MakeColumnGroups(PGLOBAL g); + bool DocWrite(PGLOBAL g, PINCOL icp); + int Write(PGLOBAL g); + bool DocDelete(PGLOBAL g); + void Rewind(void); + void Close(void); + PSZ Mini(PGLOBAL g, PCOL colp, const bson_t *bson, bool b); + void GetColumnValue(PGLOBAL g, PCOL colp); + bool AddValue(PGLOBAL g, PCOL colp, bson_t *doc, char *key, bool upd); + +protected: + // Members + PCPARM Pcg; + mongoc_uri_t *Uri; + mongoc_client_pool_t *Pool; // Thread safe client pool + mongoc_client_t *Client; // The MongoDB client + mongoc_database_t *Database; // The MongoDB database + mongoc_collection_t *Collection; // The MongoDB collection + mongoc_cursor_t *Cursor; + const bson_t *Document; + bson_t *Query; // MongoDB cursor filter + bson_t *Opts; // MongoDB cursor options + bson_error_t Error; + bson_iter_t Iter; // Used to retrieve column value + bson_iter_t Desc; // Descendant iter + PINCOL Fpc; // To insert INCOL classes + bool m_Connected; +}; // end of class CMgoConn diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp index 324d59ab40e78..5cd6a4f2be453 100644 --- a/storage/connect/colblk.cpp +++ b/storage/connect/colblk.cpp @@ -197,7 +197,7 @@ int COLBLK::GetLengthEx(void) void COLBLK::ReadColumn(PGLOBAL g) { sprintf(g->Message, MSG(UNDEFINED_AM), "ReadColumn"); - throw TYPE_COLBLK; + throw (int)TYPE_COLBLK; } // end of ReadColumn /***********************************************************************/ @@ -208,7 +208,7 @@ void COLBLK::ReadColumn(PGLOBAL g) void COLBLK::WriteColumn(PGLOBAL g) { sprintf(g->Message, MSG(UNDEFINED_AM), "WriteColumn"); - throw TYPE_COLBLK; + throw (int)TYPE_COLBLK; } // end of WriteColumn /***********************************************************************/ @@ -232,7 +232,7 @@ void COLBLK::Printf(PGLOBAL, FILE *f, uint n) fprintf(f, " coluse=%04X status=%04X buftyp=%d value=%p name=%s\n", ColUse, Status, Buf_Type, Value, Name); - } // end of Print + } // end of Printf /***********************************************************************/ /* Make string output of a column descriptor block. */ @@ -240,7 +240,7 @@ void COLBLK::Printf(PGLOBAL, FILE *f, uint n) void COLBLK::Prints(PGLOBAL, char *ps, uint) { sprintf(ps, "R%d.%s", To_Tdb->GetTdb_No(), Name); - } // end of Print + } // end of Prints /***********************************************************************/ @@ -262,7 +262,7 @@ SPCBLK::SPCBLK(PCOLUMN cp) void SPCBLK::WriteColumn(PGLOBAL g) { sprintf(g->Message, MSG(SPCOL_READONLY), Name); - throw TYPE_COLBLK; + throw (int)TYPE_COLBLK; } // end of WriteColumn /***********************************************************************/ @@ -412,4 +412,3 @@ void SIDBLK::ReadColumn(PGLOBAL) // } // endif Sname } // end of ReadColumn - diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index 608aa0407877f..b22933d9ebb08 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -38,7 +38,8 @@ class DllExport COLBLK : public XOBJECT { virtual PTDB GetTo_Tdb(void) {return To_Tdb;} virtual int GetClustered(void) {return 0;} virtual int IsClustered(void) {return FALSE;} - PCOL GetNext(void) {return Next;} + virtual PSZ GetJpath(PGLOBAL g, bool proj) {return NULL;} + PCOL GetNext(void) {return Next;} PSZ GetName(void) {return Name;} int GetIndex(void) {return Index;} ushort GetColUse(void) {return ColUse;} diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index e15cc724b85c1..08d35b059328c 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2017 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -185,10 +185,10 @@ bool CntInfo(PGLOBAL g, PTDB tp, PXF info) /***********************************************************************/ PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h) { - PTDB tdbp; + PTDB tdbp = NULL; PTABLE tabp; PDBUSER dup = PlgGetUser(g); - volatile PCATLG cat = (dup) ? dup->Catalog : NULL; // Safe over longjmp + volatile PCATLG cat = (dup) ? dup->Catalog : NULL; // Safe over throw if (trace) printf("CntGetTDB: name=%s mode=%d cat=%p\n", name, mode, cat); diff --git a/storage/connect/connect.h b/storage/connect/connect.h index 128561b80f321..2bca8bf54cb88 100644 --- a/storage/connect/connect.h +++ b/storage/connect/connect.h @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2011 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,6 +15,7 @@ /**************** Cnt H Declares Source Code File (.H) *****************/ /* Name: CONNECT.H Version 2.4 */ +/* Author Olivier BERTRAND bertrandop@gmail.com */ /* This file contains the some based classes declares. */ /***********************************************************************/ #include "filamtxt.h" diff --git a/storage/connect/engmsg.h b/storage/connect/engmsg.h index 14808758efd87..c072511065eca 100644 --- a/storage/connect/engmsg.h +++ b/storage/connect/engmsg.h @@ -1,3 +1,4 @@ +/* Copyright (C) MariaDB Corporation Ab */ #define MSG_ACCESS_VIOLATN "Access violation" #define MSG_ADD_BAD_TYPE "Array add value type mismatch (%s -> %s)" #define MSG_ALLOC_ERROR "Error allocating %s" diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp index 2ac0071a92db9..44abd962c564f 100644 --- a/storage/connect/filamdbf.cpp +++ b/storage/connect/filamdbf.cpp @@ -696,7 +696,7 @@ bool DBFFAM::AllocateBuffer(PGLOBAL g) } // endif Headlen /**************************************************************************/ - /* Position the file at the beginning of the data. */ + /* Position the file at the begining of the data. */ /**************************************************************************/ if (Tdbp->GetMode() == MODE_INSERT) rc = fseek(Stream, 0, SEEK_END); @@ -1036,7 +1036,7 @@ bool DBMFAM::AllocateBuffer(PGLOBAL g) } // endif Headlen /**************************************************************************/ - /* Position the file at the beginning of the data. */ + /* Position the file at the begining of the data. */ /**************************************************************************/ Fpos = Mempos = Memory + Headlen; Top--; // Because of EOF marker diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp index 537f77d01acbf..871613cb4b440 100755 --- a/storage/connect/filamvct.cpp +++ b/storage/connect/filamvct.cpp @@ -5,7 +5,7 @@ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index eb06ee7ad1eee..9e7fb3e63c7a9 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -455,7 +455,7 @@ bool UNZIPUTL::WildMatch(PCSZ pat, PCSZ str) { if (!*++pat) return TRUE; goto loopStart; default: - if (mapCaseTable[(uchar)*s] != mapCaseTable[(uchar)*p]) + if (mapCaseTable[(uint)*s] != mapCaseTable[(uint)*p]) goto starCheck; break; } /* endswitch */ diff --git a/storage/connect/filter.cpp b/storage/connect/filter.cpp index da44b129ccbdd..c2a89bc8721a0 100644 --- a/storage/connect/filter.cpp +++ b/storage/connect/filter.cpp @@ -33,11 +33,11 @@ #include "tabcol.h" #include "xtable.h" #include "array.h" -//#include "subquery.h" #include "filter.h" -//#include "token.h" -//#include "select.h" #include "xindex.h" +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) +#include "tabext.h" +#endif // MONGO_SUPPORT || JDBC_SUPPORT /***********************************************************************/ /* Utility routines. */ @@ -87,7 +87,7 @@ BYTE OpBmp(PGLOBAL g, OPVAL opc) case OP_EXIST: bt = 0x00; break; default: sprintf(g->Message, MSG(BAD_FILTER_OP), opc); - throw TYPE_ARRAY; + throw (int)TYPE_ARRAY; } // endswitch opc return bt; @@ -1406,6 +1406,86 @@ PFIL FILTER::Copy(PTABS t) } // end of Copy #endif // 0 +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) +/***********************************************************************/ +/* Make selector json representation for Mongo tables. */ +/***********************************************************************/ +bool FILTER::MakeSelector(PGLOBAL g, PSTRG s) +{ + s->Append('{'); + + if (Opc == OP_AND || Opc == OP_OR) { + if (GetArgType(0) != TYPE_FILTER || GetArgType(1) != TYPE_FILTER) + return true; + + s->Append("\"$"); + s->Append(Opc == OP_AND ? "and" : "or"); + s->Append("\":["); + + if (((PFIL)Arg(0))->MakeSelector(g, s)) + return true; + + s->Append(','); + + if (((PFIL)Arg(1))->MakeSelector(g, s)) + return true; + + s->Append(']'); + } else { + if (GetArgType(0) != TYPE_COLBLK) + return true; + + s->Append('"'); + s->Append(((PCOL)Arg(0))->GetJpath(g, false)); + s->Append("\":{\"$"); + + switch (Opc) { + case OP_EQ: + s->Append("eq"); + break; + case OP_NE: + s->Append("ne"); + break; + case OP_GT: + s->Append("gt"); + break; + case OP_GE: + s->Append("gte"); + break; + case OP_LT: + s->Append("lt"); + break; + case OP_LE: + s->Append("lte"); + break; + case OP_NULL: + case OP_LIKE: + case OP_EXIST: + default: + return true; + } // endswitch Opc + + s->Append("\":"); + + if (GetArgType(1) == TYPE_COLBLK) { + s->Append("\"$"); + s->Append(((PEXTCOL)Arg(1))->GetJpath(g, false)); + s->Append('"'); + } else { + char buf[501]; + + Arg(1)->Prints(g, buf, 500); + s->Append(buf); + } // endif Type + + s->Append('}'); + } // endif Opc + + s->Append('}'); + return false; +} // end of MakeSelector +#endif // MONGO_SUPPORT || JDBC_SUPPORT + /*********************************************************************/ /* Make file output of FILTER contents. */ /*********************************************************************/ @@ -1437,7 +1517,7 @@ void FILTER::Printf(PGLOBAL g, FILE *f, uint n) } // endfor fp - } // end of Print + } // end of Printf /***********************************************************************/ /* Make string output of TABLE contents (z should be checked). */ @@ -1579,7 +1659,7 @@ void FILTER::Prints(PGLOBAL g, char *ps, uint z) bcp = bxp; } while (bcp); // enddo - } // end of Print + } // end of Prints /* -------------------- Derived Classes Functions -------------------- */ @@ -1697,8 +1777,6 @@ PFIL PrepareFilter(PGLOBAL g, PFIL fp, bool having) if (trace) htrc("PrepareFilter: fp=%p having=%d\n", fp, having); -//if (fp) -// fp->Print(g, debug, 0); while (fp) { if (fp->Opc == OP_SEP) @@ -1712,7 +1790,7 @@ PFIL PrepareFilter(PGLOBAL g, PFIL fp, bool having) break; // Remove eventual ending separator(s) // if (fp->Convert(g, having)) -// throw TYPE_ARRAY; +// (int)throw TYPE_ARRAY; filp = fp; fp = fp->Next; @@ -1745,7 +1823,7 @@ DllExport bool ApplyFilter(PGLOBAL g, PFIL filp) // return TRUE; if (filp->Eval(g)) - throw TYPE_FILTER; + throw (int)TYPE_FILTER; if (trace > 1) htrc("PlugFilter filp=%p result=%d\n", diff --git a/storage/connect/filter.h b/storage/connect/filter.h index 22d1e4ed4be3e..85c75a2227e8b 100644 --- a/storage/connect/filter.h +++ b/storage/connect/filter.h @@ -1,7 +1,7 @@ /*************** Filter H Declares Source Code File (.H) ***************/ -/* Name: FILTER.H Version 1.2 */ +/* Name: FILTER.H Version 1.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2010-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2010-2017 */ /* */ /* This file contains the FILTER and derived classes declares. */ /***********************************************************************/ @@ -61,6 +61,9 @@ class DllExport FILTER : public XOBJECT { /* Filter description block */ //virtual PXOB CheckSubQuery(PGLOBAL, PSQL); //virtual bool CheckLocal(PTDB); //virtual int CheckSpcCol(PTDB tdbp, int n); +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + bool MakeSelector(PGLOBAL g, PSTRG s); +#endif // MONGO_SUPPORT || JDBC_SUPPORT virtual void Printf(PGLOBAL g, FILE *f, uint n); virtual void Prints(PGLOBAL g, char *ps, uint z); // PFIL Linearize(bool nosep); diff --git a/storage/connect/global.h b/storage/connect/global.h index a2030fdb5d07d..cb756494efc31 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -1,6 +1,7 @@ /***********************************************************************/ /* GLOBAL.H: Declaration file used by all CONNECT implementations. */ -/* (C) Copyright Olivier Bertrand 1993-2017 */ +/* (C) Copyright MariaDB Corporation Ab */ +/* Author Olivier Bertrand 1993-2017 */ /***********************************************************************/ /***********************************************************************/ @@ -90,6 +91,7 @@ #define TYPE_BIGINT 5 #define TYPE_LIST 6 #define TYPE_INT 7 +#define TYPE_DATE 8 #define TYPE_DECIM 9 #define TYPE_BIN 10 #define TYPE_PCHAR 11 diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 887d692ba690e..72d6ddda8b194 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2017 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -98,8 +98,7 @@ rnd_next signals that it has reached the end of its data. Calls to ha_connect::extra() are hints as to what will be occuring to the request. - Happy use!
- -Olivier + Author Olivier Bertrand */ #ifdef USE_PRAGMA_IMPLEMENTATION @@ -209,8 +208,11 @@ pthread_mutex_t parmut = PTHREAD_MUTEX_INITIALIZER; /***********************************************************************/ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); PQRYRES VirColumns(PGLOBAL g, bool info); -PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info); +PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info); PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info); +#if defined(MONGO_SUPPORT) +PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ url, PTOS topt, bool info); +#endif // MONGO_SUPPORT int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v); void PushWarning(PGLOBAL g, THD *thd, int level); bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host, PCSZ db, @@ -505,7 +507,8 @@ ha_create_table_option connect_table_option_list[]= HA_TOPTION_STRING("CATFUNC", catfunc), HA_TOPTION_STRING("SRCDEF", srcdef), HA_TOPTION_STRING("COLIST", colist), - HA_TOPTION_STRING("OPTION_LIST", oplist), + HA_TOPTION_STRING("FILTER", filter), + HA_TOPTION_STRING("OPTION_LIST", oplist), HA_TOPTION_STRING("DATA_CHARSET", data_charset), HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1), HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1), @@ -675,6 +678,10 @@ static int connect_init_func(void *p) XmlInitParserLib(); #endif // LIBXML2_SUPPORT +#if defined(MONGO_SUPPORT) + mongo_init(true); +#endif // MONGO_SUPPORT + init_connect_psi_keys(); connect_hton= (handlerton *)p; @@ -693,7 +700,7 @@ static int connect_init_func(void *p) DTVAL::SetTimeShift(); // Initialize time zone shift once for all BINCOL::SetEndian(); // Initialize host endian setting #if defined(JDBC_SUPPORT) - JDBConn::SetJVM(); + JAVAConn::SetJVM(); #endif // JDBC_SUPPORT DBUG_RETURN(0); } // end of connect_init_func @@ -713,8 +720,12 @@ static int connect_done_func(void *) XmlCleanupParserLib(); #endif // LIBXML2_SUPPORT +#if defined(MONGO_SUPPORT) + mongo_init(false); +#endif // MONGO_SUPPORT + #ifdef JDBC_SUPPORT - JDBConn::ResetJVM(); + JAVAConn::ResetJVM(); #endif // JDBC_SUPPORT #if defined(__WIN__) @@ -1025,26 +1036,43 @@ PCSZ GetListOption(PGLOBAL g, PCSZ opname, PCSZ oplist, PCSZ def) return (char*)def; char key[16], val[256]; - char *pk, *pv, *pn; + char *pv, *pn, *pk= (char*)oplist; PCSZ opval= def; int n; - for (pk= (char*)oplist; pk; pk= ++pn) { + while (*pk == ' ') + pk++; + + for (; pk; pk= pn) { pn= strchr(pk, ','); pv= strchr(pk, '='); if (pv && (!pn || pv < pn)) { - n= MY_MIN(static_cast(pv - pk), sizeof(key) - 1); - memcpy(key, pk, n); + n = MY_MIN(static_cast(pv - pk), sizeof(key) - 1); + memcpy(key, pk, n); + + while (n && key[n - 1] == ' ') + n--; + key[n]= 0; - pv++; - n= MY_MIN((pn ? pn - pv : strlen(pv)), sizeof(val) - 1); + + while(*(++pv) == ' ') ; + + n= MY_MIN((pn ? pn - pv : strlen(pv)), sizeof(val) - 1); memcpy(val, pv, n); - val[n]= 0; + + while (n && val[n - 1] == ' ') + n--; + + val[n]= 0; } else { - n= MY_MIN((pn ? pn - pk : strlen(pk)), sizeof(key) - 1); + n= MY_MIN((pn ? pn - pk : strlen(pk)), sizeof(key) - 1); memcpy(key, pk, n); - key[n]= 0; + + while (n && key[n - 1] == ' ') + n--; + + key[n]= 0; val[0]= 0; } // endif pv @@ -1054,6 +1082,7 @@ PCSZ GetListOption(PGLOBAL g, PCSZ opname, PCSZ oplist, PCSZ def) } else if (!pn) break; + while (*(++pn) == ' ') ; } // endfor pk return opval; @@ -1095,7 +1124,9 @@ PCSZ GetStringTableOption(PGLOBAL g, PTOS options, PCSZ opname, PCSZ sdef) opval= options->srcdef; else if (!stricmp(opname, "Colist")) opval= options->colist; - else if (!stricmp(opname, "Data_charset")) + else if (!stricmp(opname, "Filter")) + opval = options->filter; + else if (!stricmp(opname, "Data_charset")) opval= options->data_charset; if (!opval && options->oplist) @@ -1192,7 +1223,7 @@ char *ha_connect::GetRealString(PCSZ s) { char *sv; - if (IsPartitioned() && s && *partname) { + if (IsPartitioned() && s && partname && *partname) { sv= (char*)PlugSubAlloc(xp->g, NULL, 0); sprintf(sv, s, partname); PlugSubAlloc(xp->g, NULL, strlen(sv) + 1); @@ -1497,7 +1528,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) pcf->Flags |= U_NULLS; // Mark virtual columns as such - if (!fp->stored_in_db()) + if (fp->vcol_info && !fp->stored_in_db()) pcf->Flags |= U_VIRTUAL; pcf->Key= 0; // Not used when called from MySQL @@ -1993,7 +2024,7 @@ int ha_connect::MakeRecord(char *buf) for (field= table->field; *field && !rc; field++) { fp= *field; - if (!fp->stored_in_db()) + if (fp->vcol_info && !fp->stored_in_db()) continue; // This is a virtual column if (bitmap_is_set(map, fp->field_index) || alter) { @@ -2114,7 +2145,8 @@ int ha_connect::ScanRecord(PGLOBAL g, const uchar *) for (Field **field=table->field ; *field ; field++) { fp= *field; - if (!fp->stored_in_db() || fp->option_struct->special) + if ((fp->vcol_info && !fp->stored_in_db()) || + fp->option_struct->special) continue; // Is a virtual column possible here ??? if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL @@ -2924,7 +2956,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) strncat(s, res->ptr(), res->length()); if (res->length() < 19) - strcat(s, &"1970-01-01 00:00:00"[res->length()]); + strcat(s, "1970-01-01 00:00:00" + res->length()); strcat(s, "'}"); break; @@ -2953,7 +2985,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) strncat(s, res->ptr(), res->length()); if (res->length() < 19) - strcat(s, &"1970-01-01 00:00:00"[res->length()]); + strcat(s, "1970-01-01 00:00:00" + res->length()); strcat(s, "'}"); break; @@ -3495,7 +3527,7 @@ int ha_connect::delete_row(const uchar *) /****************************************************************************/ -/* We seem to come here at the beginning of an index use. */ +/* We seem to come here at the begining of an index use. */ /****************************************************************************/ int ha_connect::index_init(uint idx, bool sorted) { @@ -4051,7 +4083,12 @@ int ha_connect::info(uint flag) DBUG_ENTER("ha_connect::info"); - if (trace) + if (!g) { + my_message(ER_UNKNOWN_ERROR, "Cannot get g pointer", MYF(0)); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } // endif g + + if (trace) htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info); // tdbp must be available to get updated info @@ -4062,7 +4099,7 @@ int ha_connect::info(uint flag) if (xmod == MODE_ANY || xmod == MODE_ALTER) { // Pure info, not a query pure= true; - xp->CheckCleanup(); + xp->CheckCleanup(xmod == MODE_ANY && valid_query_id == 0); } // endif xmod // This is necessary for getting file length @@ -4075,8 +4112,10 @@ int ha_connect::info(uint flag) } else DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen - if (!(tdbp= GetTDB(g))) - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen + if (!(tdbp = GetTDB(g))) { + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } // endif tdbp valid_info = false; } // endif tdbp @@ -4251,6 +4290,7 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, const char *dbn, bool case TAB_ODBC: case TAB_JDBC: case TAB_MYSQL: + case TAB_MONGO: case TAB_DIR: case TAB_MAC: case TAB_WMI: @@ -4429,9 +4469,9 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, break; // } // endif partitioned - case SQLCOM_END: - // Met in procedures: IF(EXISTS(SELECT... - newmode= MODE_READ; + case SQLCOM_CHECK: // TODO implement it + case SQLCOM_END: // Met in procedures: IF(EXISTS(SELECT... + newmode= MODE_READ; break; default: htrc("Unsupported sql_command=%d\n", thd_sql_command(thd)); @@ -5280,16 +5320,18 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #if defined(ODBC_SUPPORT) POPARM sop= NULL; PCSZ ucnc= NULL; - bool cnc= false; + PCSZ tabtyp = NULL; + bool cnc= false; int cto= -1, qto= -1; #endif // ODBC_SUPPORT #if defined(JDBC_SUPPORT) PJPARM sjp= NULL; +#endif // JDBC_SUPPORT +#if defined(JDBC_SUPPORT) || defined(MONGO_SUPPORT) PCSZ driver= NULL; char *url= NULL; //char *prop= NULL; - PCSZ tabtyp= NULL; -#endif // JDBC_SUPPORT +#endif // JDBC_SUPPORT || MONGO_SUPPORT uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); bool bif, ok= false, dbf= false; TABTYPE ttp= TAB_UNDEF; @@ -5342,19 +5384,17 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #endif // __WIN__ port= atoi(GetListOption(g, "port", topt->oplist, "0")); #if defined(ODBC_SUPPORT) - mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0")); + tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL); + 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 -#if defined(JDBC_SUPPORT) +#if defined(JDBC_SUPPORT) || defined(MONGO_SUPPORT) driver= GetListOption(g, "Driver", topt->oplist, NULL); -// url= GetListOption(g, "URL", topt->oplist, NULL); -// prop = GetListOption(g, "Properties", topt->oplist, NULL); - tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL); -#endif // JDBC_SUPPORT +#endif // JDBC_SUPPORT || MONGO_SUPPORT #if defined(PROMPT_OK) cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0")); #endif // PROMPT_OK @@ -5476,16 +5516,16 @@ static int connect_assisted_discovery(handlerton *, THD* thd, supfnc |= (FNC_DRIVER | FNC_TABLE); break; #endif // JDBC_SUPPORT - case TAB_DBF: - dbf= true; - // fall through - case TAB_CSV: - if (!fn && fnc != FNC_NO) - sprintf(g->Message, "Missing %s file name", topt->type); - else if (sep && strlen(sep) > 1) - sprintf(g->Message, "Invalid separator %s", sep); - else - ok= true; + case TAB_DBF: + dbf = true; + // fall through + case TAB_CSV: + if (!fn && fnc != FNC_NO) + sprintf(g->Message, "Missing %s file name", topt->type); + else if (sep && strlen(sep) > 1) + sprintf(g->Message, "Invalid separator %s", sep); + else + ok = true; break; case TAB_MYSQL: @@ -5558,12 +5598,22 @@ static int connect_assisted_discovery(handlerton *, THD* thd, case TAB_XML: #endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT case TAB_JSON: - if (!fn && !zfn && !mul) + dsn = strz(g, create_info->connect_string); + + if (!fn && !zfn && !mul && !dsn) sprintf(g->Message, "Missing %s file name", topt->type); else ok = true; break; +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + case TAB_MONGO: + if (!topt->tabname) + topt->tabname = tab; + + ok = true; + break; +#endif // MONGO_SUPPORT || JDBC_SUPPORT case TAB_VIR: ok = true; break; @@ -5704,8 +5754,36 @@ static int connect_assisted_discovery(handlerton *, THD* thd, qrp = VirColumns(g, fnc == FNC_COL); break; case TAB_JSON: - qrp = JSONColumns(g, (char*)db, topt, fnc == FNC_COL); + qrp = JSONColumns(g, db, dsn, topt, fnc == FNC_COL); + break; +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + case TAB_MONGO: + if (!(url = strz(g, create_info->connect_string)) || !*url) + url = "mongodb://localhost:27017"; + +#if !defined(MONGO_SUPPORT) + driver = "JAVA"; + // strcpy(g->Message, "No column discovery for Java MONGO tables yet"); + // Temporarily use the JSONColumns function + qrp = JSONColumns(g, db, url, topt, fnc == FNC_COL); +#elif !defined(JDBC_SUPPORT) + driver = "C"; + qrp = MGOColumns(g, db, url, topt, fnc == FNC_COL); +#else // MONGO_SUPPORT && JDBC_SUPPORT + if (!driver) + driver = "C"; + + if (toupper(*driver) == 'C') { + qrp = MGOColumns(g, db, url, topt, fnc == FNC_COL); + } else { + // strcpy(g->Message, "No column discovery for Java MONGO tables yet"); + // Temporarily use the JSONColumns function + qrp = JSONColumns(g, db, url, topt, fnc == FNC_COL); + } // endif driver + +#endif // MONGO_SUPPORT && JDBC_SUPPORT break; +#endif // MONGO_SUPPORT || JDBC_SUPPORT #if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT) case TAB_XML: qrp = XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL); @@ -6021,6 +6099,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, TABTYPE type; TABLE *st= table; // Probably unuseful THD *thd= ha_thd(); + LEX_CSTRING cnc = table_arg->s->connect_string; #if defined(WITH_PARTITION_STORAGE_ENGINE) partition_info *part_info= table_arg->part_info; #endif // WITH_PARTITION_STORAGE_ENGINE @@ -6068,7 +6147,8 @@ int ha_connect::create(const char *name, TABLE *table_arg, if (check_privileges(thd, options, GetDBfromName(name))) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - inward= IsFileType(type) && !options->filename; + inward= IsFileType(type) && !options->filename && + (type != TAB_JSON || !cnc.length); if (options->data_charset) { const CHARSET_INFO *data_charset; @@ -6165,7 +6245,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } // endif CheckSelf - }break; + } break; default: /* do nothing */; break; } // endswitch ttp @@ -6176,7 +6256,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, // Note that if no support is specified, the default is MS-DOM // on Windows and libxml2 otherwise - switch (*xsup) { + switch (toupper(*xsup)) { case '*': #if defined(__WIN__) dom= true; @@ -6243,7 +6323,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, for (field= table_arg->field; *field; field++) { fp= *field; - if (!fp->stored_in_db()) + if (fp->vcol_info && !fp->stored_in_db()) continue; // This is a virtual column if (fp->flags & AUTO_INCREMENT_FLAG) { diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index 3788a3882b63a..1d2db91bc6fca 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2015 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,6 +14,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ /** @file ha_connect.h + Author Olivier Bertrand @brief The ha_connect engine is a prototype storage engine to access external data. diff --git a/storage/connect/inihandl.c b/storage/connect/inihandl.c index e5eb356777992..0ce0eb9fa0d6a 100644 --- a/storage/connect/inihandl.c +++ b/storage/connect/inihandl.c @@ -193,7 +193,7 @@ static void PROFILE_Save( FILE *file, PROFILESECTION *section ) } for (key = section->key; key; key = key->next) - if (key->name[0]) { + if (key->name && key->name[0]) { fprintf(file, "%s", SVP(key->name)); if (key->value) diff --git a/storage/connect/javaconn.cpp b/storage/connect/javaconn.cpp new file mode 100644 index 0000000000000..9fc44c5cbfec4 --- /dev/null +++ b/storage/connect/javaconn.cpp @@ -0,0 +1,599 @@ +/************ Javaconn C++ Functions Source Code File (.CPP) ***********/ +/* Name: JAVAConn.CPP Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the JAVA connection classes functions. */ +/***********************************************************************/ + +#if defined(__WIN__) +// This is needed for RegGetValue +#define _WINVER 0x0601 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 +#endif // __WIN__ + +/***********************************************************************/ +/* Include relevant MariaDB header file. */ +/***********************************************************************/ +#include +#include +#if defined(__WIN__) +#include // for getcwd +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +#else // !__WIN__ +#if defined(UNIX) +#include +#else // !UNIX +#endif // !UNIX +#include +#include // for getenv +#define NODW +#endif // !__WIN__ + +/***********************************************************************/ +/* Required objects includes. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "colblk.h" +#include "xobject.h" +#include "xtable.h" +#include "tabext.h" +#include "javaconn.h" +#include "resource.h" +#include "valblk.h" +#include "osutil.h" + +#if defined(__WIN__) +extern "C" HINSTANCE s_hModule; // Saved module handle +#endif // __WIN__ +#define nullptr 0 + +//TYPCONV GetTypeConv(); +//int GetConvSize(); +extern char *JvmPath; // The connect_jvm_path global variable value +extern char *ClassPath; // The connect_class_path global variable value + +char *GetJavaWrapper(void); // The connect_java_wrapper variable value + +/***********************************************************************/ +/* Static JAVAConn objects. */ +/***********************************************************************/ +void *JAVAConn::LibJvm = NULL; +CRTJVM JAVAConn::CreateJavaVM = NULL; +GETJVM JAVAConn::GetCreatedJavaVMs = NULL; +#if defined(_DEBUG) +GETDEF JAVAConn::GetDefaultJavaVMInitArgs = NULL; +#endif // _DEBUG + +/***********************************************************************/ +/* Some macro's (should be defined elsewhere to be more accessible) */ +/***********************************************************************/ +#if defined(_DEBUG) +#define ASSERT(f) assert(f) +#define DEBUG_ONLY(f) (f) +#else // !_DEBUG +#define ASSERT(f) ((void)0) +#define DEBUG_ONLY(f) ((void)0) +#endif // !_DEBUG + +/***********************************************************************/ +/* Allocate the structure used to refer to the result set. */ +/***********************************************************************/ +static JCATPARM *AllocCatInfo(PGLOBAL g, JCATINFO fid, PCSZ db, + PCSZ tab, PQRYRES qrp) +{ + JCATPARM *cap; + +#if defined(_DEBUG) + assert(qrp); +#endif + + if ((cap = (JCATPARM *)PlgDBSubAlloc(g, NULL, sizeof(JCATPARM)))) { + memset(cap, 0, sizeof(JCATPARM)); + cap->Id = fid; + cap->Qrp = qrp; + cap->DB = db; + cap->Tab = tab; + } // endif cap + + return cap; +} // end of AllocCatInfo + +/***********************************************************************/ +/* JAVAConn construction/destruction. */ +/***********************************************************************/ +JAVAConn::JAVAConn(PGLOBAL g, PCSZ wrapper) +{ + m_G = g; + jvm = nullptr; // Pointer to the JVM (Java Virtual Machine) + env = nullptr; // Pointer to native interface + jdi = nullptr; // Pointer to the java wrapper class + job = nullptr; // The java wrapper class object + errid = nullptr; + DiscFunc = "Disconnect"; + Msg = NULL; + m_Wrap = (wrapper) ? wrapper : GetJavaWrapper(); + + if (!strchr(m_Wrap, '/')) { + // Add the wrapper package name + char *wn = (char*)PlugSubAlloc(g, NULL, strlen(m_Wrap) + 10); + m_Wrap = strcat(strcpy(wn, "wrappers/"), m_Wrap); + } // endif m_Wrap + + m_Opened = false; + m_Connected = false; + m_Rows = 0; +//*m_ErrMsg = '\0'; +} // end of JAVAConn + +//JAVAConn::~JAVAConn() +// { +//if (Connected()) +// EndCom(); + +// } // end of ~JAVAConn + +/***********************************************************************/ +/* Screen for errors. */ +/***********************************************************************/ +bool JAVAConn::Check(jint rc) +{ + jstring s; + + if (env->ExceptionCheck()) { + jthrowable exc = env->ExceptionOccurred(); + jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object"), + "toString", "()Ljava/lang/String;"); + + if (exc != nullptr && tid != nullptr) { + jstring s = (jstring)env->CallObjectMethod(exc, tid); + const char *utf = env->GetStringUTFChars(s, (jboolean)false); + env->DeleteLocalRef(s); + Msg = PlugDup(m_G, utf); + } else + Msg = "Exception occured"; + + env->ExceptionClear(); + } else if (rc < 0) { + s = (jstring)env->CallObjectMethod(job, errid); + Msg = (char*)env->GetStringUTFChars(s, (jboolean)false); + } else + Msg = NULL; + + return (Msg != NULL); +} // end of Check + +/***********************************************************************/ +/* Get MethodID if not exists yet. */ +/***********************************************************************/ +bool JAVAConn::gmID(PGLOBAL g, jmethodID& mid, const char *name, const char *sig) +{ + if (mid == nullptr) { + mid = env->GetMethodID(jdi, name, sig); + + if (Check()) { + strcpy(g->Message, Msg); + return true; + } else + return false; + + } else + return false; + +} // end of gmID + +#if 0 +/***********************************************************************/ +/* Utility routine. */ +/***********************************************************************/ +int JAVAConn::GetMaxValue(int n) +{ + jint m; + jmethodID maxid = nullptr; + + if (gmID(m_G, maxid, "GetMaxValue", "(I)I")) + return -1; + + // call method + if (Check(m = env->CallIntMethod(job, maxid, n))) + htrc("GetMaxValue: %s", Msg); + + return (int)m; +} // end of GetMaxValue +#endif // 0 + +/***********************************************************************/ +/* Reset the JVM library. */ +/***********************************************************************/ +void JAVAConn::ResetJVM(void) +{ + if (LibJvm) { +#if defined(__WIN__) + FreeLibrary((HMODULE)LibJvm); +#else // !__WIN__ + dlclose(LibJvm); +#endif // !__WIN__ + LibJvm = NULL; + CreateJavaVM = NULL; + GetCreatedJavaVMs = NULL; +#if defined(_DEBUG) + GetDefaultJavaVMInitArgs = NULL; +#endif // _DEBUG + } // endif LibJvm + +} // end of ResetJVM + +/***********************************************************************/ +/* Dynamically link the JVM library. */ +/* The purpose of this function is to allow using the CONNECT plugin */ +/* for other table types when the Java JDK is not installed. */ +/***********************************************************************/ +bool JAVAConn::GetJVM(PGLOBAL g) +{ + int ntry; + + if (!LibJvm) { + char soname[512]; + +#if defined(__WIN__) + for (ntry = 0; !LibJvm && ntry < 3; ntry++) { + if (!ntry && JvmPath) { + strcat(strcpy(soname, JvmPath), "\\jvm.dll"); + ntry = 3; // No other try + } else if (ntry < 2 && getenv("JAVA_HOME")) { + strcpy(soname, getenv("JAVA_HOME")); + + if (ntry == 1) + strcat(soname, "\\jre"); + + strcat(soname, "\\bin\\client\\jvm.dll"); + } else { + // Try to find it through the registry + char version[16]; + char javaKey[64] = "SOFTWARE\\JavaSoft\\Java Runtime Environment"; + LONG rc; + DWORD BufferSize = 16; + + strcpy(soname, "jvm.dll"); // In case it fails + + if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion", + RRF_RT_ANY, NULL, (PVOID)&version, &BufferSize)) == ERROR_SUCCESS) { + strcat(strcat(javaKey, "\\"), version); + BufferSize = sizeof(soname); + + if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "RuntimeLib", + RRF_RT_ANY, NULL, (PVOID)&soname, &BufferSize)) != ERROR_SUCCESS) + printf("RegGetValue: rc=%ld\n", rc); + + } // endif rc + + ntry = 3; // Try this only once + } // endelse + + // Load the desired shared library + LibJvm = LoadLibrary(soname); + } // endfor ntry + + // Get the needed entries + if (!LibJvm) { + char buf[256]; + DWORD rc = GetLastError(); + + sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, + (LPTSTR)buf, sizeof(buf), NULL); + strcat(strcat(g->Message, ": "), buf); + } else if (!(CreateJavaVM = (CRTJVM)GetProcAddress((HINSTANCE)LibJvm, + "JNI_CreateJavaVM"))) { + sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_CreateJavaVM"); + FreeLibrary((HMODULE)LibJvm); + LibJvm = NULL; + } else if (!(GetCreatedJavaVMs = (GETJVM)GetProcAddress((HINSTANCE)LibJvm, + "JNI_GetCreatedJavaVMs"))) { + sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_GetCreatedJavaVMs"); + FreeLibrary((HMODULE)LibJvm); + LibJvm = NULL; +#if defined(_DEBUG) + } else if (!(GetDefaultJavaVMInitArgs = (GETDEF)GetProcAddress((HINSTANCE)LibJvm, + "JNI_GetDefaultJavaVMInitArgs"))) { + sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), + "JNI_GetDefaultJavaVMInitArgs"); + FreeLibrary((HMODULE)LibJvm); + LibJvm = NULL; +#endif // _DEBUG + } // endif LibJvm +#else // !__WIN__ + const char *error = NULL; + + for (ntry = 0; !LibJvm && ntry < 2; ntry++) { + if (!ntry && JvmPath) { + strcat(strcpy(soname, JvmPath), "/libjvm.so"); + ntry = 2; + } else if (!ntry && getenv("JAVA_HOME")) { + // TODO: Replace i386 by a better guess + strcat(strcpy(soname, getenv("JAVA_HOME")), "/jre/lib/i386/client/libjvm.so"); + } else { // Will need LD_LIBRARY_PATH to be set + strcpy(soname, "libjvm.so"); + ntry = 2; + } // endelse + + LibJvm = dlopen(soname, RTLD_LAZY); + } // endfor ntry + + // Load the desired shared library + if (!LibJvm) { + error = dlerror(); + sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error)); + } else if (!(CreateJavaVM = (CRTJVM)dlsym(LibJvm, "JNI_CreateJavaVM"))) { + error = dlerror(); + sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_CreateJavaVM", SVP(error)); + dlclose(LibJvm); + LibJvm = NULL; + } else if (!(GetCreatedJavaVMs = (GETJVM)dlsym(LibJvm, "JNI_GetCreatedJavaVMs"))) { + error = dlerror(); + sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_GetCreatedJavaVMs", SVP(error)); + dlclose(LibJvm); + LibJvm = NULL; +#if defined(_DEBUG) + } else if (!(GetDefaultJavaVMInitArgs = (GETDEF)dlsym(LibJvm, + "JNI_GetDefaultJavaVMInitArgs"))) { + error = dlerror(); + sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_GetDefaultJavaVMInitArgs", SVP(error)); + dlclose(LibJvm); + LibJvm = NULL; +#endif // _DEBUG + } // endif LibJvm +#endif // !__WIN__ + + } // endif LibJvm + + return LibJvm == NULL; +} // end of GetJVM + +/***********************************************************************/ +/* Open: connect to a data source. */ +/***********************************************************************/ +bool JAVAConn::Open(PGLOBAL g) +{ + bool brc = true, err = false; + jboolean jt = (trace > 0); + + // Link or check whether jvm library was linked + if (GetJVM(g)) + return true; + + // Firstly check whether the jvm was already created + JavaVM* jvms[1]; + jsize jsz; + jint rc = GetCreatedJavaVMs(jvms, 1, &jsz); + + if (rc == JNI_OK && jsz == 1) { + // jvm already existing + jvm = jvms[0]; + rc = jvm->AttachCurrentThread((void**)&env, nullptr); + + if (rc != JNI_OK) { + strcpy(g->Message, "Cannot attach jvm to the current thread"); + return true; + } // endif rc + + } else { + /*******************************************************************/ + /* Create a new jvm */ + /*******************************************************************/ + PSTRG jpop = new(g)STRING(g, 512, "-Djava.class.path=."); + char *cp = NULL; + char sep; + +#if defined(__WIN__) + sep = ';'; +#define N 1 + //#define N 2 + //#define N 3 +#else + sep = ':'; +#define N 1 +#endif + + // Add wrappers jar files + AddJars(jpop, sep); + + //================== prepare loading of Java VM ============================ + JavaVMInitArgs vm_args; // Initialization arguments + JavaVMOption* options = new JavaVMOption[N]; // JVM invocation options + + // where to find java .class + if (ClassPath && *ClassPath) { + jpop->Append(sep); + jpop->Append(ClassPath); + } // endif ClassPath + + // Java source will be compiled as a jar file installed in the plugin dir + jpop->Append(sep); + jpop->Append(GetPluginDir()); + jpop->Append("JdbcInterface.jar"); + + // All wrappers are pre-compiled in JavaWrappers.jar in the plugin dir + jpop->Append(sep); + jpop->Append(GetPluginDir()); + jpop->Append("JavaWrappers.jar"); + + if ((cp = getenv("CLASSPATH"))) { + jpop->Append(sep); + jpop->Append(cp); + } // endif cp + + if (trace) { + htrc("ClassPath=%s\n", ClassPath); + htrc("CLASSPATH=%s\n", cp); + htrc("%s\n", jpop->GetStr()); + } // endif trace + + options[0].optionString = jpop->GetStr(); +#if N == 2 + options[1].optionString = "-Xcheck:jni"; +#endif +#if N == 3 + options[1].optionString = "-Xms256M"; + options[2].optionString = "-Xmx512M"; +#endif +#if defined(_DEBUG) + vm_args.version = JNI_VERSION_1_2; // minimum Java version + rc = GetDefaultJavaVMInitArgs(&vm_args); +#else + vm_args.version = JNI_VERSION_1_6; // minimum Java version +#endif // _DEBUG + vm_args.nOptions = N; // number of options + vm_args.options = options; + vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail + + //=============== load and initialize Java VM and JNI interface ============= + rc = CreateJavaVM(&jvm, (void**)&env, &vm_args); // YES !! + delete options; // we then no longer need the initialisation options. + + switch (rc) { + case JNI_OK: + strcpy(g->Message, "VM successfully created"); + brc = false; + break; + case JNI_ERR: + strcpy(g->Message, "Initialising JVM failed: unknown error"); + break; + case JNI_EDETACHED: + strcpy(g->Message, "Thread detached from the VM"); + break; + case JNI_EVERSION: + strcpy(g->Message, "JNI version error"); + break; + case JNI_ENOMEM: + strcpy(g->Message, "Not enough memory"); + break; + case JNI_EEXIST: + strcpy(g->Message, "VM already created"); + break; + case JNI_EINVAL: + strcpy(g->Message, "Invalid arguments"); + break; + default: + sprintf(g->Message, "Unknown return code %d", (int)rc); + break; + } // endswitch rc + + if (trace) + htrc("%s\n", g->Message); + + if (brc) + return true; + + //=============== Display JVM version =============== + jint ver = env->GetVersion(); + printf("JVM Version %d.%d\n", ((ver >> 16) & 0x0f), (ver & 0x0f)); + } // endif rc + + // try to find the java wrapper class + jdi = env->FindClass(m_Wrap); + + if (jdi == nullptr) { + sprintf(g->Message, "ERROR: class %s not found!", m_Wrap); + return true; + } // endif jdi + +#if 0 // Suppressed because it does not make any usable change + if (b && jpath && *jpath) { + // Try to add that path the the jvm class path + jmethodID alp = env->GetStaticMethodID(jdi, "addLibraryPath", + "(Ljava/lang/String;)I"); + + if (alp == nullptr) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } else { + char *msg; + jstring path = env->NewStringUTF(jpath); + rc = env->CallStaticIntMethod(jdi, alp, path); + + if ((msg = Check(rc))) { + strcpy(g->Message, msg); + env->DeleteLocalRef(path); + return RC_FX; + } else switch (rc) { + case JNI_OK: + printf("jpath added\n"); + break; + case JNI_EEXIST: + printf("jpath already exist\n"); + break; + case JNI_ERR: + default: + strcpy(g->Message, "Error adding jpath"); + env->DeleteLocalRef(path); + return RC_FX; + } // endswitch rc + + env->DeleteLocalRef(path); + } // endif alp + + } // endif jpath +#endif // 0 + + // if class found, continue + jmethodID ctor = env->GetMethodID(jdi, "", "(Z)V"); + + if (ctor == nullptr) { + sprintf(g->Message, "ERROR: %s constructor not found!", m_Wrap); + return true; + } else + job = env->NewObject(jdi, ctor, jt); + + if (job == nullptr) { + sprintf(g->Message, "%s class object not constructed!", m_Wrap); + return true; + } // endif job + + // If the object is successfully constructed, + // we can then search for the method we want to call, + // and invoke it for the object: + errid = env->GetMethodID(jdi, "GetErrmsg", "()Ljava/lang/String;"); + + if (env->ExceptionCheck()) { + strcpy(g->Message, "ERROR: method GetErrmsg() not found!"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return true; + } // endif Check + + m_Opened = true; + return false; +} // end of Open + +/***********************************************************************/ +/* Disconnect connection */ +/***********************************************************************/ +void JAVAConn::Close() +{ + jint rc; + + if (m_Connected) { + jmethodID did = nullptr; + + // Could have been detached in case of join + rc = jvm->AttachCurrentThread((void**)&env, nullptr); + + if (gmID(m_G, did, DiscFunc, "()I")) + printf("%s\n", Msg); + else if (Check(env->CallIntMethod(job, did))) + printf("%s: %s\n", DiscFunc, Msg); + + m_Connected = false; + } // endif m_Connected + + if ((rc = jvm->DetachCurrentThread()) != JNI_OK) + printf("DetachCurrentThread: rc=%d\n", (int)rc); + + m_Opened = false; +} // end of Close diff --git a/storage/connect/javaconn.h b/storage/connect/javaconn.h new file mode 100644 index 0000000000000..fba633945f09d --- /dev/null +++ b/storage/connect/javaconn.h @@ -0,0 +1,129 @@ +/***********************************************************************/ +/* JavaConn.h : header file for the Java connection classes. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Included C-definition files required by the interface. */ +/***********************************************************************/ +#include "block.h" +#include "jdbccat.h" + +/***********************************************************************/ +/* Java native interface. */ +/***********************************************************************/ +#include + +/***********************************************************************/ +/* Constants and defines. */ +/***********************************************************************/ +// Miscellaneous sizing info +#define MAX_NUM_OF_MSG 10 // Max number of error messages +//efine MAX_CURRENCY 30 // Max size of Currency($) string +#define MAX_TNAME_LEN 32 // Max size of table names +//efine MAX_FNAME_LEN 256 // Max size of field names +//efine MAX_STRING_INFO 256 // Max size of string from SQLGetInfo +//efine MAX_DNAME_LEN 256 // Max size of Recordset names +//efine MAX_CONNECT_LEN 512 // Max size of Connect string +//efine MAX_CURSOR_NAME 18 // Max size of a cursor name +#define DEFAULT_FIELD_TYPE 0 // TYPE_NULL + +#if !defined(__WIN__) +typedef unsigned char *PUCHAR; +#endif // !__WIN__ + +enum JCATINFO { + CAT_TAB = 1, // JDBC Tables + CAT_COL = 2, // JDBC Columns + CAT_KEY = 3, // JDBC PrimaryKeys +//CAT_STAT = 4, // SQLStatistics +//CAT_SPC = 5 // SQLSpecialColumns +}; + +/***********************************************************************/ +/* This structure is used to control the catalog functions. */ +/***********************************************************************/ +typedef struct tagJCATPARM { + JCATINFO Id; // Id to indicate function + PQRYRES Qrp; // Result set pointer + PCSZ DB; // Database (Schema) + PCSZ Tab; // Table name or pattern + PCSZ Pat; // Table type or column pattern +} JCATPARM; + +typedef jint(JNICALL *CRTJVM) (JavaVM **, void **, void *); +typedef jint(JNICALL *GETJVM) (JavaVM **, jsize, jsize *); +#if defined(_DEBUG) +typedef jint(JNICALL *GETDEF) (void *); +#endif // _DEBUG + +class JAVAConn; + +/***********************************************************************/ +/* JAVAConn class. */ +/***********************************************************************/ +class JAVAConn : public BLOCK { + friend class TDBJMG; +private: + JAVAConn(); // Standard (unused) constructor + +public: + // Constructor + JAVAConn(PGLOBAL g, PCSZ wrapper); + + // Set static variables + static void SetJVM(void) { + LibJvm = NULL; + CreateJavaVM = NULL; + GetCreatedJavaVMs = NULL; +#if defined(_DEBUG) + GetDefaultJavaVMInitArgs = NULL; +#endif // _DEBUG + } // end of SetJVM + + static void ResetJVM(void); + static bool GetJVM(PGLOBAL g); + + // Implementation +public: + //virtual ~JAVAConn(); + bool IsOpen(void) { return m_Opened; } + bool IsConnected(void) { return m_Connected; } + + // Java operations +protected: + bool gmID(PGLOBAL g, jmethodID& mid, const char *name, const char *sig); + bool Check(jint rc = 0); + +public: + virtual void AddJars(PSTRG jpop, char sep) = 0; + virtual bool Connect(PJPARM sop) = 0; + virtual bool Open(PGLOBAL g); + virtual bool MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, + PCSZ filter, bool pipe) = 0; + virtual void Close(void); + +protected: + // Members +#if defined(__WIN__) + static HANDLE LibJvm; // Handle to the jvm DLL +#else // !__WIN__ + static void *LibJvm; // Handle for the jvm shared library +#endif // !__WIN__ + static CRTJVM CreateJavaVM; + static GETJVM GetCreatedJavaVMs; +#if defined(_DEBUG) + static GETDEF GetDefaultJavaVMInitArgs; +#endif // _DEBUG + PGLOBAL m_G; + JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine) + JNIEnv *env; // Pointer to native interface + jclass jdi; // Pointer to the java wrapper class + jobject job; // The java wrapper class object + jmethodID errid; // The GetErrmsg method ID + bool m_Opened; + bool m_Connected; + PCSZ DiscFunc; + PCSZ Msg; + PCSZ m_Wrap; + int m_Rows; +}; // end of JAVAConn class definition diff --git a/storage/connect/jdbccat.h b/storage/connect/jdbccat.h index 0b87df8bb5162..1210aff77d8b2 100644 --- a/storage/connect/jdbccat.h +++ b/storage/connect/jdbccat.h @@ -1,3 +1,6 @@ +#ifndef __JDBCCAT_H +#define __JDBCCAT_H + // Timeout and net wait defaults #define DEFAULT_LOGIN_TIMEOUT -1 // means do not set #define DEFAULT_QUERY_TIMEOUT -1 // means do not set @@ -8,9 +11,9 @@ typedef struct jdbc_parms { PCSZ Url; // Driver URL PCSZ User; // User connect info PCSZ Pwd; // Password connect info -//char *Properties; // Connection property list //int Cto; // Connect timeout //int Qto; // Query timeout + int Version; // Driver version int Fsize; // Fetch size bool Scrollable; // Scrollable cursor } JDBCPARM, *PJPARM; @@ -28,3 +31,5 @@ PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sop); PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp, int maxres, bool info, PJPARM sop); PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info); + +#endif // __JDBCCAT_H diff --git a/storage/connect/jdbconn.cpp b/storage/connect/jdbconn.cpp index f162a7ae64570..dbfd1b0e24d06 100644 --- a/storage/connect/jdbconn.cpp +++ b/storage/connect/jdbconn.cpp @@ -53,38 +53,28 @@ #include "osutil.h" -#if defined(__WIN__) -extern "C" HINSTANCE s_hModule; // Saved module handle -#endif // __WIN__ +//#if defined(__WIN__) +//extern "C" HINSTANCE s_hModule; // Saved module handle +//#endif // __WIN__ #define nullptr 0 TYPCONV GetTypeConv(); int GetConvSize(); -extern char *JvmPath; // The connect_jvm_path global variable value -extern char *ClassPath; // The connect_class_path global variable value +//extern char *JvmPath; // The connect_jvm_path global variable value +//extern char *ClassPath; // The connect_class_path global variable value -char *GetJavaWrapper(void); // The connect_java_wrapper variable value - -/***********************************************************************/ -/* Static JDBConn objects. */ -/***********************************************************************/ -void *JDBConn::LibJvm = NULL; -CRTJVM JDBConn::CreateJavaVM = NULL; -GETJVM JDBConn::GetCreatedJavaVMs = NULL; -#if defined(_DEBUG) -GETDEF JDBConn::GetDefaultJavaVMInitArgs = NULL; -#endif // _DEBUG +//char *GetJavaWrapper(void); // The connect_java_wrapper variable value /***********************************************************************/ /* Some macro's (should be defined elsewhere to be more accessible) */ /***********************************************************************/ -#if defined(_DEBUG) -#define ASSERT(f) assert(f) -#define DEBUG_ONLY(f) (f) -#else // !_DEBUG -#define ASSERT(f) ((void)0) -#define DEBUG_ONLY(f) ((void)0) -#endif // !_DEBUG +//#if defined(_DEBUG) +//#define ASSERT(f) assert(f) +//#define DEBUG_ONLY(f) (f) +//#else // !_DEBUG +//#define ASSERT(f) ((void)0) +//#define DEBUG_ONLY(f) ((void)0) +//#endif // !_DEBUG // To avoid gcc warning int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v); @@ -120,42 +110,47 @@ int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v) int type; switch (stp) { - case -1: // LONGVARCHAR + case -1: // LONGVARCHAR + case -16: // LONGNVARCHAR (unicode) if (GetTypeConv() != TPC_YES) return TYPE_ERROR; else len = MY_MIN(abs(len), GetConvSize()); - case 12: // VARCHAR + case 12: // VARCHAR + case -9: // NVARCHAR (unicode) v = 'V'; - case 1: // CHAR + case 1: // CHAR + case -15: // NCHAR (unicode) + case -8: // ROWID type = TYPE_STRING; break; - case 2: // NUMERIC - case 3: // DECIMAL - case -3: // VARBINARY + case 2: // NUMERIC + case 3: // DECIMAL + case -3: // VARBINARY type = TYPE_DECIM; break; - case 4: // INTEGER + case 4: // INTEGER type = TYPE_INT; break; - case 5: // SMALLINT + case 5: // SMALLINT type = TYPE_SHORT; break; - case -6: // TINYINT - case -7: // BIT + case -6: // TINYINT + case -7: // BIT + case 16: // BOOLEAN type = TYPE_TINY; break; - case 6: // FLOAT - case 7: // REAL - case 8: // DOUBLE + case 6: // FLOAT + case 7: // REAL + case 8: // DOUBLE type = TYPE_DOUBLE; break; - case 93: // TIMESTAMP, DATETIME + case 93: // TIMESTAMP, DATETIME type = TYPE_DATE; len = 19 + ((prec) ? (prec+1) : 0); v = (tn && toupper(tn[0]) == 'T') ? 'S' : 'E'; break; - case 91: // DATE, YEAR + case 91: // DATE, YEAR type = TYPE_DATE; if (!tn || toupper(tn[0]) != 'Y') { @@ -167,17 +162,27 @@ int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v) } // endif len break; - case 92: // TIME + case 92: // TIME type = TYPE_DATE; len = 8 + ((prec) ? (prec+1) : 0); v = 'T'; break; - case -5: // BIGINT + case -5: // BIGINT type = TYPE_BIGINT; break; - case 0: // NULL - case -2: // BINARY - case -4: // LONGVARBINARY + case 0: // NULL + case -2: // BINARY + case -4: // LONGVARBINARY + case 70: // DATALINK + case 2000: // JAVA_OBJECT + case 2001: // DISTINCT + case 2002: // STRUCT + case 2003: // ARRAY + case 2004: // BLOB + case 2005: // CLOB + case 2006: // REF + case 2009: // SQLXML + case 2011: // NCLOB default: type = TYPE_ERROR; len = 0; @@ -224,11 +229,11 @@ PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat, FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM}; unsigned int length[] = {0, 0, 0, 0, 6, 0, 10, 10, 6, 6, 6, 0}; bool b[] = {true, true, false, false, false, false, false, false, true, true, false, true}; - int i, n, ncol = 12; - PCOLRES crp; - PQRYRES qrp; + int i, n, ncol = 12; + PCOLRES crp; + PQRYRES qrp; JCATPARM *cap; - JDBConn *jcp = NULL; + JDBConn *jcp = NULL; /************************************************************************/ /* Do an evaluation of the result size. */ @@ -236,7 +241,7 @@ PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat, if (!info) { jcp = new(g)JDBConn(g, NULL); - if (jcp->Open(sjp) != RC_OK) // openReadOnly + noJDBCdialog + if (jcp->Connect(sjp)) // openReadOnly + noJDBCdialog return NULL; if (table && !strchr(table, '%')) { @@ -322,7 +327,7 @@ PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sjp) PQRYRES qrp; JDBConn *jcp = new(g)JDBConn(g, NULL); - if (jcp->Open(sjp)) + if (jcp->Connect(sjp)) return NULL; if (strstr(src, "%s")) { @@ -364,7 +369,7 @@ PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp, /**********************************************************************/ jcp = new(g)JDBConn(g, NULL); - if (jcp->Open(sjp) == RC_FX) + if (jcp->Connect(sjp)) return NULL; if (!maxres) @@ -508,37 +513,16 @@ PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info) /***********************************************************************/ /* JDBConn construction/destruction. */ /***********************************************************************/ -JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp) +JDBConn::JDBConn(PGLOBAL g, PCSZ wrapper) : JAVAConn(g, wrapper) { - m_G = g; - m_Tdb = tdbp; - jvm = nullptr; // Pointer to the JVM (Java Virtual Machine) - env= nullptr; // Pointer to native interface - jdi = nullptr; // Pointer to the java wrapper class - job = nullptr; // The java wrapper class object xqid = xuid = xid = grs = readid = fetchid = typid = errid = nullptr; prepid = xpid = pcid = nullptr; chrfldid = intfldid = dblfldid = fltfldid = bigfldid = nullptr; objfldid = datfldid = timfldid = tspfldid = nullptr; - //m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT; -//m_QueryTimeout = DEFAULT_QUERY_TIMEOUT; -//m_UpdateOptions = 0; - Msg = NULL; - m_Wrap = (tdbp && tdbp->WrapName) ? tdbp->WrapName : GetJavaWrapper(); - - if (!strchr(m_Wrap, '/')) { - // Add the wrapper package name - char *wn = (char*)PlugSubAlloc(g, NULL, strlen(m_Wrap) + 10); - m_Wrap = strcat(strcpy(wn, "wrappers/"), m_Wrap); - } // endif m_Wrap - -//m_Driver = NULL; -//m_Url = NULL; -//m_User = NULL; -//m_Pwd = NULL; + DiscFunc = "JdbcDisconnect"; m_Ncol = 0; m_Aff = 0; - m_Rows = 0; + //m_Rows = 0; m_Fetch = 0; m_RowsetSize = 0; m_Updatable = true; @@ -548,7 +532,6 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp) m_Opened = false; m_IDQuoteChar[0] = '"'; m_IDQuoteChar[1] = 0; - //*m_ErrMsg = '\0'; } // end of JDBConn //JDBConn::~JDBConn() @@ -558,55 +541,6 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp) // } // end of ~JDBConn -/***********************************************************************/ -/* Screen for errors. */ -/***********************************************************************/ -bool JDBConn::Check(jint rc) -{ - jstring s; - - if (env->ExceptionCheck()) { - jthrowable exc = env->ExceptionOccurred(); - jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object"), - "toString", "()Ljava/lang/String;"); - - if (exc != nullptr && tid != nullptr) { - jstring s = (jstring)env->CallObjectMethod(exc, tid); - const char *utf = env->GetStringUTFChars(s, (jboolean)false); - env->DeleteLocalRef(s); - Msg = PlugDup(m_G, utf); - } else - Msg = "Exception occured"; - - env->ExceptionClear(); - } else if (rc < 0) { - s = (jstring)env->CallObjectMethod(job, errid); - Msg = (char*)env->GetStringUTFChars(s, (jboolean)false); - } else - Msg = NULL; - - return (Msg != NULL); -} // end of Check - -/***********************************************************************/ -/* Get MethodID if not exists yet. */ -/***********************************************************************/ -bool JDBConn::gmID(PGLOBAL g, jmethodID& mid, const char *name, const char *sig) -{ - if (mid == nullptr) { - mid = env->GetMethodID(jdi, name, sig); - - if (Check()) { - strcpy(g->Message, Msg); - return true; - } else - return false; - - } else - return false; - -} // end of gmID - /***********************************************************************/ /* Utility routine. */ /***********************************************************************/ @@ -626,381 +560,52 @@ int JDBConn::GetMaxValue(int n) } // end of GetMaxValue /***********************************************************************/ -/* Reset the JVM library. */ +/* AddJars: add some jar file to the Class path. */ /***********************************************************************/ -void JDBConn::ResetJVM(void) +void JDBConn::AddJars(PSTRG jpop, char sep) { - if (LibJvm) { -#if defined(__WIN__) - FreeLibrary((HMODULE)LibJvm); -#else // !__WIN__ - dlclose(LibJvm); -#endif // !__WIN__ - LibJvm = NULL; - CreateJavaVM = NULL; - GetCreatedJavaVMs = NULL; -#if defined(_DEBUG) - GetDefaultJavaVMInitArgs = NULL; -#endif // _DEBUG - } // endif LibJvm - -} // end of ResetJVM +#if defined(DEVELOPMENT) + jpop->Append( + ";C:/Jconnectors/postgresql-9.4.1208.jar" + ";C:/Oracle/ojdbc7.jar" + ";C:/Apache/commons-dbcp2-2.1.1/commons-dbcp2-2.1.1.jar" + ";C:/Apache/commons-pool2-2.4.2/commons-pool2-2.4.2.jar" + ";C:/Apache/commons-logging-1.2/commons-logging-1.2.jar" + ";C:/Jconnectors/mysql-connector-java-6.0.2-bin.jar" + ";C:/Jconnectors/mariadb-java-client-2.0.1.jar" + ";C:/Jconnectors/sqljdbc42.jar"); +#endif // DEVELOPMENT +} // end of AddJars /***********************************************************************/ -/* Dynamically link the JVM library. */ -/* The purpose of this function is to allow using the CONNECT plugin */ -/* for other table types when the Java JDK is not installed. */ +/* Connect: connect to a data source. */ /***********************************************************************/ -bool JDBConn::GetJVM(PGLOBAL g) -{ - int ntry; - - if (!LibJvm) { - char soname[512]; - -#if defined(__WIN__) - for (ntry = 0; !LibJvm && ntry < 3; ntry++) { - if (!ntry && JvmPath) { - strcat(strcpy(soname, JvmPath), "\\jvm.dll"); - ntry = 3; // No other try - } else if (ntry < 2 && getenv("JAVA_HOME")) { - strcpy(soname, getenv("JAVA_HOME")); - - if (ntry == 1) - strcat(soname, "\\jre"); - - strcat(soname, "\\bin\\client\\jvm.dll"); - } else { - // Try to find it through the registry - char version[16]; - char javaKey[64] = "SOFTWARE\\JavaSoft\\Java Runtime Environment"; - LONG rc; - DWORD BufferSize = 16; - - strcpy(soname, "jvm.dll"); // In case it fails - - if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion", - RRF_RT_ANY, NULL, (PVOID)&version, &BufferSize)) == ERROR_SUCCESS) { - strcat(strcat(javaKey, "\\"), version); - BufferSize = sizeof(soname); - - if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "RuntimeLib", - RRF_RT_ANY, NULL, (PVOID)&soname, &BufferSize)) != ERROR_SUCCESS) - printf("RegGetValue: rc=%ld\n", rc); - - } // endif rc - - ntry = 3; // Try this only once - } // endelse - - // Load the desired shared library - LibJvm = LoadLibrary(soname); - } // endfor ntry - - // Get the needed entries - if (!LibJvm) { - char buf[256]; - DWORD rc = GetLastError(); - - sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, - (LPTSTR)buf, sizeof(buf), NULL); - strcat(strcat(g->Message, ": "), buf); - } else if (!(CreateJavaVM = (CRTJVM)GetProcAddress((HINSTANCE)LibJvm, - "JNI_CreateJavaVM"))) { - sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_CreateJavaVM"); - FreeLibrary((HMODULE)LibJvm); - LibJvm = NULL; - } else if (!(GetCreatedJavaVMs = (GETJVM)GetProcAddress((HINSTANCE)LibJvm, - "JNI_GetCreatedJavaVMs"))) { - sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_GetCreatedJavaVMs"); - FreeLibrary((HMODULE)LibJvm); - LibJvm = NULL; -#if defined(_DEBUG) - } else if (!(GetDefaultJavaVMInitArgs = (GETDEF)GetProcAddress((HINSTANCE)LibJvm, - "JNI_GetDefaultJavaVMInitArgs"))) { - sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), - "JNI_GetDefaultJavaVMInitArgs"); - FreeLibrary((HMODULE)LibJvm); - LibJvm = NULL; -#endif // _DEBUG - } // endif LibJvm -#else // !__WIN__ - const char *error = NULL; - - for (ntry = 0; !LibJvm && ntry < 2; ntry++) { - if (!ntry && JvmPath) { - strcat(strcpy(soname, JvmPath), "/libjvm.so"); - ntry = 2; - } else if (!ntry && getenv("JAVA_HOME")) { - // TODO: Replace i386 by a better guess - strcat(strcpy(soname, getenv("JAVA_HOME")), "/jre/lib/i386/client/libjvm.so"); - } else { // Will need LD_LIBRARY_PATH to be set - strcpy(soname, "libjvm.so"); - ntry = 2; - } // endelse - - LibJvm = dlopen(soname, RTLD_LAZY); - } // endfor ntry - - // Load the desired shared library - if (!LibJvm) { - error = dlerror(); - sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error)); - } else if (!(CreateJavaVM = (CRTJVM)dlsym(LibJvm, "JNI_CreateJavaVM"))) { - error = dlerror(); - sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_CreateJavaVM", SVP(error)); - dlclose(LibJvm); - LibJvm = NULL; - } else if (!(GetCreatedJavaVMs = (GETJVM)dlsym(LibJvm, "JNI_GetCreatedJavaVMs"))) { - error = dlerror(); - sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_GetCreatedJavaVMs", SVP(error)); - dlclose(LibJvm); - LibJvm = NULL; -#if defined(_DEBUG) - } else if (!(GetDefaultJavaVMInitArgs = (GETDEF)dlsym(LibJvm, - "JNI_GetDefaultJavaVMInitArgs"))) { - error = dlerror(); - sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_GetDefaultJavaVMInitArgs", SVP(error)); - dlclose(LibJvm); - LibJvm = NULL; -#endif // _DEBUG - } // endif LibJvm -#endif // !__WIN__ - - } // endif LibJvm - - return LibJvm == NULL; -} // end of GetJVM - -/***********************************************************************/ -/* Open: connect to a data source. */ -/***********************************************************************/ -int JDBConn::Open(PJPARM sop) +bool JDBConn::Connect(PJPARM sop) { int irc = RC_FX; bool err = false; + jint rc; jboolean jt = (trace > 0); PGLOBAL& g = m_G; - // Link or check whether jvm library was linked - if (GetJVM(g)) - return RC_FX; - - // Firstly check whether the jvm was already created - JavaVM* jvms[1]; - jsize jsz; - jint rc = GetCreatedJavaVMs(jvms, 1, &jsz); - - if (rc == JNI_OK && jsz == 1) { - // jvm already existing - jvm = jvms[0]; - rc = jvm->AttachCurrentThread((void**)&env, nullptr); - - if (rc != JNI_OK) { - strcpy(g->Message, "Cannot attach jvm to the current thread"); - return RC_FX; - } // endif rc - - } else { - /*******************************************************************/ - /* Create a new jvm */ - /*******************************************************************/ - PSTRG jpop = new(g)STRING(g, 512, "-Djava.class.path=."); - char *cp = NULL; - char sep; - -#if defined(__WIN__) - sep = ';'; -#define N 1 -//#define N 2 -//#define N 3 -#else - sep = ':'; -#define N 1 -#endif - - // Java source will be compiled as a jar file installed in the plugin dir - jpop->Append(sep); - jpop->Append(GetPluginDir()); - jpop->Append("JdbcInterface.jar"); - - // All wrappers are pre-compiled in JavaWrappers.jar in the plugin dir - jpop->Append(sep); - jpop->Append(GetPluginDir()); - jpop->Append("JavaWrappers.jar"); - - //================== prepare loading of Java VM ============================ - JavaVMInitArgs vm_args; // Initialization arguments - JavaVMOption* options = new JavaVMOption[N]; // JVM invocation options - - // where to find java .class - if (ClassPath && *ClassPath) { - jpop->Append(sep); - jpop->Append(ClassPath); - } // endif ClassPath - - if ((cp = getenv("CLASSPATH"))) { - jpop->Append(sep); - jpop->Append(cp); - } // endif cp - - if (trace) { - htrc("ClassPath=%s\n", ClassPath); - htrc("CLASSPATH=%s\n", cp); - htrc("%s\n", jpop->GetStr()); - } // endif trace - - options[0].optionString = jpop->GetStr(); -#if N == 2 - options[1].optionString = "-Xcheck:jni"; -#endif -#if N == 3 - options[1].optionString = "-Xms256M"; - options[2].optionString = "-Xmx512M"; -#endif -#if defined(_DEBUG) - vm_args.version = JNI_VERSION_1_2; // minimum Java version - rc = GetDefaultJavaVMInitArgs(&vm_args); -#else - vm_args.version = JNI_VERSION_1_6; // minimum Java version -#endif // _DEBUG - vm_args.nOptions = N; // number of options - vm_args.options = options; - vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail - - //=============== load and initialize Java VM and JNI interface ============= - rc = CreateJavaVM(&jvm, (void**)&env, &vm_args); // YES !! - delete options; // we then no longer need the initialisation options. - - switch (rc) { - case JNI_OK: - strcpy(g->Message, "VM successfully created"); - irc = RC_OK; - break; - case JNI_ERR: - strcpy(g->Message, "Initialising JVM failed: unknown error"); - break; - case JNI_EDETACHED: - strcpy(g->Message, "Thread detached from the VM"); - break; - case JNI_EVERSION: - strcpy(g->Message, "JNI version error"); - break; - case JNI_ENOMEM: - strcpy(g->Message, "Not enough memory"); - break; - case JNI_EEXIST: - strcpy(g->Message, "VM already created"); - break; - case JNI_EINVAL: - strcpy(g->Message, "Invalid arguments"); - break; - default: - sprintf(g->Message, "Unknown return code %d", (int)rc); - break; - } // endswitch rc - - if (trace) - htrc("%s\n", g->Message); - - if (irc != RC_OK) - return irc; - - //=============== Display JVM version =============== - jint ver = env->GetVersion(); - printf("JVM Version %d.%d\n", ((ver>>16)&0x0f), (ver&0x0f)); - } // endif rc - - // try to find the java wrapper class - jdi = env->FindClass(m_Wrap); - - if (jdi == nullptr) { - sprintf(g->Message, "ERROR: class %s not found!", m_Wrap); - return RC_FX; - } // endif jdi - -#if 0 // Suppressed because it does not make any usable change - if (b && jpath && *jpath) { - // Try to add that path the the jvm class path - jmethodID alp = env->GetStaticMethodID(jdi, "addLibraryPath", - "(Ljava/lang/String;)I"); - - if (alp == nullptr) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } else { - char *msg; - jstring path = env->NewStringUTF(jpath); - rc = env->CallStaticIntMethod(jdi, alp, path); - - if ((msg = Check(rc))) { - strcpy(g->Message, msg); - env->DeleteLocalRef(path); - return RC_FX; - } else switch (rc) { - case JNI_OK: - printf("jpath added\n"); - break; - case JNI_EEXIST: - printf("jpath already exist\n"); - break; - case JNI_ERR: - default: - strcpy(g->Message, "Error adding jpath"); - env->DeleteLocalRef(path); - return RC_FX; - } // endswitch rc - - env->DeleteLocalRef(path); - } // endif alp - - } // endif jpath -#endif // 0 - - // if class found, continue - jmethodID ctor = env->GetMethodID(jdi, "", "(Z)V"); - - if (ctor == nullptr) { - sprintf(g->Message, "ERROR: %s constructor not found!", m_Wrap); - return RC_FX; - } else - job = env->NewObject(jdi, ctor, jt); - - // If the object is successfully constructed, - // we can then search for the method we want to call, - // and invoke it for the object: - if (job == nullptr) { - sprintf(g->Message, "%s class object not constructed!", m_Wrap); - return RC_FX; - } // endif job - - errid = env->GetMethodID(jdi, "GetErrmsg", "()Ljava/lang/String;"); - - if (env->ExceptionCheck()) { - strcpy(g->Message, "ERROR: method GetErrmsg() not found!"); - env->ExceptionDescribe(); - env->ExceptionClear(); - return RC_FX; - } // endif Check + /*******************************************************************/ + /* Create or attach a JVM. */ + /*******************************************************************/ + if (Open(g)) + return true; if (!sop) // DRIVER catalog table - return RC_OK; + return false; jmethodID cid = nullptr; if (gmID(g, cid, "JdbcConnect", "([Ljava/lang/String;IZ)I")) - return RC_FX; + return true; // Build the java string array jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4 env->FindClass("java/lang/String"), NULL); // Strings -//m_Driver = sop->Driver; -//m_Url = sop->Url; -//m_User = sop->User; -//m_Pwd = sop->Pwd; m_Scrollable = sop->Scrollable; m_RowsetSize = sop->Fsize; //m_LoginTimeout = sop->Cto; @@ -1020,9 +625,6 @@ int JDBConn::Open(PJPARM sop) if (sop->Pwd) env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd)); -//if (sop->Properties) -// env->SetObjectArrayElement(parms, 4, env->NewStringUTF(sop->Properties)); - // call method rc = env->CallIntMethod(job, cid, parms, m_RowsetSize, m_Scrollable); err = Check(rc); @@ -1030,7 +632,7 @@ int JDBConn::Open(PJPARM sop) if (err) { sprintf(g->Message, "Connecting: %s rc=%d", Msg, (int)rc); - return RC_FX; + return true; } // endif Msg jmethodID qcid = nullptr; @@ -1049,17 +651,18 @@ int JDBConn::Open(PJPARM sop) } // endif qcid if (gmID(g, typid, "ColumnType", "(ILjava/lang/String;)I")) - return RC_FX; + return true; else m_Opened = true; - return RC_OK; -} // end of Open + return false; +} // end of Connect + /***********************************************************************/ /* Execute an SQL command. */ /***********************************************************************/ -int JDBConn::ExecSQLcommand(PCSZ sql) +int JDBConn::ExecuteCommand(PCSZ sql) { int rc; jint n; @@ -1095,7 +698,7 @@ int JDBConn::ExecSQLcommand(PCSZ sql) } // endif ncol return rc; -} // end of ExecSQLcommand +} // end of ExecuteCommand /***********************************************************************/ /* Fetch next row. */ @@ -1155,38 +758,12 @@ int JDBConn::Rewind(PCSZ sql) jboolean b = env->CallBooleanMethod(job, fetchid, 0); rbuf = m_Rows; - } else if (ExecSQLcommand(sql) != RC_FX) + } else if (ExecuteCommand(sql) != RC_FX) rbuf = 0; return rbuf; } // end of Rewind -/***********************************************************************/ -/* Disconnect connection */ -/***********************************************************************/ -void JDBConn::Close() -{ - if (m_Opened) { - jint rc; - jmethodID did = nullptr; - - // Could have been detached in case of join - rc = jvm->AttachCurrentThread((void**)&env, nullptr); - - if (gmID(m_G, did, "JdbcDisconnect", "()I")) - printf("%s\n", Msg); - else if (Check(env->CallIntMethod(job, did))) - printf("jdbcDisconnect: %s\n", Msg); - - if ((rc = jvm->DetachCurrentThread()) != JNI_OK) - printf("DetachCurrentThread: rc=%d\n", (int)rc); - - //rc = jvm->DestroyJavaVM(); - m_Opened = false; - } // endif m_Opened - -} // end of Close - /***********************************************************************/ /* Retrieve and set the column value from the result set. */ /***********************************************************************/ @@ -1200,7 +777,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) if (rank == 0) if (!name || (jn = env->NewStringUTF(name)) == nullptr) { sprintf(g->Message, "Fail to allocate jstring %s", SVP(name)); - throw TYPE_AM_JDBC; + throw (int)TYPE_AM_JDBC; } // endif name // Returns 666 is case of error @@ -1208,7 +785,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) if (Check((ctyp == 666) ? -1 : 1)) { sprintf(g->Message, "Getting ctyp: %s", Msg); - throw TYPE_AM_JDBC; + throw (int)TYPE_AM_JDBC; } // endif Check if (val->GetNullable()) @@ -1225,9 +802,12 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) switch (ctyp) { case 12: // VARCHAR + case -9: // NVARCHAR case -1: // LONGVARCHAR case 1: // CHAR - case 3: // DECIMAL + case -15: // NCHAR + case 3: // DECIMAL + case -8: // ROWID if (jb && ctyp != 3) cn = (jstring)jb; else if (!gmID(g, chrfldid, "StringField", "(ILjava/lang/String;)Ljava/lang/String;")) @@ -1245,6 +825,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) case 4: // INTEGER case 5: // SMALLINT case -6: // TINYINT + case 16: // BOOLEAN case -7: // BIT if (!gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I")) val->SetValue((int)env->CallIntMethod(job, intfldid, rank, jn)); @@ -1315,7 +896,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) env->DeleteLocalRef(jn); sprintf(g->Message, "SetColumnValue: %s rank=%d ctyp=%d", Msg, rank, (int)ctyp); - throw TYPE_AM_JDBC; + throw (int)TYPE_AM_JDBC; } // endif Check if (rank == 0) @@ -1405,7 +986,7 @@ int JDBConn::ExecuteUpdate(PCSZ sql) /***********************************************************************/ /* Get the number of lines of the result set. */ /***********************************************************************/ -int JDBConn::GetResultSize(PCSZ sql, JDBCCOL *colp) +int JDBConn::GetResultSize(PCSZ sql, PCOL colp) { int rc, n = 0; @@ -1546,53 +1127,6 @@ bool JDBConn::SetParam(JDBCCOL *colp) return rc; } // end of SetParam -#if 0 - /***********************************************************************/ - /* Get the list of Data Sources and set it in qrp. */ - /***********************************************************************/ - bool JDBConn::GetDataSources(PQRYRES qrp) - { - bool rv = false; - UCHAR *dsn, *des; - UWORD dir = SQL_FETCH_FIRST; - SWORD n1, n2, p1, p2; - PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next; - RETCODE rc; - - n1 = crp1->Clen; - n2 = crp2->Clen; - - try { - rc = SQLAllocEnv(&m_henv); - - if (!Check(rc)) - ThrowDJX(rc, "SQLAllocEnv"); // Fatal - - for (int i = 0; i < qrp->Maxres; i++) { - dsn = (UCHAR*)crp1->Kdata->GetValPtr(i); - des = (UCHAR*)crp2->Kdata->GetValPtr(i); - rc = SQLDataSources(m_henv, dir, dsn, n1, &p1, des, n2, &p2); - - if (rc == SQL_NO_DATA_FOUND) - break; - else if (!Check(rc)) - ThrowDJX(rc, "SQLDataSources"); - - qrp->Nblin++; - dir = SQL_FETCH_NEXT; - } // endfor i - - } - catch (DJX *x) { - sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0)); - rv = true; - } // end try/catch - - Close(); - return rv; - } // end of GetDataSources -#endif // 0 - /***********************************************************************/ /* Get the list of Drivers and set it in qrp. */ /***********************************************************************/ @@ -1658,7 +1192,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) jint *n = nullptr; jstring label; jmethodID colid = nullptr; - int rc = ExecSQLcommand(src); + int rc = ExecuteCommand(src); if (rc == RC_NF) { strcpy(g->Message, "Srcdef is not returning a result set"); @@ -1943,6 +1477,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) } // endif len pval[n] = AllocateValue(g, crp->Type, len); + pval[n]->SetNullable(true); if (crp->Type == TYPE_STRING) { pbuf[n] = (char*)PlugSubAlloc(g, NULL, len); @@ -1982,10 +1517,10 @@ bool JDBConn::SetParam(JDBCCOL *colp) /***********************************************************************/ /* Allocate a CONNECT result structure from the JDBC result. */ /***********************************************************************/ - PQRYRES JDBConn::AllocateResult(PGLOBAL g) + PQRYRES JDBConn::AllocateResult(PGLOBAL g, PTDB tdbp) { bool uns; - PJDBCCOL colp; + PCOL colp; PCOLRES *pcrp, crp; PQRYRES qrp; @@ -2010,8 +1545,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) qrp->Nblin = 0; qrp->Cursor = 0; - for (colp = (PJDBCCOL)m_Tdb->Columns; colp; - colp = (PJDBCCOL)colp->GetNext()) + for (colp = tdbp->GetColumns(); colp; colp = colp->GetNext()) if (!colp->IsSpecial()) { *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); crp = *pcrp; @@ -2039,10 +1573,9 @@ bool JDBConn::SetParam(JDBCCOL *colp) memset(crp->Nulls, ' ', m_Rows); } // endelse Nullable - colp->SetCrp(crp); + ((EXTCOL*)colp)->SetCrp(crp); } // endif colp *pcrp = NULL; - //qrp->Nblin = n; return qrp; } // end of AllocateResult diff --git a/storage/connect/jdbconn.h b/storage/connect/jdbconn.h index 73271c8f5be9a..56f318d238b54 100644 --- a/storage/connect/jdbconn.h +++ b/storage/connect/jdbconn.h @@ -1,61 +1,7 @@ /***********************************************************************/ /* JDBConn.h : header file for the JDBC connection classes. */ /***********************************************************************/ -//nclude /* Windows include file */ -//nclude /* Message crackers */ - -/***********************************************************************/ -/* Included C-definition files required by the interface. */ -/***********************************************************************/ -#include "block.h" - -/***********************************************************************/ -/* JDBC interface. */ -/***********************************************************************/ -#include - -/***********************************************************************/ -/* Constants and defines. */ -/***********************************************************************/ -// Miscellaneous sizing info -#define MAX_NUM_OF_MSG 10 // Max number of error messages -//efine MAX_CURRENCY 30 // Max size of Currency($) string -#define MAX_TNAME_LEN 32 // Max size of table names -//efine MAX_FNAME_LEN 256 // Max size of field names -//efine MAX_STRING_INFO 256 // Max size of string from SQLGetInfo -//efine MAX_DNAME_LEN 256 // Max size of Recordset names -//efine MAX_CONNECT_LEN 512 // Max size of Connect string -//efine MAX_CURSOR_NAME 18 // Max size of a cursor name -#define DEFAULT_FIELD_TYPE 0 // TYPE_NULL - -#if !defined(__WIN__) -typedef unsigned char *PUCHAR; -#endif // !__WIN__ - -enum JCATINFO { - CAT_TAB = 1, // JDBC Tables - CAT_COL = 2, // JDBC Columns - CAT_KEY = 3, // JDBC PrimaryKeys -//CAT_STAT = 4, // SQLStatistics -//CAT_SPC = 5 // SQLSpecialColumns -}; - -/***********************************************************************/ -/* This structure is used to control the catalog functions. */ -/***********************************************************************/ -typedef struct tagJCATPARM { - JCATINFO Id; // Id to indicate function - PQRYRES Qrp; // Result set pointer - PCSZ DB; // Database (Schema) - PCSZ Tab; // Table name or pattern - PCSZ Pat; // Table type or column pattern -} JCATPARM; - -typedef jint(JNICALL *CRTJVM) (JavaVM **, void **, void *); -typedef jint(JNICALL *GETJVM) (JavaVM **, jsize, jsize *); -#if defined(_DEBUG) -typedef jint(JNICALL *GETDEF) (void *); -#endif // _DEBUG +#include "javaconn.h" // JDBC connection to a data source class TDBJDBC; @@ -66,7 +12,7 @@ class TDBXJDC; /***********************************************************************/ /* JDBConn class. */ /***********************************************************************/ -class JDBConn : public BLOCK { +class JDBConn : public JAVAConn { friend class TDBJDBC; friend class TDBXJDC; //friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&); @@ -74,118 +20,80 @@ class JDBConn : public BLOCK { JDBConn(); // Standard (unused) constructor public: - JDBConn(PGLOBAL g, TDBJDBC *tdbp); + // Constructor + JDBConn(PGLOBAL g, PCSZ wrapper); - int Open(PJPARM sop); - int Rewind(PCSZ sql); - void Close(void); - PQRYRES AllocateResult(PGLOBAL g); + virtual void AddJars(PSTRG jpop, char sep); + PQRYRES AllocateResult(PGLOBAL g, PTDB tdbp); // Attributes public: - char *GetQuoteChar(void) { return m_IDQuoteChar; } - // Database successfully opened? - bool IsOpen(void) { return m_Opened; } -//PSZ GetStringInfo(ushort infotype); - int GetMaxValue(int infotype); -//PSZ GetConnect(void) { return m_Connect; } + char *GetQuoteChar(void) { return m_IDQuoteChar; } + virtual int GetMaxValue(int infotype); public: // Operations - //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(PCSZ sql, JDBCCOL *colp); - int ExecuteQuery(PCSZ sql); - int ExecuteUpdate(PCSZ sql); - int Fetch(int pos = 0); + virtual bool Connect(PJPARM sop); + virtual bool MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, + PCSZ filter, bool pipe) {return true;} + virtual int GetResultSize(PCSZ sql, PCOL colp); + virtual int ExecuteCommand(PCSZ sql); + virtual int ExecuteQuery(PCSZ sql); + virtual int ExecuteUpdate(PCSZ sql); + virtual int Fetch(int pos = 0); + virtual void SetColumnValue(int rank, PSZ name, PVAL val); + + // Jdbc operations bool PrepareSQL(PCSZ sql); - int ExecuteSQL(void); + int ExecuteSQL(void); // Prepared statement bool SetParam(JDBCCOL *colp); - int ExecSQLcommand(PCSZ sql); - void SetColumnValue(int rank, PSZ name, PVAL val); int GetCatInfo(JCATPARM *cap); - //bool GetDataSources(PQRYRES qrp); bool GetDrivers(PQRYRES qrp); PQRYRES GetMetaData(PGLOBAL g, PCSZ src); - -public: - // Set static variables - static void SetJVM(void) { - LibJvm = NULL; - CreateJavaVM = NULL; - GetCreatedJavaVMs = NULL; -#if defined(_DEBUG) - GetDefaultJavaVMInitArgs = NULL; -#endif // _DEBUG - } // end of SetJVM - - static void ResetJVM(void); - static bool GetJVM(PGLOBAL g); + int Rewind(PCSZ sql); // Implementation public: //virtual ~JDBConn(); - // JDBC operations -protected: - bool gmID(PGLOBAL g, jmethodID& mid, const char *name, const char *sig); - bool Check(jint rc = 0); -//void ThrowDJX(int rc, PSZ msg/*, HSTMT hstmt = SQL_NULL_HSTMT*/); -//void ThrowDJX(PSZ msg); -//void Free(void); - protected: // Members -#if defined(__WIN__) - static HANDLE LibJvm; // Handle to the jvm DLL -#else // !__WIN__ - static void *LibJvm; // Handle for the jvm shared library -#endif // !__WIN__ - static CRTJVM CreateJavaVM; - static GETJVM GetCreatedJavaVMs; -#if defined(_DEBUG) - static GETDEF GetDefaultJavaVMInitArgs; -#endif // _DEBUG - PGLOBAL m_G; - TDBJDBC *m_Tdb; - JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine) - JNIEnv *env; // Pointer to native interface - jclass jdi; // Pointer to the java wrapper class - jobject job; // The java wrapper class object - jmethodID xqid; // The ExecuteQuery method ID - jmethodID xuid; // The ExecuteUpdate method ID - jmethodID xid; // The Execute method ID - jmethodID grs; // The GetResult method ID - jmethodID readid; // The ReadNext method ID - jmethodID fetchid; // The Fetch method ID - jmethodID typid; // The ColumnType method ID - jmethodID prepid; // The CreatePrepStmt method ID - jmethodID xpid; // The ExecutePrep method ID - jmethodID pcid; // The ClosePrepStmt method ID - jmethodID errid; // The GetErrmsg method ID - jmethodID objfldid; // The ObjectField method ID - jmethodID chrfldid; // The StringField method ID - jmethodID intfldid; // The IntField method ID - jmethodID dblfldid; // The DoubleField method ID - jmethodID fltfldid; // The FloatField method ID - jmethodID datfldid; // The DateField method ID - jmethodID timfldid; // The TimeField method ID - jmethodID tspfldid; // The TimestampField method ID - jmethodID bigfldid; // The BigintField method ID - PCSZ Msg; - char *m_Wrap; +#if 0 + JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine) + JNIEnv *env; // Pointer to native interface + jclass jdi; // Pointer to the java wrapper class + jobject job; // The java wrapper class object + jmethodID errid; // The GetErrmsg method ID +#endif // 0 + jmethodID xqid; // The ExecuteQuery method ID + jmethodID xuid; // The ExecuteUpdate method ID + jmethodID xid; // The Execute method ID + jmethodID grs; // The GetResult method ID + jmethodID readid; // The ReadNext method ID + jmethodID fetchid; // The Fetch method ID + jmethodID typid; // The ColumnType method ID + jmethodID prepid; // The CreatePrepStmt method ID + jmethodID xpid; // The ExecutePrep method ID + jmethodID pcid; // The ClosePrepStmt method ID + jmethodID objfldid; // The ObjectField method ID + jmethodID chrfldid; // The StringField method ID + jmethodID intfldid; // The IntField method ID + jmethodID dblfldid; // The DoubleField method ID + jmethodID fltfldid; // The FloatField method ID + jmethodID datfldid; // The DateField method ID + jmethodID timfldid; // The TimeField method ID + jmethodID tspfldid; // The TimestampField method ID + jmethodID bigfldid; // The BigintField method ID +// PCSZ Msg; +// PCSZ m_Wrap; char m_IDQuoteChar[2]; PCSZ m_Pwd; int m_Ncol; int m_Aff; - int m_Rows; int m_Fetch; int m_RowsetSize; jboolean m_Updatable; jboolean m_Transact; jboolean m_Scrollable; - bool m_Opened; bool m_Full; }; // end of JDBConn class definition diff --git a/storage/connect/jmgfam.cpp b/storage/connect/jmgfam.cpp new file mode 100644 index 0000000000000..c7115cdd72024 --- /dev/null +++ b/storage/connect/jmgfam.cpp @@ -0,0 +1,357 @@ +/************ JMONGO FAM C++ Program Source Code File (.CPP) ***********/ +/* PROGRAM NAME: jmgfam.cpp */ +/* ------------- */ +/* Version 1.0 */ +/* */ +/* COPYRIGHT: */ +/* ---------- */ +/* (C) Copyright to the author Olivier BERTRAND 20017 */ +/* */ +/* WHAT THIS PROGRAM DOES: */ +/* ----------------------- */ +/* This program are the Java MongoDB access method classes. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the System header files. */ +/***********************************************************************/ +#include "my_global.h" +#if defined(__WIN__) +//#include +//#include +//#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include +#else // !__WIN__ +#if defined(UNIX) || defined(UNIV_LINUX) +//#include +#include +//#if !defined(sun) // Sun has the ftruncate fnc. +//#define USETEMP // Force copy mode for DELETE +//#endif // !sun +#else // !UNIX +//#include +#endif // !UNIX +//#include +#endif // !__WIN__ + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/* filamtxt.h is header containing the file AM classes declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "reldef.h" +#include "filamtxt.h" +#include "tabdos.h" +#include "tabjson.h" +#include "jmgfam.h" + +#if defined(UNIX) || defined(UNIV_LINUX) +#include "osutil.h" +//#define _fileno fileno +//#define _O_RDONLY O_RDONLY +#endif + +/* --------------------------- Class JMGFAM -------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +JMGFAM::JMGFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL) +{ + Jcp = NULL; + //Client = NULL; + //Database = NULL; + //Collection = NULL; + //Cursor = NULL; + //Query = NULL; + //Opts = NULL; + Ops.Driver = tdp->Schema; + Ops.Url = tdp->Uri; + Ops.User = NULL; + Ops.Pwd = NULL; + Ops.Scrollable = false; + Ops.Fsize = 0; + Ops.Version = tdp->Version; + To_Fbt = NULL; + Mode = MODE_ANY; + Uristr = tdp->Uri; + Db_name = tdp->Schema; + Coll_name = tdp->Collname; + Options = tdp->Options; + Filter = tdp->Filter; + Wrapname = tdp->Wrapname; + Done = false; + Pipe = tdp->Pipe; + Version = tdp->Version; + Lrecl = tdp->Lrecl + tdp->Ending; + Curpos = 0; +} // end of JMGFAM standard constructor + +JMGFAM::JMGFAM(PJMGFAM tdfp) : DOSFAM(tdfp) +{ + //Client = tdfp->Client; + //Database = NULL; + //Collection = tdfp->Collection; + //Cursor = tdfp->Cursor; + //Query = tdfp->Query; + //Opts = tdfp->Opts; + Ops = tdfp->Ops; + To_Fbt = tdfp->To_Fbt; + Mode = tdfp->Mode; + Uristr = tdfp->Uristr; + Db_name = tdfp->Db_name; + Coll_name = tdfp->Coll_name; + Options = tdfp->Options; + Filter = NULL; + Wrapname = tdfp->Wrapname; + Done = tdfp->Done; + Pipe = tdfp->Pipe; + Version = tdfp->Version; +} // end of JMGFAM copy constructor + +/***********************************************************************/ +/* Reset: reset position values at the beginning of file. */ +/***********************************************************************/ +void JMGFAM::Reset(void) +{ + TXTFAM::Reset(); + Fpos = Tpos = Spos = 0; +} // end of Reset + +/***********************************************************************/ +/* MGO GetFileLength: returns file size in number of bytes. */ +/***********************************************************************/ +int JMGFAM::GetFileLength(PGLOBAL g) +{ + return 0; +} // end of GetFileLength + +/***********************************************************************/ +/* Cardinality: returns table cardinality in number of rows. */ +/* This function can be called with a null argument to test the */ +/* availability of Cardinality implementation (1 yes, 0 no). */ +/***********************************************************************/ +int JMGFAM::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + + return (!Init(g)) ? Jcp->CollSize(g) : 0; +} // end of Cardinality + +/***********************************************************************/ +/* Note: This function is not really implemented yet. */ +/***********************************************************************/ +int JMGFAM::MaxBlkSize(PGLOBAL, int s) +{ + return s; +} // end of MaxBlkSize + +/***********************************************************************/ +/* Init: initialize MongoDB processing. */ +/***********************************************************************/ +bool JMGFAM::Init(PGLOBAL g) +{ + if (Done) + return false; + + /*********************************************************************/ + /* Open an JDBC connection for this table. */ + /* Note: this may not be the proper way to do. Perhaps it is better */ + /* to test whether a connection is already open for this datasource */ + /* and if so to allocate just a new result set. But this only for */ + /* drivers allowing concurency in getting results ??? */ + /*********************************************************************/ + if (!Jcp) + Jcp = new(g) JMgoConn(g, Coll_name, Wrapname); + else if (Jcp->IsOpen()) + Jcp->Close(); + + if (Jcp->Connect(&Ops)) + return true; + + Done = true; + return false; +} // end of Init + +/***********************************************************************/ +/* OpenTableFile: Open a MongoDB table. */ +/***********************************************************************/ +bool JMGFAM::OpenTableFile(PGLOBAL g) +{ + Mode = Tdbp->GetMode(); + + if (Pipe && Mode != MODE_READ) { + strcpy(g->Message, "Pipeline tables are read only"); + return true; + } // endif Pipe + + if (Init(g)) + return true; + + if (Jcp->GetMethodId(g, Mode)) + return true; + + if (Mode == MODE_DELETE && !Tdbp->GetNext()) { + // Delete all documents + if (!Jcp->MakeCursor(g, Tdbp, "all", Filter, false)) + if (Jcp->DocDelete(g, true) == RC_OK) + return false; + + return true; + } // endif Mode + + if (Mode == MODE_INSERT) + Jcp->MakeColumnGroups(g, Tdbp); + + if (Mode != MODE_UPDATE) + return Jcp->MakeCursor(g, Tdbp, Options, Filter, Pipe); + + return false; + } // end of OpenTableFile + +/***********************************************************************/ +/* GetRowID: return the RowID of last read record. */ +/***********************************************************************/ +int JMGFAM::GetRowID(void) +{ + return Rows; +} // end of GetRowID + +/***********************************************************************/ +/* GetPos: return the position of last read record. */ +/***********************************************************************/ +int JMGFAM::GetPos(void) +{ + return Fpos; +} // end of GetPos + +/***********************************************************************/ +/* GetNextPos: return the position of next record. */ +/***********************************************************************/ +int JMGFAM::GetNextPos(void) +{ + return Fpos; // TODO +} // end of GetNextPos + +/***********************************************************************/ +/* SetPos: Replace the table at the specified position. */ +/***********************************************************************/ +bool JMGFAM::SetPos(PGLOBAL g, int pos) +{ + Fpos = pos; + Placed = true; + return false; +} // end of SetPos + +/***********************************************************************/ +/* Record file position in case of UPDATE or DELETE. */ +/***********************************************************************/ +bool JMGFAM::RecordPos(PGLOBAL g) +{ + strcpy(g->Message, "JMGFAM::RecordPos NIY"); + return true; +} // end of RecordPos + +/***********************************************************************/ +/* Initialize Fpos and the current position for indexed DELETE. */ +/***********************************************************************/ +int JMGFAM::InitDelete(PGLOBAL g, int fpos, int spos) +{ + strcpy(g->Message, "JMGFAM::InitDelete NIY"); + return RC_FX; +} // end of InitDelete + +/***********************************************************************/ +/* Skip one record in file. */ +/***********************************************************************/ +int JMGFAM::SkipRecord(PGLOBAL g, bool header) +{ + return RC_OK; // Dummy +} // end of SkipRecord + +/***********************************************************************/ +/* ReadBuffer: Get next document from a collection. */ +/***********************************************************************/ +int JMGFAM::ReadBuffer(PGLOBAL g) +{ + int rc = RC_FX; + + if (!Curpos && Mode == MODE_UPDATE) + if (Jcp->MakeCursor(g, Tdbp, Options, Filter, Pipe)) + return RC_FX; + + if (++CurNum >= Rbuf) { + Rbuf = Jcp->Fetch(); + Curpos++; + CurNum = 0; + } // endif CurNum + + if (Rbuf > 0) { + PSZ str = Jcp->GetDocument(); + + if (str) { + if (trace == 1) + htrc("%s\n", str); + + strncpy(Tdbp->GetLine(), str, Lrecl); + rc = RC_OK; + } else + strcpy(g->Message, "Null document"); + + } else if (!Rbuf) + rc = RC_EF; + + return rc; +} // end of ReadBuffer + +/***********************************************************************/ +/* WriteBuffer: File write routine for MGO access method. */ +/***********************************************************************/ +int JMGFAM::WriteBuffer(PGLOBAL g) +{ + int rc = RC_OK; + + if (Mode == MODE_INSERT) { + rc = Jcp->DocWrite(g); + } else if (Mode == MODE_DELETE) { + rc = Jcp->DocDelete(g, false); + } else if (Mode == MODE_UPDATE) { + rc = Jcp->DocUpdate(g, Tdbp); + } // endif Mode + + return rc; +} // end of WriteBuffer + +/***********************************************************************/ +/* Data Base delete line routine for MGO and BLK access methods. */ +/***********************************************************************/ +int JMGFAM::DeleteRecords(PGLOBAL g, int irc) +{ + return (irc == RC_OK) ? WriteBuffer(g) : RC_OK; +} // end of DeleteRecords + +/***********************************************************************/ +/* Table file close routine for MGO access method. */ +/***********************************************************************/ +void JMGFAM::CloseTableFile(PGLOBAL g, bool) +{ + Jcp->Close(); + Done = false; +} // end of CloseTableFile + +/***********************************************************************/ +/* Rewind routine for MGO access method. */ +/***********************************************************************/ +void JMGFAM::Rewind(void) +{ + Jcp->Rewind(); +} // end of Rewind + diff --git a/storage/connect/jmgfam.h b/storage/connect/jmgfam.h new file mode 100644 index 0000000000000..5c80d99383386 --- /dev/null +++ b/storage/connect/jmgfam.h @@ -0,0 +1,79 @@ +/************** MongoFam H Declares Source Code File (.H) **************/ +/* Name: jmgfam.h Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the JAVA MongoDB access method classes declares */ +/***********************************************************************/ +#pragma once + +/***********************************************************************/ +/* Include MongoDB library header files. */ +/***********************************************************************/ +#include "block.h" +//#include "mongo.h" +#include "jmgoconn.h" + +typedef class JMGFAM *PJMGFAM; +typedef class MGODEF *PMGODEF; + +/***********************************************************************/ +/* This is the Java MongoDB Access Method class declaration. */ +/***********************************************************************/ +class DllExport JMGFAM : public DOSFAM { + friend void mongo_init(bool); +public: + // Constructor + JMGFAM(PJDEF tdp); + JMGFAM(PJMGFAM txfp); + + // Implementation + virtual AMT GetAmType(void) { return TYPE_AM_MGO; } + virtual bool GetUseTemp(void) { return false; } + virtual int GetPos(void); + virtual int GetNextPos(void); + virtual PTXF Duplicate(PGLOBAL g) { return (PTXF)new(g) JMGFAM(this); } + void SetLrecl(int lrecl) { Lrecl = lrecl; } + + // Methods + virtual void Reset(void); + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); + virtual int MaxBlkSize(PGLOBAL g, int s); + virtual bool AllocateBuffer(PGLOBAL g) { return false; } + virtual int GetRowID(void); + virtual bool RecordPos(PGLOBAL g); + virtual bool SetPos(PGLOBAL g, int recpos); + virtual int SkipRecord(PGLOBAL g, bool header); + virtual bool OpenTableFile(PGLOBAL g); + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + +protected: + virtual bool OpenTempFile(PGLOBAL g) { return false; } + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b) { return false; } + virtual int RenameTempFile(PGLOBAL g) { return RC_OK; } + virtual int InitDelete(PGLOBAL g, int fpos, int spos); + bool Init(PGLOBAL g); +//bool MakeCursor(PGLOBAL g); + + // Members + JMgoConn *Jcp; // Points to a Mongo connection class + JDBCPARM Ops; // Additional parameters + PFBLOCK To_Fbt; // Pointer to temp file block + MODE Mode; + PCSZ Uristr; + PCSZ Db_name; + PCSZ Coll_name; + PCSZ Options; + PCSZ Filter; + PSZ Wrapname; + bool Done; // Init done + bool Pipe; + int Version; + int Curpos; // Cursor position of last fetch +}; // end of class JMGFAM + diff --git a/storage/connect/jmgoconn.cpp b/storage/connect/jmgoconn.cpp new file mode 100644 index 0000000000000..cb0729ed1f7cb --- /dev/null +++ b/storage/connect/jmgoconn.cpp @@ -0,0 +1,811 @@ +/************ JMgoConn C++ Functions Source Code File (.CPP) ***********/ +/* Name: JMgoConn.CPP Version 1.1 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the MongoDB Java connection classes functions. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant MariaDB header file. */ +/***********************************************************************/ +#include + +/***********************************************************************/ +/* Required objects includes. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "colblk.h" +#include "xobject.h" +#include "xtable.h" +#include "filter.h" +#include "jmgoconn.h" + +#define nullptr 0 + +bool IsNum(PSZ s); + +/* --------------------------- Class JNCOL --------------------------- */ + +/***********************************************************************/ +/* Add a column in the column list. */ +/***********************************************************************/ +void JNCOL::AddCol(PGLOBAL g, PCOL colp, PSZ jp) +{ + char *p; + PJKC kp, kcp; + + if ((p = strchr(jp, '.'))) { + PJNCOL icp; + + *p++ = 0; + + for (kp = Klist; kp; kp = kp->Next) + if (kp->Jncolp && !strcmp(jp, kp->Key)) + break; + + if (!kp) { + icp = new(g) JNCOL(IsNum(p)); + kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL)); + kcp->Next = NULL; + kcp->Jncolp = icp; + kcp->Colp = NULL; + + if (Array) { + kcp->Key = NULL; + kcp->N = atoi(p); + } else { + kcp->Key = PlugDup(g, jp); + kcp->N = 0; + } // endif Array + + if (Klist) { + for (kp = Klist; kp->Next; kp = kp->Next); + + kp->Next = kcp; + } else + Klist = kcp; + + } else + icp = kp->Jncolp; + + *(p - 1) = '.'; + icp->AddCol(g, colp, p); + } else { + kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL)); + + kcp->Next = NULL; + kcp->Jncolp = NULL; + kcp->Colp = colp; + + if (Array) { + kcp->Key = NULL; + kcp->N = atoi(jp); + } else { + kcp->Key = jp; + kcp->N = 0; + } // endif Array + + if (Klist) { + for (kp = Klist; kp->Next; kp = kp->Next); + + kp->Next = kcp; + } else + Klist = kcp; + + } // endif jp + +} // end of AddCol + +/***********************************************************************/ +/* JMgoConn construction/destruction. */ +/***********************************************************************/ +JMgoConn::JMgoConn(PGLOBAL g, PCSZ collname, PCSZ wrapper) + : JAVAConn(g, wrapper) +{ + CollName = collname; + readid = fetchid = getdocid = objfldid = fcollid = acollid = + mkdocid = docaddid = mkarid = araddid = insertid = updateid = + deleteid = gcollid = countid = rewindid = nullptr; + DiscFunc = "MongoDisconnect"; + Fpc = NULL; + m_Version = 0; + m_Fetch = 0; + m_Version = 0; +} // end of JMgoConn + +/***********************************************************************/ +/* AddJars: add some jar file to the Class path. */ +/***********************************************************************/ +void JMgoConn::AddJars(PSTRG jpop, char sep) +{ +#if defined(DEVELOPMENT) + if (m_Version == 2) { + //jpop->Append(sep); + //jpop->Append("C:/Eclipse/workspace/MongoWrap2/bin"); + jpop->Append(sep); + jpop->Append("C:/mongo-java-driver/mongo-java-driver-2.13.3.jar"); + } else { + //jpop->Append(sep); + //jpop->Append("C:/Eclipse/workspace/MongoWrap3/bin"); + jpop->Append(sep); + jpop->Append("C:/mongo-java-driver/mongo-java-driver-3.4.2.jar"); + } // endif m_Version +#endif // DEVELOPMENT +} // end of AddJars + +/***********************************************************************/ +/* Connect: connect to a data source. */ +/***********************************************************************/ +bool JMgoConn::Connect(PJPARM sop) +{ + bool err = false; + jint rc; + jboolean brc; + jstring cln; + PGLOBAL& g = m_G; + + m_Version = sop->Version; + + /*******************************************************************/ + /* Create or attach a JVM. */ + /*******************************************************************/ + if (Open(g)) + return true; + + /*******************************************************************/ + /* Connect to MongoDB. */ + /*******************************************************************/ + jmethodID cid = nullptr; + + if (gmID(g, cid, "MongoConnect", "([Ljava/lang/String;)I")) + return true; + + // Build the java string array + jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4 + env->FindClass("java/lang/String"), NULL); // Strings + + //m_Scrollable = sop->Scrollable; + //m_RowsetSize = sop->Fsize; + + // change some elements + if (sop->Driver) + env->SetObjectArrayElement(parms, 0, env->NewStringUTF(sop->Url)); + + if (sop->Url) + env->SetObjectArrayElement(parms, 1, env->NewStringUTF(sop->Driver)); + + if (sop->User) + env->SetObjectArrayElement(parms, 2, env->NewStringUTF(sop->User)); + + if (sop->Pwd) + env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd)); + + // call method + rc = env->CallIntMethod(job, cid, parms); + err = Check(rc); + env->DeleteLocalRef(parms); // Not used anymore + + if (err) { + sprintf(g->Message, "Connecting: %s rc=%d", Msg, (int)rc); + return true; + } // endif Msg + + /*********************************************************************/ + /* Get the collection. */ + /*********************************************************************/ + if (gmID(g, gcollid, "GetCollection", "(Ljava/lang/String;)Z")) + return true; + + cln = env->NewStringUTF(CollName); + brc = env->CallBooleanMethod(job, gcollid, cln); + env->DeleteLocalRef(cln); + + if (Check(brc ? -1 : 0)) { + sprintf(g->Message, "GetCollection: %s", Msg); + return true; + } // endif Msg + + m_Connected = true; + return false; +} // end of Connect + +/***********************************************************************/ +/* CollSize: returns the number of documents in the collection. */ +/***********************************************************************/ +int JMgoConn::CollSize(PGLOBAL g) +{ + if (!gmID(g, countid, "GetCollSize", "()J")) { + jlong card = env->CallLongMethod(job, countid); + + return (int)card; + } else + return 2; // Make MariaDB happy + +} // end of CollSize + +/***********************************************************************/ +/* OpenDB: Data Base open routine for MONGO access method. */ +/***********************************************************************/ +bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, + PCSZ filter, bool pipe) +{ + const char *p; + bool b = false, id = (tdbp->GetMode() != MODE_READ), all = false; + uint len; + PCOL cp; + PSZ jp; + PCSZ op = NULL, sf = NULL, Options = options; + PSTRG s = NULL; + + if (Options && !stricmp(Options, "all")) { + Options = NULL; + all = true; + } // endif Options + + for (cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) + if (!strcmp(cp->GetName(), "_id")) + id = true; + else if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && (!Options || pipe)) + all = true; + + if (pipe && Options) { + if (trace) + htrc("Pipeline: %s\n", Options); + + p = strrchr(Options, ']'); + + if (!p) { + strcpy(g->Message, "Missing ] in pipeline"); + return true; + } else + *(char*)p = 0; + + s = new(g) STRING(g, 1023, (PSZ)Options); + + if (tdbp->GetFilter()) { + s->Append(",{\"$match\":"); + + if (tdbp->GetFilter()->MakeSelector(g, s)) { + strcpy(g->Message, "Failed making selector"); + return NULL; + } else + s->Append('}'); + + tdbp->SetFilter(NULL); // Not needed anymore + } // endif To_Filter + + if (!all && tdbp->GetColumns()) { + // Project list + len = s->GetLength(); + s->Append(",{\"$project\":{\""); + + if (!id) + s->Append("_id\":0,\""); + + for (PCOL cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) { + if (b) + s->Append(",\""); + else + b = true; + + if ((jp = cp->GetJpath(g, true))) + s->Append(jp); + else { + s->Truncate(len); + goto nop; + } // endif Jpath + + s->Append("\":1"); + } // endfor cp + + s->Append("}}"); + } // endif all + + nop: + s->Append("]}"); + s->Resize(s->GetLength() + 1); + *(char*)p = ']'; // Restore Colist for discovery + p = s->GetStr(); + + if (trace) + htrc("New Pipeline: %s\n", p); + + return AggregateCollection(p); + } else { + if (filter || tdbp->GetFilter()) { + if (trace) { + if (filter) + htrc("Filter: %s\n", filter); + + if (tdbp->GetFilter()) { + char buf[512]; + + tdbp->GetFilter()->Prints(g, buf, 511); + htrc("To_Filter: %s\n", buf); + } // endif To_Filter + + } // endif trace + + s = new(g) STRING(g, 1023, (PSZ)filter); + len = s->GetLength(); + + if (tdbp->GetFilter()) { + if (filter) + s->Append(','); + + if (tdbp->GetFilter()->MakeSelector(g, s)) { + strcpy(g->Message, "Failed making selector"); + return NULL; + } // endif Selector + + tdbp->SetFilter(NULL); // Not needed anymore + } // endif To_Filter + + if (trace) + htrc("selector: %s\n", s->GetStr()); + + s->Resize(s->GetLength() + 1); + sf = PlugDup(g, s->GetStr()); + } // endif Filter + + if (!all) { + if (Options && *Options) { + if (trace) + htrc("options=%s\n", Options); + + op = Options; + } else if (tdbp->GetColumns()) { + // Projection list + if (s) + s->Set("{\""); + else + s = new(g) STRING(g, 511, "{\""); + + if (!id) + s->Append("_id\":0,\""); + + for (PCOL cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) { + if (b) + s->Append(",\""); + else + b = true; + + if ((jp = cp->GetJpath(g, true))) + s->Append(jp); + else { + // Can this happen? + htrc("Fail getting projection path of %s\n", cp->GetName()); + goto nope; + } // endif Jpath + + s->Append("\":1"); + } // endfor cp + + s->Append("}"); + s->Resize(s->GetLength() + 1); + op = s->GetStr(); + } else { + // count(*) ? + op = "{\"_id\":1}"; + } // endif Options + + } // endif all + + nope: + return FindCollection(sf, op); + } // endif Pipe + +} // end of MakeCursor + +/***********************************************************************/ +/* Find a collection and make cursor. */ +/***********************************************************************/ +bool JMgoConn::FindCollection(PCSZ query, PCSZ proj) +{ + bool rc = true; + jboolean brc; + jstring qry = nullptr, prj = nullptr; + PGLOBAL& g = m_G; + + // Get the methods used to execute a query and get the result + if (!gmID(g, fcollid, "FindColl", "(Ljava/lang/String;Ljava/lang/String;)Z")) { + if (query) + qry = env->NewStringUTF(query); + + if (proj) + prj = env->NewStringUTF(proj); + + brc = env->CallBooleanMethod(job, fcollid, qry, prj); + + if (!Check(brc ? -1 : 0)) { + rc = false; + } else + sprintf(g->Message, "FindColl: %s", Msg); + + if (query) + env->DeleteLocalRef(qry); + + if (proj) + env->DeleteLocalRef(prj); + + } // endif xqid + + return rc; +} // end of FindCollection + +/***********************************************************************/ +/* Find a collection and make cursor. */ +/***********************************************************************/ +bool JMgoConn::AggregateCollection(PCSZ pipeline) +{ + bool rc = true; + jboolean brc; + jstring pip = nullptr; + PGLOBAL& g = m_G; + + // Get the methods used to execute a query and get the result + if (!gmID(g, acollid, "AggregateColl", "(Ljava/lang/String;)Z")) { + pip = env->NewStringUTF(pipeline); + + brc = env->CallBooleanMethod(job, acollid, pip); + + if (!Check(brc ? -1 : 0)) { + rc = false; + } else + sprintf(g->Message, "AggregateColl: %s", Msg); + + env->DeleteLocalRef(pip); + } // endif acollid + + return rc; +} // end of AggregateCollection + +/***********************************************************************/ +/* Fetch next row. */ +/***********************************************************************/ +int JMgoConn::Fetch(int pos) +{ + jint rc = JNI_ERR; + PGLOBAL& g = m_G; + + //if (m_Full) // Result set has one row + // return 1; + + //if (pos) { + // if (!m_Scrollable) { + // strcpy(g->Message, "Cannot fetch(pos) if FORWARD ONLY"); + // return rc; + // } else if (gmID(m_G, fetchid, "Fetch", "(I)Z")) + // return rc; + + // if (env->CallBooleanMethod(job, fetchid, pos)) + // rc = m_Rows; + + //} else { + if (gmID(g, readid, "ReadNext", "()I")) + return (int)rc; + + rc = env->CallIntMethod(job, readid); + + if (!Check(rc)) { + //if (rc == 0) + // m_Full = (m_Fetch == 1); + //else + // m_Fetch++; + + m_Rows += (int)rc; + } else + sprintf(g->Message, "Fetch: %s", Msg); + + //} // endif pos + + return (int)rc; +} // end of Fetch + +/***********************************************************************/ +/* Get the Json string of the current document. */ +/***********************************************************************/ +PSZ JMgoConn::GetDocument(void) +{ + PGLOBAL& g = m_G; + PSZ doc = NULL; + jstring jdc; + + if (!gmID(g, getdocid, "GetDoc", "()Ljava/lang/String;")) { + jdc = (jstring)env->CallObjectMethod(job, getdocid); + + if (jdc) + doc = (PSZ)env->GetStringUTFChars(jdc, (jboolean)false); + + } // endif getdocid + + return doc; + } // end of GetDocument + +/***********************************************************************/ +/* Group columns for inserting or updating. */ +/***********************************************************************/ +void JMgoConn::MakeColumnGroups(PGLOBAL g, PTDB tdbp) +{ + Fpc = new(g) JNCOL(false); + + for (PCOL colp = tdbp->GetColumns(); colp; colp = colp->GetNext()) + if (!colp->IsSpecial()) + Fpc->AddCol(g, colp, colp->GetJpath(g, false)); + +} // end of MakeColumnGroups + +/***********************************************************************/ +/* Get additional method ID. */ +/***********************************************************************/ +bool JMgoConn::GetMethodId(PGLOBAL g, MODE mode) +{ + if (mode == MODE_UPDATE) { + if (gmID(g, mkdocid, "MakeDocument", "()Ljava/lang/Object;")) + return true; + + if (gmID(g, docaddid, "DocAdd", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z")) + return true; + + if (gmID(g, updateid, "CollUpdate", "(Ljava/lang/Object;)J")) + return true; + + } else if (mode == MODE_INSERT) { + if (gmID(g, mkdocid, "MakeDocument", "()Ljava/lang/Object;")) + return true; + + if (gmID(g, docaddid, "DocAdd", + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z")) + return true; + + if (gmID(g, mkarid, "MakeArray", "()Ljava/lang/Object;")) + return true; + + if (gmID(g, araddid, "ArrayAdd", "(Ljava/lang/Object;ILjava/lang/Object;)Z")) + return true; + + if (gmID(g, insertid, "CollInsert", "(Ljava/lang/Object;)Z")) + return true; + + } else if (mode == MODE_DELETE) + if (gmID(g, deleteid, "CollDelete", "(Z)J")) + return true; + + return gmID(g, rewindid, "Rewind", "()Z"); +} // end of GetMethodId + +/***********************************************************************/ +/* MakeObject. */ +/***********************************************************************/ +jobject JMgoConn::MakeObject(PGLOBAL g, PCOL colp, bool&error ) +{ + jclass cls; + jmethodID cns = nullptr; // Constructor + jobject val = nullptr; + PVAL valp = colp->GetValue(); + + error = false; + + if (valp->IsNull()) + return NULL; + + try { + switch (valp->GetType()) { + case TYPE_STRING: + val = env->NewStringUTF(valp->GetCharValue()); + break; + case TYPE_INT: + case TYPE_SHORT: + cls = env->FindClass("java/lang/Integer"); + cns = env->GetMethodID(cls, "", "(I)V"); + val = env->NewObject(cls, cns, valp->GetIntValue()); + break; + case TYPE_TINY: + cls = env->FindClass("java/lang/Boolean"); + cns = env->GetMethodID(cls, "", "(Z)V"); + val = env->NewObject(cls, cns, (valp->GetIntValue() != 0)); + break; + case TYPE_BIGINT: + cls = env->FindClass("java/lang/Long"); + cns = env->GetMethodID(cls, "", "(J)V"); + val = env->NewObject(cls, cns, valp->GetBigintValue()); + break; + case TYPE_DOUBLE: + cls = env->FindClass("java/lang/Double"); + cns = env->GetMethodID(cls, "", "(D)V"); + val = env->NewObject(cls, cns, valp->GetFloatValue()); + break; + default: + sprintf(g->Message, "Cannot make object from %d type", valp->GetType()); + error = true; + break; + } // endswitch Type + + } catch (...) { + sprintf(g->Message, "Cannot make object from %s value", colp->GetName()); + error = true; + } // end try/catch + + return val; +} // end of MakeObject + +/***********************************************************************/ +/* MakeDoc. */ +/***********************************************************************/ +jobject JMgoConn::MakeDoc(PGLOBAL g, PJNCOL jcp) +{ + bool error = false; + jobject parent, child, val; + jstring jkey; + + if (jcp->Array) + parent = env->CallObjectMethod(job, mkarid); + else + parent = env->CallObjectMethod(job, mkdocid); + + for (PJKC kp = jcp->Klist; kp; kp = kp->Next) + if (kp->Jncolp) { + if (!(child = MakeDoc(g, kp->Jncolp))) + return NULL; + + if (!jcp->Array) { + jkey = env->NewStringUTF(kp->Key); + + if (env->CallBooleanMethod(job, docaddid, parent, jkey, child)) + return NULL; + + env->DeleteLocalRef(jkey); + } else + if (env->CallBooleanMethod(job, araddid, parent, kp->N, child)) + return NULL; + + } else { + if (!(val = MakeObject(g, kp->Colp, error))) { + if (error) + return NULL; + + } else if (!jcp->Array) { + jkey = env->NewStringUTF(kp->Key); + + if (env->CallBooleanMethod(job, docaddid, parent, jkey, val)) + return NULL; + + env->DeleteLocalRef(jkey); + } else if (env->CallBooleanMethod(job, araddid, parent, kp->N, val)) { + if (Check(-1)) + sprintf(g->Message, "ArrayAdd: %s", Msg); + else + sprintf(g->Message, "ArrayAdd: unknown error"); + + return NULL; + } // endif ArrayAdd + + } // endif Jncolp + + return parent; +} // end of MakeDoc + +/***********************************************************************/ +/* Insert a new document in the collation. */ +/***********************************************************************/ +int JMgoConn::DocWrite(PGLOBAL g) +{ + jobject doc; + + if (!Fpc || !(doc = MakeDoc(g, Fpc))) + return RC_FX; + + if (env->CallBooleanMethod(job, insertid, doc)) { + if (Check(-1)) + sprintf(g->Message, "CollInsert: %s", Msg); + else + sprintf(g->Message, "CollInsert: unknown error"); + + return RC_FX; + } // endif Insert + + return RC_OK; +} // end of DocWrite + +/***********************************************************************/ +/* Update the current document from the collection. */ +/***********************************************************************/ +int JMgoConn::DocUpdate(PGLOBAL g, PTDB tdbp) +{ + int rc = RC_OK; + bool error; + PCOL colp; + jstring jkey; + jobject val, upd, updlist = env->CallObjectMethod(job, mkdocid); + + // Make the list of changes to do + for (colp = tdbp->GetSetCols(); colp; colp = colp->GetNext()) { + jkey = env->NewStringUTF(colp->GetJpath(g, false)); + val = MakeObject(g, colp, error); + + if (error) + return RC_FX; + + if (env->CallBooleanMethod(job, docaddid, updlist, jkey, val)) + return NULL; + + env->DeleteLocalRef(jkey); + } // endfor colp + + // Make the update parameter + upd = env->CallObjectMethod(job, mkdocid); + jkey = env->NewStringUTF("$set"); + + if (env->CallBooleanMethod(job, docaddid, upd, jkey, updlist)) + return NULL; + + env->DeleteLocalRef(jkey); + + jlong ar = env->CallLongMethod(job, updateid, upd); + + if (trace) + htrc("DocUpdate: ar = %ld\n", ar); + + if (Check((int)ar)) { + sprintf(g->Message, "CollUpdate: %s", Msg); + rc = RC_FX; + } // endif ar + + return rc; +} // end of DocUpdate + +/***********************************************************************/ +/* Remove all or only the current document from the collection. */ +/***********************************************************************/ +int JMgoConn::DocDelete(PGLOBAL g, bool all) +{ + int rc = RC_OK; + jlong ar = env->CallLongMethod(job, deleteid, all); + + if (trace) + htrc("DocDelete: ar = %ld\n", ar); + + if (Check((int)ar)) { + sprintf(g->Message, "CollDelete: %s", Msg); + rc = RC_FX; + } // endif ar + + return rc; +} // end of DocDelete + +/***********************************************************************/ +/* Rewind the collection. */ +/***********************************************************************/ +bool JMgoConn::Rewind(void) +{ + return env->CallBooleanMethod(job, rewindid); +} // end of Rewind + +/***********************************************************************/ +/* Retrieve the column string value from the document. */ +/***********************************************************************/ +PSZ JMgoConn::GetColumnValue(PSZ path) +{ + PGLOBAL& g = m_G; + PSZ fld = NULL; + jstring fn, jn = nullptr; + + if (!path || (jn = env->NewStringUTF(path)) == nullptr) { + sprintf(g->Message, "Fail to allocate jstring %s", SVP(path)); + throw (int)TYPE_AM_MGO; + } // endif name + + if (!gmID(g, objfldid, "GetField", "(Ljava/lang/String;)Ljava/lang/String;")) { + fn = (jstring)env->CallObjectMethod(job, objfldid, jn); + + if (fn) + fld = (PSZ)env->GetStringUTFChars(fn, (jboolean)false); + + } // endif objfldid + + return fld; +} // end of GetColumnValue + diff --git a/storage/connect/jmgoconn.h b/storage/connect/jmgoconn.h new file mode 100644 index 0000000000000..8e8577efe970f --- /dev/null +++ b/storage/connect/jmgoconn.h @@ -0,0 +1,136 @@ +/***********************************************************************/ +/* JMgoConn.h : header file for the MongoDB connection classes. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Java interface. */ +/***********************************************************************/ +#include "javaconn.h" + +// Java connection to a MongoDB data source +class TDBJMG; +class JMGCOL; + +/***********************************************************************/ +/* Include MongoDB library header files. */ +/***********************************************************************/ +typedef class JNCOL *PJNCOL; +typedef class MGODEF *PMGODEF; +typedef class TDBJMG *PTDBJMG; +typedef class JMGCOL *PJMGCOL; + +#if 0 +/***********************************************************************/ +/* Class used to get the columns of a mongo collection. */ +/***********************************************************************/ +class MGODISC : public BLOCK { +public: + // Constructor + MGODISC(PGLOBAL g, int *lg); + + // Functions + int GetColumns(PGLOBAL g, char *db, PTOS topt); + bool FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc, + char *pcn, char *pfmt, int i, int k, bool b); + + // Members + BCOL bcol; + PBCOL bcp, fbcp, pbcp; + PMGODEF tdp; + TDBJMG *tmgp; + int *length; + int n, k, lvl; + bool all; +}; // end of MGODISC +#endif // 0 + +typedef struct JKCOL { + JKCOL *Next; + PJNCOL Jncolp; + PCOL Colp; + char *Key; + int N; +} *PJKC; + +/***********************************************************************/ +/* Used when inserting values in a MongoDB collection. */ +/***********************************************************************/ +class JNCOL : public BLOCK { +public: + // Constructor + JNCOL(bool ar) { Klist = NULL; Array = ar; } + + // Methods + void AddCol(PGLOBAL g, PCOL colp, PSZ jp); + + //Members + PJKC Klist; + bool Array; +}; // end of JNCOL; + +/***********************************************************************/ +/* JMgoConn class. */ +/***********************************************************************/ +class JMgoConn : public JAVAConn { + friend class TDBJMG; + //friend class TDBXJDC; + //friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&); +private: + JMgoConn(); // Standard (unused) constructor + +public: + // Constructor + JMgoConn(PGLOBAL g, PCSZ collname, PCSZ wrapper); + + // Implementation +public: + virtual void AddJars(PSTRG jpop, char sep); + virtual bool Connect(PJPARM sop); + virtual bool MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, PCSZ filter, bool pipe); +// PQRYRES AllocateResult(PGLOBAL g, TDBEXT *tdbp, int n); + + // Attributes +public: +// virtual int GetMaxValue(int infotype); + +public: + // Operations + virtual int Fetch(int pos = 0); + virtual PSZ GetColumnValue(PSZ name); + + int CollSize(PGLOBAL g); + bool FindCollection(PCSZ query, PCSZ proj); + bool AggregateCollection(PCSZ pipeline); + void MakeColumnGroups(PGLOBAL g, PTDB tdbp); + bool GetMethodId(PGLOBAL g, MODE mode); + jobject MakeObject(PGLOBAL g, PCOL colp, bool& error); + jobject MakeDoc(PGLOBAL g, PJNCOL jcp); + int DocWrite(PGLOBAL g); + int DocUpdate(PGLOBAL g, PTDB tdbp); + int DocDelete(PGLOBAL g, bool all); + bool Rewind(void); + PSZ GetDocument(void); + +protected: + // Members + PCSZ CollName; // The collation name + jmethodID gcollid; // The GetCollection method ID + jmethodID countid; // The GetCollSize method ID + jmethodID fcollid; // The FindColl method ID + jmethodID acollid; // The AggregateColl method ID + jmethodID readid; // The ReadNext method ID + jmethodID fetchid; // The Fetch method ID + jmethodID rewindid; // The Rewind method ID + jmethodID getdocid; // The GetDoc method ID + jmethodID objfldid; // The ObjectField method ID + jmethodID mkdocid; // The MakeDocument method ID + jmethodID docaddid; // The DocAdd method ID + jmethodID mkarid; // The MakeArray method ID + jmethodID araddid; // The ArrayAdd method ID + jmethodID insertid; // The CollInsert method ID + jmethodID updateid; // The CollUpdate method ID + jmethodID deleteid; // The CollDelete method ID + PJNCOL Fpc; // To JNCOL classes + int m_Fetch; + int m_Version; // Java driver version (2 or 3) +}; // end of JMgoConn class definition diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index f8b1caa13e20f..bf0d6c0d676ee 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -53,6 +53,36 @@ void trans_func(unsigned int u, _EXCEPTION_POINTERS* pExp) char *GetExceptionDesc(PGLOBAL g, unsigned int e); #endif // SE_CATCH +/***********************************************************************/ +/* IsNum: check whether this string is all digits. */ +/***********************************************************************/ +bool IsNum(PSZ s) +{ + for (char *p = s; *p; p++) + if (*p == ']') + break; + else if (!isdigit(*p) || *p == '-') + return false; + + return true; +} // end of IsNum + +/***********************************************************************/ +/* NextChr: return the first found '[' or Sep pointer. */ +/***********************************************************************/ +char *NextChr(PSZ s, char sep) +{ + char *p1 = strchr(s, '['); + char *p2 = strchr(s, sep); + + if (!p2) + return p1; + else if (p1) + return MY_MIN(p1, p2); + + return p2; +} // end of NextChr + /***********************************************************************/ /* Parse a json string. */ @@ -992,7 +1022,24 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text) if (!First && n) return NULL; - else for (PJPR jp = First; jp; jp = jp->Next) + else if (n == 1 && Size == 1 && !strcmp(First->GetKey(), "$date")) { + int i; + + First->Val->GetText(g, text); + i = (text[1] == '-' ? 2 : 1); + + if (IsNum(text + i)) { + // Date is in milliseconds + int j = (int)strlen(text); + + if (j >= 4 + i) + text[j - 3] = 0; // Change it to seconds + else + strcpy(text, " 0"); + + } // endif text + + } else for (PJPR jp = First; jp; jp = jp->Next) jp->Val->GetText(g, text); if (n) @@ -1312,7 +1359,7 @@ PSZ JVALUE::GetText(PGLOBAL g, PSZ text) if (s) strcat(strcat(text, " "), s); else - strcat(text, " ???"); + strcat(text, " "); return text; } // end of GetText diff --git a/storage/connect/json.h b/storage/connect/json.h index 49675ce8559ec..685c1dddcf20f 100644 --- a/storage/connect/json.h +++ b/storage/connect/json.h @@ -1,7 +1,7 @@ /**************** json H Declares Source Code File (.H) ****************/ /* Name: json.h Version 1.2 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2014 - 2017 */ /* */ /* This file contains the JSON classes declares. */ /***********************************************************************/ @@ -13,11 +13,12 @@ #define X #endif -enum JTYP {TYPE_STRG = 1, - TYPE_DBL = 2, - TYPE_BOOL = 4, - TYPE_BINT = 5, - TYPE_INTG = 7, +enum JTYP {TYPE_STRG = TYPE_STRING, + TYPE_DBL = TYPE_DOUBLE, + TYPE_BOOL = TYPE_TINY, + TYPE_BINT = TYPE_BIGINT, + TYPE_DTM = TYPE_DATE, + TYPE_INTG = TYPE_INT, TYPE_JSON = 12, TYPE_JAR, TYPE_JOB, diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index 87e818e610819..b44e9c1309b8a 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -27,9 +27,11 @@ #endif #define M 7 -uint GetJsonGrpSize(void); -static int IsJson(UDF_ARGS *args, uint i); -static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i); +bool IsNum(PSZ s); +char *NextChr(PSZ s, char sep); +uint GetJsonGrpSize(void); +static int IsJson(UDF_ARGS *args, uint i); +static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i); static char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error); static char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, @@ -111,10 +113,9 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) PJNODE jnp = &Nodes[i]; if (*p) { - if (p[--n] == ']') { - p[n--] = 0; - p++; - } else { + if (p[n - 1] == ']') { + p[--n] = 0; + } else if (!IsNum(p)) { // Wrong array specification sprintf(g->Message, "Invalid array specification %s", p); return true; @@ -124,8 +125,7 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) b = true; // To check whether a numeric Rank was specified - for (int k = 0; dg && p[k]; k++) - dg = isdigit(p[k]) > 0; + dg = IsNum(p); if (!n) { // Default specifications @@ -160,13 +160,12 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) // Set the Op value; switch (*p) { case '+': jnp->Op = OP_ADD; break; - case '*': jnp->Op = OP_MULT; break; + case 'x': jnp->Op = OP_MULT; break; case '>': jnp->Op = OP_MAX; break; case '<': jnp->Op = OP_MIN; break; case '!': jnp->Op = OP_SEP; break; // Average case '#': jnp->Op = OP_NUM; break; - case 'x': - case 'X': // Expand this array + case '*': // Expand this array strcpy(g->Message, "Expand not supported by this function"); return true; default: @@ -232,9 +231,9 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) /*********************************************************************************/ my_bool JSNX::ParseJpath(PGLOBAL g) { - char *p, *p2 = NULL, *pbuf = NULL; + char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL; int i; - my_bool mul = false; + my_bool a, mul = false; if (Parsed) return false; // Already done @@ -245,8 +244,12 @@ my_bool JSNX::ParseJpath(PGLOBAL g) if (!(pbuf = PlgDBDup(g, Jpath))) return true; - // The Jpath must be analyzed - for (i = 0, p = pbuf; (p = strchr(p, ':')); i++, p++) + if (*pbuf == '$') pbuf++; + if (*pbuf == '.') pbuf++; + if (*pbuf == '[') p1 = pbuf++; + + // Estimate the required number of nodes + for (i = 0, p = pbuf; (p = NextChr(p, '.')); i++, p++) Nod++; // One path node found if (!(Nodes = (PJNODE)PlgDBSubAlloc(g, NULL, (++Nod) * sizeof(JNODE)))) @@ -255,12 +258,28 @@ my_bool JSNX::ParseJpath(PGLOBAL g) memset(Nodes, 0, (Nod)* sizeof(JNODE)); // Analyze the Jpath for this column - for (i = 0, p = pbuf; i < Nod; i++, p = (p2 ? p2 + 1 : p + strlen(p))) { - if ((p2 = strchr(p, ':'))) - *p2 = 0; + for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) { + a = (p1 != NULL); + p1 = strchr(p, '['); + p2 = strchr(p, '.'); + + if (!p2) + p2 = p1; + else if (p1) { + if (p1 < p2) + p2 = p1; + else if (p1 == p2 + 1) + *p2++ = 0; // Old syntax .[ + else + p1 = NULL; + + } // endif p1 + + if (p2) + *p2++ = 0; // Jpath must be explicit - if (*p == 0 || *p == '[') { + if (a || *p == 0 || *p == '[' || IsNum(p)) { // Analyse intermediate array processing if (SetArrayOptions(g, p, i, Nodes[i-1].Key)) return true; @@ -279,6 +298,7 @@ my_bool JSNX::ParseJpath(PGLOBAL g) } // endfor i, p + Nod = i; MulVal = AllocateValue(g, Value); Parsed = true; return false; @@ -711,6 +731,7 @@ PSZ JSNX::Locate(PGLOBAL g, PJSON jsp, PJVAL jvp, int k) // Write to the path string Jp = new(g) JOUTSTR(g); + Jp->WriteChr('$'); Jvalp = jvp; K = k; @@ -769,7 +790,12 @@ my_bool JSNX::LocateArray(PJAR jarp) /*********************************************************************************/ my_bool JSNX::LocateObject(PJOB jobp) { - size_t m = Jp->N; + size_t m; + + if (Jp->WriteChr('.')) + return true; + + m = Jp->N; for (PJPR pair = jobp->First; pair && !Found; pair = pair->Next) { Jp->N = m; @@ -790,19 +816,12 @@ my_bool JSNX::LocateObject(PJOB jobp) /*********************************************************************************/ my_bool JSNX::LocateValue(PJVAL jvp) { - if (CompareTree(Jvalp, jvp)) { + if (CompareTree(Jvalp, jvp)) Found = (--K == 0); - } else if (jvp->GetArray()) { - if (Jp->WriteChr(':')) - return true; - + else if (jvp->GetArray()) return LocateArray(jvp->GetArray()); - } else if (jvp->GetObject()) { - if (Jp->WriteChr(':')) - return true; - + else if (jvp->GetObject()) return LocateObject(jvp->GetObject()); - } // endif's return false; } // end of LocateValue @@ -848,6 +867,7 @@ PSZ JSNX::LocateAll(PGLOBAL g, PJSON jsp, PJVAL jvp, int mx) if (!g->Message[0]) strcpy(g->Message, "Invalid json tree"); + return NULL; } else { if (Jp->N > 1) Jp->N--; @@ -858,7 +878,6 @@ PSZ JSNX::LocateAll(PGLOBAL g, PJSON jsp, PJVAL jvp, int mx) return Jp->Strp; } // endif's - return NULL; } // end of LocateAll /*********************************************************************************/ @@ -964,26 +983,26 @@ my_bool JSNX::CompareTree(PJSON jp1, PJSON jp2) /*********************************************************************************/ my_bool JSNX::AddPath(void) { - char s[16]; - my_bool b = false; + char s[16]; - if (Jp->WriteChr('"')) + if (Jp->WriteStr("\"$")) return true; for (int i = 0; i <= I; i++) { - if (b) { - if (Jp->WriteChr(':')) return true; - } else - b = true; - if (Jpnp[i].Type == TYPE_JAR) { sprintf(s, "[%d]", Jpnp[i].N + B); if (Jp->WriteStr(s)) return true; - } else if (Jp->WriteStr(Jpnp[i].Key)) - return true; + } else { + if (Jp->WriteChr('.')) + return true; + + if (Jp->WriteStr(Jpnp[i].Key)) + return true; + + } // endif's } // endfor i @@ -1379,6 +1398,7 @@ static my_bool CalcLen(UDF_ARGS *args, my_bool obj, memlen += (k + sizeof(JOBJECT) + sizeof(JPAIR)); } else memlen += sizeof(JARRAY); + switch (args->arg_type[i]) { case STRING_RESULT: if (n == 2 && args->args[i]) { @@ -1757,16 +1777,16 @@ void jsonvalue_deinit(UDF_INIT* initid) /*********************************************************************************/ /* Make a Json array containing all the parameters. */ /*********************************************************************************/ -my_bool json_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message) +my_bool json_make_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { unsigned long reslen, memlen; CalcLen(args, false, reslen, memlen); return JsonInit(initid, args, message, false, reslen, memlen); -} // end of json_array_init +} // end of json_make_array_init -char *json_array(UDF_INIT *initid, UDF_ARGS *args, char *result, - unsigned long *res_length, char *, char *) +char *json_make_array(UDF_INIT *initid, UDF_ARGS *args, char *result, + unsigned long *res_length, char *, char *) { char *str; PGLOBAL g = (PGLOBAL)initid->ptr; @@ -1793,12 +1813,12 @@ char *json_array(UDF_INIT *initid, UDF_ARGS *args, char *result, *res_length = strlen(str); return str; -} // end of json_array +} // end of json_make_array void json_array_deinit(UDF_INIT* initid) { JsonFreeMem((PGLOBAL)initid->ptr); -} // end of json_array_deinit +} // end of json_make_array_deinit /*********************************************************************************/ /* Add one or several values to a Json array. */ @@ -2081,16 +2101,16 @@ void json_array_delete_deinit(UDF_INIT* initid) /*********************************************************************************/ /* Make a Json Object containing all the parameters. */ /*********************************************************************************/ -my_bool json_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message) +my_bool json_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { unsigned long reslen, memlen; CalcLen(args, true, reslen, memlen); return JsonInit(initid, args, message, false, reslen, memlen); -} // end of json_object_init +} // end of json_make_object_init -char *json_object(UDF_INIT *initid, UDF_ARGS *args, char *result, - unsigned long *res_length, char *, char *) +char *json_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result, + unsigned long *res_length, char *, char *) { char *str = NULL; PGLOBAL g = (PGLOBAL)initid->ptr; @@ -2115,12 +2135,12 @@ char *json_object(UDF_INIT *initid, UDF_ARGS *args, char *result, *res_length = strlen(str); return str; -} // end of json_object +} // end of json_make_object -void json_object_deinit(UDF_INIT* initid) +void json_make_object_deinit(UDF_INIT* initid) { JsonFreeMem((PGLOBAL)initid->ptr); -} // end of json_object_deinit +} // end of json_make_object_deinit /*********************************************************************************/ /* Make a Json Object containing all not null parameters. */ @@ -3623,7 +3643,7 @@ void jsoncontains_path_deinit(UDF_INIT* initid) /*********************************************************************************/ /* This function is used by the json_set/insert/update_item functions. */ /*********************************************************************************/ -static char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, +char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error) { char *p, *path, *str = NULL; @@ -4891,7 +4911,7 @@ void jbin_item_merge_deinit(UDF_INIT* initid) /*********************************************************************************/ /* This function is used by the jbin_set/insert/update functions. */ /*********************************************************************************/ -static char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, +char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error) { char *p, *path; @@ -5306,4 +5326,3 @@ long long countin(UDF_INIT *initid, UDF_ARGS *args, char *result, free(str2); return n; } // end of countin - diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h index 5f4b98a0652d8..53fa555ee089a 100644 --- a/storage/connect/jsonudf.h +++ b/storage/connect/jsonudf.h @@ -1,7 +1,7 @@ /******************** tabjson H Declares Source Code File (.H) *******************/ -/* Name: jsonudf.h Version 1.2 */ +/* Name: jsonudf.h Version 1.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2015-2017 */ /* */ /* This file contains the JSON UDF function and class declares. */ /*********************************************************************************/ @@ -37,9 +37,9 @@ extern "C" { DllExport char *jsonvalue(UDF_EXEC_ARGS); DllExport void jsonvalue_deinit(UDF_INIT*); - DllExport my_bool json_array_init(UDF_INIT*, UDF_ARGS*, char*); - DllExport char *json_array(UDF_EXEC_ARGS); - DllExport void json_array_deinit(UDF_INIT*); + DllExport my_bool json_make_array_init(UDF_INIT*, UDF_ARGS*, char*); + DllExport char *json_make_array(UDF_EXEC_ARGS); + DllExport void json_make_array_deinit(UDF_INIT*); DllExport my_bool json_array_add_values_init(UDF_INIT*, UDF_ARGS*, char*); DllExport char *json_array_add_values(UDF_EXEC_ARGS); @@ -53,9 +53,9 @@ extern "C" { DllExport char *json_array_delete(UDF_EXEC_ARGS); DllExport void json_array_delete_deinit(UDF_INIT*); - DllExport my_bool json_object_init(UDF_INIT*, UDF_ARGS*, char*); - DllExport char *json_object(UDF_EXEC_ARGS); - DllExport void json_object_deinit(UDF_INIT*); + DllExport my_bool json_make_object_init(UDF_INIT*, UDF_ARGS*, char*); + DllExport char *json_make_object(UDF_EXEC_ARGS); + DllExport void json_make_object_deinit(UDF_INIT*); DllExport my_bool json_object_nonull_init(UDF_INIT*, UDF_ARGS*, char*); DllExport char *json_object_nonull(UDF_EXEC_ARGS); diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp new file mode 100644 index 0000000000000..07b8beb8ce706 --- /dev/null +++ b/storage/connect/mongo.cpp @@ -0,0 +1,103 @@ +/************** mongo C++ Program Source Code File (.CPP) **************/ +/* PROGRAM NAME: mongo Version 1.0 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* These programs are the MGODEF class execution routines. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the MariaDB header file. */ +/***********************************************************************/ +#include + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "xtable.h" +#include "tabext.h" +#if defined(MONGO_SUPPORT) +#include "tabmgo.h" +#endif // MONGO_SUPPORT +#if defined(JDBC_SUPPORT) +#include "tabjmg.h" +#endif // JDBC_SUPPORT + +/* -------------------------- Class MGODEF --------------------------- */ + +MGODEF::MGODEF(void) +{ + Driver = NULL; + Uri = NULL; + Colist = NULL; + Filter = NULL; + Level = 0; + Base = 0; + Version = 0; + Pipe = false; +} // end of MGODEF constructor + +/***********************************************************************/ +/* DefineAM: define specific AM block values. */ +/***********************************************************************/ +bool MGODEF::DefineAM(PGLOBAL g, LPCSTR, int poff) +{ + if (EXTDEF::DefineAM(g, "MGO", poff)) + return true; + else if (!Tabschema) + Tabschema = GetStringCatInfo(g, "Dbname", "*"); + +# if !defined(JDBC_SUPPORT) + Driver = "C"; +#elif !defined(MONGO_SUPPORT) + Driver = "JAVA"; +#else + Driver = GetStringCatInfo(g, "Driver", "C"); +#endif + Uri = GetStringCatInfo(g, "Connect", "mongodb://localhost:27017"); + Colist = GetStringCatInfo(g, "Colist", NULL); + Filter = GetStringCatInfo(g, "Filter", NULL); + Base = GetIntCatInfo("Base", 0) ? 1 : 0; + Version = GetIntCatInfo("Version", 3); + + if (Version == 2) + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface"); + else + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface"); + + Pipe = GetBoolCatInfo("Pipeline", false); + return false; +} // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new Table Description Block. */ +/***********************************************************************/ +PTDB MGODEF::GetTable(PGLOBAL g, MODE m) +{ + if (Catfunc == FNC_COL) { +#if defined(MONGO_SUPPORT) + if (Driver && toupper(*Driver) == 'C') + return new(g)TDBGOL(this); +#endif // MONGO_SUPPORT +#if defined(JDBC_SUPPORT) + return new(g)TDBJGL(this); +#else // !JDBC_SUPPORT + strcpy(g->Message, "No column find, no MONGO nor Java support"); + return NULL; +#endif // !JDBC_SUPPORT + } // endif Catfunc + +#if defined(MONGO_SUPPORT) + if (Driver && toupper(*Driver) == 'C') + return new(g) TDBMGO(this); +#endif // MONGO_SUPPORT +#if defined(JDBC_SUPPORT) + return new(g) TDBJMG(this); +#else // !JDBC_SUPPORT + strcpy(g->Message, "No MONGO nor Java support"); + return NULL; +#endif // !JDBC_SUPPORT +} // end of GetTable + diff --git a/storage/connect/mongo.h b/storage/connect/mongo.h new file mode 100644 index 0000000000000..26d83b38bbce4 --- /dev/null +++ b/storage/connect/mongo.h @@ -0,0 +1,63 @@ +/**************** mongo H Declares Source Code File (.H) ***************/ +/* Name: mongo.h Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the common MongoDB classes declares. */ +/***********************************************************************/ +#ifndef __MONGO_H +#define __MONGO_H + +#include "osutil.h" +#include "block.h" +#include "colblk.h" + +typedef class MGODEF *PMGODEF; + +typedef struct _bncol { + struct _bncol *Next; + char *Name; + char *Fmt; + int Type; + int Len; + int Scale; + bool Cbn; + bool Found; +} BCOL, *PBCOL; + +/***********************************************************************/ +/* MongoDB table. */ +/***********************************************************************/ +class DllExport MGODEF : public EXTDEF { /* Table description */ + friend class TDBMGO; + friend class TDBJMG; + friend class TDBGOL; + friend class TDBJGL; + friend class MGOFAM; + friend class MGODISC; + friend PQRYRES MGOColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool); +public: + // Constructor + MGODEF(void); + + // Implementation + virtual const char *GetType(void) { return "MONGO"; } + + // Methods + virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); + virtual PTDB GetTable(PGLOBAL g, MODE m); + +protected: + // Members + PCSZ Driver; /* MongoDB Driver (C or JAVA) */ + PCSZ Uri; /* MongoDB connection URI */ + PSZ Wrapname; /* Java wrapper name */ + PCSZ Colist; /* Options list */ + PCSZ Filter; /* Filtering query */ + int Level; /* Used for catalog table */ + int Base; /* The array index base */ + int Version; /* The Java driver version */ + bool Pipe; /* True is Colist is a pipeline */ +}; // end of MGODEF + +#endif // __MONGO_H diff --git a/storage/connect/mongofam.cpp b/storage/connect/mongofam.cpp new file mode 100644 index 0000000000000..e40ed422d0624 --- /dev/null +++ b/storage/connect/mongofam.cpp @@ -0,0 +1,271 @@ +/************ MONGO FAM C++ Program Source Code File (.CPP) ************/ +/* PROGRAM NAME: mongofam.cpp */ +/* ------------- */ +/* Version 1.3 */ +/* */ +/* COPYRIGHT: */ +/* ---------- */ +/* (C) Copyright to the author Olivier BERTRAND 20017 */ +/* */ +/* WHAT THIS PROGRAM DOES: */ +/* ----------------------- */ +/* This program are the MongoDB access method classes. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the System header files. */ +/***********************************************************************/ +#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. */ +/* filamtxt.h is header containing the file AM classes declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "reldef.h" +#include "filamtxt.h" +#include "tabdos.h" +#include "tabjson.h" +#include "mongofam.h" + +#if defined(UNIX) || defined(UNIV_LINUX) +#include "osutil.h" +#endif + +/* --------------------------- Class MGOFAM -------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +MGOFAM::MGOFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL) +{ + Cmgp = NULL; + Pcg.Tdbp = NULL; + + if (tdp) { + Pcg.Uristr = tdp->Uri; + Pcg.Db_name = tdp->Schema; + Pcg.Coll_name = tdp->Collname; + Pcg.Options = tdp->Options; + Pcg.Filter = tdp->Filter; + Pcg.Pipe = tdp->Pipe && tdp->Options != NULL; + } else { + Pcg.Uristr = NULL; + Pcg.Db_name = NULL; + Pcg.Coll_name = NULL; + Pcg.Options = NULL; + Pcg.Filter = NULL; + Pcg.Pipe = false; + } // endif tdp + + To_Fbt = NULL; + Mode = MODE_ANY; + Done = false; + Lrecl = tdp->Lrecl + tdp->Ending; +} // end of MGOFAM standard constructor + + MGOFAM::MGOFAM(PMGOFAM tdfp) : DOSFAM(tdfp) +{ + Pcg = tdfp->Pcg; + To_Fbt = tdfp->To_Fbt; + Mode = tdfp->Mode; + Done = tdfp->Done; + } // end of MGOFAM copy constructor + +/***********************************************************************/ +/* Reset: reset position values at the beginning of file. */ +/***********************************************************************/ +void MGOFAM::Reset(void) +{ + TXTFAM::Reset(); + Fpos = Tpos = Spos = 0; +} // end of Reset + +/***********************************************************************/ +/* MGO GetFileLength: returns file size in number of bytes. */ +/***********************************************************************/ +int MGOFAM::GetFileLength(PGLOBAL g) +{ + return 0; +} // end of GetFileLength + +/***********************************************************************/ +/* Cardinality: returns the number of documents in the collection. */ +/* This function can be called with a null argument to test the */ +/* availability of Cardinality implementation (1 yes, 0 no). */ +/***********************************************************************/ +int MGOFAM::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + + return (!Init(g)) ? Cmgp->CollSize(g) : 0; +} // end of Cardinality + +/***********************************************************************/ +/* Note: This function is not really implemented yet. */ +/***********************************************************************/ +int MGOFAM::MaxBlkSize(PGLOBAL, int s) +{ + return s; +} // end of MaxBlkSize + +/***********************************************************************/ +/* Init: initialize MongoDB processing. */ +/***********************************************************************/ +bool MGOFAM::Init(PGLOBAL g) +{ + if (Done) + return false; + + /*********************************************************************/ + /* Open an C connection for this table. */ + /*********************************************************************/ + if (!Cmgp) { + Pcg.Tdbp = Tdbp; + Cmgp = new(g) CMgoConn(g, &Pcg); + } else if (Cmgp->IsConnected()) + Cmgp->Close(); + + if (Cmgp->Connect(g)) + return true; + + Done = true; + return false; +} // end of Init + +/***********************************************************************/ +/* OpenTableFile: Open a MongoDB table. */ +/***********************************************************************/ +bool MGOFAM::OpenTableFile(PGLOBAL g) +{ + Mode = Tdbp->GetMode(); + + if (Pcg.Pipe && Mode != MODE_READ) { + strcpy(g->Message, "Pipeline tables are read only"); + return true; + } // endif Pipe + + if (Init(g)) + return true; + + if (Mode == MODE_DELETE && !Tdbp->GetNext()) + // Delete all documents + return Cmgp->DocDelete(g); + else if (Mode == MODE_INSERT) + Cmgp->MakeColumnGroups(g); + + return false; +} // end of OpenTableFile + +/***********************************************************************/ +/* GetRowID: return the RowID of last read record. */ +/***********************************************************************/ +int MGOFAM::GetRowID(void) +{ + return Rows; +} // end of GetRowID + +/***********************************************************************/ +/* GetPos: return the position of last read record. */ +/***********************************************************************/ +int MGOFAM::GetPos(void) +{ + return Fpos; +} // end of GetPos + +/***********************************************************************/ +/* GetNextPos: return the position of next record. */ +/***********************************************************************/ +int MGOFAM::GetNextPos(void) +{ + return Fpos; // TODO +} // end of GetNextPos + +/***********************************************************************/ +/* SetPos: Replace the table at the specified position. */ +/***********************************************************************/ +bool MGOFAM::SetPos(PGLOBAL g, int pos) +{ + Fpos = pos; + Placed = true; + return false; +} // end of SetPos + +/***********************************************************************/ +/* Record file position in case of UPDATE or DELETE. */ +/***********************************************************************/ +bool MGOFAM::RecordPos(PGLOBAL g) +{ + strcpy(g->Message, "MGOFAM::RecordPos NIY"); + return true; +} // end of RecordPos + +/***********************************************************************/ +/* Initialize Fpos and the current position for indexed DELETE. */ +/***********************************************************************/ +int MGOFAM::InitDelete(PGLOBAL g, int fpos, int spos) +{ + strcpy(g->Message, "MGOFAM::InitDelete NIY"); + return RC_FX; +} // end of InitDelete + +/***********************************************************************/ +/* Skip one record in file. */ +/***********************************************************************/ +int MGOFAM::SkipRecord(PGLOBAL g, bool header) +{ + return RC_OK; // Dummy +} // end of SkipRecord + +/***********************************************************************/ +/* ReadBuffer: Get next document from a collection. */ +/***********************************************************************/ +int MGOFAM::ReadBuffer(PGLOBAL g) +{ + int rc = Cmgp->ReadNext(g); + + if (rc != RC_OK) + return rc; + + strncpy(Tdbp->GetLine(), Cmgp->GetDocument(g), Lrecl); + return RC_OK; +} // end of ReadBuffer + +/***********************************************************************/ +/* WriteBuffer: File write routine for MGO access method. */ +/***********************************************************************/ +int MGOFAM::WriteBuffer(PGLOBAL g) +{ + return Cmgp->Write(g); +} // end of WriteBuffer + +/***********************************************************************/ +/* Data Base delete line routine for MGO and BLK access methods. */ +/***********************************************************************/ +int MGOFAM::DeleteRecords(PGLOBAL g, int irc) +{ + return (irc == RC_OK) ? WriteBuffer(g) : RC_OK; +} // end of DeleteRecords + +/***********************************************************************/ +/* Table file close routine for MGO access method. */ +/***********************************************************************/ +void MGOFAM::CloseTableFile(PGLOBAL g, bool) +{ + Cmgp->Close(); + Done = false; +} // end of CloseTableFile + +/***********************************************************************/ +/* Rewind routine for MGO access method. */ +/***********************************************************************/ +void MGOFAM::Rewind(void) +{ + Cmgp->Rewind(); +} // end of Rewind + diff --git a/storage/connect/mongofam.h b/storage/connect/mongofam.h new file mode 100644 index 0000000000000..99cc6128ffdf1 --- /dev/null +++ b/storage/connect/mongofam.h @@ -0,0 +1,65 @@ +/************** MongoFam H Declares Source Code File (.H) **************/ +/* Name: mongofam.h Version 1.4 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the MongoDB access method classes declares. */ +/***********************************************************************/ +#include "cmgoconn.h" + +typedef class TXTFAM *PTXF; +typedef class MGOFAM *PMGOFAM; +typedef class MGODEF *PMGODEF; +typedef class TDBMGO *PTDBMGO; + +/***********************************************************************/ +/* This is the MongoDB Access Method class declaration. */ +/***********************************************************************/ +class DllExport MGOFAM : public DOSFAM { + friend void mongo_init(bool); +public: + // Constructor + MGOFAM(PJDEF tdp); + MGOFAM(PMGOFAM txfp); + + // Implementation + virtual AMT GetAmType(void) { return TYPE_AM_MGO; } + virtual bool GetUseTemp(void) { return false; } + virtual int GetPos(void); + virtual int GetNextPos(void); + void SetTdbp(PTDBDOS tdbp) { Tdbp = tdbp; } + virtual PTXF Duplicate(PGLOBAL g) { return (PTXF)new(g) MGOFAM(this); } + void SetLrecl(int lrecl) { Lrecl = lrecl; } + + // Methods + virtual void Reset(void); + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); + virtual int MaxBlkSize(PGLOBAL g, int s); + virtual bool AllocateBuffer(PGLOBAL g) { return false; } + virtual int GetRowID(void); + virtual bool RecordPos(PGLOBAL g); + virtual bool SetPos(PGLOBAL g, int recpos); + virtual int SkipRecord(PGLOBAL g, bool header); + virtual bool OpenTableFile(PGLOBAL g); + virtual int ReadBuffer(PGLOBAL g); + virtual int WriteBuffer(PGLOBAL g); + virtual int DeleteRecords(PGLOBAL g, int irc); + virtual void CloseTableFile(PGLOBAL g, bool abort); + virtual void Rewind(void); + +protected: + virtual bool OpenTempFile(PGLOBAL g) { return false; } + virtual bool MoveIntermediateLines(PGLOBAL g, bool *b) { return false; } + virtual int RenameTempFile(PGLOBAL g) { return RC_OK; } + virtual int InitDelete(PGLOBAL g, int fpos, int spos); + bool Init(PGLOBAL g); + + // Members + CMgoConn *Cmgp; // Points to a C Mongo connection class + CMGOPARM Pcg; // Parms passed to Cmgp + PFBLOCK To_Fbt; // Pointer to temp file block + MODE Mode; + bool Done; // Init done +}; // end of class MGOFAM + diff --git a/storage/connect/msgid.h b/storage/connect/msgid.h index 0e9c036dc49a4..cee78aa1783b6 100644 --- a/storage/connect/msgid.h +++ b/storage/connect/msgid.h @@ -1,3 +1,4 @@ +/* Copyright (C) MariaDB Corporation Ab */ #define MSG_ACCESS_VIOLATN 200 #define MSG_ADD_BAD_TYPE 201 #define MSG_ALLOC_ERROR 202 diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 750cf3c0639cc..906ac734157bb 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2017 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -86,7 +86,7 @@ #if defined(JDBC_SUPPORT) #define NJDBC #include "tabjdbc.h" -#endif // ODBC_SUPPORT +#endif // JDBC_SUPPORT #if defined(PIVOT_SUPPORT) #include "tabpivot.h" #endif // PIVOT_SUPPORT @@ -96,6 +96,9 @@ #if defined(XML_SUPPORT) #include "tabxml.h" #endif // XML_SUPPORT +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) +#include "mongo.h" +#endif // MONGO_SUPPORT || JDBC_SUPPORT #if defined(ZIP_SUPPORT) #include "tabzip.h" #endif // ZIP_SUPPORT @@ -130,21 +133,21 @@ TABTYPE GetTypeID(const char *type) : (!stricmp(type, "CSV")) ? TAB_CSV : (!stricmp(type, "FMT")) ? TAB_FMT : (!stricmp(type, "DBF")) ? TAB_DBF -#ifdef XML_SUPPORT +#if defined(XML_SUPPORT) : (!stricmp(type, "XML")) ? TAB_XML #endif : (!stricmp(type, "INI")) ? TAB_INI : (!stricmp(type, "VEC")) ? TAB_VEC -#ifdef ODBC_SUPPORT +#if defined(ODBC_SUPPORT) : (!stricmp(type, "ODBC")) ? TAB_ODBC #endif -#ifdef JDBC_SUPPORT +#if defined(JDBC_SUPPORT) : (!stricmp(type, "JDBC")) ? TAB_JDBC #endif : (!stricmp(type, "MYSQL")) ? TAB_MYSQL : (!stricmp(type, "MYPRX")) ? TAB_MYSQL : (!stricmp(type, "DIR")) ? TAB_DIR -#ifdef __WIN__ +#if defined(__WIN__) : (!stricmp(type, "MAC")) ? TAB_MAC : (!stricmp(type, "WMI")) ? TAB_WMI #endif @@ -153,13 +156,16 @@ TABTYPE GetTypeID(const char *type) : (!stricmp(type, "OCCUR")) ? TAB_OCCUR : (!stricmp(type, "CATLG")) ? TAB_PRX // Legacy : (!stricmp(type, "PROXY")) ? TAB_PRX -#ifdef PIVOT_SUPPORT +#if defined(PIVOT_SUPPORT) : (!stricmp(type, "PIVOT")) ? TAB_PIVOT #endif : (!stricmp(type, "VIR")) ? TAB_VIR : (!stricmp(type, "JSON")) ? TAB_JSON -#ifdef ZIP_SUPPORT +#if defined(ZIP_SUPPORT) : (!stricmp(type, "ZIP")) ? TAB_ZIP +#endif +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + : (!stricmp(type, "MONGO")) ? TAB_MONGO #endif : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY; } // end of GetTypeID @@ -307,6 +313,7 @@ int GetIndexType(TABTYPE type) case TAB_MYSQL: case TAB_ODBC: case TAB_JDBC: + case TAB_MONGO: xtyp= 2; break; case TAB_VIR: @@ -550,6 +557,9 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) #endif // PIVOT_SUPPORT case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break; +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + case TAB_MONGO: tdp = new(g) MGODEF; break; +#endif // MONGO_SUPPORT || JDBC_SUPPORT #if defined(ZIP_SUPPORT) case TAB_ZIP: tdp= new(g) ZIPDEF; break; #endif // ZIP_SUPPORT diff --git a/storage/connect/mycat.h b/storage/connect/mycat.h index b6bdd5e5e11e7..f0f889722dd3a 100644 --- a/storage/connect/mycat.h +++ b/storage/connect/mycat.h @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2015 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ /**************** MYCAT H Declares Source Code File (.H) ***************/ /* Name: MYCAT.H Version 2.3 */ -/* */ +/* Author: Olivier Bertrand */ /* This file contains the CONNECT plugin MYCAT class definitions. */ /***********************************************************************/ #ifndef __MYCAT__H @@ -47,6 +47,7 @@ struct ha_table_option_struct { const char *catfunc; const char *srcdef; const char *colist; + const char *filter; const char *oplist; const char *data_charset; ulonglong lrecl; diff --git a/storage/connect/mysql-test/connect/disabled.def b/storage/connect/mysql-test/connect/disabled.def index 64d7ece3fe144..217e61e00b64d 100644 --- a/storage/connect/mysql-test/connect/disabled.def +++ b/storage/connect/mysql-test/connect/disabled.def @@ -13,6 +13,5 @@ jdbc : Variable settings depend on machine configuration jdbc_new : Variable settings depend on machine configuration jdbc_oracle : Variable settings depend on machine configuration jdbc_postgresql : Variable settings depend on machine configuration -json : TABLE_TYPE = JSON conflicts with the SQL syntax -json_udf : conflicts with the server JSON functions -json_udf_bin : conflicts with the server JSON functions +json_mgo : Need MongoDB running and its C Driver installed +mongo : Need MongoDB running and its C Driver installed diff --git a/storage/connect/mysql-test/connect/r/alter_xml.result b/storage/connect/mysql-test/connect/r/alter_xml.result index f2250b78d2dbc..7cdb1e5d21cd5 100644 --- a/storage/connect/mysql-test/connect/r/alter_xml.result +++ b/storage/connect/mysql-test/connect/r/alter_xml.result @@ -1,5 +1,3 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml # # Testing changing table type (not in-place) # @@ -16,7 +14,7 @@ c d # This is because the XML top node name defaults to the table name. # Sure enough the temporary table name begins with '#' and is rejected by XML. # Therefore the top node name must be specified (along with the row nodes name). -ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='rownode=row'; +ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=domdoc,rownode=row'; SELECT * FROM t1; c d 1 One @@ -27,7 +25,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `c` int(11) NOT NULL, `d` char(10) NOT NULL -) ENGINE=CONNECT DEFAULT CHARSET=latin1 `HEADER`=1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='rownode=row' +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `HEADER`=1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=domdoc,rownode=row' # Let us see the XML file CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.xml'; Warnings: @@ -67,7 +65,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `c` int(11) NOT NULL, `d` char(10) NOT NULL `FIELD_FORMAT`='@' -) ENGINE=CONNECT DEFAULT CHARSET=latin1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='rownode=row' `HEADER`=0 +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=domdoc,rownode=row' `HEADER`=0 SELECT * FROM t2; line diff --git a/storage/connect/mysql-test/connect/r/alter_xml2.result b/storage/connect/mysql-test/connect/r/alter_xml2.result new file mode 100644 index 0000000000000..8eb56e3dcc3af --- /dev/null +++ b/storage/connect/mysql-test/connect/r/alter_xml2.result @@ -0,0 +1,86 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +# +# Testing changing table type (not in-place) +# +CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1 QUOTED=1; +Warnings: +Warning 1105 No file name. Table will use t1.csv +INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three'); +SELECT * FROM t1; +c d +1 One +2 Two +3 Three +# This would fail if the top node name is not specified. +# This is because the XML top node name defaults to the table name. +# Sure enough the temporary table name begins with '#' and is rejected by XML. +# Therefore the top node name must be specified (along with the row nodes name). +ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=libxml2,rownode=row'; +SELECT * FROM t1; +c d +1 One +2 Two +3 Three +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` int(11) NOT NULL, + `d` char(10) NOT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `HEADER`=1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=libxml2,rownode=row' +# Let us see the XML file +CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.xml'; +Warnings: +Warning 1105 No table_type. Will be set to DOS +SELECT * FROM t2; +line + + + + + c + d + + + 1 + One + + + 2 + Two + + + 3 + Three + + +# NOTE: The first (ignored) row is due to the remaining HEADER=1 option. +# Testing field option modification +ALTER TABLE t1 MODIFY d CHAR(10) NOT NULL FIELD_FORMAT='@', HEADER=0; +SELECT * FROM t1; +c d +1 One +2 Two +3 Three +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` int(11) NOT NULL, + `d` char(10) NOT NULL `FIELD_FORMAT`='@' +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=libxml2,rownode=row' `HEADER`=0 +SELECT * FROM t2; +line + + + + + 1 + + + 2 + + + 3 + + +DROP TABLE t1, t2; diff --git a/storage/connect/mysql-test/connect/r/dir.result b/storage/connect/mysql-test/connect/r/dir.result index 99556c9b72dff..e10bb458d62f0 100644 --- a/storage/connect/mysql-test/connect/r/dir.result +++ b/storage/connect/mysql-test/connect/r/dir.result @@ -25,9 +25,8 @@ SELECT fname, ftype, size FROM t1 ORDER BY fname, ftype, size; fname ftype size boys .txt 282 boyswin .txt 288 -SET STATEMENT sql_mode = '' FOR INSERT INTO t1 VALUES ('','','',''); -ERROR HY000: Got error 174 'COLBLK SetBuffer: undefined Access Method' from CONNECT +ERROR 22007: Incorrect double value: '' for column 'size' at row 1 DROP TABLE t1; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.txt'; ERROR HY000: Cannot get column info for table type DIR diff --git a/storage/connect/mysql-test/connect/r/infoschema-9739.result b/storage/connect/mysql-test/connect/r/infoschema-9739.result index bcebec1d0e0ad..992f4ed0d583b 100644 --- a/storage/connect/mysql-test/connect/r/infoschema-9739.result +++ b/storage/connect/mysql-test/connect/r/infoschema-9739.result @@ -1,6 +1,4 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml -create table t1 (i int) engine=Connect table_type=XML; +create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=domdoc'; Warnings: Warning 1105 No file name. Table will use t1.xml select * from information_schema.tables where create_options like '%table_type=XML%'; diff --git a/storage/connect/mysql-test/connect/r/infoschema2-9739.result b/storage/connect/mysql-test/connect/r/infoschema2-9739.result new file mode 100644 index 0000000000000..7d8a6839ea5f2 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/infoschema2-9739.result @@ -0,0 +1,12 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=libxml2'; +Warnings: +Warning 1105 No file name. Table will use t1.xml +select * from information_schema.tables where create_options like '%table_type=XML%'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT +Warnings: +Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' +Warning 1296 Got error 174 'File t1.xml not found' from CONNECT +drop table t1; diff --git a/storage/connect/mysql-test/connect/r/jdbc_new.result b/storage/connect/mysql-test/connect/r/jdbc_new.result index 6f97716659807..33d8bd3b7d86c 100644 --- a/storage/connect/mysql-test/connect/r/jdbc_new.result +++ b/storage/connect/mysql-test/connect/r/jdbc_new.result @@ -1,3 +1,7 @@ +connect master,127.0.0.1,root,,test,$MASTER_MYPORT,; +connect slave,127.0.0.1,root,,test,$SLAVE_MYPORT,; +connection master; +connection slave; SET GLOBAL time_zone='+1:00'; CREATE TABLE t1 (a int, b char(10)); INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03'); @@ -11,6 +15,7 @@ NULL NULL # # Testing errors # +connection master; SET GLOBAL time_zone='+1:00'; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=unknown'; @@ -36,10 +41,14 @@ ERROR HY000: Got error 174 'ExecuteQuery: java.sql.SQLSyntaxErrorException: Unkn DROP TABLE t1; CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root'; +connection slave; ALTER TABLE t1 RENAME t1backup; +connection master; SELECT * FROM t1; ERROR HY000: Got error 174 'ExecuteQuery: java.sql.SQLSyntaxErrorException: Table 'test.t1' doesn't exist' from CONNECT +connection slave; ALTER TABLE t1backup RENAME t1; +connection master; DROP TABLE t1; # # Testing SELECT, etc. @@ -108,6 +117,7 @@ NULL NULL 2 0 3 0 DROP TABLE t1; +connection slave; DROP TABLE t1; # # Testing numeric data types @@ -126,6 +136,7 @@ t1 CREATE TABLE `t1` ( `h` decimal(20,5) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265); +connection master; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root'; SHOW CREATE TABLE t1; @@ -144,6 +155,7 @@ SELECT * FROM t1; a b c d e f g h 100 3333 41235 1234567890 235000000000 3 3 3141.59265 DROP TABLE t1; +connection slave; DROP TABLE t1; # # Testing character data types @@ -159,6 +171,7 @@ INSERT INTO t1 VALUES('Welcome','Hello, World'); SELECT * FROM t1; a b Welcome Hello, World +connection master; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root'; SHOW CREATE TABLE t1; @@ -171,6 +184,7 @@ SELECT * FROM t1; a b Welcome Hello, World DROP TABLE t1; +connection slave; DROP TABLE t1; # # Testing temporal data types @@ -182,10 +196,10 @@ t1 CREATE TABLE `t1` ( `a` date DEFAULT NULL, `b` datetime DEFAULT NULL, `c` time DEFAULT NULL, - `d` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `e` year(4) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -INSERT INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23'); +INSERT IGNORE INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23'); Warnings: Note 1265 Data truncated for column 'a' at row 1 Note 1265 Data truncated for column 'c' at row 1 @@ -193,6 +207,7 @@ Warning 1265 Data truncated for column 'e' at row 1 SELECT * FROM t1; a b c d e 2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003 +connection master; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root'; SHOW CREATE TABLE t1; @@ -201,13 +216,15 @@ t1 CREATE TABLE `t1` ( `a` date DEFAULT NULL, `b` datetime DEFAULT NULL, `c` time DEFAULT NULL, - `d` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `e` year(4) DEFAULT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root' `TABLE_TYPE`='JDBC' SELECT * FROM t1; a b c d e 2003-05-27 2003-05-27 11:45:23 10:45:23 2003-05-27 10:45:23 2003 DROP TABLE t1; +connection slave; DROP TABLE t1; SET GLOBAL time_zone=SYSTEM; +connection master; SET GLOBAL time_zone=SYSTEM; diff --git a/storage/connect/mysql-test/connect/r/json.result b/storage/connect/mysql-test/connect/r/json.result index aa6b04c58c76b..6b6f40d2c4777 100644 --- a/storage/connect/mysql-test/connect/r/json.result +++ b/storage/connect/mysql-test/connect/r/json.result @@ -24,15 +24,15 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15), -Language CHAR(2) FIELD_FORMAT='LANG', -Subject CHAR(32) FIELD_FORMAT='SUBJECT', -Authors INT(2) FIELD_FORMAT='AUTHOR:[#]', -Title CHAR(32) FIELD_FORMAT='TITLE', -Translation CHAR(32) FIELD_FORMAT='TRANSLATION', -Translator CHAR(80) FIELD_FORMAT='TRANSLATOR', -Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', -Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', -Year int(4) FIELD_FORMAT='DATEPUB' +Language CHAR(2) FIELD_FORMAT='$.LANG', +Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', +Authors INT(2) FIELD_FORMAT='$.AUTHOR[#]', +Title CHAR(32) FIELD_FORMAT='$.TITLE', +Translation CHAR(32) FIELD_FORMAT='$.TRANSLATION', +Translator CHAR(80) FIELD_FORMAT='$.TRANSLATOR', +Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', +Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', +Year int(4) FIELD_FORMAT='$.DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; SELECT * FROM t1; @@ -46,16 +46,16 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15), -Language CHAR(2) FIELD_FORMAT='LANG', -Subject CHAR(32) FIELD_FORMAT='SUBJECT', -AuthorFN CHAR(128) FIELD_FORMAT='AUTHOR:[" and "]:FIRSTNAME', -AuthorLN CHAR(128) FIELD_FORMAT='AUTHOR:[" and "]:LASTNAME', -Title CHAR(32) FIELD_FORMAT='TITLE', -Translation CHAR(32) FIELD_FORMAT='TRANSLATION', -Translator CHAR(80) FIELD_FORMAT='TRANSLATOR', -Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', -Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', -Year int(4) FIELD_FORMAT='DATEPUB' +Language CHAR(2) FIELD_FORMAT='$.LANG', +Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', +AuthorFN CHAR(128) FIELD_FORMAT='$.AUTHOR[" and "].FIRSTNAME', +AuthorLN CHAR(128) FIELD_FORMAT='$.AUTHOR[" and "].LASTNAME', +Title CHAR(32) FIELD_FORMAT='$.TITLE', +Translation CHAR(32) FIELD_FORMAT='$.TRANSLATION', +Translator CHAR(80) FIELD_FORMAT='$.TRANSLATOR', +Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', +Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', +Year int(4) FIELD_FORMAT='$.DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; SELECT * FROM t1; @@ -69,16 +69,16 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15), -Language CHAR(2) FIELD_FORMAT='LANG', -Subject CHAR(32) FIELD_FORMAT='SUBJECT', -AuthorFN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:FIRSTNAME', -AuthorLN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:LASTNAME', -Title CHAR(32) FIELD_FORMAT='TITLE', -Translation CHAR(32) FIELD_FORMAT='TRANSLATION', -Translator CHAR(80) FIELD_FORMAT='TRANSLATOR', -Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', -Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', -Year int(4) FIELD_FORMAT='DATEPUB' +Language CHAR(2) FIELD_FORMAT='$.LANG', +Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', +AuthorFN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].FIRSTNAME', +AuthorLN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].LASTNAME', +Title CHAR(32) FIELD_FORMAT='$.TITLE', +Translation CHAR(32) FIELD_FORMAT='$.TRANSLATION', +Translator CHAR(80) FIELD_FORMAT='$.TRANSLATOR', +Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', +Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', +Year int(4) FIELD_FORMAT='$.DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; SELECT * FROM t1; @@ -97,7 +97,7 @@ ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher L CREATE TABLE t2 ( FIRSTNAME CHAR(32), LASTNAME CHAR(32)) -ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json' OPTION_LIST='Object=[1]:AUTHOR'; +ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json' OPTION_LIST='Object=$[1].AUTHOR'; SELECT * FROM t2; FIRSTNAME LASTNAME William J. Pardi @@ -176,17 +176,17 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15) NOT NULL, -Language CHAR(2) FIELD_FORMAT='LANG', -Subject CHAR(32) FIELD_FORMAT='SUBJECT', -AuthorFN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:FIRSTNAME', -AuthorLN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:LASTNAME', -Title CHAR(32) FIELD_FORMAT='TITLE', -Translation CHAR(32) FIELD_FORMAT='TRANSLATED:PREFIX', -TranslatorFN CHAR(80) FIELD_FORMAT='TRANSLATED:TRANSLATOR:FIRSTNAME', -TranslatorLN CHAR(80) FIELD_FORMAT='TRANSLATED:TRANSLATOR:LASTNAME', -Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', -Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', -Year int(4) FIELD_FORMAT='DATEPUB', +Language CHAR(2) FIELD_FORMAT='$.LANG', +Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', +AuthorFN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].FIRSTNAME', +AuthorLN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].LASTNAME', +Title CHAR(32) FIELD_FORMAT='$.TITLE', +Translation CHAR(32) FIELD_FORMAT='$.TRANSLATED.PREFIX', +TranslatorFN CHAR(80) FIELD_FORMAT='$.TRANSLATED.TRANSLATOR.FIRSTNAME', +TranslatorLN CHAR(80) FIELD_FORMAT='$.TRANSLATED.TRANSLATOR.LASTNAME', +Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', +Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', +Year int(4) FIELD_FORMAT='$.DATEPUB', INDEX IX(ISBN) ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bib0.json' LRECL=320 OPTION_LIST='Pretty=0'; @@ -209,9 +209,9 @@ DROP TABLE t1; # CREATE TABLE t1 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[X]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK::EXPENSE:["+"]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK::EXPENSE:[+]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[*].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[].EXPENSE["+"].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[].EXPENSE[+].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t1; WHO WEEK WHAT AMOUNT @@ -230,9 +230,9 @@ DROP TABLE t1; # CREATE TABLE t1 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[X]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[*].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[*].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[*].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t1; WHO WEEK WHAT AMOUNT @@ -266,14 +266,14 @@ DROP TABLE t1; # CREATE TABLE t1 ( WHO CHAR(12) NOT NULL, -WEEKS CHAR(12) NOT NULL FIELD_FORMAT='WEEK:[", "]:NUMBER', -SUMS CHAR(64) NOT NULL FIELD_FORMAT='WEEK:["+"]:EXPENSE:[+]:AMOUNT', -SUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[+]:EXPENSE:[+]:AMOUNT', -AVGS CHAR(64) NOT NULL FIELD_FORMAT='WEEK:["+"]:EXPENSE:[!]:AMOUNT', -SUMAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[+]:EXPENSE:[!]:AMOUNT', -AVGSUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[!]:EXPENSE:[+]:AMOUNT', -AVGAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[!]:EXPENSE:[!]:AMOUNT', -AVERAGE DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[!]:EXPENSE:[X]:AMOUNT') +WEEKS CHAR(12) NOT NULL FIELD_FORMAT='$.WEEK[", "].NUMBER', +SUMS CHAR(64) NOT NULL FIELD_FORMAT='$.WEEK["+"].EXPENSE[+].AMOUNT', +SUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[+].EXPENSE[+].AMOUNT', +AVGS CHAR(64) NOT NULL FIELD_FORMAT='$.WEEK["+"].EXPENSE[!].AMOUNT', +SUMAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[+].EXPENSE[!].AMOUNT', +AVGSUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[!].EXPENSE[+].AMOUNT', +AVGAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[!].EXPENSE[!].AMOUNT', +AVERAGE DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[!].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t1; WHO WEEKS SUMS SUM AVGS SUMAVG AVGSUM AVGAVG AVERAGE @@ -286,9 +286,9 @@ DROP TABLE t1; # CREATE TABLE t2 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[0]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[0]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[0]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[0].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[0].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[0].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t2; WHO WEEK WHAT AMOUNT @@ -302,9 +302,9 @@ Janet 3 Food 18.00 Janet 3 Beer 18.00 CREATE TABLE t3 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[1]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[1]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[1]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[1].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[1].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[1].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t3; WHO WEEK WHAT AMOUNT @@ -318,9 +318,9 @@ Beth 4 Beer 15.00 Janet 4 Car 17.00 CREATE TABLE t4 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[2]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[2]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[2]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[2].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[2].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[2].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t4; WHO WEEK WHAT AMOUNT @@ -374,8 +374,8 @@ DROP TABLE t1, t2, t3, t4; CREATE TABLE t2 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp3.json'; SELECT * FROM t2; WHO WEEK WHAT AMOUNT @@ -390,8 +390,8 @@ Janet 3 Beer 18.00 CREATE TABLE t3 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp4.json'; SELECT * FROM t3; WHO WEEK WHAT AMOUNT @@ -406,8 +406,8 @@ Janet 4 Car 17.00 CREATE TABLE t4 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp5.json'; SELECT * FROM t4; WHO WEEK WHAT AMOUNT @@ -425,8 +425,8 @@ Janet 5 Food 12.00 CREATE TABLE t1 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp*.json' MULTIPLE=1; SELECT * FROM t1 ORDER BY WHO, WEEK, WHAT, AMOUNT; WHO WEEK WHAT AMOUNT @@ -461,8 +461,8 @@ DROP TABLE t1; CREATE TABLE t1 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp%s.json'; ALTER TABLE t1 PARTITION BY LIST COLUMNS(WEEK) ( diff --git a/storage/connect/mysql-test/connect/r/json_udf.result b/storage/connect/mysql-test/connect/r/json_udf.result index 1e83834cb8f1d..a36d3fe539d11 100644 --- a/storage/connect/mysql-test/connect/r/json_udf.result +++ b/storage/connect/mysql-test/connect/r/json_udf.result @@ -35,18 +35,18 @@ JsonValue('[11, 22, 33]' json_) [11,22,33] [11,22,33] [11,22,33] -SELECT Json_Array(); -Json_Array() +SELECT Json_Make_Array(); +Json_Make_Array() [] -SELECT Json_Array(56, 3.1416, 'My name is "Foo"', NULL); -Json_Array(56, 3.1416, 'My name is "Foo"', NULL) +SELECT Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL); +Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL) [56,3.141600,"My name is \"Foo\"",null] -SELECT Json_Array(Json_Array(56, 3.1416, 'foo'), TRUE); -Json_Array(Json_Array(56, 3.1416, 'foo'), TRUE) +SELECT Json_Make_Array(Json_Make_Array(56, 3.1416, 'foo'), TRUE); +Json_Make_Array(Json_Make_Array(56, 3.1416, 'foo'), TRUE) [[56,3.141600,"foo"],true] -SELECT Json_Array_Add(Json_Array(56, 3.1416, 'foo', NULL)) Array; +SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL)) Array; ERROR HY000: Can't initialize function 'json_array_add'; This function must have at least 2 arguments -SELECT Json_Array_Add(Json_Array(56, 3.1416, 'foo', NULL), 'One more') Array; +SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Array; Array [56,3.141600,"foo",null,"One more"] SELECT Json_Array_Add(JsonValue('one value'), 'One more'); @@ -70,33 +70,33 @@ Array SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 9); Json_Array_Add('[5,3,8,7,9]' json_, 4, 9) [5,3,8,7,9,4] -SELECT Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), '[2]', 33, 1); -Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), '[2]', 33, 1) +SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), '[2]', 33, 1); +Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), '[2]', 33, 1) [1,2,[11,22],"[2]"] -SELECT Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), 33, '[2]', 1); -Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), 33, '[2]', 1) +SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, '[2]', 1); +Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, '[2]', 1) [1,2,[11,33,22]] -SELECT Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), 33, 1, '[2]'); -Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), 33, 1, '[2]') +SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, 1, '[2]'); +Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, 1, '[2]') [1,2,[11,33,22]] -SELECT Json_Array_Add_Values(Json_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array; +SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array; Array [56,3.141600,"machin",null,"One more","Two more"] -SELECT Json_Array_Add_Values(Json_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1; +SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1; Array [56,3.141600,"machin","One more","Two more"] [56,3.141600,"machin","One more","Two more"] [56,3.141600,"machin","One more","Two more"] [56,3.141600,"machin","One more","Two more"] [56,3.141600,"machin","One more","Two more"] -SELECT Json_Array_Add_Values(Json_Array(56, 3.1416, 'machin'), n) Array FROM t1; +SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), n) Array FROM t1; Array [56,3.141600,"machin",1] [56,3.141600,"machin",2] [56,3.141600,"machin",3] [56,3.141600,"machin",4] [56,3.141600,"machin",5] -SELECT Json_Array_Add_Values(Json_Array(n, 3.1416, 'machin'), n) Array FROM t1; +SELECT Json_Array_Add_Values(Json_Make_Array(n, 3.1416, 'machin'), n) Array FROM t1; Array [1,3.141600,"machin",1] [2,3.141600,"machin",2] @@ -106,49 +106,49 @@ Array SELECT Json_Array_Add_Values('[56]', 3.1416, 'machin') Array; Array [56,3.141600,"machin"] -SELECT Json_Array_Delete(Json_Array(56, 3.1416, 'My name is "Foo"', NULL), 0); -Json_Array_Delete(Json_Array(56, 3.1416, 'My name is "Foo"', NULL), 0) +SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0); +Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0) [3.141600,"My name is \"Foo\"",null] -SELECT Json_Array_Delete(Json_Object(56, 3.1416, 'My name is Foo', NULL), 2); -Json_Array_Delete(Json_Object(56, 3.1416, 'My name is Foo', NULL), 2) +SELECT Json_Array_Delete(Json_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2); +Json_Array_Delete(Json_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2) {"56":56,"3.1416":3.141600,"My name is Foo":"My name is Foo","NULL":null} Warnings: Warning 1105 First argument target is not an array -SELECT Json_Array_Delete(Json_Array(56, 3.1416, 'My name is "Foo"', NULL), '2'); -Json_Array_Delete(Json_Array(56, 3.1416, 'My name is "Foo"', NULL), '2') +SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2'); +Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2') [56,3.141600,"My name is \"Foo\"",null] Warnings: Warning 1105 Missing or null array index -SELECT Json_Array_Delete(json_array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2); -Json_Array_Delete(json_array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2) +SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2); +Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2) [56,3.141600,"My name is \"Foo\"",null] Warnings: -Warning 1105 No sub-item at '2' -SELECT Json_Object(56, 3.1416, 'foo', NULL); -Json_Object(56, 3.1416, 'foo', NULL) +Warning 1105 First argument target is not an array +SELECT Json_Make_Object(56, 3.1416, 'foo', NULL); +Json_Make_Object(56, 3.1416, 'foo', NULL) {"56":56,"3.1416":3.141600,"foo":"foo","NULL":null} -SELECT Json_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty); -Json_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty) +SELECT Json_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty); +Json_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty) {"qty":56,"price":3.141600,"truc":"foo","garanty":null} -SELECT Json_Object(); -Json_Object() +SELECT Json_Make_Object(); +Json_Make_Object() {} -SELECT Json_Object(Json_Array(56, 3.1416, 'foo'), NULL); -Json_Object(Json_Array(56, 3.1416, 'foo'), NULL) -{"Array(56, 3.1416, 'foo')":[56,3.141600,"foo"],"NULL":null} -SELECT Json_Array(Json_Object(56 "qty", 3.1416 "price", 'foo') ,NULL); -Json_Array(Json_Object(56 "qty", 3.1416 "price", 'foo') ,NULL) +SELECT Json_Make_Object(Json_Make_Array(56, 3.1416, 'foo'), NULL); +Json_Make_Object(Json_Make_Array(56, 3.1416, 'foo'), NULL) +{"Make_Array(56, 3.1416, 'foo')":[56,3.141600,"foo"],"NULL":null} +SELECT Json_Make_Array(Json_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL); +Json_Make_Array(Json_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL) [{"qty":56,"price":3.141600,"foo":"foo"},null] SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL); Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL) {"qty":56,"price":3.141600,"truc":"machin","garanty":null} SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty'); ERROR HY000: Can't initialize function 'json_object_key'; This function must have an even number of arguments -SELECT Json_Object_Add(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color); -Json_Object_Add(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color) +SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color); +Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color) {"qty":56,"price":3.141600,"truc":"machin","garanty":null,"color":"blue"} -SELECT Json_Object_Add(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price); -Json_Object_Add(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price) +SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price); +Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price) {"qty":56,"price":45.990000,"truc":"machin","garanty":null} SELECT Json_Object_Add(Json_File('notexist.json'), 'cheese' item, '[1]', 1); Json_Object_Add(Json_File('notexist.json'), 'cheese' item, '[1]', 1) @@ -156,13 +156,13 @@ NULL Warnings: Warning 1105 Error 2 opening notexist.json Warning 1105 First argument target is not an object -SELECT Json_Object_Delete(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc'); -Json_Object_Delete(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc') +SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc'); +Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc') {"qty":56,"price":3.141600,"garanty":null} -SELECT Json_Object_Delete(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose'); -Json_Object_Delete(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose') +SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose'); +Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose') {"qty":56,"price":3.141600,"truc":"machin","garanty":null} -SELECT Json_Object_List(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List"; +SELECT Json_Object_List(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List"; Key List ["qty","price","truc","garanty"] SELECT Json_Object_List('{"qty":56, "price":3.1416, "truc":"machin", "garanty":null}') "Key List"; @@ -183,12 +183,12 @@ TRANSLATOR CHAR(80), PUBLISHER CHAR(32), DATEPUB int(4) ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; -SELECT Json_Array(AUTHOR, TITLE, DATEPUB) FROM t2; -Json_Array(AUTHOR, TITLE, DATEPUB) +SELECT Json_Make_Array(AUTHOR, TITLE, DATEPUB) FROM t2; +Json_Make_Array(AUTHOR, TITLE, DATEPUB) ["Jean-Christophe Bernadac","Construire une application XML",1999] ["William J. Pardi","XML en Action",1999] -SELECT Json_Object(AUTHOR, TITLE, DATEPUB) FROM t2; -Json_Object(AUTHOR, TITLE, DATEPUB) +SELECT Json_Make_Object(AUTHOR, TITLE, DATEPUB) FROM t2; +Json_Make_Object(AUTHOR, TITLE, DATEPUB) {"AUTHOR":"Jean-Christophe Bernadac","TITLE":"Construire une application XML","DATEPUB":1999} {"AUTHOR":"William J. Pardi","TITLE":"XML en Action","DATEPUB":1999} SELECT Json_Array_Grp(TITLE, DATEPUB) FROM t2; @@ -206,8 +206,8 @@ DEPARTMENT CHAr(4) NOT NULL FLAG=41, SECRETARY CHAR(5) DEFAULT NULL FLAG=46, SALARY DOUBLE(8,2) NOT NULL FLAG=52 ) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=8 FILE_NAME='employee.dat' ENDING=1; -SELECT Json_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT'; -Json_Object(SERIALNO, NAME, TITLE, SALARY) +SELECT Json_Make_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT'; +Json_Make_Object(SERIALNO, NAME, TITLE, SALARY) {"SERIALNO":"78943","NAME":"MERCHANT","TITLE":"SALESMAN","SALARY":8700.000000} SELECT DEPARTMENT, Json_Array_Grp(NAME) FROM t3 GROUP BY DEPARTMENT; DEPARTMENT Json_Array_Grp(NAME) @@ -220,8 +220,8 @@ Warning 1105 Result truncated to json_grp_size values SELECT JsonSet_Grp_Size(30); JsonSet_Grp_Size(30) 30 -SELECT Json_Object(title, Json_Array_Grp(name) `json_names`) from t3 GROUP BY title; -Json_Object(title, Json_Array_Grp(name) `json_names`) +SELECT Json_Make_Object(title, Json_Array_Grp(name) `json_names`) from t3 GROUP BY title; +Json_Make_Object(title, Json_Array_Grp(name) `json_names`) {"title":"ADMINISTRATOR","names":["GOOSEPEN","FUNNIGUY","SHRINKY"]} {"title":"DIRECTOR","names":["QUINN","WERTHER","STRONG"]} {"title":"ENGINEER","names":["BROWNY","ORELLY","MARTIN","TONGHO","WALTER","SMITH"]} @@ -230,26 +230,26 @@ Json_Object(title, Json_Array_Grp(name) `json_names`) {"title":"SCIENTIST","names":["BIGHEAD","BIGHORN"]} {"title":"SECRETARY","names":["MESSIFUL","HONEY","SHORTSIGHT","CHERRY","MONAPENNY"]} {"title":"TYPIST","names":["KITTY","PLUMHEAD"]} -SELECT Json_Array(DEPARTMENT, Json_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT; -Json_Array(DEPARTMENT, Json_Array_Grp(NAME)) +SELECT Json_Make_Array(DEPARTMENT, Json_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT; +Json_Make_Array(DEPARTMENT, Json_Array_Grp(NAME)) ["0021",["STRONG","SHORTSIGHT"]] ["0318",["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]] ["0319",["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL","GOOSEPEN"]] ["2452",["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]] -SELECT Json_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT; -Json_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) +SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT; +Json_Make_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) {"DEPARTMENT":"0021","NAMES":["STRONG","SHORTSIGHT"]} {"DEPARTMENT":"0318","NAMES":["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]} {"DEPARTMENT":"0319","NAMES":["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL","GOOSEPEN"]} {"DEPARTMENT":"2452","NAMES":["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]} -SELECT Json_Object(DEPARTMENT, Json_Array_Grp(Json_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT; -Json_Object(DEPARTMENT, Json_Array_Grp(Json_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) +SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT; +Json_Make_Object(DEPARTMENT, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) {"DEPARTMENT":"0021","EMPLOYES":[{"SERIALNO":"87777","NAME":"STRONG","TITLE":"DIRECTOR","SALARY":23000.000000},{"SERIALNO":"22222","NAME":"SHORTSIGHT","TITLE":"SECRETARY","SALARY":5500.000000}]} {"DEPARTMENT":"0318","EMPLOYES":[{"SERIALNO":"74200","NAME":"BANCROFT","TITLE":"SALESMAN","SALARY":9600.000000},{"SERIALNO":"24888","NAME":"PLUMHEAD","TITLE":"TYPIST","SALARY":2800.000000},{"SERIALNO":"27845","NAME":"HONEY","TITLE":"SECRETARY","SALARY":4900.000000},{"SERIALNO":"73452","NAME":"TONGHO","TITLE":"ENGINEER","SALARY":6800.000000},{"SERIALNO":"74234","NAME":"WALTER","TITLE":"ENGINEER","SALARY":7400.000000},{"SERIALNO":"77777","NAME":"SHRINKY","TITLE":"ADMINISTRATOR","SALARY":7500.000000},{"SERIALNO":"70012","NAME":"WERTHER","TITLE":"DIRECTOR","SALARY":14500.000000},{"SERIALNO":"78943","NAME":"MERCHANT","TITLE":"SALESMAN","SALARY":8700.000000},{"SERIALNO":"73111","NAME":"WHEELFOR","TITLE":"SALESMAN","SALARY":10030.000000}]} {"DEPARTMENT":"0319","EMPLOYES":[{"SERIALNO":"76543","NAME":"BULLOZER","TITLE":"SALESMAN","SALARY":14800.000000},{"SERIALNO":"40567","NAME":"QUINN","TITLE":"DIRECTOR","SALARY":14000.000000},{"SERIALNO":"00137","NAME":"BROWNY","TITLE":"ENGINEER","SALARY":10500.000000},{"SERIALNO":"12345","NAME":"KITTY","TITLE":"TYPIST","SALARY":3000.450000},{"SERIALNO":"33333","NAME":"MONAPENNY","TITLE":"SECRETARY","SALARY":3800.000000},{"SERIALNO":"00023","NAME":"MARTIN","TITLE":"ENGINEER","SALARY":10000.000000},{"SERIALNO":"07654","NAME":"FUNNIGUY","TITLE":"ADMINISTRATOR","SALARY":8500.000000},{"SERIALNO":"45678","NAME":"BUGHAPPY","TITLE":"PROGRAMMER","SALARY":8500.000000},{"SERIALNO":"56789","NAME":"FODDERMAN","TITLE":"SALESMAN","SALARY":7000.000000},{"SERIALNO":"55555","NAME":"MESSIFUL","TITLE":"SECRETARY","SALARY":5000.500000},{"SERIALNO":"98765","NAME":"GOOSEPEN","TITLE":"ADMINISTRATOR","SALARY":4700.000000}]} {"DEPARTMENT":"2452","EMPLOYES":[{"SERIALNO":"34567","NAME":"BIGHEAD","TITLE":"SCIENTIST","SALARY":8000.000000},{"SERIALNO":"31416","NAME":"ORELLY","TITLE":"ENGINEER","SALARY":13400.000000},{"SERIALNO":"36666","NAME":"BIGHORN","TITLE":"SCIENTIST","SALARY":11000.000000},{"SERIALNO":"02345","NAME":"SMITH","TITLE":"ENGINEER","SALARY":9000.000000},{"SERIALNO":"11111","NAME":"CHERRY","TITLE":"SECRETARY","SALARY":4500.000000}]} -SELECT Json_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE; -Json_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) +SELECT Json_Make_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE; +Json_Make_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) {"DEPARTMENT":"0021","TITLE":"DIRECTOR","EMPLOYES":[{"SERIALNO":"87777","NAME":"STRONG","SALARY":23000.000000}]} {"DEPARTMENT":"0021","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"22222","NAME":"SHORTSIGHT","SALARY":5500.000000}]} {"DEPARTMENT":"0318","TITLE":"ADMINISTRATOR","EMPLOYES":[{"SERIALNO":"77777","NAME":"SHRINKY","SALARY":7500.000000}]} @@ -273,8 +273,8 @@ ERROR HY000: Can't initialize function 'json_object_grp'; This function requires SELECT Json_Object_Grp(NAME, SALARY) FROM t3; Json_Object_Grp(NAME, SALARY) {"BANCROFT":9600.000000,"SMITH":9000.000000,"MERCHANT":8700.000000,"FUNNIGUY":8500.000000,"BUGHAPPY":8500.000000,"BIGHEAD":8000.000000,"SHRINKY":7500.000000,"WALTER":7400.000000,"FODDERMAN":7000.000000,"TONGHO":6800.000000,"SHORTSIGHT":5500.000000,"MESSIFUL":5000.500000,"HONEY":4900.000000,"GOOSEPEN":4700.000000,"CHERRY":4500.000000,"MONAPENNY":3800.000000,"KITTY":3000.450000,"PLUMHEAD":2800.000000,"STRONG":23000.000000,"BULLOZER":14800.000000,"WERTHER":14500.000000,"QUINN":14000.000000,"ORELLY":13400.000000,"BIGHORN":11000.000000,"BROWNY":10500.000000,"WHEELFOR":10030.000000,"MARTIN":10000.000000} -SELECT Json_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT; -Json_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") +SELECT Json_Make_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT; +Json_Make_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") {"DEPARTMENT":"0021","SALARIES":{"STRONG":23000.000000,"SHORTSIGHT":5500.000000}} {"DEPARTMENT":"0318","SALARIES":{"BANCROFT":9600.000000,"PLUMHEAD":2800.000000,"HONEY":4900.000000,"TONGHO":6800.000000,"WALTER":7400.000000,"SHRINKY":7500.000000,"WERTHER":14500.000000,"MERCHANT":8700.000000,"WHEELFOR":10030.000000}} {"DEPARTMENT":"0319","SALARIES":{"BULLOZER":14800.000000,"QUINN":14000.000000,"BROWNY":10500.000000,"KITTY":3000.450000,"MONAPENNY":3800.000000,"MARTIN":10000.000000,"FUNNIGUY":8500.000000,"BUGHAPPY":8500.000000,"FODDERMAN":7000.000000,"MESSIFUL":5000.500000,"GOOSEPEN":4700.000000}} @@ -309,26 +309,26 @@ SELECT JsonGet_String(Json_Array_Grp(name),'[>]') FROM t3; JsonGet_String(Json_Array_Grp(name),'[>]') WHEELFOR SET @j1 = '[45,28,36,45,89]'; -SELECT JsonGet_String(@j1,'[1]'); -JsonGet_String(@j1,'[1]') +SELECT JsonGet_String(@j1,'1'); +JsonGet_String(@j1,'1') 28 -SELECT JsonGet_String(@j1 json_,'[3]'); -JsonGet_String(@j1 json_,'[3]') +SELECT JsonGet_String(@j1 json_,'3'); +JsonGet_String(@j1 json_,'3') 45 -SELECT JsonGet_String(Json_Array(45,28,36,45,89),'[3]'); -JsonGet_String(Json_Array(45,28,36,45,89),'[3]') +SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'3'); +JsonGet_String(Json_Make_Array(45,28,36,45,89),'3') 45 -SELECT JsonGet_String(Json_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",JsonGet_String(Json_Array(45,28,36,45,89),'[+]') "sum"; +SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",JsonGet_String(Json_Make_Array(45,28,36,45,89),'[+]') "sum"; list egal sum 45+28+36+45+89 = 243.00 -SELECT JsonGet_String(Json_Array(json_array(45,28),json_array(36,45,89)),'[1]:[0]'); -JsonGet_String(Json_Array(json_array(45,28),json_array(36,45,89)),'[1]:[0]') +SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0'); +JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0') 36 -SELECT JsonGet_String(Json_Array(json_array(45,28),json_array(36,45,89)),'[1]:*'); -JsonGet_String(Json_Array(json_array(45,28),json_array(36,45,89)),'[1]:*') +SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.*'); +JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.*') [36,45,89] -SELECT JsonGet_String(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc'); -JsonGet_String(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc') +SELECT JsonGet_String(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc'); +JsonGet_String(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc') machin SET @j2 = '{"qty":56,"price":3.141600,"truc":"machin","garanty":null}'; SELECT JsonGet_String(@j2 json_,'truc'); @@ -345,14 +345,14 @@ JsonGet_String(NULL json_, NULL) NULL Warnings: Warning 1105 -SELECT department, JsonGet_String(Json_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries:[+]') Sumsal FROM t3 GROUP BY department; +SELECT department, JsonGet_String(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department; department Sumsal 0021 28500.00 0318 72230.00 0319 89800.95 2452 45900.00 -SELECT JsonGet_Int(@j1, '[4]'); -JsonGet_Int(@j1, '[4]') +SELECT JsonGet_Int(@j1, '4'); +JsonGet_Int(@j1, '4') 89 SELECT JsonGet_Int(@j1, '[#]'); JsonGet_Int(@j1, '[#]') @@ -360,26 +360,26 @@ JsonGet_Int(@j1, '[#]') SELECT JsonGet_Int(@j1, '[+]'); JsonGet_Int(@j1, '[+]') 243 -SELECT JsonGet_Int(@j1 json_, '[3]'); -JsonGet_Int(@j1 json_, '[3]') +SELECT JsonGet_Int(@j1 json_, '3'); +JsonGet_Int(@j1 json_, '3') 45 -SELECT JsonGet_Int(Json_Array(45,28,36,45,89), '[3]'); -JsonGet_Int(Json_Array(45,28,36,45,89), '[3]') +SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '3'); +JsonGet_Int(Json_Make_Array(45,28,36,45,89), '3') 45 -SELECT JsonGet_Int(Json_Array(45,28,36,45,89), '["+"]'); -JsonGet_Int(Json_Array(45,28,36,45,89), '["+"]') +SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '["+"]'); +JsonGet_Int(Json_Make_Array(45,28,36,45,89), '["+"]') 45 -SELECT JsonGet_Int(Json_Array(45,28,36,45,89), '[+]'); -JsonGet_Int(Json_Array(45,28,36,45,89), '[+]') +SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]'); +JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]') 243 -SELECT JsonGet_Int(Json_Array(json_array(45,28), json_array(36,45,89)), '[1]:[0]'); -JsonGet_Int(Json_Array(json_array(45,28), json_array(36,45,89)), '[1]:[0]') +SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0'); +JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0') 36 -SELECT JsonGet_Int(Json_Array(json_array(45,28), json_array(36,45,89)), '[0]:[1]'); -JsonGet_Int(Json_Array(json_array(45,28), json_array(36,45,89)), '[0]:[1]') +SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '0.1'); +JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '0.1') 28 -SELECT JsonGet_Int(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty'); -JsonGet_Int(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty') +SELECT JsonGet_Int(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty'); +JsonGet_Int(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty') 56 SELECT JsonGet_Int(@j2 json_, 'price'); JsonGet_Int(@j2 json_, 'price') @@ -390,38 +390,38 @@ JsonGet_Int(@j2, 'qty') SELECT JsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose'); JsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose') NULL -SELECT JsonGet_Int(JsonGet_String(Json_Array(Json_Array(45,28),Json_Array(36,45,89)), '[1]:*'), '[+]') sum; +SELECT JsonGet_Int(JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)), '1.*'), '[+]') sum; sum 170 -SELECT department, JsonGet_Int(Json_Object(department, Json_Array_Grp(salary) "Json_salaries"), 'salaries:[+]') Sumsal FROM t3 GROUP BY department; +SELECT department, JsonGet_Int(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"), 'salaries.[+]') Sumsal FROM t3 GROUP BY department; department Sumsal 0021 28500 0318 72230 0319 89800 2452 45900 -SELECT JsonGet_Real(@j1, '[2]'); -JsonGet_Real(@j1, '[2]') +SELECT JsonGet_Real(@j1, '2'); +JsonGet_Real(@j1, '2') 36.000000000000000 -SELECT JsonGet_Real(@j1 json_, '[3]', 2); -JsonGet_Real(@j1 json_, '[3]', 2) +SELECT JsonGet_Real(@j1 json_, '3', 2); +JsonGet_Real(@j1 json_, '3', 2) 45.00 -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '[3]'); -JsonGet_Real(Json_Array(45,28,36,45,89), '[3]') +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '3'); +JsonGet_Real(Json_Make_Array(45,28,36,45,89), '3') 45.000000000000000 -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '["+"]'); -JsonGet_Real(Json_Array(45,28,36,45,89), '["+"]') +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '["+"]'); +JsonGet_Real(Json_Make_Array(45,28,36,45,89), '["+"]') 45.000000000000000 -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '[+]'); -JsonGet_Real(Json_Array(45,28,36,45,89), '[+]') +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[+]'); +JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[+]') 243.000000000000000 -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '[!]'); -JsonGet_Real(Json_Array(45,28,36,45,89), '[!]') +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]'); +JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]') 48.600000000000000 -SELECT JsonGet_Real(Json_Array(json_array(45,28), json_array(36,45,89)), '[1]:[0]'); -JsonGet_Real(Json_Array(json_array(45,28), json_array(36,45,89)), '[1]:[0]') +SELECT JsonGet_Real(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0'); +JsonGet_Real(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0') 36.000000000000000 -SELECT JsonGet_Real(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price'); -JsonGet_Real(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price') +SELECT JsonGet_Real(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price'); +JsonGet_Real(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price') 3.141600000000000 SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty'); JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty') @@ -435,7 +435,7 @@ JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'pric SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose'); JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose') NULL -SELECT department, JsonGet_Real(Json_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries:[+]') Sumsal FROM t3 GROUP BY department; +SELECT department, JsonGet_Real(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department; department Sumsal 0021 28500.000000000000000 0318 72230.000000000000000 @@ -445,11 +445,11 @@ department Sumsal # Documentation examples # SELECT -JsonGet_Int(Json_Array(45,28,36,45,89), '[4]') "Rank", -JsonGet_Int(Json_Array(45,28,36,45,89), '[#]') "Number", -JsonGet_String(Json_Array(45,28,36,45,89), '[","]') "Concat", -JsonGet_Int(Json_Array(45,28,36,45,89), '[+]') "Sum", -JsonGet_Real(Json_Array(45,28,36,45,89), '[!]', 2) "Avg"; +JsonGet_Int(Json_Make_Array(45,28,36,45,89), '4') "Rank", +JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[#]') "Number", +JsonGet_String(Json_Make_Array(45,28,36,45,89), '[","]') "Concat", +JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]') "Sum", +JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]', 2) "Avg"; Rank Number Concat Sum Avg 89 5 45,28,36,45,89 243 48.60 SELECT @@ -464,33 +464,33 @@ Real # # Testing Locate # -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin'); -JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin') -truc -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56); -JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56) -qty -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416); -JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416) -price -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose'); -JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose') +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin'); +JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin') +$.truc +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56); +JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56) +$.qty +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416); +JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416) +$.price +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose'); +JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose') NULL SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'Jack') Path; Path -AUTHORS:[1]:FN +$.AUTHORS[1].FN SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'jack' ci) Path; Path -AUTHORS:[1]:FN +$.AUTHORS[1].FN SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"Jack", "LN":"London"}' json_) Path; Path -AUTHORS:[1] +$.AUTHORS[1] SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"jack", "LN":"London"}' json_) Path; Path NULL SELECT JsonLocate('[45,28,36,45,89]',36); JsonLocate('[45,28,36,45,89]',36) -[2] +$[2] SELECT JsonLocate('[45,28,36,45,89]' json_,28.0); JsonLocate('[45,28,36,45,89]' json_,28.0) NULL @@ -499,71 +499,71 @@ Json_Locate_All('[45,28,36,45,89]',10) [] SELECT Json_Locate_All('[45,28,36,45,89]',45); Json_Locate_All('[45,28,36,45,89]',45) -["[0]","[3]"] +["$[0]","$[3]"] SELECT Json_Locate_All('[[45,28],36,45,89]',45); Json_Locate_All('[[45,28],36,45,89]',45) -["[0]:[0]","[2]"] +["$[0][0]","$[2]"] SELECT Json_Locate_All('[[45,28,45],36,45,89]',45); Json_Locate_All('[[45,28,45],36,45,89]',45) -["[0]:[0]","[0]:[2]","[2]"] +["$[0][0]","$[0][2]","$[2]"] SELECT Json_Locate_All('[[45,28,45],36,45,89]',JsonGet_Int('[3,45]','[1]')); Json_Locate_All('[[45,28,45],36,45,89]',JsonGet_Int('[3,45]','[1]')) -["[0]:[0]","[0]:[2]","[2]"] +["$[0][0]","$[0][2]","$[2]"] SELECT JsonLocate('[[45,28,45],36,45,89]',45,n) from t1; JsonLocate('[[45,28,45],36,45,89]',45,n) -[0]:[0] -[0]:[2] -[2] +$[0][0] +$[0][2] +$[2] NULL NULL SELECT JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) FROM t1; JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) -[0]:[0] -[0]:[2] -[2] +$[0][0] +$[0][2] +$[2] NULL NULL SELECT JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) AS `Path` FROM t1 GROUP BY n HAVING `Path` IS NOT NULL; Path -[0]:[0] -[0]:[2] -[2] +$[0][0] +$[0][2] +$[2] SELECT Json_Locate_All('[45,28,[36,45,89]]',45); Json_Locate_All('[45,28,[36,45,89]]',45) -["[0]","[2]:[1]"] +["$[0]","$[2][1]"] SELECT Json_Locate_All('[[45,28],[36,45.0,89]]',JsonValue(45.0)); Json_Locate_All('[[45,28],[36,45.0,89]]',JsonValue(45.0)) [] SELECT Json_Locate_All('[[45,28],[36,45.0,89]]',45.0); Json_Locate_All('[[45,28],[36,45.0,89]]',45.0) -["[1]:[1]"] +["$[1][1]"] SELECT JsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_); JsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_) -[1] +$[1] SELECT JsonLocate('[[45,28],[36,45,89]]','[45,28]' json_); JsonLocate('[[45,28],[36,45,89]]','[45,28]' json_) -[0] +$[0] SELECT Json_Locate_All('[[45,28],[[36,45],89]]','45') "All paths"; All paths [] SELECT Json_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_); Json_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_) -["[1]:[0]"] +["$[1][0]"] SELECT JsonGet_Int(Json_Locate_All('[[45,28],[[36,45],89]]',45), '[#]') "Nb of occurs"; Nb of occurs 2 SELECT Json_Locate_All('[[45,28],[[36,45],89]]',45,2); Json_Locate_All('[[45,28],[[36,45],89]]',45,2) -["[0]:[0]"] -SELECT JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'[0]'); -JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'[0]') -[0] +["$[0][0]"] +SELECT JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'0'); +JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'0') +$[0] SELECT JsonLocate(Json_File('test/biblio.json'), 'Knab'); JsonLocate(Json_File('test/biblio.json'), 'Knab') -[0]:AUTHOR:[1]:LASTNAME +$[0].AUTHOR[1].LASTNAME SELECT Json_Locate_All('test/biblio.json' jfile_, 'Knab'); Json_Locate_All('test/biblio.json' jfile_, 'Knab') -["[0]:AUTHOR:[1]:LASTNAME"] +["$[0].AUTHOR[1].LASTNAME"] # # Testing json files # @@ -595,54 +595,54 @@ Warning 1105 File pretty format doesn't match the specified pretty value SELECT Json_File('test/fx.json', 0); Json_File('test/fx.json', 0) [{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}] -SELECT Json_File('test/fx.json', '[0]'); -Json_File('test/fx.json', '[0]') +SELECT Json_File('test/fx.json', '0'); +Json_File('test/fx.json', '0') {"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]} SELECT Json_File('test/fx.json', '[?]'); Json_File('test/fx.json', '[?]') NULL Warnings: Warning 1105 Invalid function specification ? -SELECT JsonGet_String(Json_File('test/fx.json'), '[1]:*'); -JsonGet_String(Json_File('test/fx.json'), '[1]:*') +SELECT JsonGet_String(Json_File('test/fx.json'), '1.*'); +JsonGet_String(Json_File('test/fx.json'), '1.*') {"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]} -SELECT JsonGet_String(Json_File('test/fx.json'), '[1]'); -JsonGet_String(Json_File('test/fx.json'), '[1]') -6 car roadster 56000 ??? -SELECT JsonGet_Int(Json_File('test/fx.json'), '[1]:mileage') AS Mileage; +SELECT JsonGet_String(Json_File('test/fx.json'), '1'); +JsonGet_String(Json_File('test/fx.json'), '1') +6 car roadster 56000 +SELECT JsonGet_Int(Json_File('test/fx.json'), '1.mileage') AS Mileage; Mileage 56000 -SELECT JsonGet_Real(Json_File('test/fx.json'), '[0]:price', 2) AS Price; +SELECT JsonGet_Real(Json_File('test/fx.json'), '0.price', 2) AS Price; Price 5.65 -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 'ratings'); -Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 'ratings') +SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings'); +Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings') {"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4,6]} -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 1, 'ratings'); -Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 1, 'ratings') +SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 1, 'ratings'); +Json_Array_Add(Json_File('test/fx.json', '2'), 6, 1, 'ratings') {"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,6,4]} -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 'ratings', 1); -Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 'ratings', 1) +SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings', 1); +Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings', 1) {"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,6,4]} -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]:ratings'), 6, 0); -Json_Array_Add(Json_File('test/fx.json', '[2]:ratings'), 6, 0) +SELECT Json_Array_Add(Json_File('test/fx.json', '2.ratings'), 6, 0); +Json_Array_Add(Json_File('test/fx.json', '2.ratings'), 6, 0) [6,2,4] -SELECT Json_Array_Delete(Json_File('test/fx.json', '[2]'), 'ratings', 1); -Json_Array_Delete(Json_File('test/fx.json', '[2]'), 'ratings', 1) +SELECT Json_Array_Delete(Json_File('test/fx.json', '2'), 'ratings', 1); +Json_Array_Delete(Json_File('test/fx.json', '2'), 'ratings', 1) {"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2]} -SELECT Json_Object_Add(Json_File('test/fx.json', '[2]'), 'france' origin); -Json_Object_Add(Json_File('test/fx.json', '[2]'), 'france' origin) +SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 'france' origin); +Json_Object_Add(Json_File('test/fx.json', '2'), 'france' origin) {"_id":7,"type":"food","item":"meat","origin":"france","ratings":[2,4]} -SELECT Json_Object_Add(Json_File('test/fx.json', '[2]'), 70 H, 'size'); -Json_Object_Add(Json_File('test/fx.json', '[2]'), 70 H, 'size') +SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 70 H, 'size'); +Json_Object_Add(Json_File('test/fx.json', '2'), 70 H, 'size') {"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]} Warnings: Warning 1105 No sub-item at 'size' -SELECT Json_Object_Add(Json_File('test/fx.json', '[3]'), 70 H, 'size'); -Json_Object_Add(Json_File('test/fx.json', '[3]'), 70 H, 'size') +SELECT Json_Object_Add(Json_File('test/fx.json', '3'), 70 H, 'size'); +Json_Object_Add(Json_File('test/fx.json', '3'), 70 H, 'size') {"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":70},"ratings":[5,8,7]} -SELECT Json_Object_List(Json_File('test/fx.json', '[3]:size')); -Json_Object_List(Json_File('test/fx.json', '[3]:size')) +SELECT Json_Object_List(Json_File('test/fx.json', '3.size')); +Json_Object_List(Json_File('test/fx.json', '3.size')) ["W","L","H"] DROP TABLE t1; DROP TABLE t2; diff --git a/storage/connect/mysql-test/connect/r/json_udf_bin.result b/storage/connect/mysql-test/connect/r/json_udf_bin.result index 4e59b51c52983..0c009d612fe23 100644 --- a/storage/connect/mysql-test/connect/r/json_udf_bin.result +++ b/storage/connect/mysql-test/connect/r/json_udf_bin.result @@ -29,8 +29,8 @@ Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), NULL), SELECT Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), TRUE), 1, '[1]'); Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), TRUE), 1, '[1]') [56,[3.141600],true] -SELECT Json_Array(1, TRUE, 0, FALSE); -Json_Array(1, TRUE, 0, FALSE) +SELECT Json_Make_Array(1, TRUE, 0, FALSE); +Json_Make_Array(1, TRUE, 0, FALSE) [1,true,0,false] SELECT Json_Serialize(Jbin_Array(TRUE, FALSE)); Json_Serialize(Jbin_Array(TRUE, FALSE)) @@ -63,94 +63,94 @@ Json_Serialize(Jbin_File('gloss.json')) {"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}} SELECT JsonLocate(Jbin_File('gloss.json'),'XML'); JsonLocate(Jbin_File('gloss.json'),'XML') -glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso:[1] +$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso[1] SELECT Json_Object_Key('first', 'foo', 'second', Jbin_Array('a', 33)); Json_Object_Key('first', 'foo', 'second', Jbin_Array('a', 33)) {"first":"foo","second":["a",33]} -SELECT Json_Get_Item(Json_Array('a','b','c'), '[1]'); -Json_Get_Item(Json_Array('a','b','c'), '[1]') +SELECT Json_Get_Item(Json_Make_Array('a','b','c'), '$[1]'); +Json_Get_Item(Json_Make_Array('a','b','c'), '$[1]') NULL -SELECT Json_Get_Item(Json_Object('foo' AS "first", Json_Array('a', 33) AS "json_second"), 'second') AS "item"; +SELECT Json_Get_Item(Json_Make_Object('foo' AS "first", Json_Make_Array('a', 33) AS "json_second"), '$.second') AS "item"; item ["a",33] -SELECT Json_Get_Item(Jbin_Object('foo' first, Jbin_Array('a', 33) jbin_second), 'second:*') item; +SELECT Json_Get_Item(Jbin_Object('foo' first, Jbin_Array('a', 33) jbin_second), '$.second') item; item ["a",33] -SELECT Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv'); -Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv') +SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv'); +Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv') {"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}} -SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv')); -Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv')) +SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv')); +Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv')) {"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}} -SELECT Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv:*'); -Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv:*') +SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv'); +Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv') {"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}} -SELECT JsonGet_String(Json_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso') lang; +SELECT JsonGet_String(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') lang; lang GML -SELECT Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso') "See also"; +SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') "See also"; See also ["GML","XML"] -SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso')) "See also"; +SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso')) "See also"; See also ["GML","XML"] -SELECT JsonGet_String(Json_Get_Item(Json_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso'),'[0]') lang; +SELECT JsonGet_String(Json_Get_Item(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso'),'$[0]') lang; lang GML # # Test Item Get/Set/Insert/Update UDF's # -SELECT Json_Get_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '[]'); -Json_Get_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '[]') +SELECT Json_Get_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[]'); +Json_Get_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[]') [1,2,{"trois":3,"quatre":4}] -SELECT Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '[1]'); -Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '[1]') +SELECT Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[1]'); +Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[1]') NULL -SELECT Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '[1]'); -Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '[1]') +SELECT Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$[1]'); +Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$[1]') NULL -SELECT Json_Set_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4))); -Json_Set_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4))) +SELECT Json_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4))); +Json_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4))) [1,2,{"trois":3,"quatre":4}] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 'foo'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$.foo'); ERROR HY000: Can't initialize function 'json_set_item'; This function must have an odd number of arguments -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq') [1,2,{"trois":3,"quatre":4,"cinq":5}] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '[1]'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '[1]') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '$[1]'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '$[1]') [1,7,{"trois":3,"quatre":4}] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 7, '[1]'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 7, '[1]') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 7, '$[1]'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 7, '$[1]') [1,7,{"trois":3,"quatre":4,"cinq":5}] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Array(7, 8, 9), '[1]'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Array(7, 8, 9), '[1]') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Make_Array(7, 8, 9), '$[1]'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Make_Array(7, 8, 9), '$[1]') [1,[7,8,9],{"trois":3,"quatre":4}] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[2]'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[2]') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2]'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2]') [1,2,[7,8,9]] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[2]:*'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[2]:*') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2].*'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2].*') [1,2,{"trois":3,"quatre":4}] Warnings: Warning 1105 Invalid specification * in a write path -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, 'foo'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, 'foo') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, '$.foo'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, '$.foo') [1,2,{"trois":3,"quatre":4}] -SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '[1]:[2]'); -Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '[1]:[2]') +SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '$[1][2]'); +Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '$[1][2]') [1,[7,8,"toto"],{"trois":3,"quatre":4}] -SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '[2]:nxt:total:[]'); -Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '[2]:nxt:total:[]') +SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '$[2].nxt.total[]'); +Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '$[2].nxt.total[]') [1,[7,8,9],{"trois":3,"quatre":4,"nxt":{"total":[300]}}] -SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 300, '[2]:nxt:total:[]'); -Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 300, '[2]:nxt:total:[]') +SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 300, '$[2].nxt.total[]'); +Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 300, '$[2].nxt.total[]') [1,[7,8,9,10],{"trois":3,"quatre":4,"cinq":5,"nxt":{"total":[300]}}] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[1]', 5, '[2]:cinq', 10, '[1]:[]'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[1]', 5, '[2]:cinq', 10, '[1]:[]') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[1]', 5, '$[2].cinq', 10, '$[1][]'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[1]', 5, '$[2].cinq', 10, '$[1][]') [1,[7,8,9,10],{"trois":3,"quatre":4,"cinq":5}] -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '[2]:quatre'); -Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '[2]:quatre') +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '$[2].quatre'); +Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '$[2].quatre') [1,2,{"trois":3,"quatre":44}] SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, 'truc'); Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, 'truc') @@ -163,32 +163,32 @@ Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '*' [1,2,{"trois":3,"quatre":4}] Warnings: Warning 1105 Invalid specification * in a write path -SELECT Json_Serialize(Jbin_Set_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq')); -Json_Serialize(Jbin_Set_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq')) +SELECT Json_Serialize(Jbin_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq')); +Json_Serialize(Jbin_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq')) [1,2,{"trois":3,"quatre":4,"cinq":5}] -SELECT Json_Insert_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq'); -Json_Insert_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq') +SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'); +Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq') [1,2,{"trois":3,"quatre":4,"cinq":5}] -SELECT Json_Update_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq'); -Json_Update_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq') +SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'); +Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq') [1,2,{"trois":3,"quatre":4}] -SELECT Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 44, '[2]:quatre'); -Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 44, '[2]:quatre') +SELECT Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre'); +Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre') [1,[7,8,9,10],{"trois":3,"quatre":4,"cinq":5}] -SELECT Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 44, '[2]:quatre'); -Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 44, '[2]:quatre') +SELECT Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre'); +Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre') [1,[7,8,9],{"trois":3,"quatre":44}] -SELECT Json_Insert_Item(Json_Array(1, Json_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[1]', 300, '[2]:nxt:total:[]'); -Json_Insert_Item(Json_Array(1, Json_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[1]', 300, '[2]:nxt:total:[]') +SELECT Json_Insert_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]'); +Json_Insert_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]') [1,[7,8,9],{"trois":3,"quatre":4,"cinq":5,"nxt":{"total":[300]}}] -SELECT Json_Update_Item(Json_Array(1, Json_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[1]', 300, '[2]:nxt:total:[]'); -Json_Update_Item(Json_Array(1, Json_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[1]', 300, '[2]:nxt:total:[]') +SELECT Json_Update_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]'); +Json_Update_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]') [1,[7,10,9],{"trois":3,"quatre":4}] -SELECT Json_Insert_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[]'); -Json_Insert_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[]') +SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]'); +Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]') [1,2,{"trois":3,"quatre":4},5] -SELECT Json_Update_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[]'); -Json_Update_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[]') +SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]'); +Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]') [1,2,{"trois":3,"quatre":4}] # # Test merging items UDF's @@ -196,7 +196,7 @@ Json_Update_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, SELECT Json_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')); Json_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')) ["a","b","c","d","e","f"] -SELECT Json_Item_Merge(Json_Array('a','b','c'), Json_Array('d','e','f')) AS "Result"; +SELECT Json_Item_Merge(Json_Make_Array('a','b','c'), Json_Make_Array('d','e','f')) AS "Result"; Result ["a","b","c","d","e","f"] SELECT Json_Array_Add(Jbin_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')), 'and', 3); @@ -216,7 +216,7 @@ Json_Object_Add(Jbin_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "a",5 "e",6 "f")); Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "a",5 "e",6 "f")) {"a":4,"b":2,"c":3,"e":5,"f":6} -SELECT Json_Item_Merge('foo', Json_Array('d','e','f')); +SELECT Json_Item_Merge('foo', Json_Make_Array('d','e','f')); ERROR HY000: Can't initialize function 'json_item_merge'; First argument must be a json item # # Test making file UDF's @@ -294,17 +294,17 @@ Json_File('bt1.json', 2) SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json'); Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json') bt1.json -SELECT Json_Object(Jbin_Array_Add(Jbin_Array('a','b','c'), 'd') "Jbin_foo") AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_Array('a','b','c'), 'd') "Jbin_foo") AS "Result"; Result {"foo":["a","b","c","d"]} -SELECT Json_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')) AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')) AS "Result"; Result {"Array_Add(Jbin_File('bt1.json'), 'd')":["a","b","c","d"]} -SELECT Json_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1") AS "Result"; Result {"bt1":["a","b","c","d"]} # This does modify the file -SELECT Json_Object(Json_Array_Add(Jbin_File('bt1.json'), 'd') "Jfile_bt1") AS "Result"; +SELECT Json_Make_Object(Json_Array_Add(Jbin_File('bt1.json'), 'd') "Jfile_bt1") AS "Result"; Result {"bt1":["a","b","c","d"]} SELECT Json_File('bt1.json'); @@ -319,7 +319,7 @@ Json_File('bt1.json') SELECT Json_File(Json_Array_Delete(Jbin_File('bt1.json'), 3), 2); Json_File(Json_Array_Delete(Jbin_File('bt1.json'), 3), 2) ["a","b","c"] -SELECT Json_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1", n "t1") AS "Result" from t1; Result {"bt1":["a","b","c","d"],"t1":1} {"bt1":["a","b","c","d"],"t1":2} @@ -432,23 +432,23 @@ SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json'); Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json') bt1.json # Test DELETE from file -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 1)) AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 1)) AS "Result"; Result {"Array_Delete(Jbin_File('bt1.json'), 1)":["a","c"]} -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 2) "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 2) "Jbin_bt1") AS "Result"; Result {"bt1":["a","b"]} -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 0) "Jbin_bt1", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 0) "Jbin_bt1", n "t1") AS "Result" from t1; Result {"bt1":["b","c"],"t1":1} {"bt1":["b","c"],"t1":2} {"bt1":["b","c"],"t1":3} -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; Result {"bt1":["a","b"]} {"bt1":["a"]} {"bt1":[]} -SELECT Json_Object(Json_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; +SELECT Json_Make_Object(Json_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; Result {"bt1":["a","b"]} {"bt1":["a"]} @@ -475,17 +475,17 @@ SELECT Json_Serialize(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d")); Json_Serialize(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d")) {"a":1,"b":2,"c":3,"d":4} # First query (file not modified) -SELECT Json_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jbin_new") AS "Result"; +SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jbin_new") AS "Result"; Result {"new":{"a":1,"b":2,"c":3,"d":4}} # First query (file modified) -SELECT Json_Object(Json_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jfile_new") AS "Result"; +SELECT Json_Make_Object(Json_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jfile_new") AS "Result"; Result {"new":{"a":1,"b":2,"c":3,"d":4}} SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0); Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0) bt2.json -SELECT Json_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d") "Jbin_new", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d") "Jbin_new", n "t1") AS "Result" from t1; Result {"new":{"a":1,"b":2,"c":3,"d":4},"t1":1} {"new":{"a":1,"b":2,"c":3,"d":4},"t1":2} @@ -526,22 +526,22 @@ SELECT Json_File(Json_Item_Merge(Jbin_File('bt2.json'), Jbin_Object(4 "d",5 "e", Result {"a":1,"b":2,"c":3,"d":4,"e":5,"f":6} -SELECT Json_Item_Merge(Json_Object(1 "a", 2 "b", 3 "c"), Json_Object(4 "d",5 "b",6 "f")) AS "Result"; +SELECT Json_Item_Merge(Json_Make_Object(1 "a", 2 "b", 3 "c"), Json_Make_Object(4 "d",5 "b",6 "f")) AS "Result"; Result {"a":1,"b":5,"c":3,"d":4,"f":6} -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'b')) AS "Result"; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'b')) AS "Result"; Result {"Object_Delete(Jbin_File('bt2.json'), 'b')":{"a":1,"c":3,"d":4,"e":5,"f":6}} -SELECT Json_Object(Jbin_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Jbin_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; Result {"bt1":{"a":1,"d":4,"e":5,"f":6}} -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; Result {"bt1":{"a":1,"d":4,"e":5,"f":6}} -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jfile_bt1") AS "Result"; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jfile_bt1") AS "Result"; Result {"bt1":{"a":1,"d":4,"e":5,"f":6}} -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'a') "Jbin_bt1", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'a') "Jbin_bt1", n "t1") AS "Result" from t1; Result {"bt1":{"d":4,"e":5,"f":6},"t1":1} {"bt1":{"d":4,"e":5,"f":6},"t1":2} @@ -552,14 +552,14 @@ Key list SELECT Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0); Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0) bt3.json -SELECT Json_Array_Add(Json_File('bt3.json', 'b'), 66); -Json_Array_Add(Json_File('bt3.json', 'b'), 66) +SELECT Json_Array_Add(Json_File('bt3.json', '$.b'), 66); +Json_Array_Add(Json_File('bt3.json', '$.b'), 66) [44,55,66] -SELECT Json_Array_Add(Json_File('bt3.json'), 66, 'b'); -Json_Array_Add(Json_File('bt3.json'), 66, 'b') +SELECT Json_Array_Add(Json_File('bt3.json'), 66, '$.b'); +Json_Array_Add(Json_File('bt3.json'), 66, '$.b') {"a":1,"b":[44,55,66]} -SELECT Json_Array_Add(Jbin_File('bt3.json', 'b'), 66); -Json_Array_Add(Jbin_File('bt3.json', 'b'), 66) +SELECT Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66); +Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66) bt3.json SELECT Json_File('bt3.json', 3); Json_File('bt3.json', 3) @@ -573,15 +573,15 @@ jfile_cols CHAR(12) NOT NULL) ENGINE= MYISAM; INSERT INTO t2 VALUES(1,'bt3.json'); # In this table, the jfile_cols column just contains a file name -UPDATE t2 SET jfile_cols = Json_Array_Add(Jbin_File('bt3.json', 'b'), 66) WHERE n = 1; +UPDATE t2 SET jfile_cols = Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66) WHERE n = 1; SELECT JsonGet_String(jfile_cols, '*') FROM t2; JsonGet_String(jfile_cols, '*') {"a":1,"b":[44,55,66]} -UPDATE t2 SET jfile_cols = Json_Insert_Item(jfile_cols, 77, 'b:[]') WHERE n = 1; -SELECT JsonGet_String(jfile_cols, 'b:*') FROM t2; -JsonGet_String(jfile_cols, 'b:*') +UPDATE t2 SET jfile_cols = Json_Insert_Item(jfile_cols, 77, '$.b[]') WHERE n = 1; +SELECT JsonGet_String(jfile_cols, '$.b.*') FROM t2; +JsonGet_String(jfile_cols, '$.b.*') [44,55,66,77] -UPDATE t2 SET jfile_cols = Json_Insert_Item(Jbin_Insert_Item(jfile_cols, 88, 'b:') , 99, 'b:') WHERE n = 1; +UPDATE t2 SET jfile_cols = Json_Insert_Item(Jbin_Insert_Item(jfile_cols, 88, '$.b[]') , 99, '$.b[]') WHERE n = 1; SELECT JsonGet_String(jfile_cols, '*') FROM t2; JsonGet_String(jfile_cols, '*') {"a":1,"b":[44,55,66,77,88,99]} diff --git a/storage/connect/mysql-test/connect/r/mul_new.result b/storage/connect/mysql-test/connect/r/mul_new.result new file mode 100644 index 0000000000000..ba8112f5d1f60 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/mul_new.result @@ -0,0 +1,136 @@ +# +# Testing multiple 1 +# +CREATE TABLE t1 ( +Chiffre int(3) NOT NULL, +Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num1.csv' LRECL=20 HEADER=1; +INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six'); +SELECT * FROM t1; +Chiffre Lettre +1 One +2 Two +3 Three +4 Four +5 Five +6 Six +CREATE TABLE t2 ( +Chiffre int(3) NOT NULL, +Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num2.csv' LRECL=20 HEADER=1; +INSERT INTO t2 VALUES(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten'),(11,'Eleven'),(12,'Twelve'); +SELECT * FROM t2; +Chiffre Lettre +7 Seven +8 Eight +9 Nine +10 Ten +11 Eleven +12 Twelve +CREATE TABLE t3 ( +Chiffre int(3) NOT NULL, +Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num3.csv' LRECL=20 HEADER=1; +INSERT INTO t3 VALUES(13,'Thirteen'),(14,'Fourteen'),(15,'Fifteen'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen'); +SELECT * FROM t3; +Chiffre Lettre +13 Thirteen +14 Fourteen +15 Fifteen +16 Sixteen +17 Seventeen +18 Eighteen +CREATE TABLE t4 ( +Chiffre int(3) NOT NULL, +Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num4.csv' LRECL=20 HEADER=1; +INSERT INTO t4 VALUES(19,'Nineteen'),(20,'Twenty'),(21,'Twenty one'),(22,'Twenty two'),(23,'Tenty three'),(24,'Twenty four'); +SELECT * FROM t4; +Chiffre Lettre +19 Nineteen +20 Twenty +21 Twenty one +22 Twenty two +23 Tenty three +24 Twenty four +CREATE TABLE t5 ( +Chiffre int(3) NOT NULL, +Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num5.csv' LRECL=20 HEADER=1; +INSERT INTO t5 VALUES(25,'Twenty five'),(26,'Twenty six'),(27,'Twenty seven'),(28,'Twenty eight'),(29,'Tenty eight'),(30,'Thirty'); +SELECT * FROM t5; +Chiffre Lettre +25 Twenty five +26 Twenty six +27 Twenty seven +28 Twenty eight +29 Tenty eight +30 Thirty +CREATE TABLE t_all ( +Chiffre int(3) not null, +Lettre char(16) not null) +ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num?.csv' HEADER=1 LRECL=20 MULTIPLE=1; +SELECT * FROM t_all ORDER BY Chiffre; +Chiffre Lettre +1 One +2 Two +3 Three +4 Four +5 Five +6 Six +13 Thirteen +14 Fourteen +15 Fifteen +16 Sixteen +17 Seventeen +18 Eighteen +25 Twenty five +26 Twenty six +27 Twenty seven +28 Twenty eight +29 Tenty eight +30 Thirty +# +# Testing multiple 3 +# +ALTER TABLE t_all MULTIPLE=3; +Warnings: +Warning 1105 This is an outward table, table data were not modified. +SELECT * FROM t_all ORDER BY Chiffre; +Chiffre Lettre +1 One +2 Two +3 Three +4 Four +5 Five +6 Six +7 Seven +8 Eight +9 Nine +10 Ten +11 Eleven +12 Twelve +13 Thirteen +14 Fourteen +15 Fifteen +16 Sixteen +17 Seventeen +18 Eighteen +19 Nineteen +20 Twenty +21 Twenty one +22 Twenty two +23 Tenty three +24 Twenty four +25 Twenty five +26 Twenty six +27 Twenty seven +28 Twenty eight +29 Tenty eight +30 Thirty +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t_all; diff --git a/storage/connect/mysql-test/connect/r/mysql_exec.result b/storage/connect/mysql-test/connect/r/mysql_exec.result index 1801456fd7411..c0400bc82e7e1 100644 --- a/storage/connect/mysql-test/connect/r/mysql_exec.result +++ b/storage/connect/mysql-test/connect/r/mysql_exec.result @@ -20,7 +20,7 @@ SELECT * FROM t1 WHERE command IN ('Warning','Note', "insert into t1(msg) values('One'),(NULL),('Three')", "insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'", "insert into t1(message) values('Four'),('Five'),('Six')", -'insert into t1(id) values(NULL)', +'insert ignore into t1(id) values(NULL)', "update t1 set msg = 'Four' where id = 4", 'select * from t1'); command warnings number message @@ -31,8 +31,9 @@ insert into t1(msg) values('One'),(NULL),('Three') 1 3 Affected rows Warning 0 1048 Column 'msg' cannot be null insert into t1 values(2,'Deux') on duplicate key update msg = 'Two' 0 2 Affected rows insert into t1(message) values('Four'),('Five'),('Six') 0 1054 Remote: Unknown column 'message' in 'field list' -insert into t1(id) values(NULL) 0 1364 Remote: Field 'msg' doesn't have a default value -update t1 set msg = 'Four' where id = 4 0 0 Affected rows +insert ignore into t1(id) values(NULL) 1 1 Affected rows +Warning 0 1364 Field 'msg' doesn't have a default value +update t1 set msg = 'Four' where id = 4 0 1 Affected rows select * from t1 0 2 Result set columns # # Checking Using Procedure @@ -43,12 +44,13 @@ Note 1305 PROCEDURE test.p1 does not exist CREATE PROCEDURE p1(cmd varchar(512)) READS SQL DATA SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd); -CALL p1('insert into t1(id) values(NULL)'); +CALL p1('insert ignore into t1(id) values(NULL)'); command warnings number message -insert into t1(id) values(NULL) 0 1364 Remote: Field 'msg' doesn't have a default value +insert ignore into t1(id) values(NULL) 1 1 Affected rows +Warning 0 1364 Field 'msg' doesn't have a default value CALL p1('update t1 set msg = "Five" where id = 5'); command warnings number message -update t1 set msg = "Five" where id = 5 0 0 Affected rows +update t1 set msg = "Five" where id = 5 0 1 Affected rows DROP PROCEDURE p1; DROP TABLE t1; connection slave; @@ -57,6 +59,8 @@ id msg 1 One 2 Two 3 Three +4 Four +5 Five DROP TABLE t1; connection master; DROP TABLE IF EXISTS connect.t1; diff --git a/storage/connect/mysql-test/connect/r/odbc_oracle.result b/storage/connect/mysql-test/connect/r/odbc_oracle.result index 8dc7dc07bb1cb..db7f78f67cd06 100644 --- a/storage/connect/mysql-test/connect/r/odbc_oracle.result +++ b/storage/connect/mysql-test/connect/r/odbc_oracle.result @@ -72,11 +72,11 @@ TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtr' CATFUNC=Columns; SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name; Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks - MTR T1 A 3 DECIMAL 38 40 0 10 1 - MTR T1 B 6 NUMBER 38 40 NULL NULL 1 - MTR T2 A 12 VARCHAR2 64 64 NULL NULL 1 - MTR V1 A 3 DECIMAL 38 40 0 10 1 - MTR V1 B 6 NUMBER 38 40 NULL NULL 1 +NULL MTR T1 A 3 DECIMAL 38 40 0 10 1 NULL +NULL MTR T1 B 6 NUMBER 38 40 NULL NULL 1 NULL +NULL MTR T2 A 12 VARCHAR2 64 64 NULL NULL 1 NULL +NULL MTR V1 A 3 DECIMAL 38 40 0 10 1 NULL +NULL MTR V1 B 6 NUMBER 38 40 NULL NULL 1 NULL DROP TABLE t1; # All columns in all schemas (limited with WHERE) CREATE TABLE t1 ENGINE=CONNECT @@ -84,18 +84,18 @@ TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.%'; SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name; Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks - MTR T1 A 3 DECIMAL 38 40 0 10 1 - MTR T1 B 6 NUMBER 38 40 NULL NULL 1 - MTR T2 A 12 VARCHAR2 64 64 NULL NULL 1 - MTR V1 A 3 DECIMAL 38 40 0 10 1 - MTR V1 B 6 NUMBER 38 40 NULL NULL 1 +NULL MTR T1 A 3 DECIMAL 38 40 0 10 1 NULL +NULL MTR T1 B 6 NUMBER 38 40 NULL NULL 1 NULL +NULL MTR T2 A 12 VARCHAR2 64 64 NULL NULL 1 NULL +NULL MTR V1 A 3 DECIMAL 38 40 0 10 1 NULL +NULL MTR V1 B 6 NUMBER 38 40 NULL NULL 1 NULL DROP TABLE t1; # All tables "T1" in all schemas (limited with WHERE) CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.T1'; SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name; Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks - MTR T1 A 3 DECIMAL 38 40 0 10 1 - MTR T1 B 6 NUMBER 38 40 NULL NULL 1 +NULL MTR T1 A 3 DECIMAL 38 40 0 10 1 NULL +NULL MTR T1 B 6 NUMBER 38 40 NULL NULL 1 NULL DROP TABLE t1; # Table "T1" in the schema "MTR" CREATE TABLE t1 ENGINE=CONNECT @@ -103,8 +103,8 @@ TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='MTR.T1'; SELECT * FROM t1 ORDER BY Table_Schema, Table_Name; Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks - MTR T1 A 3 DECIMAL 38 40 0 10 1 - MTR T1 B 6 NUMBER 38 40 NULL NULL 1 +NULL MTR T1 A 3 DECIMAL 38 40 0 10 1 NULL +NULL MTR T1 B 6 NUMBER 38 40 NULL NULL 1 NULL DROP TABLE t1; # All tables "T1" in all schemas (filtered with WHERE) CREATE TABLE t1 ENGINE=CONNECT @@ -112,8 +112,8 @@ TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.T1'; SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name; Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks - MTR T1 A 3 DECIMAL 38 40 0 10 1 - MTR T1 B 6 NUMBER 38 40 NULL NULL 1 +NULL MTR T1 A 3 DECIMAL 38 40 0 10 1 NULL +NULL MTR T1 B 6 NUMBER 38 40 NULL NULL 1 NULL DROP TABLE t1; # # Checking tables diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result index eea53bf55c784..99739b1ec102c 100644 --- a/storage/connect/mysql-test/connect/r/xml.result +++ b/storage/connect/mysql-test/connect/r/xml.result @@ -1,5 +1,3 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml SET NAMES utf8; # # Testing tag values @@ -12,7 +10,7 @@ TRANSLATOR CHAR(40), PUBLISHER CHAR(40), DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t1; AUTHOR Jean-Christophe Bernadac TITLE Construire une application XML @@ -36,7 +34,7 @@ TRANSLATOR CHAR(40), PUBLISHER CHAR(40), DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t1; author NULL TITLE Construire une application XML @@ -57,7 +55,7 @@ ISBN CHAR(15), LANG CHAR(2), SUBJECT CHAR(32) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='Coltype=@,xmlsup=libxml2'; + OPTION_LIST='Coltype=@,xmlsup=domdoc'; SELECT * FROM t1; ISBN 9782212090819 LANG fr @@ -74,7 +72,7 @@ isbn CHAR(15), LANG CHAR(2), SUBJECT CHAR(32) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='Coltype=@,xmlsup=libxml2'; + OPTION_LIST='Coltype=@,xmlsup=domdoc'; SELECT * FROM t1; isbn NULL LANG fr @@ -97,7 +95,7 @@ PUBLISHER CHAR(40), DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t1; ISBN 9782212090819 LANG fr @@ -130,7 +128,7 @@ PUBLISHER CHAR(40), DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml' TABNAME='BIBLIO' - OPTION_LIST='rownode=BOOK,xmlsup=libxml2'; + OPTION_LIST='rownode=BOOK,xmlsup=domdoc'; INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB) VALUES('9782212090529','fr','général','Alain Michard', 'XML, Langage et Applications','Eyrolles Paris',1998); @@ -160,47 +158,47 @@ TRANSLATOR NULL PUBLISHER Eyrolles Paris DATEPUB 1998 SELECT LOAD_FILE('MYSQLD_DATADIR/test/xsample2.xml') AS xml; -xml - - - - Jean-Christophe - Bernadac - - - François - Knab - - Construire une application XML - - Eyrolles - Paris - - 1999 - - - - William J. - Pardi - - - James - Guerin - - XML en Action - - Microsoft Press - Paris - - 1999 - - - Alain Michard - XML, Langage et Applications - Eyrolles Paris - 1998 - - +xml + + + + Jean-Christophe + Bernadac + + + François + Knab + + Construire une application XML + + Eyrolles + Paris + + 1999 + + + + William J. + Pardi + + + James + Guerin + + XML en Action + + Microsoft Press + Paris + + 1999 + + + Alain Michard + XML, Langage et Applications + Eyrolles Paris + 1998 + + DROP TABLE t1; # @@ -220,7 +218,7 @@ publisher CHAR(20) FIELD_FORMAT='PUBLISHER/NAME', location CHAR(20) FIELD_FORMAT='PUBLISHER/PLACE', year INT(4) FIELD_FORMAT='DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc'; SELECT * FROM t1; isbn 9782212090819 language fr @@ -262,7 +260,7 @@ CREATE TABLE t1 ( isbn CHAR(15) FIELD_FORMAT='@isbn' ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc'; SELECT * FROM t1; isbn NULL isbn NULL @@ -274,20 +272,20 @@ CREATE TABLE t1 ( c CHAR(16) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2' + OPTION_LIST='xmlsup=domdoc' DATA_CHARSET=latin1; ERROR HY000: DATA_CHARSET='latin1' is not supported for TABLE_TYPE=XML CREATE TABLE t1 ( c CHAR(16) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2' + OPTION_LIST='xmlsup=domdoc' DATA_CHARSET=utf8; SHOW CREATE TABLE t1; Table t1 Create Table CREATE TABLE `t1` ( `c` char(16) DEFAULT NULL -) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=XML `FILE_NAME`='latin1.xml' `OPTION_LIST`='xmlsup=libxml2' `DATA_CHARSET`=utf8 +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=XML `FILE_NAME`='latin1.xml' `OPTION_LIST`='xmlsup=domdoc' `DATA_CHARSET`=utf8 SELECT c, HEX(c) FROM t1; c ÃÂÃÄÅÆÇ HEX(c) C1C2C3C4C5C6C7 @@ -296,7 +294,7 @@ CREATE TABLE t1 ( c CHAR(16) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT c, HEX(c) FROM t1; c ÃÂÃÄÅÆÇ HEX(c) C1C2C3C4C5C6C7 @@ -305,7 +303,7 @@ CREATE TABLE t1 ( c CHAR(16) CHARACTER SET utf8 ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT c, HEX(c) FROM t1; c ÃÂÃÄÅÆÇ HEX(c) C381C382C383C384C385C386C387 @@ -318,7 +316,7 @@ CREATE TABLE t1 ( c CHAR(16) CHARACTER SET cp1251 ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT c, HEX(c) FROM t1; c ??????? HEX(c) 3F3F3F3F3F3F3F @@ -333,44 +331,13 @@ DROP TABLE t1; # # Testing Cyrillic # -CREATE TABLE t1 -( -c CHAR(16) CHARACTER SET utf8 -) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' - OPTION_LIST='xmlsup=libxml2,rownode=b'; -SELECT * FROM t1; -c БВГДЕЖЗ -INSERT INTO t1 VALUES ('ИКЛМÐ'); -SELECT c, HEX(c) FROM t1; -c БВГДЕЖЗ -HEX(c) D091D092D093D094D095D096D097 -c ИКЛМР-HEX(c) D098D09AD09BD09CD09D -DROP TABLE t1; -CREATE TABLE t1 -( -c CHAR(16) CHARACTER SET cp1251 -) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' - OPTION_LIST='xmlsup=libxml2,rownode=b'; -SELECT * FROM t1; -c БВГДЕЖЗ -c ИКЛМР-INSERT INTO t1 VALUES ('ОПРСТ'); -SELECT c, HEX(c) FROM t1; -c БВГДЕЖЗ -HEX(c) C1C2C3C4C5C6C7 -c ИКЛМР-HEX(c) C8CACBCCCD -c ОПРСТ -HEX(c) CECFD0D1D2 -DROP TABLE t1; # # Testing that the underlying file is created with a proper Encoding # CREATE TABLE t1 (node VARCHAR(50)) CHARACTER SET latin1 ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' - OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=utf-8'; + OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=utf-8'; INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); SELECT node, hex(node) FROM t1; node ÀÃÂÃ @@ -384,7 +351,7 @@ HEX(EXTRACTVALUE(@a,'/t1/line/node')) C380C381C382C383 CREATE TABLE t1 (node VARCHAR(50)) CHARACTER SET latin1 ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' - OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; + OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1'; INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); SELECT node, hex(node) FROM t1; node ÀÃÂÃ @@ -401,31 +368,26 @@ HEX(EXTRACTVALUE(@a,'/t1/line/node')) C0C1C2C3 CREATE TABLE t1 (node VARCHAR(50)) CHARACTER SET utf8 ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' - OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; + OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1'; INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3); +Warnings: +Level Warning +Code 1105 +Message Com error: Unable to save character to 'iso-8859-1' encoding. + INSERT INTO t1 VALUES ('&<>"\''); SELECT node, hex(node) FROM t1; -node ÀÃÂÃ -hex(node) C380C381C382C383 -node ÐБВГ -hex(node) D090D091D092D093 node &<>"' hex(node) 263C3E2227 DROP TABLE t1; SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); SELECT CAST(@a AS CHAR CHARACTER SET latin1); -CAST(@a AS CHAR CHARACTER SET latin1) - - - - ÀÃÂÃ - - - АБВГ - - - &<>"' - - +CAST(@a AS CHAR CHARACTER SET latin1) + + + + &<>"' + + diff --git a/storage/connect/mysql-test/connect/r/xml2.result b/storage/connect/mysql-test/connect/r/xml2.result new file mode 100644 index 0000000000000..eea53bf55c784 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2.result @@ -0,0 +1,431 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +SET NAMES utf8; +# +# Testing tag values +# +CREATE TABLE t1 +( +AUTHOR CHAR(50), +TITLE CHAR(32), +TRANSLATOR CHAR(40), +PUBLISHER CHAR(40), +DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t1; +AUTHOR Jean-Christophe Bernadac +TITLE Construire une application XML +TRANSLATOR NULL +PUBLISHER Eyrolles Paris +DATEPUB 1999 +AUTHOR William J. Pardi +TITLE XML en Action +TRANSLATOR James Guerin +PUBLISHER Microsoft Press Paris +DATEPUB 1999 +DROP TABLE t1; +# +# Testing that tag names are case sensitive +# +CREATE TABLE t1 +( +author CHAR(50), +TITLE CHAR(32), +TRANSLATOR CHAR(40), +PUBLISHER CHAR(40), +DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t1; +author NULL +TITLE Construire une application XML +TRANSLATOR NULL +PUBLISHER Eyrolles Paris +DATEPUB 1999 +author NULL +TITLE XML en Action +TRANSLATOR James Guerin +PUBLISHER Microsoft Press Paris +DATEPUB 1999 +DROP TABLE t1; +# +# Testing attribute values +# +CREATE TABLE t1 ( +ISBN CHAR(15), +LANG CHAR(2), +SUBJECT CHAR(32) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='Coltype=@,xmlsup=libxml2'; +SELECT * FROM t1; +ISBN 9782212090819 +LANG fr +SUBJECT applications +ISBN 9782840825685 +LANG fr +SUBJECT applications +DROP TABLE t1; +# +# Testing that attribute names are case sensitive +# +CREATE TABLE t1 ( +isbn CHAR(15), +LANG CHAR(2), +SUBJECT CHAR(32) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='Coltype=@,xmlsup=libxml2'; +SELECT * FROM t1; +isbn NULL +LANG fr +SUBJECT applications +isbn NULL +LANG fr +SUBJECT applications +DROP TABLE t1; +# +# Testing mixed tag and attribute values +# +CREATE TABLE t1 ( +ISBN CHAR(15) FIELD_FORMAT='@', +LANG CHAR(2) FIELD_FORMAT='@', +SUBJECT CHAR(32) FIELD_FORMAT='@', +AUTHOR CHAR(50), +TITLE CHAR(32), +TRANSLATOR CHAR(40), +PUBLISHER CHAR(40), +DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK' + OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t1; +ISBN 9782212090819 +LANG fr +SUBJECT applications +AUTHOR Jean-Christophe Bernadac +TITLE Construire une application XML +TRANSLATOR NULL +PUBLISHER Eyrolles Paris +DATEPUB 1999 +ISBN 9782840825685 +LANG fr +SUBJECT applications +AUTHOR William J. Pardi +TITLE XML en Action +TRANSLATOR James Guerin +PUBLISHER Microsoft Press Paris +DATEPUB 1999 +DROP TABLE t1; +# +# Testing INSERT on mixed tag and attribute values +# +CREATE TABLE t1 ( +ISBN CHAR(15) FIELD_FORMAT='@', +LANG CHAR(2) FIELD_FORMAT='@', +SUBJECT CHAR(32) FIELD_FORMAT='@', +AUTHOR CHAR(50), +TITLE CHAR(32), +TRANSLATOR CHAR(40), +PUBLISHER CHAR(40), +DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml' + TABNAME='BIBLIO' + OPTION_LIST='rownode=BOOK,xmlsup=libxml2'; +INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB) +VALUES('9782212090529','fr','général','Alain Michard', +'XML, Langage et Applications','Eyrolles Paris',1998); +SELECT * FROM t1; +ISBN 9782212090819 +LANG fr +SUBJECT applications +AUTHOR Jean-Christophe Bernadac +TITLE Construire une application XML +TRANSLATOR NULL +PUBLISHER Eyrolles Paris +DATEPUB 1999 +ISBN 9782840825685 +LANG fr +SUBJECT applications +AUTHOR William J. Pardi +TITLE XML en Action +TRANSLATOR James Guerin +PUBLISHER Microsoft Press Paris +DATEPUB 1999 +ISBN 9782212090529 +LANG fr +SUBJECT général +AUTHOR Alain Michard +TITLE XML, Langage et Applications +TRANSLATOR NULL +PUBLISHER Eyrolles Paris +DATEPUB 1998 +SELECT LOAD_FILE('MYSQLD_DATADIR/test/xsample2.xml') AS xml; +xml + + + + Jean-Christophe + Bernadac + + + François + Knab + + Construire une application XML + + Eyrolles + Paris + + 1999 + + + + William J. + Pardi + + + James + Guerin + + XML en Action + + Microsoft Press + Paris + + 1999 + + + Alain Michard + XML, Langage et Applications + Eyrolles Paris + 1998 + + + +DROP TABLE t1; +# +# Testing XPath +# +CREATE TABLE t1 ( +isbn CHAR(15) FIELD_FORMAT='@ISBN', +language CHAR(2) FIELD_FORMAT='@LANG', +subject CHAR(32) FIELD_FORMAT='@SUBJECT', +authorfn CHAR(20) FIELD_FORMAT='AUTHOR/FIRSTNAME', +authorln CHAR(20) FIELD_FORMAT='AUTHOR/LASTNAME', +title CHAR(32) FIELD_FORMAT='TITLE', +translated CHAR(32) FIELD_FORMAT='TRANSLATOR/@PREFIX', +tranfn CHAR(20) FIELD_FORMAT='TRANSLATOR/FIRSTNAME', +tranln CHAR(20) FIELD_FORMAT='TRANSLATOR/LASTNAME', +publisher CHAR(20) FIELD_FORMAT='PUBLISHER/NAME', +location CHAR(20) FIELD_FORMAT='PUBLISHER/PLACE', +year INT(4) FIELD_FORMAT='DATEPUB' +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; +SELECT * FROM t1; +isbn 9782212090819 +language fr +subject applications +authorfn Jean-Christophe +authorln Bernadac +title Construire une application XML +translated NULL +tranfn NULL +tranln NULL +publisher Eyrolles +location Paris +year 1999 +isbn 9782840825685 +language fr +subject applications +authorfn William J. +authorln Pardi +title XML en Action +translated adapté de l'anglais par +tranfn James +tranln Guerin +publisher Microsoft Press +location Paris +year 1999 +SELECT isbn, title, translated, tranfn, tranln, location FROM t1 +WHERE translated <> ''; +isbn 9782840825685 +title XML en Action +translated adapté de l'anglais par +tranfn James +tranln Guerin +location Paris +DROP TABLE t1; +# +# Testing that XPath is case sensitive +# +CREATE TABLE t1 +( +isbn CHAR(15) FIELD_FORMAT='@isbn' +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; +SELECT * FROM t1; +isbn NULL +isbn NULL +DROP TABLE t1; +# +# Testing character sets +# +CREATE TABLE t1 +( +c CHAR(16) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2' + DATA_CHARSET=latin1; +ERROR HY000: DATA_CHARSET='latin1' is not supported for TABLE_TYPE=XML +CREATE TABLE t1 +( +c CHAR(16) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2' + DATA_CHARSET=utf8; +SHOW CREATE TABLE t1; +Table t1 +Create Table CREATE TABLE `t1` ( + `c` char(16) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=XML `FILE_NAME`='latin1.xml' `OPTION_LIST`='xmlsup=libxml2' `DATA_CHARSET`=utf8 +SELECT c, HEX(c) FROM t1; +c ÃÂÃÄÅÆÇ +HEX(c) C1C2C3C4C5C6C7 +DROP TABLE t1; +CREATE TABLE t1 +( +c CHAR(16) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT c, HEX(c) FROM t1; +c ÃÂÃÄÅÆÇ +HEX(c) C1C2C3C4C5C6C7 +DROP TABLE t1; +CREATE TABLE t1 +( +c CHAR(16) CHARACTER SET utf8 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT c, HEX(c) FROM t1; +c ÃÂÃÄÅÆÇ +HEX(c) C381C382C383C384C385C386C387 +DROP TABLE t1; +# +# Conversion from latin1 to cp1251 produces a warning. +# Question marks are returned. +# +CREATE TABLE t1 +( +c CHAR(16) CHARACTER SET cp1251 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT c, HEX(c) FROM t1; +c ??????? +HEX(c) 3F3F3F3F3F3F3F +Warnings: +Level Warning +Code 1366 +Message Incorrect string value: '\xC3\x81\xC3\x82\xC3\x83...' for column 'c' at row 1 +Level Warning +Code 1105 +Message Out of range value ÃÂÃÄÅÆÇ for column 'c' at row 1 +DROP TABLE t1; +# +# Testing Cyrillic +# +CREATE TABLE t1 +( +c CHAR(16) CHARACTER SET utf8 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' + OPTION_LIST='xmlsup=libxml2,rownode=b'; +SELECT * FROM t1; +c БВГДЕЖЗ +INSERT INTO t1 VALUES ('ИКЛМÐ'); +SELECT c, HEX(c) FROM t1; +c БВГДЕЖЗ +HEX(c) D091D092D093D094D095D096D097 +c ИКЛМР+HEX(c) D098D09AD09BD09CD09D +DROP TABLE t1; +CREATE TABLE t1 +( +c CHAR(16) CHARACTER SET cp1251 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' + OPTION_LIST='xmlsup=libxml2,rownode=b'; +SELECT * FROM t1; +c БВГДЕЖЗ +c ИКЛМР+INSERT INTO t1 VALUES ('ОПРСТ'); +SELECT c, HEX(c) FROM t1; +c БВГДЕЖЗ +HEX(c) C1C2C3C4C5C6C7 +c ИКЛМР+HEX(c) C8CACBCCCD +c ОПРСТ +HEX(c) CECFD0D1D2 +DROP TABLE t1; +# +# Testing that the underlying file is created with a proper Encoding +# +CREATE TABLE t1 (node VARCHAR(50)) +CHARACTER SET latin1 +ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' + OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=utf-8'; +INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); +SELECT node, hex(node) FROM t1; +node ÀÃÂÃ +hex(node) C0C1C2C3 +DROP TABLE t1; +SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); +SELECT LEFT(@a,38); +LEFT(@a,38) +SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); +HEX(EXTRACTVALUE(@a,'/t1/line/node')) C380C381C382C383 +CREATE TABLE t1 (node VARCHAR(50)) +CHARACTER SET latin1 +ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' + OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; +INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); +SELECT node, hex(node) FROM t1; +node ÀÃÂÃ +hex(node) C0C1C2C3 +DROP TABLE t1; +SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); +SELECT LEFT(@a,43); +LEFT(@a,43) +SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); +HEX(EXTRACTVALUE(@a,'/t1/line/node')) C0C1C2C3 +# +# Testing XML entities +# +CREATE TABLE t1 (node VARCHAR(50)) +CHARACTER SET utf8 +ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' + OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; +INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); +INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3); +INSERT INTO t1 VALUES ('&<>"\''); +SELECT node, hex(node) FROM t1; +node ÀÃÂÃ +hex(node) C380C381C382C383 +node ÐБВГ +hex(node) D090D091D092D093 +node &<>"' +hex(node) 263C3E2227 +DROP TABLE t1; +SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml'); +SELECT CAST(@a AS CHAR CHARACTER SET latin1); +CAST(@a AS CHAR CHARACTER SET latin1) + + + + ÀÃÂÃ + + + АБВГ + + + &<>"' + + + diff --git a/storage/connect/mysql-test/connect/r/xml2_grant.result b/storage/connect/mysql-test/connect/r/xml2_grant.result new file mode 100644 index 0000000000000..817d3f5bf5723 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_grant.result @@ -0,0 +1,107 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +# +# Beginning of grant.inc +# +CREATE USER user@localhost; +GRANT ALL PRIVILEGES ON *.* TO user@localhost; +REVOKE FILE ON *.* FROM user@localhost; +connect user,localhost,user,,; +connection user; +SELECT user(); +user() +user@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +Warnings: +Warning 1105 No file name. Table will use t1.xml +INSERT INTO t1 VALUES (10); +SELECT * FROM t1; +a +10 +UPDATE t1 SET a=20; +SELECT * FROM t1; +a +20 +DELETE FROM t1; +SELECT * FROM t1; +a +INSERT INTO t1 VALUES(10); +TRUNCATE TABLE t1; +SELECT * FROM t1; +a +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +connection default; +SELECT user(); +user() +root@localhost +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; +INSERT INTO t1 VALUES (10); +connection user; +SELECT user(); +user() +user@localhost +INSERT INTO t1 VALUES (10); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE t1 SET a=20; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +TRUNCATE TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 READONLY=1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ALTER TABLE t1 FILE_NAME='t2.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DROP TABLE t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +CREATE VIEW v1 AS SELECT * FROM t1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +# Testing a VIEW created with FILE privileges but accessed with no FILE +connection default; +SELECT user(); +user() +root@localhost +CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1; +connection user; +SELECT user(); +user() +user@localhost +SELECT * FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +INSERT INTO v1 VALUES (2); +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +UPDATE v1 SET a=123; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +DELETE FROM v1; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +connection default; +SELECT user(); +user() +root@localhost +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +Warnings: +Warning 1105 No file name. Table will use t1.xml +INSERT INTO t1 VALUES (10); +connection user; +SELECT user(); +user() +user@localhost +ALTER TABLE t1 FILE_NAME='t1.EXT'; +ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +connection default; +DROP TABLE t1; +disconnect user; +DROP USER user@localhost; +# +# End of grant.inc +# diff --git a/storage/connect/mysql-test/connect/r/xml2_html.result b/storage/connect/mysql-test/connect/r/xml2_html.result new file mode 100644 index 0000000000000..143f46529f67b --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_html.result @@ -0,0 +1,32 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +SET NAMES utf8; +# +# Testing HTML like XML file +# +CREATE TABLE beers ( +`Name` CHAR(16) FIELD_FORMAT='brandName', +`Origin` CHAR(16) FIELD_FORMAT='origin', +`Description` CHAR(32) FIELD_FORMAT='details') +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml' +TABNAME='table' OPTION_LIST='xmlsup=libxml2,rownode=tr,colnode=td'; +SELECT * FROM beers; +Name Origin Description +Huntsman Bath, UK Wonderful hop, light alcohol +Tuborg Danmark In small bottles +DROP TABLE beers; +# +# Testing HTML file +# +CREATE TABLE coffee ( +`Name` CHAR(16), +`Cups` INT(8), +`Type` CHAR(16), +`Sugar` CHAR(4)) +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm' +TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=libxml2,Coltype=HTML'; +SELECT * FROM coffee; +Name Cups Type Sugar +T. Sexton 10 Espresso No +J. Dinnen 5 Decaf Yes +DROP TABLE coffee; diff --git a/storage/connect/mysql-test/connect/r/xml2_mdev5261.result b/storage/connect/mysql-test/connect/r/xml2_mdev5261.result new file mode 100644 index 0000000000000..0ee5712dd0257 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_mdev5261.result @@ -0,0 +1,25 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +SET NAMES utf8; +CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N'; +ERROR HY000: Table type XML is not indexable +CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N'; +DESCRIBE t1; +Field Type Null Key Default Extra +i int(11) NO NULL +ALTER TABLE t1 ADD UNIQUE(i); +ERROR HY000: Table type XML is not indexable +CREATE UNIQUE INDEX i ON t1(i); +ERROR HY000: Table type XML is not indexable +DESCRIBE t1; +Field Type Null Key Default Extra +i int(11) NO NULL +INSERT INTO t1 VALUES(2),(5),(7); +SELECT * FROM t1 WHERE i = 5; +i +5 +ALTER TABLE t1 DROP INDEX i; +ERROR 42000: Can't DROP INDEX `i`; check that it exists +DROP INDEX i ON t1; +ERROR 42000: Can't DROP INDEX `i`; check that it exists +DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/r/xml2_mult.result b/storage/connect/mysql-test/connect/r/xml2_mult.result new file mode 100644 index 0000000000000..a9592e986c0bd --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_mult.result @@ -0,0 +1,102 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +SET NAMES utf8; +# +# Testing expanded values +# +CREATE TABLE `bookstore` ( +`category` CHAR(16) NOT NULL FIELD_FORMAT='@', +`title` VARCHAR(50) NOT NULL, +`lang` char(2) NOT NULL FIELD_FORMAT='title/@', +`author` VARCHAR(24) NOT NULL, +`year` INT(4) NOT NULL, +`price` DOUBLE(8,2) NOT NULL) +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2'; +SELECT * FROM bookstore; +category title lang author year price +COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 +CHILDREN Harry Potter en J K. Rowling 2005 29.99 +WEB XQuery Kick Start en James McGovern 2003 49.99 +WEB XQuery Kick Start en Per Bothner 2003 49.99 +WEB XQuery Kick Start en Kurt Cagle 2003 49.99 +WEB XQuery Kick Start en James Linn 2003 49.99 +WEB XQuery Kick Start en Vaidyanathan Nagarajan 2003 49.99 +WEB Learning XML en Erik T. Ray 2003 39.95 +SELECT category, title, price FROM bookstore; +category title price +COOKING Everyday Italian 30.00 +CHILDREN Harry Potter 29.99 +WEB XQuery Kick Start 49.99 +WEB Learning XML 39.95 +SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%'; +category title author price +CHILDREN Harry Potter J K. Rowling 29.99 +WEB XQuery Kick Start Kurt Cagle 49.99 +WEB Learning XML Erik T. Ray 39.95 +SELECT category, title, price FROM bookstore WHERE author LIKE 'J%'; +category title price +CHILDREN Harry Potter 29.99 +WEB XQuery Kick Start 49.99 +WEB XQuery Kick Start 49.99 +# +# Limiting expanded values +# +ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2'; +SELECT * FROM bookstore; +category title lang author year price +COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 +CHILDREN Harry Potter en J K. Rowling 2005 29.99 +WEB XQuery Kick Start en James McGovern 2003 49.99 +WEB XQuery Kick Start en Per Bothner 2003 49.99 +WEB XQuery Kick Start en Kurt Cagle 2003 49.99 +WEB Learning XML en Erik T. Ray 2003 39.95 +Warnings: +Warning 1105 Mutiple values limited to 3 +# One line lost because the where clause is applied only on the first 3 rows +SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; +category title author price +CHILDREN Harry Potter J K. Rowling 29.99 +WEB XQuery Kick Start James McGovern 49.99 +Warnings: +Warning 1105 Mutiple values limited to 3 +# +# Testing concatenated values +# +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2'; +# truncated +SELECT * FROM bookstore; +category title lang author year price +COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 +CHILDREN Harry Potter en J K. Rowling 2005 29.99 +WEB XQuery Kick Start en James McGovern, Per Both 2003 49.99 +WEB Learning XML en Erik T. Ray 2003 39.95 +Warnings: +Warning 1105 Truncated author content +# increase author size +ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL; +SELECT * FROM bookstore; +category title lang author year price +COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 +CHILDREN Harry Potter en J K. Rowling 2005 29.99 +WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn, Vaidyanathan Nagarajan 2003 49.99 +WEB Learning XML en Erik T. Ray 2003 39.95 +# +# Limiting concatenated values +# +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2'; +SELECT * FROM bookstore; +category title lang author year price +COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 +CHILDREN Harry Potter en J K. Rowling 2005 29.99 +WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn 2003 49.99 +WEB Learning XML en Erik T. Ray 2003 39.95 +Warnings: +Warning 1105 Mutiple values limited to 4 +# The where clause is applied on the concatenated column result +SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; +category title author price +CHILDREN Harry Potter J K. Rowling 29.99 +WEB XQuery Kick Start James McGovern, Per Bothner, Kurt Cagle, James Linn 49.99 +Warnings: +Warning 1105 Mutiple values limited to 4 +DROP TABLE bookstore; diff --git a/storage/connect/mysql-test/connect/r/xml2_zip.result b/storage/connect/mysql-test/connect/r/xml2_zip.result new file mode 100644 index 0000000000000..f176149c53ff2 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_zip.result @@ -0,0 +1,98 @@ +Warnings: +Warning 1105 No file name. Table will use t1.xml +# +# Testing zipped XML tables +# +CREATE TABLE t1 ( +ISBN CHAR(13) NOT NULL FIELD_FORMAT='@', +LANG CHAR(2) NOT NULL FIELD_FORMAT='@', +SUBJECT CHAR(12) NOT NULL FIELD_FORMAT='@', +AUTHOR_FIRSTNAME CHAR(15) NOT NULL FIELD_FORMAT='AUTHOR/FIRSTNAME', +AUTHOR_LASTNAME CHAR(8) NOT NULL FIELD_FORMAT='AUTHOR/LASTNAME', +TRANSLATOR_PREFIX CHAR(24) DEFAULT NULL FIELD_FORMAT='TRANSLATOR/@PREFIX', +TRANSLATOR_FIRSTNAME CHAR(6) DEFAULT NULL FIELD_FORMAT='TRANSLATOR/FIRSTNAME', +TRANSLATOR_LASTNAME CHAR(6) DEFAULT NULL FIELD_FORMAT='TRANSLATOR/LASTNAME', +TITLE CHAR(30) NOT NULL, +PUBLISHER_NAME CHAR(15) NOT NULL FIELD_FORMAT='PUBLISHER/NAME', +PUBLISHER_PLACE CHAR(5) NOT NULL FIELD_FORMAT='PUBLISHER/PLACE', +DATEPUB CHAR(4) NOT NULL +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES +OPTION_LIST='entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=libxml2,expand=1,mulnode=AUTHOR'; +SELECT * FROM t1; +ISBN 9782212090819 +LANG fr +SUBJECT applications +AUTHOR_FIRSTNAME Jean-Christophe +AUTHOR_LASTNAME Bernadac +TRANSLATOR_PREFIX NULL +TRANSLATOR_FIRSTNAME NULL +TRANSLATOR_LASTNAME NULL +TITLE Construire une application XML +PUBLISHER_NAME Eyrolles +PUBLISHER_PLACE Paris +DATEPUB 1999 +ISBN 9782212090819 +LANG fr +SUBJECT applications +AUTHOR_FIRSTNAME François +AUTHOR_LASTNAME Knab +TRANSLATOR_PREFIX NULL +TRANSLATOR_FIRSTNAME NULL +TRANSLATOR_LASTNAME NULL +TITLE Construire une application XML +PUBLISHER_NAME Eyrolles +PUBLISHER_PLACE Paris +DATEPUB 1999 +ISBN 9782840825685 +LANG fr +SUBJECT applications +AUTHOR_FIRSTNAME William J. +AUTHOR_LASTNAME Pardi +TRANSLATOR_PREFIX adapté de l'anglais par +TRANSLATOR_FIRSTNAME James +TRANSLATOR_LASTNAME Guerin +TITLE XML en Action +PUBLISHER_NAME Microsoft Press +PUBLISHER_PLACE Paris +DATEPUB 1999 +ISBN 9782212090529 +LANG fr +SUBJECT général +AUTHOR_FIRSTNAME Alain +AUTHOR_LASTNAME Michard +TRANSLATOR_PREFIX NULL +TRANSLATOR_FIRSTNAME NULL +TRANSLATOR_LASTNAME NULL +TITLE XML, Langage et Applications +PUBLISHER_NAME Eyrolles +PUBLISHER_PLACE Paris +DATEPUB 2003 +CREATE TABLE t2 +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES +OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t2; +ISBN 9782212090819 +LANG fr +SUBJECT applications +AUTHOR Jean-Christophe Bernadac +TRANSLATOR NULL +TITLE Construire une application XML +PUBLISHER Eyrolles Paris +DATEPUB 1999 +ISBN 9782840825685 +LANG fr +SUBJECT applications +AUTHOR William J. Pardi +TRANSLATOR James Guerin +TITLE XML en Action +PUBLISHER Microsoft Press Paris +DATEPUB 1999 +ISBN 9782212090529 +LANG fr +SUBJECT général +AUTHOR Alain Michard +TRANSLATOR NULL +TITLE XML, Langage et Applications +PUBLISHER Eyrolles Paris +DATEPUB 2003 +DROP TABLE t1,t2; diff --git a/storage/connect/mysql-test/connect/r/xml_grant.result b/storage/connect/mysql-test/connect/r/xml_grant.result index 817d3f5bf5723..950ae4a3b3500 100644 --- a/storage/connect/mysql-test/connect/r/xml_grant.result +++ b/storage/connect/mysql-test/connect/r/xml_grant.result @@ -1,5 +1,3 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml # # Beginning of grant.inc # @@ -11,7 +9,7 @@ connection user; SELECT user(); user() user@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row'; Warnings: Warning 1105 No file name. Table will use t1.xml INSERT INTO t1 VALUES (10); @@ -34,13 +32,13 @@ SELECT * FROM v1; a DROP VIEW v1; DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row' FILE_NAME='t1.EXT'; ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) connection default; SELECT user(); user() root@localhost -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row' FILE_NAME='t1.EXT'; INSERT INTO t1 VALUES (10); connection user; SELECT user(); @@ -88,7 +86,7 @@ user() root@localhost DROP VIEW v1; DROP TABLE t1; -CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row'; Warnings: Warning 1105 No file name. Table will use t1.xml INSERT INTO t1 VALUES (10); diff --git a/storage/connect/mysql-test/connect/r/xml_html.result b/storage/connect/mysql-test/connect/r/xml_html.result index 143f46529f67b..4b984a49901b3 100644 --- a/storage/connect/mysql-test/connect/r/xml_html.result +++ b/storage/connect/mysql-test/connect/r/xml_html.result @@ -1,5 +1,3 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml SET NAMES utf8; # # Testing HTML like XML file @@ -9,7 +7,7 @@ CREATE TABLE beers ( `Origin` CHAR(16) FIELD_FORMAT='origin', `Description` CHAR(32) FIELD_FORMAT='details') ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml' -TABNAME='table' OPTION_LIST='xmlsup=libxml2,rownode=tr,colnode=td'; +TABNAME='table' OPTION_LIST='xmlsup=domdoc,rownode=tr,colnode=td'; SELECT * FROM beers; Name Origin Description Huntsman Bath, UK Wonderful hop, light alcohol @@ -24,7 +22,7 @@ CREATE TABLE coffee ( `Type` CHAR(16), `Sugar` CHAR(4)) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm' -TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=libxml2,Coltype=HTML'; +TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=domdoc,Coltype=HTML'; SELECT * FROM coffee; Name Cups Type Sugar T. Sexton 10 Espresso No diff --git a/storage/connect/mysql-test/connect/r/xml_mdev5261.result b/storage/connect/mysql-test/connect/r/xml_mdev5261.result index f91194d570c39..b5ae32c7784ea 100644 --- a/storage/connect/mysql-test/connect/r/xml_mdev5261.result +++ b/storage/connect/mysql-test/connect/r/xml_mdev5261.result @@ -1,9 +1,7 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml SET NAMES utf8; -CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='Rownode=N'; +CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N'; ERROR HY000: Table type XML is not indexable -CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='Rownode=N'; +CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N'; DESCRIBE t1; Field Type Null Key Default Extra i int(11) NO NULL diff --git a/storage/connect/mysql-test/connect/r/xml_mult.result b/storage/connect/mysql-test/connect/r/xml_mult.result index a9592e986c0bd..d89debadfab78 100644 --- a/storage/connect/mysql-test/connect/r/xml_mult.result +++ b/storage/connect/mysql-test/connect/r/xml_mult.result @@ -1,5 +1,3 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml SET NAMES utf8; # # Testing expanded values @@ -11,7 +9,7 @@ CREATE TABLE `bookstore` ( `author` VARCHAR(24) NOT NULL, `year` INT(4) NOT NULL, `price` DOUBLE(8,2) NOT NULL) -ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2'; +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=domdoc'; SELECT * FROM bookstore; category title lang author year price COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 @@ -41,7 +39,7 @@ WEB XQuery Kick Start 49.99 # # Limiting expanded values # -ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2'; +ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=domdoc'; SELECT * FROM bookstore; category title lang author year price COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 @@ -62,7 +60,7 @@ Warning 1105 Mutiple values limited to 3 # # Testing concatenated values # -ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2'; +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=domdoc'; # truncated SELECT * FROM bookstore; category title lang author year price @@ -83,7 +81,7 @@ WEB Learning XML en Erik T. Ray 2003 39.95 # # Limiting concatenated values # -ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2'; +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=domdoc'; SELECT * FROM bookstore; category title lang author year price COOKING Everyday Italian en Giada De Laurentiis 2005 30.00 diff --git a/storage/connect/mysql-test/connect/r/xml_zip.result b/storage/connect/mysql-test/connect/r/xml_zip.result index f176149c53ff2..f7790e4cfff72 100644 --- a/storage/connect/mysql-test/connect/r/xml_zip.result +++ b/storage/connect/mysql-test/connect/r/xml_zip.result @@ -1,5 +1,3 @@ -Warnings: -Warning 1105 No file name. Table will use t1.xml # # Testing zipped XML tables # @@ -17,7 +15,7 @@ PUBLISHER_NAME CHAR(15) NOT NULL FIELD_FORMAT='PUBLISHER/NAME', PUBLISHER_PLACE CHAR(5) NOT NULL FIELD_FORMAT='PUBLISHER/PLACE', DATEPUB CHAR(4) NOT NULL ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES -OPTION_LIST='entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=libxml2,expand=1,mulnode=AUTHOR'; +OPTION_LIST='entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=domdoc,expand=1,mulnode=AUTHOR'; SELECT * FROM t1; ISBN 9782212090819 LANG fr @@ -69,7 +67,7 @@ PUBLISHER_PLACE Paris DATEPUB 2003 CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES -OPTION_LIST='xmlsup=libxml2'; +OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t2; ISBN 9782212090819 LANG fr diff --git a/storage/connect/mysql-test/connect/r/zip.result b/storage/connect/mysql-test/connect/r/zip.result index c03b27bd428b8..c81546a4689f8 100644 --- a/storage/connect/mysql-test/connect/r/zip.result +++ b/storage/connect/mysql-test/connect/r/zip.result @@ -171,16 +171,16 @@ DROP TABLE t1,t2,t3,t4; # CREATE TABLE t1 ( _id INT(2) NOT NULL, -name_first CHAR(9) NOT NULL FIELD_FORMAT='name:first', -name_aka CHAR(4) DEFAULT NULL FIELD_FORMAT='name:aka', -name_last CHAR(10) NOT NULL FIELD_FORMAT='name:last', +name_first CHAR(9) NOT NULL FIELD_FORMAT='$.name.first', +name_aka CHAR(4) DEFAULT NULL FIELD_FORMAT='$.name.aka', +name_last CHAR(10) NOT NULL FIELD_FORMAT='$.name.last', title CHAR(12) DEFAULT NULL, birth CHAR(20) DEFAULT NULL, death CHAR(20) DEFAULT NULL, -contribs CHAR(7) NOT NULL FIELD_FORMAT='contribs:', -awards_award CHAR(42) DEFAULT NULL FIELD_FORMAT='awards::award', -awards_year CHAR(4) DEFAULT NULL FIELD_FORMAT='awards::year', -awards_by CHAR(38) DEFAULT NULL FIELD_FORMAT='awards::by' +contribs CHAR(7) NOT NULL FIELD_FORMAT='$.contribs', +awards_award CHAR(42) DEFAULT NULL FIELD_FORMAT='$.awards.award', +awards_year CHAR(4) DEFAULT NULL FIELD_FORMAT='$.awards.year', +awards_by CHAR(38) DEFAULT NULL FIELD_FORMAT='$.awards.by' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bios.zip' OPTION_LIST='ENTRY=bios.json,LOAD=bios.json' ZIPPED=YES; SELECT * FROM t1; _id name_first name_aka name_last title birth death contribs awards_award awards_year awards_by @@ -211,16 +211,16 @@ _id name_first name_aka name_last title birth death contribs awards_award awards 10 Martin NULL Odersky NULL NULL NULL Scala NULL NULL NULL CREATE TABLE t3 ( _id INT(2) NOT NULL, -firstname CHAR(9) NOT NULL FIELD_FORMAT='name:first', -aka CHAR(4) DEFAULT NULL FIELD_FORMAT='name:aka', -lastname CHAR(10) NOT NULL FIELD_FORMAT='name:last', +firstname CHAR(9) NOT NULL FIELD_FORMAT='$.name.first', +aka CHAR(4) DEFAULT NULL FIELD_FORMAT='$.name.aka', +lastname CHAR(10) NOT NULL FIELD_FORMAT='$.name.last', title CHAR(12) DEFAULT NULL, birth date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'", death date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'", -contribs CHAR(64) NOT NULL FIELD_FORMAT='contribs:[", "]', -award CHAR(42) DEFAULT NULL FIELD_FORMAT='awards:[x]:award', -year CHAR(4) DEFAULT NULL FIELD_FORMAT='awards:[x]:year', -`by` CHAR(38) DEFAULT NULL FIELD_FORMAT='awards:[x]:by' +contribs CHAR(64) NOT NULL FIELD_FORMAT='$.contribs.[", "]', +award CHAR(42) DEFAULT NULL FIELD_FORMAT='$.awards[*].award', +year CHAR(4) DEFAULT NULL FIELD_FORMAT='$.awards[*].year', +`by` CHAR(38) DEFAULT NULL FIELD_FORMAT='$.awards[*].by' ) ENGINE=CONNECT TABLE_TYPE='json' FILE_NAME='bios.zip' ZIPPED=YES; SELECT * FROM t3 WHERE _id = 1; _id firstname aka lastname title birth death contribs award year by diff --git a/storage/connect/mysql-test/connect/t/alter_xml.test b/storage/connect/mysql-test/connect/t/alter_xml.test index 0b876296e58f0..8b2164d5548b3 100644 --- a/storage/connect/mysql-test/connect/t/alter_xml.test +++ b/storage/connect/mysql-test/connect/t/alter_xml.test @@ -1,4 +1,4 @@ ---source have_libxml2.inc +--source windows.inc --echo # --echo # Testing changing table type (not in-place) @@ -11,7 +11,7 @@ SELECT * FROM t1; --echo # This is because the XML top node name defaults to the table name. --echo # Sure enough the temporary table name begins with '#' and is rejected by XML. --echo # Therefore the top node name must be specified (along with the row nodes name). -ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='rownode=row'; +ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=domdoc,rownode=row'; SELECT * FROM t1; SHOW CREATE TABLE t1; diff --git a/storage/connect/mysql-test/connect/t/alter_xml2.test b/storage/connect/mysql-test/connect/t/alter_xml2.test new file mode 100644 index 0000000000000..d67c80c4e9fb5 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/alter_xml2.test @@ -0,0 +1,29 @@ +--source have_libxml2.inc + +--echo # +--echo # Testing changing table type (not in-place) +--echo # +CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1 QUOTED=1; +INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three'); +SELECT * FROM t1; + +--echo # This would fail if the top node name is not specified. +--echo # This is because the XML top node name defaults to the table name. +--echo # Sure enough the temporary table name begins with '#' and is rejected by XML. +--echo # Therefore the top node name must be specified (along with the row nodes name). +ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=libxml2,rownode=row'; +SELECT * FROM t1; +SHOW CREATE TABLE t1; + +--echo # Let us see the XML file +CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.xml'; +SELECT * FROM t2; +--echo # NOTE: The first (ignored) row is due to the remaining HEADER=1 option. + +--echo # Testing field option modification +ALTER TABLE t1 MODIFY d CHAR(10) NOT NULL FIELD_FORMAT='@', HEADER=0; +SELECT * FROM t1; +SHOW CREATE TABLE t1; +SELECT * FROM t2; + +DROP TABLE t1, t2; diff --git a/storage/connect/mysql-test/connect/t/dir.test b/storage/connect/mysql-test/connect/t/dir.test index 8a56d4f8829de..684b5522b08e3 100644 --- a/storage/connect/mysql-test/connect/t/dir.test +++ b/storage/connect/mysql-test/connect/t/dir.test @@ -23,10 +23,7 @@ ALTER TABLE t1 OPTION_LIST='subdir=0'; SHOW CREATE TABLE t1; --replace_result $MYSQLD_DATADIR DATADIR/ SELECT fname, ftype, size FROM t1 ORDER BY fname, ftype, size; - -# TODO: add a better error message ---error ER_GET_ERRMSG -SET STATEMENT sql_mode = '' FOR +--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD INSERT INTO t1 VALUES ('','','',''); DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/t/infoschema-9739.test b/storage/connect/mysql-test/connect/t/infoschema-9739.test index e9eb7fb796eb7..de61164d10de3 100644 --- a/storage/connect/mysql-test/connect/t/infoschema-9739.test +++ b/storage/connect/mysql-test/connect/t/infoschema-9739.test @@ -2,8 +2,8 @@ # MDEV-9739 Assertion `m_status == DA_ERROR || m_status == DA_OK' failed in Diagnostics_area::message() ; connect.xml* tests fail in buildbot # ---source have_libxml2.inc +--source windows.inc -create table t1 (i int) engine=Connect table_type=XML; +create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=domdoc'; select * from information_schema.tables where create_options like '%table_type=XML%'; drop table t1; diff --git a/storage/connect/mysql-test/connect/t/infoschema2-9739.test b/storage/connect/mysql-test/connect/t/infoschema2-9739.test new file mode 100644 index 0000000000000..345274b057757 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/infoschema2-9739.test @@ -0,0 +1,9 @@ +# +# MDEV-9739 Assertion `m_status == DA_ERROR || m_status == DA_OK' failed in Diagnostics_area::message() ; connect.xml* tests fail in buildbot +# + +--source have_libxml2.inc + +create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=libxml2'; +select * from information_schema.tables where create_options like '%table_type=XML%'; +drop table t1; diff --git a/storage/connect/mysql-test/connect/t/jdbc_new.test b/storage/connect/mysql-test/connect/t/jdbc_new.test index 86c4ad57c5f0d..36e8f36ced052 100644 --- a/storage/connect/mysql-test/connect/t/jdbc_new.test +++ b/storage/connect/mysql-test/connect/t/jdbc_new.test @@ -161,7 +161,7 @@ DROP TABLE t1; CREATE TABLE t1 (a date, b datetime, c time, d timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, e year); SHOW CREATE TABLE t1; -INSERT INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23'); +INSERT IGNORE INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23'); SELECT * FROM t1; connection master; diff --git a/storage/connect/mysql-test/connect/t/json.test b/storage/connect/mysql-test/connect/t/json.test index fa962d3b302ef..018489525f792 100644 --- a/storage/connect/mysql-test/connect/t/json.test +++ b/storage/connect/mysql-test/connect/t/json.test @@ -35,15 +35,15 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15), - Language CHAR(2) FIELD_FORMAT='LANG', - Subject CHAR(32) FIELD_FORMAT='SUBJECT', - Authors INT(2) FIELD_FORMAT='AUTHOR:[#]', - Title CHAR(32) FIELD_FORMAT='TITLE', - Translation CHAR(32) FIELD_FORMAT='TRANSLATION', - Translator CHAR(80) FIELD_FORMAT='TRANSLATOR', - Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', - Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', - Year int(4) FIELD_FORMAT='DATEPUB' + Language CHAR(2) FIELD_FORMAT='$.LANG', + Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', + Authors INT(2) FIELD_FORMAT='$.AUTHOR[#]', + Title CHAR(32) FIELD_FORMAT='$.TITLE', + Translation CHAR(32) FIELD_FORMAT='$.TRANSLATION', + Translator CHAR(80) FIELD_FORMAT='$.TRANSLATOR', + Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', + Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', + Year int(4) FIELD_FORMAT='$.DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; SELECT * FROM t1; @@ -55,16 +55,16 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15), - Language CHAR(2) FIELD_FORMAT='LANG', - Subject CHAR(32) FIELD_FORMAT='SUBJECT', - AuthorFN CHAR(128) FIELD_FORMAT='AUTHOR:[" and "]:FIRSTNAME', - AuthorLN CHAR(128) FIELD_FORMAT='AUTHOR:[" and "]:LASTNAME', - Title CHAR(32) FIELD_FORMAT='TITLE', - Translation CHAR(32) FIELD_FORMAT='TRANSLATION', - Translator CHAR(80) FIELD_FORMAT='TRANSLATOR', - Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', - Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', - Year int(4) FIELD_FORMAT='DATEPUB' + Language CHAR(2) FIELD_FORMAT='$.LANG', + Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', + AuthorFN CHAR(128) FIELD_FORMAT='$.AUTHOR[" and "].FIRSTNAME', + AuthorLN CHAR(128) FIELD_FORMAT='$.AUTHOR[" and "].LASTNAME', + Title CHAR(32) FIELD_FORMAT='$.TITLE', + Translation CHAR(32) FIELD_FORMAT='$.TRANSLATION', + Translator CHAR(80) FIELD_FORMAT='$.TRANSLATOR', + Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', + Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', + Year int(4) FIELD_FORMAT='$.DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; SELECT * FROM t1; @@ -76,16 +76,16 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15), - Language CHAR(2) FIELD_FORMAT='LANG', - Subject CHAR(32) FIELD_FORMAT='SUBJECT', - AuthorFN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:FIRSTNAME', - AuthorLN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:LASTNAME', - Title CHAR(32) FIELD_FORMAT='TITLE', - Translation CHAR(32) FIELD_FORMAT='TRANSLATION', - Translator CHAR(80) FIELD_FORMAT='TRANSLATOR', - Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', - Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', - Year int(4) FIELD_FORMAT='DATEPUB' + Language CHAR(2) FIELD_FORMAT='$.LANG', + Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', + AuthorFN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].FIRSTNAME', + AuthorLN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].LASTNAME', + Title CHAR(32) FIELD_FORMAT='$.TITLE', + Translation CHAR(32) FIELD_FORMAT='$.TRANSLATION', + Translator CHAR(80) FIELD_FORMAT='$.TRANSLATOR', + Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', + Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', + Year int(4) FIELD_FORMAT='$.DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; SELECT * FROM t1; @@ -98,7 +98,7 @@ SELECT * FROM t1 WHERE ISBN = '9782212090819'; CREATE TABLE t2 ( FIRSTNAME CHAR(32), LASTNAME CHAR(32)) -ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json' OPTION_LIST='Object=[1]:AUTHOR'; +ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json' OPTION_LIST='Object=$[1].AUTHOR'; SELECT * FROM t2; INSERT INTO t2 VALUES('Charles','Dickens'); SELECT * FROM t1; @@ -122,17 +122,17 @@ DROP TABLE t1; CREATE TABLE t1 ( ISBN CHAR(15) NOT NULL, - Language CHAR(2) FIELD_FORMAT='LANG', - Subject CHAR(32) FIELD_FORMAT='SUBJECT', - AuthorFN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:FIRSTNAME', - AuthorLN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:LASTNAME', - Title CHAR(32) FIELD_FORMAT='TITLE', - Translation CHAR(32) FIELD_FORMAT='TRANSLATED:PREFIX', - TranslatorFN CHAR(80) FIELD_FORMAT='TRANSLATED:TRANSLATOR:FIRSTNAME', - TranslatorLN CHAR(80) FIELD_FORMAT='TRANSLATED:TRANSLATOR:LASTNAME', - Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME', - Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE', - Year int(4) FIELD_FORMAT='DATEPUB', + Language CHAR(2) FIELD_FORMAT='$.LANG', + Subject CHAR(32) FIELD_FORMAT='$.SUBJECT', + AuthorFN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].FIRSTNAME', + AuthorLN CHAR(128) FIELD_FORMAT='$.AUTHOR[*].LASTNAME', + Title CHAR(32) FIELD_FORMAT='$.TITLE', + Translation CHAR(32) FIELD_FORMAT='$.TRANSLATED.PREFIX', + TranslatorFN CHAR(80) FIELD_FORMAT='$.TRANSLATED.TRANSLATOR.FIRSTNAME', + TranslatorLN CHAR(80) FIELD_FORMAT='$.TRANSLATED.TRANSLATOR.LASTNAME', + Publisher CHAR(20) FIELD_FORMAT='$.PUBLISHER.NAME', + Location CHAR(16) FIELD_FORMAT='$.PUBLISHER.PLACE', + Year int(4) FIELD_FORMAT='$.DATEPUB', INDEX IX(ISBN) ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bib0.json' LRECL=320 OPTION_LIST='Pretty=0'; @@ -148,9 +148,9 @@ DROP TABLE t1; --echo # CREATE TABLE t1 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[X]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK::EXPENSE:["+"]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK::EXPENSE:[+]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[*].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[].EXPENSE["+"].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[].EXPENSE[+].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t1; DROP TABLE t1; @@ -160,9 +160,9 @@ DROP TABLE t1; --echo # CREATE TABLE t1 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[X]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[*].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[*].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[*].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; #--error ER_GET_ERRMSG SELECT * FROM t1; @@ -173,14 +173,14 @@ DROP TABLE t1; --echo # CREATE TABLE t1 ( WHO CHAR(12) NOT NULL, -WEEKS CHAR(12) NOT NULL FIELD_FORMAT='WEEK:[", "]:NUMBER', -SUMS CHAR(64) NOT NULL FIELD_FORMAT='WEEK:["+"]:EXPENSE:[+]:AMOUNT', -SUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[+]:EXPENSE:[+]:AMOUNT', -AVGS CHAR(64) NOT NULL FIELD_FORMAT='WEEK:["+"]:EXPENSE:[!]:AMOUNT', -SUMAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[+]:EXPENSE:[!]:AMOUNT', -AVGSUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[!]:EXPENSE:[+]:AMOUNT', -AVGAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[!]:EXPENSE:[!]:AMOUNT', -AVERAGE DOUBLE(8,2) NOT NULL FIELD_FORMAT='WEEK:[!]:EXPENSE:[X]:AMOUNT') +WEEKS CHAR(12) NOT NULL FIELD_FORMAT='$.WEEK[", "].NUMBER', +SUMS CHAR(64) NOT NULL FIELD_FORMAT='$.WEEK["+"].EXPENSE[+].AMOUNT', +SUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[+].EXPENSE[+].AMOUNT', +AVGS CHAR(64) NOT NULL FIELD_FORMAT='$.WEEK["+"].EXPENSE[!].AMOUNT', +SUMAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[+].EXPENSE[!].AMOUNT', +AVGSUM DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[!].EXPENSE[+].AMOUNT', +AVGAVG DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[!].EXPENSE[!].AMOUNT', +AVERAGE DOUBLE(8,2) NOT NULL FIELD_FORMAT='$.WEEK[!].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t1; DROP TABLE t1; @@ -190,25 +190,25 @@ DROP TABLE t1; --echo # CREATE TABLE t2 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[0]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[0]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[0]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[0].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[0].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[0].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t2; CREATE TABLE t3 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[1]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[1]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[1]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[1].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[1].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[1].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t3; CREATE TABLE t4 ( WHO CHAR(12), -WEEK INT(2) FIELD_FORMAT='WEEK:[2]:NUMBER', -WHAT CHAR(32) FIELD_FORMAT='WEEK:[2]:EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[2]:EXPENSE:[X]:AMOUNT') +WEEK INT(2) FIELD_FORMAT='$.WEEK[2].NUMBER', +WHAT CHAR(32) FIELD_FORMAT='$.WEEK[2].EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.WEEK[2].EXPENSE[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json'; SELECT * FROM t4; @@ -230,24 +230,24 @@ DROP TABLE t1, t2, t3, t4; CREATE TABLE t2 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp3.json'; SELECT * FROM t2; CREATE TABLE t3 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp4.json'; SELECT * FROM t3; CREATE TABLE t4 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp5.json'; SELECT * FROM t4; @@ -257,8 +257,8 @@ SELECT * FROM t4; CREATE TABLE t1 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp*.json' MULTIPLE=1; SELECT * FROM t1 ORDER BY WHO, WEEK, WHAT, AMOUNT; DROP TABLE t1; @@ -269,8 +269,8 @@ DROP TABLE t1; CREATE TABLE t1 ( WHO CHAR(12), WEEK INT(2), -WHAT CHAR(32) FIELD_FORMAT='EXPENSE:[X]:WHAT', -AMOUNT DOUBLE(8,2) FIELD_FORMAT='EXPENSE:[X]:AMOUNT') +WHAT CHAR(32) FIELD_FORMAT='$.EXPENSE[*].WHAT', +AMOUNT DOUBLE(8,2) FIELD_FORMAT='$.EXPENSE.[*].AMOUNT') ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp%s.json'; ALTER TABLE t1 PARTITION BY LIST COLUMNS(WEEK) ( diff --git a/storage/connect/mysql-test/connect/t/json_udf.inc b/storage/connect/mysql-test/connect/t/json_udf.inc index 2ade7ad02fe22..4f675023c447e 100644 --- a/storage/connect/mysql-test/connect/t/json_udf.inc +++ b/storage/connect/mysql-test/connect/t/json_udf.inc @@ -9,11 +9,11 @@ if (!$HA_CONNECT_SO) { --skip Needs a dynamically built ha_connect.so } ---eval CREATE FUNCTION json_array RETURNS STRING SONAME '$HA_CONNECT_SO'; +--eval CREATE FUNCTION json_make_array RETURNS STRING SONAME '$HA_CONNECT_SO'; --eval CREATE FUNCTION json_array_add RETURNS STRING SONAME '$HA_CONNECT_SO'; --eval CREATE FUNCTION json_array_add_values RETURNS STRING SONAME '$HA_CONNECT_SO'; --eval CREATE FUNCTION json_array_delete RETURNS STRING SONAME '$HA_CONNECT_SO'; ---eval CREATE FUNCTION json_object RETURNS STRING SONAME '$HA_CONNECT_SO'; +--eval CREATE FUNCTION json_make_object RETURNS STRING SONAME '$HA_CONNECT_SO'; --eval CREATE FUNCTION json_object_nonull RETURNS STRING SONAME '$HA_CONNECT_SO'; --eval CREATE FUNCTION json_object_key RETURNS STRING SONAME '$HA_CONNECT_SO'; --eval CREATE FUNCTION json_object_add RETURNS STRING SONAME '$HA_CONNECT_SO'; diff --git a/storage/connect/mysql-test/connect/t/json_udf.test b/storage/connect/mysql-test/connect/t/json_udf.test index d11e2fd7cf6c4..35dbbfed7065e 100644 --- a/storage/connect/mysql-test/connect/t/json_udf.test +++ b/storage/connect/mysql-test/connect/t/json_udf.test @@ -22,13 +22,13 @@ SELECT JsonValue(FALSE); SELECT JsonValue(); SELECT JsonValue('[11, 22, 33]' json_) FROM t1; # -SELECT Json_Array(); -SELECT Json_Array(56, 3.1416, 'My name is "Foo"', NULL); -SELECT Json_Array(Json_Array(56, 3.1416, 'foo'), TRUE); +SELECT Json_Make_Array(); +SELECT Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL); +SELECT Json_Make_Array(Json_Make_Array(56, 3.1416, 'foo'), TRUE); # --error ER_CANT_INITIALIZE_UDF -SELECT Json_Array_Add(Json_Array(56, 3.1416, 'foo', NULL)) Array; -SELECT Json_Array_Add(Json_Array(56, 3.1416, 'foo', NULL), 'One more') Array; +SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL)) Array; +SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Array; --error ER_CANT_INITIALIZE_UDF SELECT Json_Array_Add(JsonValue('one value'), 'One more'); --error ER_CANT_INITIALIZE_UDF @@ -39,38 +39,38 @@ SELECT Json_Array_Add(5 json_, 'One more'); SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 0); SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 2) Array; SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 9); -SELECT Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), '[2]', 33, 1); -SELECT Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), 33, '[2]', 1); -SELECT Json_Array_Add(Json_Array(1, 2, Json_Array(11, 22)), 33, 1, '[2]'); +SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), '[2]', 33, 1); +SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, '[2]', 1); +SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, 1, '[2]'); # -SELECT Json_Array_Add_Values(Json_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array; -SELECT Json_Array_Add_Values(Json_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1; -SELECT Json_Array_Add_Values(Json_Array(56, 3.1416, 'machin'), n) Array FROM t1; -SELECT Json_Array_Add_Values(Json_Array(n, 3.1416, 'machin'), n) Array FROM t1; +SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array; +SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1; +SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), n) Array FROM t1; +SELECT Json_Array_Add_Values(Json_Make_Array(n, 3.1416, 'machin'), n) Array FROM t1; SELECT Json_Array_Add_Values('[56]', 3.1416, 'machin') Array; # -SELECT Json_Array_Delete(Json_Array(56, 3.1416, 'My name is "Foo"', NULL), 0); -SELECT Json_Array_Delete(Json_Object(56, 3.1416, 'My name is Foo', NULL), 2); -SELECT Json_Array_Delete(Json_Array(56, 3.1416, 'My name is "Foo"', NULL), '2'); -SELECT Json_Array_Delete(json_array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2); +SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0); +SELECT Json_Array_Delete(Json_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2); +SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2'); +SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2); # -SELECT Json_Object(56, 3.1416, 'foo', NULL); -SELECT Json_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty); -SELECT Json_Object(); -SELECT Json_Object(Json_Array(56, 3.1416, 'foo'), NULL); -SELECT Json_Array(Json_Object(56 "qty", 3.1416 "price", 'foo') ,NULL); +SELECT Json_Make_Object(56, 3.1416, 'foo', NULL); +SELECT Json_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty); +SELECT Json_Make_Object(); +SELECT Json_Make_Object(Json_Make_Array(56, 3.1416, 'foo'), NULL); +SELECT Json_Make_Array(Json_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL); SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL); --error ER_CANT_INITIALIZE_UDF SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty'); # -SELECT Json_Object_Add(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color); -SELECT Json_Object_Add(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price); +SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color); +SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price); SELECT Json_Object_Add(Json_File('notexist.json'), 'cheese' item, '[1]', 1); # -SELECT Json_Object_Delete(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc'); -SELECT Json_Object_Delete(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose'); +SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc'); +SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose'); # -SELECT Json_Object_List(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List"; +SELECT Json_Object_List(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List"; SELECT Json_Object_List('{"qty":56, "price":3.1416, "truc":"machin", "garanty":null}') "Key List"; --echo # @@ -89,8 +89,8 @@ CREATE TABLE t2 DATEPUB int(4) ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json'; -SELECT Json_Array(AUTHOR, TITLE, DATEPUB) FROM t2; -SELECT Json_Object(AUTHOR, TITLE, DATEPUB) FROM t2; +SELECT Json_Make_Array(AUTHOR, TITLE, DATEPUB) FROM t2; +SELECT Json_Make_Object(AUTHOR, TITLE, DATEPUB) FROM t2; --error ER_CANT_INITIALIZE_UDF SELECT Json_Array_Grp(TITLE, DATEPUB) FROM t2; SELECT Json_Array_Grp(TITLE) FROM t2; @@ -106,19 +106,19 @@ CREATE TABLE t3 ( SALARY DOUBLE(8,2) NOT NULL FLAG=52 ) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=8 FILE_NAME='employee.dat' ENDING=1; -SELECT Json_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT'; +SELECT Json_Make_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT'; SELECT DEPARTMENT, Json_Array_Grp(NAME) FROM t3 GROUP BY DEPARTMENT; #SET connect_json_grp_size=30; Deprecated SELECT JsonSet_Grp_Size(30); -SELECT Json_Object(title, Json_Array_Grp(name) `json_names`) from t3 GROUP BY title; -SELECT Json_Array(DEPARTMENT, Json_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT; -SELECT Json_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT; -SELECT Json_Object(DEPARTMENT, Json_Array_Grp(Json_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT; -SELECT Json_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE; +SELECT Json_Make_Object(title, Json_Array_Grp(name) `json_names`) from t3 GROUP BY title; +SELECT Json_Make_Array(DEPARTMENT, Json_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT; +SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT; +SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT; +SELECT Json_Make_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE; --error ER_CANT_INITIALIZE_UDF SELECT Json_Object_Grp(SALARY) FROM t3; SELECT Json_Object_Grp(NAME, SALARY) FROM t3; -SELECT Json_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT; +SELECT Json_Make_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT; SELECT Json_Array_Grp(NAME) FROM t3; # SELECT Json_Object_Key(name, title) FROM t3 WHERE DEPARTMENT = 318; @@ -131,59 +131,59 @@ SELECT JsonGet_String(Json_Array_Grp(name),'[#]') FROM t3; SELECT JsonGet_String(Json_Array_Grp(name),'[","]') FROM t3; SELECT JsonGet_String(Json_Array_Grp(name),'[>]') FROM t3; SET @j1 = '[45,28,36,45,89]'; -SELECT JsonGet_String(@j1,'[1]'); -SELECT JsonGet_String(@j1 json_,'[3]'); -SELECT JsonGet_String(Json_Array(45,28,36,45,89),'[3]'); -SELECT JsonGet_String(Json_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",JsonGet_String(Json_Array(45,28,36,45,89),'[+]') "sum"; -SELECT JsonGet_String(Json_Array(json_array(45,28),json_array(36,45,89)),'[1]:[0]'); -SELECT JsonGet_String(Json_Array(json_array(45,28),json_array(36,45,89)),'[1]:*'); -SELECT JsonGet_String(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc'); +SELECT JsonGet_String(@j1,'1'); +SELECT JsonGet_String(@j1 json_,'3'); +SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'3'); +SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",JsonGet_String(Json_Make_Array(45,28,36,45,89),'[+]') "sum"; +SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0'); +SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.*'); +SELECT JsonGet_String(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc'); SET @j2 = '{"qty":56,"price":3.141600,"truc":"machin","garanty":null}'; SELECT JsonGet_String(@j2 json_,'truc'); SELECT JsonGet_String(@j2,'truc'); SELECT JsonGet_String(@j2,'chose'); SELECT JsonGet_String(NULL json_, NULL); -SELECT department, JsonGet_String(Json_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries:[+]') Sumsal FROM t3 GROUP BY department; +SELECT department, JsonGet_String(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department; # -SELECT JsonGet_Int(@j1, '[4]'); +SELECT JsonGet_Int(@j1, '4'); SELECT JsonGet_Int(@j1, '[#]'); SELECT JsonGet_Int(@j1, '[+]'); -SELECT JsonGet_Int(@j1 json_, '[3]'); -SELECT JsonGet_Int(Json_Array(45,28,36,45,89), '[3]'); -SELECT JsonGet_Int(Json_Array(45,28,36,45,89), '["+"]'); -SELECT JsonGet_Int(Json_Array(45,28,36,45,89), '[+]'); -SELECT JsonGet_Int(Json_Array(json_array(45,28), json_array(36,45,89)), '[1]:[0]'); -SELECT JsonGet_Int(Json_Array(json_array(45,28), json_array(36,45,89)), '[0]:[1]'); -SELECT JsonGet_Int(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty'); +SELECT JsonGet_Int(@j1 json_, '3'); +SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '3'); +SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '["+"]'); +SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]'); +SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0'); +SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '0.1'); +SELECT JsonGet_Int(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty'); SELECT JsonGet_Int(@j2 json_, 'price'); SELECT JsonGet_Int(@j2, 'qty'); SELECT JsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose'); -SELECT JsonGet_Int(JsonGet_String(Json_Array(Json_Array(45,28),Json_Array(36,45,89)), '[1]:*'), '[+]') sum; -SELECT department, JsonGet_Int(Json_Object(department, Json_Array_Grp(salary) "Json_salaries"), 'salaries:[+]') Sumsal FROM t3 GROUP BY department; +SELECT JsonGet_Int(JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)), '1.*'), '[+]') sum; +SELECT department, JsonGet_Int(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"), 'salaries.[+]') Sumsal FROM t3 GROUP BY department; # -SELECT JsonGet_Real(@j1, '[2]'); -SELECT JsonGet_Real(@j1 json_, '[3]', 2); -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '[3]'); -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '["+"]'); -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '[+]'); -SELECT JsonGet_Real(Json_Array(45,28,36,45,89), '[!]'); -SELECT JsonGet_Real(Json_Array(json_array(45,28), json_array(36,45,89)), '[1]:[0]'); -SELECT JsonGet_Real(Json_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price'); +SELECT JsonGet_Real(@j1, '2'); +SELECT JsonGet_Real(@j1 json_, '3', 2); +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '3'); +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '["+"]'); +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[+]'); +SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]'); +SELECT JsonGet_Real(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0'); +SELECT JsonGet_Real(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price'); SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty'); SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price'); SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price', 4); SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose'); -SELECT department, JsonGet_Real(Json_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries:[+]') Sumsal FROM t3 GROUP BY department; +SELECT department, JsonGet_Real(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department; --echo # --echo # Documentation examples --echo # SELECT - JsonGet_Int(Json_Array(45,28,36,45,89), '[4]') "Rank", - JsonGet_Int(Json_Array(45,28,36,45,89), '[#]') "Number", - JsonGet_String(Json_Array(45,28,36,45,89), '[","]') "Concat", - JsonGet_Int(Json_Array(45,28,36,45,89), '[+]') "Sum", - JsonGet_Real(Json_Array(45,28,36,45,89), '[!]', 2) "Avg"; + JsonGet_Int(Json_Make_Array(45,28,36,45,89), '4') "Rank", + JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[#]') "Number", + JsonGet_String(Json_Make_Array(45,28,36,45,89), '[","]') "Concat", + JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]') "Sum", + JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]', 2) "Avg"; SELECT JsonGet_String('{"qty":7,"price":29.50,"garanty":null}', 'price') "String", JsonGet_Int('{"qty":7,"price":29.50,"garanty":null}', 'price') "Int", @@ -193,10 +193,10 @@ SELECT JsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price', 3) "Real" --echo # --echo # Testing Locate --echo # -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin'); -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56); -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416); -SELECT JsonLocate(Json_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose'); +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin'); +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56); +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416); +SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose'); SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'Jack') Path; SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'jack' ci) Path; SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"Jack", "LN":"London"}' json_) Path; @@ -220,7 +220,7 @@ SELECT Json_Locate_All('[[45,28],[[36,45],89]]','45') "All paths"; SELECT Json_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_); SELECT JsonGet_Int(Json_Locate_All('[[45,28],[[36,45],89]]',45), '[#]') "Nb of occurs"; SELECT Json_Locate_All('[[45,28],[[36,45],89]]',45,2); -SELECT JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'[0]'); +SELECT JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'0'); SELECT JsonLocate(Json_File('test/biblio.json'), 'Knab'); SELECT Json_Locate_All('test/biblio.json' jfile_, 'Knab'); @@ -237,21 +237,21 @@ SELECT Jfile_Make(Jbin_File('test/fx.json'), 0); SELECT Json_File('test/fx.json', 1); SELECT Json_File('test/fx.json', 2); SELECT Json_File('test/fx.json', 0); -SELECT Json_File('test/fx.json', '[0]'); +SELECT Json_File('test/fx.json', '0'); SELECT Json_File('test/fx.json', '[?]'); -SELECT JsonGet_String(Json_File('test/fx.json'), '[1]:*'); -SELECT JsonGet_String(Json_File('test/fx.json'), '[1]'); -SELECT JsonGet_Int(Json_File('test/fx.json'), '[1]:mileage') AS Mileage; -SELECT JsonGet_Real(Json_File('test/fx.json'), '[0]:price', 2) AS Price; -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 'ratings'); -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 1, 'ratings'); -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]'), 6, 'ratings', 1); -SELECT Json_Array_Add(Json_File('test/fx.json', '[2]:ratings'), 6, 0); -SELECT Json_Array_Delete(Json_File('test/fx.json', '[2]'), 'ratings', 1); -SELECT Json_Object_Add(Json_File('test/fx.json', '[2]'), 'france' origin); -SELECT Json_Object_Add(Json_File('test/fx.json', '[2]'), 70 H, 'size'); -SELECT Json_Object_Add(Json_File('test/fx.json', '[3]'), 70 H, 'size'); -SELECT Json_Object_List(Json_File('test/fx.json', '[3]:size')); +SELECT JsonGet_String(Json_File('test/fx.json'), '1.*'); +SELECT JsonGet_String(Json_File('test/fx.json'), '1'); +SELECT JsonGet_Int(Json_File('test/fx.json'), '1.mileage') AS Mileage; +SELECT JsonGet_Real(Json_File('test/fx.json'), '0.price', 2) AS Price; +SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings'); +SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 1, 'ratings'); +SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings', 1); +SELECT Json_Array_Add(Json_File('test/fx.json', '2.ratings'), 6, 0); +SELECT Json_Array_Delete(Json_File('test/fx.json', '2'), 'ratings', 1); +SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 'france' origin); +SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 70 H, 'size'); +SELECT Json_Object_Add(Json_File('test/fx.json', '3'), 70 H, 'size'); +SELECT Json_Object_List(Json_File('test/fx.json', '3.size')); DROP TABLE t1; DROP TABLE t2; @@ -264,3 +264,5 @@ DROP TABLE t3; --remove_file $MYSQLD_DATADIR/test/biblio.json --remove_file $MYSQLD_DATADIR/test/employee.dat --remove_file $MYSQLD_DATADIR/test/fx.json + + diff --git a/storage/connect/mysql-test/connect/t/json_udf2.inc b/storage/connect/mysql-test/connect/t/json_udf2.inc index 4c74e2c11f230..fe23692af4672 100644 --- a/storage/connect/mysql-test/connect/t/json_udf2.inc +++ b/storage/connect/mysql-test/connect/t/json_udf2.inc @@ -1,10 +1,10 @@ --disable_query_log -DROP FUNCTION json_array; +DROP FUNCTION json_make_array; DROP FUNCTION json_array_add; DROP FUNCTION json_array_add_values; DROP FUNCTION json_array_delete; -DROP FUNCTION json_object; +DROP FUNCTION json_make_object; DROP FUNCTION json_object_nonull; DROP FUNCTION json_object_key; DROP FUNCTION json_object_add; diff --git a/storage/connect/mysql-test/connect/t/json_udf_bin.test b/storage/connect/mysql-test/connect/t/json_udf_bin.test index e4ee422c26398..cbbfca9d2d275 100644 --- a/storage/connect/mysql-test/connect/t/json_udf_bin.test +++ b/storage/connect/mysql-test/connect/t/json_udf_bin.test @@ -16,7 +16,7 @@ SELECT Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), JsonGet_ SELECT Json_Array_Delete(Jbin_Array_Add_Values(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), "One more", 2), 4); SELECT Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), NULL), '[1]', 1); SELECT Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), TRUE), 1, '[1]'); -SELECT Json_Array(1, TRUE, 0, FALSE); +SELECT Json_Make_Array(1, TRUE, 0, FALSE); SELECT Json_Serialize(Jbin_Array(TRUE, FALSE)); # SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL); @@ -35,65 +35,65 @@ SELECT Json_Serialize(Jbin_File('gloss.json')); SELECT JsonLocate(Jbin_File('gloss.json'),'XML'); # SELECT Json_Object_Key('first', 'foo', 'second', Jbin_Array('a', 33)); -SELECT Json_Get_Item(Json_Array('a','b','c'), '[1]'); -SELECT Json_Get_Item(Json_Object('foo' AS "first", Json_Array('a', 33) AS "json_second"), 'second') AS "item"; -SELECT Json_Get_Item(Jbin_Object('foo' first, Jbin_Array('a', 33) jbin_second), 'second:*') item; -SELECT Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv'); -SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv')); -SELECT Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv:*'); -SELECT JsonGet_String(Json_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso') lang; -SELECT Json_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso') "See also"; -SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso')) "See also"; -SELECT JsonGet_String(Json_Get_Item(Json_File('gloss.json'),'glossary:GlossDiv:GlossList:GlossEntry:GlossDef:GlossSeeAlso'),'[0]') lang; +SELECT Json_Get_Item(Json_Make_Array('a','b','c'), '$[1]'); +SELECT Json_Get_Item(Json_Make_Object('foo' AS "first", Json_Make_Array('a', 33) AS "json_second"), '$.second') AS "item"; +SELECT Json_Get_Item(Jbin_Object('foo' first, Jbin_Array('a', 33) jbin_second), '$.second') item; +SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv'); +SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv')); +SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv'); +SELECT JsonGet_String(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') lang; +SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') "See also"; +SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso')) "See also"; +SELECT JsonGet_String(Json_Get_Item(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso'),'$[0]') lang; --echo # --echo # Test Item Get/Set/Insert/Update UDF's --echo # -SELECT Json_Get_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '[]'); -SELECT Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '[1]'); -SELECT Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '[1]'); +SELECT Json_Get_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[]'); +SELECT Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[1]'); +SELECT Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$[1]'); # -SELECT Json_Set_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4))); +SELECT Json_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4))); --error ER_CANT_INITIALIZE_UDF -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 'foo'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '[1]'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 7, '[1]'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Array(7, 8, 9), '[1]'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[2]'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[2]:*'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, 'foo'); -SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '[1]:[2]'); -SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '[2]:nxt:total:[]'); -SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 300, '[2]:nxt:total:[]'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '[1]', 5, '[2]:cinq', 10, '[1]:[]'); -SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '[2]:quatre'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$.foo'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '$[1]'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 7, '$[1]'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Make_Array(7, 8, 9), '$[1]'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2]'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2].*'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, '$.foo'); +SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '$[1][2]'); +SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '$[2].nxt.total[]'); +SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 300, '$[2].nxt.total[]'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[1]', 5, '$[2].cinq', 10, '$[1][]'); +SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '$[2].quatre'); SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, 'truc'); SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, ''); SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '*'); -SELECT Json_Serialize(Jbin_Set_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq')); +SELECT Json_Serialize(Jbin_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq')); # -SELECT Json_Insert_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq'); -SELECT Json_Update_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq'); -SELECT Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 44, '[2]:quatre'); -SELECT Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[]', 44, '[2]:quatre'); -SELECT Json_Insert_Item(Json_Array(1, Json_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[1]', 300, '[2]:nxt:total:[]'); -SELECT Json_Update_Item(Json_Array(1, Json_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[2]:cinq', 10, '[1]:[1]', 300, '[2]:nxt:total:[]'); -SELECT Json_Insert_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[]'); -SELECT Json_Update_Item(Json_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '[]'); +SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'); +SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'); +SELECT Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre'); +SELECT Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre'); +SELECT Json_Insert_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]'); +SELECT Json_Update_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]'); +SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]'); +SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]'); --echo # --echo # Test merging items UDF's --echo # SELECT Json_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')); -SELECT Json_Item_Merge(Json_Array('a','b','c'), Json_Array('d','e','f')) AS "Result"; +SELECT Json_Item_Merge(Json_Make_Array('a','b','c'), Json_Make_Array('d','e','f')) AS "Result"; SELECT Json_Array_Add(Jbin_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')), 'and', 3); SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f")); SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",2 "c"), Jbin_Array('d','e','f')); SELECT Json_Object_Add(Jbin_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f")), 'x' AS "and"); SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "a",5 "e",6 "f")); --error ER_CANT_INITIALIZE_UDF -SELECT Json_Item_Merge('foo', Json_Array('d','e','f')); +SELECT Json_Item_Merge('foo', Json_Make_Array('d','e','f')); --echo # --echo # Test making file UDF's @@ -116,14 +116,14 @@ SELECT Json_Array_Add(Jbin_File('bt1.json'), 'd'); SELECT Json_File('bt1.json', 2); --echo # Back to the original file SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json'); -SELECT Json_Object(Jbin_Array_Add(Jbin_Array('a','b','c'), 'd') "Jbin_foo") AS "Result"; -SELECT Json_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')) AS "Result"; -SELECT Json_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_Array('a','b','c'), 'd') "Jbin_foo") AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')) AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1") AS "Result"; --echo # This does modify the file -SELECT Json_Object(Json_Array_Add(Jbin_File('bt1.json'), 'd') "Jfile_bt1") AS "Result"; +SELECT Json_Make_Object(Json_Array_Add(Jbin_File('bt1.json'), 'd') "Jfile_bt1") AS "Result"; SELECT Json_File('bt1.json'); SELECT Json_File(Json_Array_Delete(Jbin_File('bt1.json'), 3), 2); -SELECT Json_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1", n "t1") AS "Result" from t1; SELECT Json_File(Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), 'e')) AS "Result"; SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json'); SELECT Json_File(Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), 'e')) AS "Result" from t1; @@ -140,11 +140,11 @@ SELECT Json_File(Jbin_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f')) SELECT Json_File(Json_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f'))); SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json'); --echo # Test DELETE from file -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 1)) AS "Result"; -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 2) "Jbin_bt1") AS "Result"; -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 0) "Jbin_bt1", n "t1") AS "Result" from t1; -SELECT Json_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; -SELECT Json_Object(Json_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 1)) AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 2) "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 0) "Jbin_bt1", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; +SELECT Json_Make_Object(Json_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1; --echo # Show modified file SELECT Json_File('bt1.json'); --echo # Object file @@ -153,11 +153,11 @@ SELECT Json_File('bt2.json', 0); SELECT Json_File('bt2.json'); SELECT Json_Serialize(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d")); --echo # First query (file not modified) -SELECT Json_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jbin_new") AS "Result"; +SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jbin_new") AS "Result"; --echo # First query (file modified) -SELECT Json_Object(Json_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jfile_new") AS "Result"; +SELECT Json_Make_Object(Json_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jfile_new") AS "Result"; SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0); -SELECT Json_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d") "Jbin_new", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d") "Jbin_new", n "t1") AS "Result" from t1; SELECT Json_File(Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), 5 "e")) AS "Result"; SELECT Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), 5 "e") AS "Result" from t1; SELECT Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), n "n") AS "Result" from t1; @@ -167,13 +167,13 @@ SELECT Json_File('bt2.json'); SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0); SELECT Json_Serialize(Jbin_Item_Merge(Jbin_File('bt2.json'), Jbin_Object(4 "d",5 "e",6 "f"))) AS "Result"; SELECT Json_File(Json_Item_Merge(Jbin_File('bt2.json'), Jbin_Object(4 "d",5 "e",6 "f"))) AS "Result"; -SELECT Json_Item_Merge(Json_Object(1 "a", 2 "b", 3 "c"), Json_Object(4 "d",5 "b",6 "f")) AS "Result"; +SELECT Json_Item_Merge(Json_Make_Object(1 "a", 2 "b", 3 "c"), Json_Make_Object(4 "d",5 "b",6 "f")) AS "Result"; # -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'b')) AS "Result"; -SELECT Json_Object(Jbin_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jfile_bt1") AS "Result"; -SELECT Json_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'a') "Jbin_bt1", n "t1") AS "Result" from t1; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'b')) AS "Result"; +SELECT Json_Make_Object(Jbin_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result"; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jfile_bt1") AS "Result"; +SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'a') "Jbin_bt1", n "t1") AS "Result" from t1; # SELECT Json_Serialize(Jbin_Object_List(Jbin_File('bt2.json'))) "Key list"; @@ -181,9 +181,9 @@ SELECT Json_Serialize(Jbin_Object_List(Jbin_File('bt2.json'))) "Key list"; # Test documentation examples # SELECT Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0); -SELECT Json_Array_Add(Json_File('bt3.json', 'b'), 66); -SELECT Json_Array_Add(Json_File('bt3.json'), 66, 'b'); -SELECT Json_Array_Add(Jbin_File('bt3.json', 'b'), 66); +SELECT Json_Array_Add(Json_File('bt3.json', '$.b'), 66); +SELECT Json_Array_Add(Json_File('bt3.json'), 66, '$.b'); +SELECT Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66); SELECT Json_File('bt3.json', 3); SELECT Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0); # @@ -193,11 +193,11 @@ CREATE TABLE t2 ( ENGINE= MYISAM; INSERT INTO t2 VALUES(1,'bt3.json'); --echo # In this table, the jfile_cols column just contains a file name -UPDATE t2 SET jfile_cols = Json_Array_Add(Jbin_File('bt3.json', 'b'), 66) WHERE n = 1; +UPDATE t2 SET jfile_cols = Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66) WHERE n = 1; SELECT JsonGet_String(jfile_cols, '*') FROM t2; -UPDATE t2 SET jfile_cols = Json_Insert_Item(jfile_cols, 77, 'b:[]') WHERE n = 1; -SELECT JsonGet_String(jfile_cols, 'b:*') FROM t2; -UPDATE t2 SET jfile_cols = Json_Insert_Item(Jbin_Insert_Item(jfile_cols, 88, 'b:') , 99, 'b:') WHERE n = 1; +UPDATE t2 SET jfile_cols = Json_Insert_Item(jfile_cols, 77, '$.b[]') WHERE n = 1; +SELECT JsonGet_String(jfile_cols, '$.b.*') FROM t2; +UPDATE t2 SET jfile_cols = Json_Insert_Item(Jbin_Insert_Item(jfile_cols, 88, '$.b[]') , 99, '$.b[]') WHERE n = 1; SELECT JsonGet_String(jfile_cols, '*') FROM t2; DROP TABLE t1, t2; @@ -210,3 +210,4 @@ DROP TABLE t1, t2; --remove_file $MYSQLD_DATADIR/bt1.json --remove_file $MYSQLD_DATADIR/bt2.json --remove_file $MYSQLD_DATADIR/bt3.json + diff --git a/storage/connect/mysql-test/connect/t/mul_new.test b/storage/connect/mysql-test/connect/t/mul_new.test new file mode 100644 index 0000000000000..33011f6c6a703 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/mul_new.test @@ -0,0 +1,67 @@ +let $MYSQLD_DATADIR= `select @@datadir`; +--mkdir $MYSQLD_DATADIR/test/subdir/ + +--echo # +--echo # Testing multiple 1 +--echo # +CREATE TABLE t1 ( + Chiffre int(3) NOT NULL, + Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num1.csv' LRECL=20 HEADER=1; +INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six'); +SELECT * FROM t1; + +CREATE TABLE t2 ( + Chiffre int(3) NOT NULL, + Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num2.csv' LRECL=20 HEADER=1; +INSERT INTO t2 VALUES(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten'),(11,'Eleven'),(12,'Twelve'); +SELECT * FROM t2; + +CREATE TABLE t3 ( + Chiffre int(3) NOT NULL, + Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num3.csv' LRECL=20 HEADER=1; +INSERT INTO t3 VALUES(13,'Thirteen'),(14,'Fourteen'),(15,'Fifteen'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen'); +SELECT * FROM t3; + +CREATE TABLE t4 ( + Chiffre int(3) NOT NULL, + Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num4.csv' LRECL=20 HEADER=1; +INSERT INTO t4 VALUES(19,'Nineteen'),(20,'Twenty'),(21,'Twenty one'),(22,'Twenty two'),(23,'Tenty three'),(24,'Twenty four'); +SELECT * FROM t4; + +CREATE TABLE t5 ( + Chiffre int(3) NOT NULL, + Lettre char(16) NOT NULL) +ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num5.csv' LRECL=20 HEADER=1; +INSERT INTO t5 VALUES(25,'Twenty five'),(26,'Twenty six'),(27,'Twenty seven'),(28,'Twenty eight'),(29,'Tenty eight'),(30,'Thirty'); +SELECT * FROM t5; + +CREATE TABLE t_all ( + Chiffre int(3) not null, + Lettre char(16) not null) +ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num?.csv' HEADER=1 LRECL=20 MULTIPLE=1; +SELECT * FROM t_all ORDER BY Chiffre; + +--echo # +--echo # Testing multiple 3 +--echo # +ALTER TABLE t_all MULTIPLE=3; +SELECT * FROM t_all ORDER BY Chiffre; + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t_all; + +--remove_file $MYSQLD_DATADIR/test/subdir/num2.csv +--remove_file $MYSQLD_DATADIR/test/subdir/num4.csv +--rmdir $MYSQLD_DATADIR/test/subdir/ +--remove_file $MYSQLD_DATADIR/test/num1.csv +--remove_file $MYSQLD_DATADIR/test/num3.csv +--remove_file $MYSQLD_DATADIR/test/num5.csv + diff --git a/storage/connect/mysql-test/connect/t/mysql_exec.test b/storage/connect/mysql-test/connect/t/mysql_exec.test index 9226592eded45..4aad23cd588bb 100644 --- a/storage/connect/mysql-test/connect/t/mysql_exec.test +++ b/storage/connect/mysql-test/connect/t/mysql_exec.test @@ -19,7 +19,7 @@ SELECT * FROM t1 WHERE command IN ('Warning','Note', "insert into t1(msg) values('One'),(NULL),('Three')", "insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'", "insert into t1(message) values('Four'),('Five'),('Six')", - 'insert into t1(id) values(NULL)', + 'insert ignore into t1(id) values(NULL)', "update t1 set msg = 'Four' where id = 4", 'select * from t1'); @@ -31,7 +31,7 @@ CREATE PROCEDURE p1(cmd varchar(512)) READS SQL DATA SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd); -CALL p1('insert into t1(id) values(NULL)'); +CALL p1('insert ignore into t1(id) values(NULL)'); CALL p1('update t1 set msg = "Five" where id = 5'); DROP PROCEDURE p1; DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/t/xml.test b/storage/connect/mysql-test/connect/t/xml.test index 0f26b8ab5c097..0fdf8e90b6ec7 100644 --- a/storage/connect/mysql-test/connect/t/xml.test +++ b/storage/connect/mysql-test/connect/t/xml.test @@ -1,4 +1,4 @@ ---source have_libxml2.inc +--source windows.inc let $MYSQLD_DATADIR= `select @@datadir`; @@ -26,7 +26,7 @@ CREATE TABLE t1 PUBLISHER CHAR(40), DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t1; DROP TABLE t1; @@ -42,7 +42,7 @@ CREATE TABLE t1 PUBLISHER CHAR(40), DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t1; DROP TABLE t1; @@ -55,7 +55,7 @@ CREATE TABLE t1 ( LANG CHAR(2), SUBJECT CHAR(32) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='Coltype=@,xmlsup=libxml2'; + OPTION_LIST='Coltype=@,xmlsup=domdoc'; SELECT * FROM t1; DROP TABLE t1; @@ -68,7 +68,7 @@ CREATE TABLE t1 ( LANG CHAR(2), SUBJECT CHAR(32) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - OPTION_LIST='Coltype=@,xmlsup=libxml2'; + OPTION_LIST='Coltype=@,xmlsup=domdoc'; SELECT * FROM t1; DROP TABLE t1; @@ -87,7 +87,7 @@ CREATE TABLE t1 ( DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t1; DROP TABLE t1; @@ -108,7 +108,7 @@ CREATE TABLE t1 ( DATEPUB INT(4) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml' TABNAME='BIBLIO' - OPTION_LIST='rownode=BOOK,xmlsup=libxml2'; + OPTION_LIST='rownode=BOOK,xmlsup=domdoc'; INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB) VALUES('9782212090529','fr','général','Alain Michard', 'XML, Langage et Applications','Eyrolles Paris',1998); @@ -136,7 +136,7 @@ CREATE TABLE t1 ( location CHAR(20) FIELD_FORMAT='PUBLISHER/PLACE', year INT(4) FIELD_FORMAT='DATEPUB' ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc'; SELECT * FROM t1; SELECT isbn, title, translated, tranfn, tranln, location FROM t1 WHERE translated <> ''; @@ -180,7 +180,7 @@ CREATE TABLE t1 ( isbn CHAR(15) FIELD_FORMAT='@isbn' ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' - TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc'; SELECT * FROM t1; DROP TABLE t1; @@ -194,14 +194,14 @@ CREATE TABLE t1 ( c CHAR(16) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2' + OPTION_LIST='xmlsup=domdoc' DATA_CHARSET=latin1; CREATE TABLE t1 ( c CHAR(16) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2' + OPTION_LIST='xmlsup=domdoc' DATA_CHARSET=utf8; SHOW CREATE TABLE t1; SELECT c, HEX(c) FROM t1; @@ -211,7 +211,7 @@ CREATE TABLE t1 ( c CHAR(16) ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT c, HEX(c) FROM t1; DROP TABLE t1; @@ -219,7 +219,7 @@ CREATE TABLE t1 ( c CHAR(16) CHARACTER SET utf8 ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT c, HEX(c) FROM t1; DROP TABLE t1; @@ -232,7 +232,7 @@ CREATE TABLE t1 ( c CHAR(16) CHARACTER SET cp1251 ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' - OPTION_LIST='xmlsup=libxml2'; + OPTION_LIST='xmlsup=domdoc'; SELECT c, HEX(c) FROM t1; DROP TABLE t1; @@ -240,24 +240,24 @@ DROP TABLE t1; --echo # --echo # Testing Cyrillic --echo # -CREATE TABLE t1 -( - c CHAR(16) CHARACTER SET utf8 -) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' - OPTION_LIST='xmlsup=libxml2,rownode=b'; -SELECT * FROM t1; -INSERT INTO t1 VALUES ('ИКЛМÐ'); -SELECT c, HEX(c) FROM t1; -DROP TABLE t1; -CREATE TABLE t1 -( - c CHAR(16) CHARACTER SET cp1251 -) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' - OPTION_LIST='xmlsup=libxml2,rownode=b'; -SELECT * FROM t1; -INSERT INTO t1 VALUES ('ОПРСТ'); -SELECT c, HEX(c) FROM t1; -DROP TABLE t1; +#CREATE TABLE t1 +#( +# c CHAR(16) CHARACTER SET utf8 +#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' +# OPTION_LIST='xmlsup=domdoc,rownode=b'; +#SELECT * FROM t1; +#INSERT INTO t1 VALUES ('ИКЛМÐ'); +#SELECT c, HEX(c) FROM t1; +#DROP TABLE t1; +#CREATE TABLE t1 +#( +# c CHAR(16) CHARACTER SET cp1251 +#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' +# OPTION_LIST='xmlsup=domdoc,rownode=b'; +#SELECT * FROM t1; +#INSERT INTO t1 VALUES ('ОПРСТ'); +#SELECT c, HEX(c) FROM t1; +#DROP TABLE t1; --echo # @@ -266,11 +266,11 @@ DROP TABLE t1; CREATE TABLE t1 (node VARCHAR(50)) CHARACTER SET latin1 ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' - OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=utf-8'; + OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=utf-8'; INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); SELECT node, hex(node) FROM t1; DROP TABLE t1; ---chmod 0777 $MYSQLD_DATADIR/test/t1.xml +#--chmod 0777 $MYSQLD_DATADIR/test/t1.xml --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR --eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') SELECT LEFT(@a,38); @@ -280,11 +280,11 @@ SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); CREATE TABLE t1 (node VARCHAR(50)) CHARACTER SET latin1 ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' - OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; + OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1'; INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); SELECT node, hex(node) FROM t1; DROP TABLE t1; ---chmod 0777 $MYSQLD_DATADIR/test/t1.xml +#--chmod 0777 $MYSQLD_DATADIR/test/t1.xml --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR --eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') SELECT LEFT(@a,43); @@ -298,13 +298,13 @@ SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); CREATE TABLE t1 (node VARCHAR(50)) CHARACTER SET utf8 ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' - OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; + OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1'; INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3); INSERT INTO t1 VALUES ('&<>"\''); SELECT node, hex(node) FROM t1; DROP TABLE t1; ---chmod 0777 $MYSQLD_DATADIR/test/t1.xml +#--chmod 0777 $MYSQLD_DATADIR/test/t1.xml --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR --eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') SELECT CAST(@a AS CHAR CHARACTER SET latin1); diff --git a/storage/connect/mysql-test/connect/t/xml2.test b/storage/connect/mysql-test/connect/t/xml2.test new file mode 100644 index 0000000000000..0f26b8ab5c097 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xml2.test @@ -0,0 +1,320 @@ +--source have_libxml2.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +SET NAMES utf8; + +--vertical_results + +--copy_file $MTR_SUITE_DIR/std_data/xsample.xml $MYSQLD_DATADIR/test/xsample.xml +--copy_file $MTR_SUITE_DIR/std_data/latin1.xml $MYSQLD_DATADIR/test/latin1.xml +--copy_file $MTR_SUITE_DIR/std_data/cp1251.xml $MYSQLD_DATADIR/test/cp1251.xml + +#--echo $MYSQL_TEST_DIR +#--exec pwd +#SELECT LOAD_FILE('test/xsample.xml'); + + +--echo # +--echo # Testing tag values +--echo # +CREATE TABLE t1 +( + AUTHOR CHAR(50), + TITLE CHAR(32), + TRANSLATOR CHAR(40), + PUBLISHER CHAR(40), + DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing that tag names are case sensitive +--echo # +CREATE TABLE t1 +( + author CHAR(50), + TITLE CHAR(32), + TRANSLATOR CHAR(40), + PUBLISHER CHAR(40), + DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing attribute values +--echo # +CREATE TABLE t1 ( + ISBN CHAR(15), + LANG CHAR(2), + SUBJECT CHAR(32) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='Coltype=@,xmlsup=libxml2'; +SELECT * FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing that attribute names are case sensitive +--echo # +CREATE TABLE t1 ( + isbn CHAR(15), + LANG CHAR(2), + SUBJECT CHAR(32) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + OPTION_LIST='Coltype=@,xmlsup=libxml2'; +SELECT * FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing mixed tag and attribute values +--echo # +CREATE TABLE t1 ( + ISBN CHAR(15) FIELD_FORMAT='@', + LANG CHAR(2) FIELD_FORMAT='@', + SUBJECT CHAR(32) FIELD_FORMAT='@', + AUTHOR CHAR(50), + TITLE CHAR(32), + TRANSLATOR CHAR(40), + PUBLISHER CHAR(40), + DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK' + OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing INSERT on mixed tag and attribute values +--echo # +--copy_file $MTR_SUITE_DIR/std_data/xsample.xml $MYSQLD_DATADIR/test/xsample2.xml +--chmod 0644 $MYSQLD_DATADIR/test/xsample2.xml +CREATE TABLE t1 ( + ISBN CHAR(15) FIELD_FORMAT='@', + LANG CHAR(2) FIELD_FORMAT='@', + SUBJECT CHAR(32) FIELD_FORMAT='@', + AUTHOR CHAR(50), + TITLE CHAR(32), + TRANSLATOR CHAR(40), + PUBLISHER CHAR(40), + DATEPUB INT(4) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml' + TABNAME='BIBLIO' + OPTION_LIST='rownode=BOOK,xmlsup=libxml2'; +INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB) +VALUES('9782212090529','fr','général','Alain Michard', +'XML, Langage et Applications','Eyrolles Paris',1998); +SELECT * FROM t1; +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SELECT LOAD_FILE('$MYSQLD_DATADIR/test/xsample2.xml') AS xml +DROP TABLE t1; +--remove_file $MYSQLD_DATADIR/test/xsample2.xml + + +--echo # +--echo # Testing XPath +--echo # +CREATE TABLE t1 ( + isbn CHAR(15) FIELD_FORMAT='@ISBN', + language CHAR(2) FIELD_FORMAT='@LANG', + subject CHAR(32) FIELD_FORMAT='@SUBJECT', + authorfn CHAR(20) FIELD_FORMAT='AUTHOR/FIRSTNAME', + authorln CHAR(20) FIELD_FORMAT='AUTHOR/LASTNAME', + title CHAR(32) FIELD_FORMAT='TITLE', + translated CHAR(32) FIELD_FORMAT='TRANSLATOR/@PREFIX', + tranfn CHAR(20) FIELD_FORMAT='TRANSLATOR/FIRSTNAME', + tranln CHAR(20) FIELD_FORMAT='TRANSLATOR/LASTNAME', + publisher CHAR(20) FIELD_FORMAT='PUBLISHER/NAME', + location CHAR(20) FIELD_FORMAT='PUBLISHER/PLACE', + year INT(4) FIELD_FORMAT='DATEPUB' +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; +SELECT * FROM t1; +SELECT isbn, title, translated, tranfn, tranln, location FROM t1 +WHERE translated <> ''; +DROP TABLE t1; + + +# +# TODO: Connect.pdf says nodes with variable depth are not supported +# +#--echo # +#--echo # Relative paths are not supported +#--echo # +#CREATE TABLE t1 ( +# authorfn CHAR(20) FIELD_FORMAT='//FIRSTNAME', +# authorln CHAR(20) FIELD_FORMAT='//LASTNAME' +#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' +# TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1'; +#SELECT * FROM t1; +#DROP TABLE t1; + + +# +# TODO: Connect.pdf says absolute paths are not supported +# +#--echo # +#--echo # Absolute path is not supported +#--echo # +#CREATE TABLE t1 ( +# authorfn CHAR(20) FIELD_FORMAT='/BIBLIO/BOOK/AUTHOR/FIRSTNAME', +# authorln CHAR(20) FIELD_FORMAT='/BIBLIO/BOOK/AUTHOR/LASTNAME' +#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' +# TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1'; +#SELECT * FROM t1; +#DROP TABLE t1; + + +--echo # +--echo # Testing that XPath is case sensitive +--echo # +CREATE TABLE t1 +( + isbn CHAR(15) FIELD_FORMAT='@isbn' +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml' + TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2'; +SELECT * FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing character sets +--echo # + +--error ER_UNKNOWN_ERROR +CREATE TABLE t1 +( + c CHAR(16) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2' + DATA_CHARSET=latin1; + +CREATE TABLE t1 +( + c CHAR(16) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2' + DATA_CHARSET=utf8; +SHOW CREATE TABLE t1; +SELECT c, HEX(c) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 +( + c CHAR(16) +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT c, HEX(c) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 +( + c CHAR(16) CHARACTER SET utf8 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT c, HEX(c) FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Conversion from latin1 to cp1251 produces a warning. +--echo # Question marks are returned. +--echo # +CREATE TABLE t1 +( + c CHAR(16) CHARACTER SET cp1251 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml' + OPTION_LIST='xmlsup=libxml2'; +SELECT c, HEX(c) FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing Cyrillic +--echo # +CREATE TABLE t1 +( + c CHAR(16) CHARACTER SET utf8 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' + OPTION_LIST='xmlsup=libxml2,rownode=b'; +SELECT * FROM t1; +INSERT INTO t1 VALUES ('ИКЛМÐ'); +SELECT c, HEX(c) FROM t1; +DROP TABLE t1; +CREATE TABLE t1 +( + c CHAR(16) CHARACTER SET cp1251 +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml' + OPTION_LIST='xmlsup=libxml2,rownode=b'; +SELECT * FROM t1; +INSERT INTO t1 VALUES ('ОПРСТ'); +SELECT c, HEX(c) FROM t1; +DROP TABLE t1; + + +--echo # +--echo # Testing that the underlying file is created with a proper Encoding +--echo # +CREATE TABLE t1 (node VARCHAR(50)) + CHARACTER SET latin1 + ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' + OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=utf-8'; +INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); +SELECT node, hex(node) FROM t1; +DROP TABLE t1; +--chmod 0777 $MYSQLD_DATADIR/test/t1.xml +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') +SELECT LEFT(@a,38); +SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); +--remove_file $MYSQLD_DATADIR/test/t1.xml + +CREATE TABLE t1 (node VARCHAR(50)) + CHARACTER SET latin1 + ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' + OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; +INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); +SELECT node, hex(node) FROM t1; +DROP TABLE t1; +--chmod 0777 $MYSQLD_DATADIR/test/t1.xml +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') +SELECT LEFT(@a,43); +SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node')); +--remove_file $MYSQLD_DATADIR/test/t1.xml + + +--echo # +--echo # Testing XML entities +--echo # +CREATE TABLE t1 (node VARCHAR(50)) + CHARACTER SET utf8 + ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml' + OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1'; +INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3); +INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3); +INSERT INTO t1 VALUES ('&<>"\''); +SELECT node, hex(node) FROM t1; +DROP TABLE t1; +--chmod 0777 $MYSQLD_DATADIR/test/t1.xml +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml') +SELECT CAST(@a AS CHAR CHARACTER SET latin1); +--remove_file $MYSQLD_DATADIR/test/t1.xml + + + +# +# Clean up +# +--remove_file $MYSQLD_DATADIR/test/xsample.xml +--remove_file $MYSQLD_DATADIR/test/latin1.xml +--remove_file $MYSQLD_DATADIR/test/cp1251.xml diff --git a/storage/connect/mysql-test/connect/t/xml2_grant.test b/storage/connect/mysql-test/connect/t/xml2_grant.test new file mode 100644 index 0000000000000..26753c966336d --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xml2_grant.test @@ -0,0 +1,8 @@ +-- source include/not_embedded.inc +-- source have_libxml2.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +let $TABLE_OPTIONS=TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +let $FILE_EXT=XML; +--source grant.inc diff --git a/storage/connect/mysql-test/connect/t/xml2_html.test b/storage/connect/mysql-test/connect/t/xml2_html.test new file mode 100644 index 0000000000000..1c84b46ec3838 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xml2_html.test @@ -0,0 +1,39 @@ +--source have_libxml2.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +SET NAMES utf8; + +--copy_file $MTR_SUITE_DIR/std_data/beers.xml $MYSQLD_DATADIR/test/beers.xml +--copy_file $MTR_SUITE_DIR/std_data/coffee.htm $MYSQLD_DATADIR/test/coffee.htm + +--echo # +--echo # Testing HTML like XML file +--echo # +CREATE TABLE beers ( +`Name` CHAR(16) FIELD_FORMAT='brandName', +`Origin` CHAR(16) FIELD_FORMAT='origin', +`Description` CHAR(32) FIELD_FORMAT='details') +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml' +TABNAME='table' OPTION_LIST='xmlsup=libxml2,rownode=tr,colnode=td'; +SELECT * FROM beers; +DROP TABLE beers; + +--echo # +--echo # Testing HTML file +--echo # +CREATE TABLE coffee ( +`Name` CHAR(16), +`Cups` INT(8), +`Type` CHAR(16), +`Sugar` CHAR(4)) +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm' +TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=libxml2,Coltype=HTML'; +SELECT * FROM coffee; +DROP TABLE coffee; + +# +# Clean up +# +--remove_file $MYSQLD_DATADIR/test/beers.xml +--remove_file $MYSQLD_DATADIR/test/coffee.htm diff --git a/storage/connect/mysql-test/connect/t/xml2_mdev5261.test b/storage/connect/mysql-test/connect/t/xml2_mdev5261.test new file mode 100644 index 0000000000000..16640c8bb7444 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xml2_mdev5261.test @@ -0,0 +1,27 @@ +--source have_libxml2.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +SET NAMES utf8; + +# +#--echo Testing indexing on not indexable table type +# +--error ER_UNKNOWN_ERROR +CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N'; +CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N'; +DESCRIBE t1; +# one could *add* an index to an existing table +--error ER_UNKNOWN_ERROR +ALTER TABLE t1 ADD UNIQUE(i); +--error ER_UNKNOWN_ERROR +CREATE UNIQUE INDEX i ON t1(i); +DESCRIBE t1; +INSERT INTO t1 VALUES(2),(5),(7); +SELECT * FROM t1 WHERE i = 5; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t1 DROP INDEX i; +--error ER_CANT_DROP_FIELD_OR_KEY +DROP INDEX i ON t1; +DROP TABLE t1; +--remove_file $MYSQLD_DATADIR/test/xt1.xml diff --git a/storage/connect/mysql-test/connect/t/xml2_mult.test b/storage/connect/mysql-test/connect/t/xml2_mult.test new file mode 100644 index 0000000000000..cd83827fe34ce --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xml2_mult.test @@ -0,0 +1,64 @@ +--source have_libxml2.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +SET NAMES utf8; + +--copy_file $MTR_SUITE_DIR/std_data/bookstore.xml $MYSQLD_DATADIR/test/bookstore.xml + +#--echo $MYSQL_TEST_DIR +#--exec pwd +#SELECT LOAD_FILE('test/bookstore.xml'); + + +--echo # +--echo # Testing expanded values +--echo # +CREATE TABLE `bookstore` ( + `category` CHAR(16) NOT NULL FIELD_FORMAT='@', + `title` VARCHAR(50) NOT NULL, + `lang` char(2) NOT NULL FIELD_FORMAT='title/@', + `author` VARCHAR(24) NOT NULL, + `year` INT(4) NOT NULL, + `price` DOUBLE(8,2) NOT NULL) +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2'; +SELECT * FROM bookstore; +SELECT category, title, price FROM bookstore; +SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%'; +SELECT category, title, price FROM bookstore WHERE author LIKE 'J%'; + + +--echo # +--echo # Limiting expanded values +--echo # +ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2'; +SELECT * FROM bookstore; +--echo # One line lost because the where clause is applied only on the first 3 rows +SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; + + +--echo # +--echo # Testing concatenated values +--echo # +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2'; +--echo # truncated +SELECT * FROM bookstore; +--echo # increase author size +ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL; +SELECT * FROM bookstore; + + +--echo # +--echo # Limiting concatenated values +--echo # +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2'; +SELECT * FROM bookstore; +--echo # The where clause is applied on the concatenated column result +SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; +DROP TABLE bookstore; + + +# +# Clean up +# +--remove_file $MYSQLD_DATADIR/test/bookstore.xml diff --git a/storage/connect/mysql-test/connect/t/xml2_zip.test b/storage/connect/mysql-test/connect/t/xml2_zip.test new file mode 100644 index 0000000000000..d8c7894f861be --- /dev/null +++ b/storage/connect/mysql-test/connect/t/xml2_zip.test @@ -0,0 +1,41 @@ +--source have_zip.inc +--source have_libxml2.inc + +let $MYSQLD_DATADIR= `select @@datadir`; + +--vertical_results + +--copy_file $MTR_SUITE_DIR/std_data/xsample2.xml $MYSQLD_DATADIR/test/xsample2.xml + +--echo # +--echo # Testing zipped XML tables +--echo # +CREATE TABLE t1 ( +ISBN CHAR(13) NOT NULL FIELD_FORMAT='@', +LANG CHAR(2) NOT NULL FIELD_FORMAT='@', +SUBJECT CHAR(12) NOT NULL FIELD_FORMAT='@', +AUTHOR_FIRSTNAME CHAR(15) NOT NULL FIELD_FORMAT='AUTHOR/FIRSTNAME', +AUTHOR_LASTNAME CHAR(8) NOT NULL FIELD_FORMAT='AUTHOR/LASTNAME', +TRANSLATOR_PREFIX CHAR(24) DEFAULT NULL FIELD_FORMAT='TRANSLATOR/@PREFIX', +TRANSLATOR_FIRSTNAME CHAR(6) DEFAULT NULL FIELD_FORMAT='TRANSLATOR/FIRSTNAME', +TRANSLATOR_LASTNAME CHAR(6) DEFAULT NULL FIELD_FORMAT='TRANSLATOR/LASTNAME', +TITLE CHAR(30) NOT NULL, +PUBLISHER_NAME CHAR(15) NOT NULL FIELD_FORMAT='PUBLISHER/NAME', +PUBLISHER_PLACE CHAR(5) NOT NULL FIELD_FORMAT='PUBLISHER/PLACE', +DATEPUB CHAR(4) NOT NULL +) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES +OPTION_LIST='entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=libxml2,expand=1,mulnode=AUTHOR'; +SELECT * FROM t1; + +#testing discovery +CREATE TABLE t2 +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES +OPTION_LIST='xmlsup=libxml2'; +SELECT * FROM t2; +DROP TABLE t1,t2; + +# +# Clean up +# +--remove_file $MYSQLD_DATADIR/test/xsample2.xml +--remove_file $MYSQLD_DATADIR/test/xsample2.zip diff --git a/storage/connect/mysql-test/connect/t/xml_grant.test b/storage/connect/mysql-test/connect/t/xml_grant.test index 26753c966336d..94f640b9593e8 100644 --- a/storage/connect/mysql-test/connect/t/xml_grant.test +++ b/storage/connect/mysql-test/connect/t/xml_grant.test @@ -1,8 +1,8 @@ -- source include/not_embedded.inc --- source have_libxml2.inc +-- source windows.inc let $MYSQLD_DATADIR= `select @@datadir`; -let $TABLE_OPTIONS=TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row'; +let $TABLE_OPTIONS=TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row'; let $FILE_EXT=XML; --source grant.inc diff --git a/storage/connect/mysql-test/connect/t/xml_html.test b/storage/connect/mysql-test/connect/t/xml_html.test index 1c84b46ec3838..34d29953f6873 100644 --- a/storage/connect/mysql-test/connect/t/xml_html.test +++ b/storage/connect/mysql-test/connect/t/xml_html.test @@ -1,4 +1,4 @@ ---source have_libxml2.inc +--source windows.inc let $MYSQLD_DATADIR= `select @@datadir`; @@ -15,7 +15,7 @@ CREATE TABLE beers ( `Origin` CHAR(16) FIELD_FORMAT='origin', `Description` CHAR(32) FIELD_FORMAT='details') ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml' -TABNAME='table' OPTION_LIST='xmlsup=libxml2,rownode=tr,colnode=td'; +TABNAME='table' OPTION_LIST='xmlsup=domdoc,rownode=tr,colnode=td'; SELECT * FROM beers; DROP TABLE beers; @@ -28,7 +28,7 @@ CREATE TABLE coffee ( `Type` CHAR(16), `Sugar` CHAR(4)) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm' -TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=libxml2,Coltype=HTML'; +TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=domdoc,Coltype=HTML'; SELECT * FROM coffee; DROP TABLE coffee; diff --git a/storage/connect/mysql-test/connect/t/xml_mdev5261.test b/storage/connect/mysql-test/connect/t/xml_mdev5261.test index b554f251e09c6..25cace5054848 100644 --- a/storage/connect/mysql-test/connect/t/xml_mdev5261.test +++ b/storage/connect/mysql-test/connect/t/xml_mdev5261.test @@ -1,4 +1,4 @@ ---source have_libxml2.inc +--source windows.inc let $MYSQLD_DATADIR= `select @@datadir`; @@ -8,8 +8,8 @@ SET NAMES utf8; #--echo Testing indexing on not indexable table type # --error ER_UNKNOWN_ERROR -CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='Rownode=N'; -CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='Rownode=N'; +CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N'; +CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N'; DESCRIBE t1; # one could *add* an index to an existing table --error ER_UNKNOWN_ERROR diff --git a/storage/connect/mysql-test/connect/t/xml_mult.test b/storage/connect/mysql-test/connect/t/xml_mult.test index cd83827fe34ce..cf703e90da496 100644 --- a/storage/connect/mysql-test/connect/t/xml_mult.test +++ b/storage/connect/mysql-test/connect/t/xml_mult.test @@ -1,4 +1,4 @@ ---source have_libxml2.inc +--source windows.inc let $MYSQLD_DATADIR= `select @@datadir`; @@ -21,7 +21,7 @@ CREATE TABLE `bookstore` ( `author` VARCHAR(24) NOT NULL, `year` INT(4) NOT NULL, `price` DOUBLE(8,2) NOT NULL) -ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2'; +ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=domdoc'; SELECT * FROM bookstore; SELECT category, title, price FROM bookstore; SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%'; @@ -31,7 +31,7 @@ SELECT category, title, price FROM bookstore WHERE author LIKE 'J%'; --echo # --echo # Limiting expanded values --echo # -ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2'; +ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=domdoc'; SELECT * FROM bookstore; --echo # One line lost because the where clause is applied only on the first 3 rows SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; @@ -40,7 +40,7 @@ SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; --echo # --echo # Testing concatenated values --echo # -ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2'; +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=domdoc'; --echo # truncated SELECT * FROM bookstore; --echo # increase author size @@ -51,7 +51,7 @@ SELECT * FROM bookstore; --echo # --echo # Limiting concatenated values --echo # -ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2'; +ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=domdoc'; SELECT * FROM bookstore; --echo # The where clause is applied on the concatenated column result SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; diff --git a/storage/connect/mysql-test/connect/t/xml_zip.test b/storage/connect/mysql-test/connect/t/xml_zip.test index d8c7894f861be..ad31ca46d4cc6 100644 --- a/storage/connect/mysql-test/connect/t/xml_zip.test +++ b/storage/connect/mysql-test/connect/t/xml_zip.test @@ -1,5 +1,5 @@ --source have_zip.inc ---source have_libxml2.inc +--source windows.inc let $MYSQLD_DATADIR= `select @@datadir`; @@ -24,13 +24,13 @@ PUBLISHER_NAME CHAR(15) NOT NULL FIELD_FORMAT='PUBLISHER/NAME', PUBLISHER_PLACE CHAR(5) NOT NULL FIELD_FORMAT='PUBLISHER/PLACE', DATEPUB CHAR(4) NOT NULL ) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES -OPTION_LIST='entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=libxml2,expand=1,mulnode=AUTHOR'; +OPTION_LIST='entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=domdoc,expand=1,mulnode=AUTHOR'; SELECT * FROM t1; #testing discovery CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES -OPTION_LIST='xmlsup=libxml2'; +OPTION_LIST='xmlsup=domdoc'; SELECT * FROM t2; DROP TABLE t1,t2; diff --git a/storage/connect/mysql-test/connect/t/zip.test b/storage/connect/mysql-test/connect/t/zip.test index a4892e9ed4e68..dce68c17eee9f 100644 --- a/storage/connect/mysql-test/connect/t/zip.test +++ b/storage/connect/mysql-test/connect/t/zip.test @@ -83,16 +83,16 @@ DROP TABLE t1,t2,t3,t4; --echo # CREATE TABLE t1 ( _id INT(2) NOT NULL, -name_first CHAR(9) NOT NULL FIELD_FORMAT='name:first', -name_aka CHAR(4) DEFAULT NULL FIELD_FORMAT='name:aka', -name_last CHAR(10) NOT NULL FIELD_FORMAT='name:last', +name_first CHAR(9) NOT NULL FIELD_FORMAT='$.name.first', +name_aka CHAR(4) DEFAULT NULL FIELD_FORMAT='$.name.aka', +name_last CHAR(10) NOT NULL FIELD_FORMAT='$.name.last', title CHAR(12) DEFAULT NULL, birth CHAR(20) DEFAULT NULL, death CHAR(20) DEFAULT NULL, -contribs CHAR(7) NOT NULL FIELD_FORMAT='contribs:', -awards_award CHAR(42) DEFAULT NULL FIELD_FORMAT='awards::award', -awards_year CHAR(4) DEFAULT NULL FIELD_FORMAT='awards::year', -awards_by CHAR(38) DEFAULT NULL FIELD_FORMAT='awards::by' +contribs CHAR(7) NOT NULL FIELD_FORMAT='$.contribs', +awards_award CHAR(42) DEFAULT NULL FIELD_FORMAT='$.awards.award', +awards_year CHAR(4) DEFAULT NULL FIELD_FORMAT='$.awards.year', +awards_by CHAR(38) DEFAULT NULL FIELD_FORMAT='$.awards.by' ) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bios.zip' OPTION_LIST='ENTRY=bios.json,LOAD=bios.json' ZIPPED=YES; SELECT * FROM t1; @@ -104,16 +104,16 @@ SELECT * FROM t2; CREATE TABLE t3 ( _id INT(2) NOT NULL, -firstname CHAR(9) NOT NULL FIELD_FORMAT='name:first', -aka CHAR(4) DEFAULT NULL FIELD_FORMAT='name:aka', -lastname CHAR(10) NOT NULL FIELD_FORMAT='name:last', +firstname CHAR(9) NOT NULL FIELD_FORMAT='$.name.first', +aka CHAR(4) DEFAULT NULL FIELD_FORMAT='$.name.aka', +lastname CHAR(10) NOT NULL FIELD_FORMAT='$.name.last', title CHAR(12) DEFAULT NULL, birth date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'", death date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'", -contribs CHAR(64) NOT NULL FIELD_FORMAT='contribs:[", "]', -award CHAR(42) DEFAULT NULL FIELD_FORMAT='awards:[x]:award', -year CHAR(4) DEFAULT NULL FIELD_FORMAT='awards:[x]:year', -`by` CHAR(38) DEFAULT NULL FIELD_FORMAT='awards:[x]:by' +contribs CHAR(64) NOT NULL FIELD_FORMAT='$.contribs.[", "]', +award CHAR(42) DEFAULT NULL FIELD_FORMAT='$.awards[*].award', +year CHAR(4) DEFAULT NULL FIELD_FORMAT='$.awards[*].year', +`by` CHAR(38) DEFAULT NULL FIELD_FORMAT='$.awards[*].by' ) ENGINE=CONNECT TABLE_TYPE='json' FILE_NAME='bios.zip' ZIPPED=YES; SELECT * FROM t3 WHERE _id = 1; diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 3dbc2d577d5b0..a1283998068dd 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -2340,6 +2340,7 @@ int ODBConn::GetCatInfo(CATPARM *cap) } // endif len pval[n] = AllocateValue(g, crp->Type, len); + pval[n]->SetNullable(true); if (crp->Type == TYPE_STRING) { pbuf[n] = (char*)PlugSubAlloc(g, NULL, len); diff --git a/storage/connect/os.h b/storage/connect/os.h index 8056a2729901c..e2b165fb3f5fe 100644 --- a/storage/connect/os.h +++ b/storage/connect/os.h @@ -1,3 +1,4 @@ +/* Copyright (C) MariaDB Corporation Ab */ #ifndef _OS_H_INCLUDED #define _OS_H_INCLUDED diff --git a/storage/connect/osutil.c b/storage/connect/osutil.c index 66743c7403b84..da896fec50e68 100644 --- a/storage/connect/osutil.c +++ b/storage/connect/osutil.c @@ -1,3 +1,4 @@ +/* Copyright (C) MariaDB Corporation Ab */ #include "my_global.h" #include #include diff --git a/storage/connect/osutil.h b/storage/connect/osutil.h index ac63d4ee97342..7e6b8823b9b92 100644 --- a/storage/connect/osutil.h +++ b/storage/connect/osutil.h @@ -1,3 +1,4 @@ +/* Copyright (C) MariaDB Corporation Ab */ #ifndef __OSUTIL_H__ #define __OSUTIL_H__ diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 2198c44c200bf..a66e2e9832da5 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -36,8 +36,6 @@ enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */ TYPE_COLCRT = 71, /* Column creation block */ TYPE_CONST = 72, /* Constant */ -/*-------------------- type tokenized string --------------------------*/ - TYPE_DATE = 8, /* Timestamp */ /*-------------------- additional values used by LNA ------------------*/ TYPE_COLIST = 14, /* Column list */ TYPE_COL = 41, /* Column */ @@ -80,7 +78,7 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ TAB_DMY = 25, /* DMY Dummy tables NIY */ TAB_JDBC = 26, /* Table accessed via JDBC */ TAB_ZIP = 27, /* ZIP file info table */ -// TAB_MONGO = 28, /* Table retrieved from MongoDB */ + TAB_MONGO = 28, /* Table retrieved from MongoDB */ TAB_NIY = 30}; /* Table not implemented yet */ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ @@ -140,12 +138,12 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ TYPE_AM_VIR = 171, /* Virtual tables am type no */ TYPE_AM_DMY = 172, /* DMY Dummy tables am type no */ TYPE_AM_SET = 180, /* SET Set tables am type no */ - TYPE_AM_MYSQL = 192, /* MYSQL access method type no */ - TYPE_AM_MYX = 193, /* MYSQL EXEC access method type */ - TYPE_AM_CAT = 195, /* Catalog access method type no */ - TYPE_AM_ZIP = 198, /* ZIP access method type no */ - TYPE_AM_MGO = 199, /* MGO access method type no */ - TYPE_AM_OUT = 200}; /* Output relations (storage) */ + TYPE_AM_MYSQL = 190, /* MYSQL access method type no */ + TYPE_AM_MYX = 191, /* MYSQL EXEC access method type */ + TYPE_AM_CAT = 192, /* Catalog access method type no */ + TYPE_AM_ZIP = 193, /* ZIP access method type no */ + TYPE_AM_MGO = 194, /* MGO access method type no */ + TYPE_AM_OUT = 200}; /* Output relations (storage) */ enum RECFM {RECFM_NAF = -2, /* Not a file */ RECFM_OEM = -1, /* OEM file access method */ diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index b6f59bac8cffd..b25a46b7ec31f 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -473,7 +473,7 @@ bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci) tp = g->Message; else if (!(tp = new char[strlen(pat) + strlen(strg) + 2])) { strcpy(g->Message, MSG(NEW_RETURN_NULL)); - throw OP_LIKE; + throw (int)OP_LIKE; } /* endif tp */ sp = tp + strlen(pat) + 1; @@ -484,7 +484,7 @@ bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci) tp = g->Message; /* Use this as temporary work space. */ else if (!(tp = new char[strlen(pat) + 1])) { strcpy(g->Message, MSG(NEW_RETURN_NULL)); - throw OP_LIKE; + throw (int)OP_LIKE; } /* endif tp */ strcpy(tp, pat); /* Make a copy to be worked into */ diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 5284e2ef856d6..50c8b1ffc29b2 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -548,7 +548,7 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) #endif // 0 // Is the library already loaded? - if (!Hdll) + if (!Hdll && !(Hdll = dlopen(soname, RTLD_NOLOAD))) // Load the desired shared library if (!(Hdll = dlopen(soname, RTLD_LAZY))) { error = dlerror(); diff --git a/storage/connect/tabcol.cpp b/storage/connect/tabcol.cpp index 2740864a69bc2..5065d86ce6a7b 100644 --- a/storage/connect/tabcol.cpp +++ b/storage/connect/tabcol.cpp @@ -86,7 +86,7 @@ void XTAB::Printf(PGLOBAL g, FILE *f, uint n) PlugPutOut(g, f, TYPE_TDB, tp->To_Tdb, n + 2); } /* endfor tp */ - } /* end of Print */ + } /* end of Printf */ /***********************************************************************/ /* Make string output of XTAB contents. */ @@ -105,7 +105,7 @@ void XTAB::Prints(PGLOBAL, char *ps, uint z) n -= i; } // endif tp - } /* end of Print */ + } /* end of Prints */ /***********************************************************************/ @@ -149,7 +149,7 @@ void COLUMN::Printf(PGLOBAL g, FILE *f, uint n) PlugPutOut(g, f, TYPE_TABLE, To_Table, n + 2); PlugPutOut(g, f, TYPE_XOBJECT, To_Col, n + 2); - } /* end of Print */ + } /* end of Printf */ /***********************************************************************/ /* Make string output of COLUMN contents. */ @@ -166,4 +166,4 @@ void COLUMN::Prints(PGLOBAL, char *ps, uint z) strncpy(ps, buf, z); ps[z - 1] = '\0'; - } /* end of Print */ + } /* end of Prints */ diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 468966e79d994..b44705bc3cc5a 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -132,6 +132,7 @@ bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int) bool map = (am && (*am == 'M' || *am == 'm')); LPCSTR dfm = (am && (*am == 'F' || *am == 'f')) ? "F" : (am && (*am == 'B' || *am == 'b')) ? "B" + : (am && (*am == 'X' || *am == 'x')) ? "X" : (am && !stricmp(am, "DBF")) ? "D" : "V"; if ((Zipped = GetBoolCatInfo("Zipped", false))) { @@ -148,6 +149,7 @@ bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int) GetCharCatInfo("Recfm", (PSZ)dfm, buf, sizeof(buf)); Recfm = (toupper(*buf) == 'F') ? RECFM_FIX : (toupper(*buf) == 'B') ? RECFM_BIN : + (toupper(*buf) == 'X') ? RECFM_NAF : // MGO (toupper(*buf) == 'D') ? RECFM_DBF : RECFM_VAR; Lrecl = GetIntCatInfo("Lrecl", 0); @@ -1645,7 +1647,7 @@ int TDBDOS::TestBlock(PGLOBAL g) /***********************************************************************/ int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add) { - int k, n; + int k, n, rc = RC_OK; bool fixed, doit, sep, b = (pxdf != NULL); PCOL *keycols, colp; PIXDEF xdp, sxp = NULL; @@ -1690,95 +1692,105 @@ int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add) } else if (!(pxdf = dfp->GetIndx())) return RC_INFO; // No index to make - // Allocate all columns that will be used by indexes. - // This must be done before opening the table so specific - // column initialization can be done (in particular by TDBVCT) - for (n = 0, xdp = pxdf; xdp; xdp = xdp->GetNext()) - for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) { - if (!(colp = ColDB(g, kdp->GetName(), 0))) { - sprintf(g->Message, MSG(INDX_COL_NOTIN), kdp->GetName(), Name); - goto err; - } else if (colp->GetResultType() == TYPE_DECIM) { - sprintf(g->Message, "Decimal columns are not indexable yet"); - goto err; - } // endif Type - - colp->InitValue(g); - n = MY_MAX(n, xdp->GetNparts()); - } // endfor kdp - - keycols = (PCOL*)PlugSubAlloc(g, NULL, n * sizeof(PCOL)); - sep = dfp->GetBoolCatInfo("SepIndex", false); - - /*********************************************************************/ - /* Construct and save the defined indexes. */ - /*********************************************************************/ - for (xdp = pxdf; xdp; xdp = xdp->GetNext()) - if (!OpenDB(g)) { - if (xdp->IsAuto() && fixed) - // Auto increment key and fixed file: use an XXROW index - continue; // XXROW index doesn't need to be made - - // On Update, redo only indexes that are modified - doit = !To_SetCols; - n = 0; - - if (sxp) - xdp->SetID(sxp->GetID() + 1); - - for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) { - // Check whether this column was updated - for (colp = To_SetCols; !doit && colp; colp = colp->GetNext()) - if (!stricmp(kdp->GetName(), colp->GetName())) - doit = true; - - keycols[n++] = ColDB(g, kdp->GetName(), 0); - } // endfor kdp - - // If no indexed columns were updated, don't remake the index - // if indexes are in separate files. - if (!doit && sep) - continue; - - k = xdp->GetNparts(); - - // Make the index and save it - if (dfp->Huge) - pxp = new(g) XHUGE; - else - pxp = new(g) XFILE; - - if (k == 1) // Simple index - x = new(g) XINDXS(this, xdp, pxp, keycols); - else // Multi-Column index - x = new(g) XINDEX(this, xdp, pxp, keycols); - - if (!x->Make(g, sxp)) { - // Retreive define values from the index - xdp->SetMaxSame(x->GetMaxSame()); -// xdp->SetSize(x->GetSize()); - - // store KXYCOL Mxs in KPARTDEF Mxsame - xdp->SetMxsame(x); + try { + // Allocate all columns that will be used by indexes. + // This must be done before opening the table so specific + // column initialization can be done (in particular by TDBVCT) + for (n = 0, xdp = pxdf; xdp; xdp = xdp->GetNext()) + for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) { + if (!(colp = ColDB(g, kdp->GetName(), 0))) { + sprintf(g->Message, MSG(INDX_COL_NOTIN), kdp->GetName(), Name); + goto err; + } else if (colp->GetResultType() == TYPE_DECIM) { + sprintf(g->Message, "Decimal columns are not indexable yet"); + goto err; + } // endif Type + + colp->InitValue(g); + n = MY_MAX(n, xdp->GetNparts()); + } // endfor kdp + + keycols = (PCOL*)PlugSubAlloc(g, NULL, n * sizeof(PCOL)); + sep = dfp->GetBoolCatInfo("SepIndex", false); + + /*********************************************************************/ + /* Construct and save the defined indexes. */ + /*********************************************************************/ + for (xdp = pxdf; xdp; xdp = xdp->GetNext()) + if (!OpenDB(g)) { + if (xdp->IsAuto() && fixed) + // Auto increment key and fixed file: use an XXROW index + continue; // XXROW index doesn't need to be made + + // On Update, redo only indexes that are modified + doit = !To_SetCols; + n = 0; + + if (sxp) + xdp->SetID(sxp->GetID() + 1); + + for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) { + // Check whether this column was updated + for (colp = To_SetCols; !doit && colp; colp = colp->GetNext()) + if (!stricmp(kdp->GetName(), colp->GetName())) + doit = true; + + keycols[n++] = ColDB(g, kdp->GetName(), 0); + } // endfor kdp + + // If no indexed columns were updated, don't remake the index + // if indexes are in separate files. + if (!doit && sep) + continue; + + k = xdp->GetNparts(); + + // Make the index and save it + if (dfp->Huge) + pxp = new(g) XHUGE; + else + pxp = new(g) XFILE; + + if (k == 1) // Simple index + x = new(g) XINDXS(this, xdp, pxp, keycols); + else // Multi-Column index + x = new(g) XINDEX(this, xdp, pxp, keycols); + + if (!x->Make(g, sxp)) { + // Retreive define values from the index + xdp->SetMaxSame(x->GetMaxSame()); + // xdp->SetSize(x->GetSize()); + + // store KXYCOL Mxs in KPARTDEF Mxsame + xdp->SetMxsame(x); #if defined(TRACE) - printf("Make done...\n"); + printf("Make done...\n"); #endif // TRACE -// if (x->GetSize() > 0) - sxp = xdp; + // if (x->GetSize() > 0) + sxp = xdp; - xdp->SetInvalid(false); - } else - goto err; + xdp->SetInvalid(false); + } else + goto err; - } else - return RC_INFO; // Error or Physical table does not exist + } else + return RC_INFO; // Error or Physical table does not exist - if (Use == USE_OPEN) + } catch (int n) { + if (trace) + htrc("Exception %d: %s\n", n, g->Message); + rc = RC_FX; + } catch (const char *msg) { + strcpy(g->Message, msg); + rc = RC_FX; + } // end catch + + if (Use == USE_OPEN) CloseDB(g); - return RC_OK; + return rc; err: if (sxp) @@ -2725,7 +2737,7 @@ void DOSCOL::WriteColumn(PGLOBAL g) if (Value->GetBinValue(p, Long, Status)) { sprintf(g->Message, MSG(BIN_F_TOO_LONG), Name, Value->GetSize(), Long); - longjmp(g->jumper[g->jump_level], 31); + throw 31; } // endif } // end of WriteColumn @@ -2868,13 +2880,4 @@ bool DOSCOL::AddDistinctValue(PGLOBAL g) return false; } // end of AddDistinctValue -/***********************************************************************/ -/* Make file output of a Dos column descriptor block. */ -/***********************************************************************/ -void DOSCOL::Printf(PGLOBAL g, FILE *f, uint n) - { - COLBLK::Printf(g, f, n); - } // end of Print - /* ------------------------------------------------------------------- */ - diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 9722cd3777d9d..948b357dc1fed 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -232,12 +232,10 @@ 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); virtual void WriteColumn(PGLOBAL g); - virtual void Printf(PGLOBAL g, FILE *, uint); protected: virtual bool SetMinMax(PGLOBAL g); diff --git a/storage/connect/tabext.cpp b/storage/connect/tabext.cpp index 4ef88fec7464e..1d76e0417fa47 100644 --- a/storage/connect/tabext.cpp +++ b/storage/connect/tabext.cpp @@ -298,8 +298,7 @@ bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt) PCSZ ph = ((EXTDEF*)To_Def)->Phpos; if (!ph) - ph = (strstr(catp + 2, "%s")) ? const_cast("WH") : - const_cast("W"); + ph = (strstr(catp + 2, "%s")) ? "WH" : "W"; if (stricmp(ph, "H")) { fil1 = (To_CondFil && *To_CondFil->Body) diff --git a/storage/connect/tabext.h b/storage/connect/tabext.h index 497b6074d480b..7ddf2a68117f7 100644 --- a/storage/connect/tabext.h +++ b/storage/connect/tabext.h @@ -104,6 +104,8 @@ class DllExport EXTDEF : public TABDEF { /* EXT table */ /* This is the base class for all external tables. */ /***********************************************************************/ class DllExport TDBEXT : public TDB { + friend class JAVAConn; + friend class JMgoConn; public: // Constructors TDBEXT(EXTDEF *tdp); @@ -164,7 +166,7 @@ class DllExport TDBEXT : public TDB { }; // end of class TDBEXT /***********************************************************************/ -/* Virual class EXTCOL: external column. */ +/* Virtual class EXTCOL: external column. */ /***********************************************************************/ class DllExport EXTCOL : public COLBLK { friend class TDBEXT; diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 13fbe7d33dddc..516601a5eb48f 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -1047,7 +1047,7 @@ bool TDBCSV::PrepareWriting(PGLOBAL g) if (!strlen(Field[i])) { // Generally null fields are not quoted if (Quoted > 2) - // Except if explicitly required + // Except if explicitely required strcat(strcat(To_Line, qot), qot); } else if (Qot && (strchr(Field[i], Sep) || *Field[i] == Qot diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp index 7c82a2fc13834..b6a1487955b03 100644 --- a/storage/connect/tabjdbc.cpp +++ b/storage/connect/tabjdbc.cpp @@ -223,10 +223,10 @@ bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) } // endif Connect if (Url) - rc = ParseURL(g, Url); - - if (rc == RC_FX) // Error - return true; + if ((rc = ParseURL(g, Url)) == RC_FX) { + sprintf(g->Message, "Wrong JDBC URL %s", Url); + return true; + } // endif rc Wrapname = GetStringCatInfo(g, "Wrapper", NULL); return false; @@ -305,12 +305,12 @@ TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBEXT(tdp) if (tdp) { Ops.Driver = tdp->Driver; Ops.Url = tdp->Url; - WrapName = tdp->Wrapname; + Wrapname = tdp->Wrapname; Ops.User = tdp->Username; Ops.Pwd = tdp->Password; Ops.Scrollable = tdp->Scrollable; } else { - WrapName = NULL; + Wrapname = NULL; Ops.Driver = NULL; Ops.Url = NULL; Ops.User = NULL; @@ -328,7 +328,7 @@ TDBJDBC::TDBJDBC(PTDBJDBC tdbp) : TDBEXT(tdbp) { Jcp = tdbp->Jcp; // is that right ? Cnp = tdbp->Cnp; - WrapName = tdbp->WrapName; + Wrapname = tdbp->Wrapname; Ops = tdbp->Ops; Prepared = tdbp->Prepared; Werr = tdbp->Werr; @@ -562,7 +562,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g) /* Table already open, just replace it at its beginning. */ /*******************************************************************/ if (Memory == 1) { - if ((Qrp = Jcp->AllocateResult(g))) + if ((Qrp = Jcp->AllocateResult(g, this))) Memory = 2; // Must be filled else Memory = 0; // Allocation failed, don't use it @@ -596,11 +596,11 @@ bool TDBJDBC::OpenDB(PGLOBAL g) /* drivers allowing concurency in getting results ??? */ /*********************************************************************/ if (!Jcp) - Jcp = new(g)JDBConn(g, this); + Jcp = new(g)JDBConn(g, Wrapname); else if (Jcp->IsOpen()) Jcp->Close(); - if (Jcp->Open(&Ops) == RC_FX) + if (Jcp->Connect(&Ops)) return true; else if (Quoted) Quote = Jcp->GetQuoteChar(); @@ -608,7 +608,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g) Use = USE_OPEN; // Do it now in case we are recursively called /*********************************************************************/ - /* Make the command and allocate whatever is used for getting results. */ + /* Make the command and allocate whatever is used for getting results*/ /*********************************************************************/ if (Mode == MODE_READ || Mode == MODE_READX) { if (Memory > 1 && !Srcdef) { @@ -625,7 +625,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g) } else if (n) { Jcp->m_Rows = n; - if ((Qrp = Jcp->AllocateResult(g))) + if ((Qrp = Jcp->AllocateResult(g, this))) Memory = 2; // Must be filled else { strcpy(g->Message, "Result set memory allocation failed"); @@ -1134,11 +1134,11 @@ bool TDBXJDC::OpenDB(PGLOBAL g) /* drivers allowing concurency in getting results ??? */ /*********************************************************************/ if (!Jcp) { - Jcp = new(g) JDBConn(g, this); + Jcp = new(g) JDBConn(g, Wrapname); } else if (Jcp->IsOpen()) Jcp->Close(); - if (Jcp->Open(&Ops) == RC_FX) + if (Jcp->Connect(&Ops)) return true; Use = USE_OPEN; // Do it now in case we are recursively called @@ -1173,7 +1173,7 @@ int TDBXJDC::ReadDB(PGLOBAL g) else Query->Set(Cmdlist->Cmd); - if ((rc = Jcp->ExecSQLcommand(Query->GetStr())) == RC_FX) + if ((rc = Jcp->ExecuteCommand(Query->GetStr())) == RC_FX) Nerr++; if (rc == RC_NF) diff --git a/storage/connect/tabjdbc.h b/storage/connect/tabjdbc.h index d8ec65d02d886..d422ed26ef2d0 100644 --- a/storage/connect/tabjdbc.h +++ b/storage/connect/tabjdbc.h @@ -41,7 +41,7 @@ class DllExport JDBCDEF : public EXTDEF { /* Logical table description */ // Members PSZ Driver; /* JDBC driver */ PSZ Url; /* JDBC driver URL */ - PSZ Wrapname; /* Java wrapper name */ + PSZ Wrapname; /* Java driver name */ }; // end of JDBCDEF #if !defined(NJDBC) @@ -89,7 +89,7 @@ class TDBJDBC : public TDBEXT { JDBConn *Jcp; // Points to a JDBC connection class JDBCCOL *Cnp; // Points to count(*) column JDBCPARM Ops; // Additional parameters - char *WrapName; // Points to Java wrapper name + PSZ Wrapname; // Points to Java wrapper name bool Prepared; // True when using prepared statement bool Werr; // Write error bool Rerr; // Rewind error @@ -173,7 +173,6 @@ class JSRCCOL : public JDBCCOL { // Methods virtual void ReadColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g); - // void Printf(PGLOBAL g, FILE *, uint); protected: // Members diff --git a/storage/connect/tabjmg.cpp b/storage/connect/tabjmg.cpp new file mode 100644 index 0000000000000..bf147e76cc055 --- /dev/null +++ b/storage/connect/tabjmg.cpp @@ -0,0 +1,508 @@ +/************** tabjmg C++ Program Source Code File (.CPP) *************/ +/* PROGRAM NAME: tabjmg Version 1.2 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* This file contains the MongoDB classes using the Java Driver. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the MariaDB header file. */ +/***********************************************************************/ +#include + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "xtable.h" +#include "maputil.h" +#include "filamtxt.h" +#include "tabext.h" +#include "tabjmg.h" +#include "tabmul.h" +#include "checklvl.h" +#include "resource.h" +#include "mycat.h" // for FNC_COL +#include "filter.h" + +/***********************************************************************/ +/* This should be an option. */ +/***********************************************************************/ +#define MAXCOL 200 /* Default max column nb in result */ +#define TYPE_UNKNOWN 12 /* Must be greater than other types */ + +PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info); + +/* --------------------------- Class TDBJMG -------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBJMG class. */ +/***********************************************************************/ +TDBJMG::TDBJMG(PMGODEF tdp) : TDBEXT(tdp) +{ + Jcp = NULL; +//Cnp = NULL; + + if (tdp) { + Ops.Driver = tdp->Tabschema; + Ops.Url = tdp->Uri; + Ops.Version = tdp->Version; + Uri = tdp->Uri; + Db_name = tdp->Tabschema; + Wrapname = tdp->Wrapname; + Coll_name = tdp->Tabname; + Options = tdp->Colist; + Filter = tdp->Filter; + B = tdp->Base ? 1 : 0; + Pipe = tdp->Pipe && Options != NULL; + } else { + Ops.Driver = NULL; + Ops.Url = NULL; + Ops.Version = 0; + Uri = NULL; + Db_name = NULL; + Coll_name = NULL; + Options = NULL; + Filter = NULL; + B = 0; + Pipe = false; + } // endif tdp + + Ops.User = NULL; + Ops.Pwd = NULL; + Ops.Scrollable = false; + Ops.Fsize = Ops.CheckSize(Rows); + Fpos = -1; + N = 0; + Done = false; +} // end of TDBJMG standard constructor + +TDBJMG::TDBJMG(TDBJMG *tdbp) : TDBEXT(tdbp) +{ + Uri = tdbp->Uri; +//Pool = tdbp->Pool; +//Client = tdbp->Client; +//Database = NULL; +//Collection = tdbp->Collection; +//Cursor = tdbp->Cursor; +//Query = tdbp->Query; +//Opts = tdbp->Opts; +//Fpc = tdbp->Fpc; +//Cnd = tdbp->Cnd; +//Uristr = tdbp->Uristr; + Db_name = tdbp->Db_name;; + Coll_name = tdbp->Coll_name; + Options = tdbp->Options; + Filter = tdbp->Filter; + B = tdbp->B; + Fpos = tdbp->Fpos; + N = tdbp->N; + Done = tdbp->Done; + Pipe = tdbp->Pipe; +} // end of TDBJMG copy constructor + +// Used for update +PTDB TDBJMG::Clone(PTABS t) +{ + PTDB tp; + PJMGCOL cp1, cp2; + PGLOBAL g = t->G; + + tp = new(g) TDBJMG(this); + + for (cp1 = (PJMGCOL)Columns; cp1; cp1 = (PJMGCOL)cp1->GetNext()) + if (!cp1->IsSpecial()) { + cp2 = new(g) JMGCOL(cp1, tp); // Make a copy + NewPointer(t, cp1, cp2); + } // endif cp1 + + return tp; +} // end of Clone + +/***********************************************************************/ +/* Allocate JSN column description block. */ +/***********************************************************************/ +PCOL TDBJMG::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) +{ + PJMGCOL colp = new(g) JMGCOL(g, cdp, this, cprec, n); + +//colp->Mbuf = (char*)PlugSubAlloc(g, NULL, colp->Long + 1); + return colp; + //return (colp->ParseJpath(g)) ? NULL : colp; +} // end of MakeCol + +/***********************************************************************/ +/* InsertSpecialColumn: Put a special column ahead of the column list.*/ +/***********************************************************************/ +PCOL TDBJMG::InsertSpecialColumn(PCOL colp) +{ + if (!colp->IsSpecial()) + return NULL; + + colp->SetNext(Columns); + Columns = colp; + return colp; +} // end of InsertSpecialColumn + +/***********************************************************************/ +/* MONGO Cardinality: returns table size in number of rows. */ +/***********************************************************************/ +int TDBJMG::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + else if (Cardinal < 0) + Cardinal = (!Init(g)) ? Jcp->CollSize(g) : 0; + + return Cardinal; +} // end of Cardinality + +/***********************************************************************/ +/* MONGO GetMaxSize: returns collection size estimate. */ +/***********************************************************************/ +int TDBJMG::GetMaxSize(PGLOBAL g) +{ + if (MaxSize < 0) + MaxSize = Cardinality(g); + + return MaxSize; +} // end of GetMaxSize + +/***********************************************************************/ +/* Init: initialize MongoDB processing. */ +/***********************************************************************/ +bool TDBJMG::Init(PGLOBAL g) +{ + if (Done) + return false; + + /*********************************************************************/ + /* Open an JDBC connection for this table. */ + /* Note: this may not be the proper way to do. Perhaps it is better */ + /* to test whether a connection is already open for this datasource */ + /* and if so to allocate just a new result set. But this only for */ + /* drivers allowing concurency in getting results ??? */ + /*********************************************************************/ + if (!Jcp) + Jcp = new(g) JMgoConn(g, Coll_name, Wrapname); + else if (Jcp->IsOpen()) + Jcp->Close(); + + if (Jcp->Connect(&Ops)) + return true; + + Done = true; + return false; +} // end of Init + +/***********************************************************************/ +/* OpenDB: Data Base open routine for MONGO access method. */ +/***********************************************************************/ +bool TDBJMG::OpenDB(PGLOBAL g) +{ + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open replace it at its beginning. */ + /*******************************************************************/ + if (Jcp->Rewind()) + return true; + + Fpos = -1; + return false; + } // endif Use + + /*********************************************************************/ + /* First opening. */ + /*********************************************************************/ + if (Pipe && Mode != MODE_READ) { + strcpy(g->Message, "Pipeline tables are read only"); + return true; + } // endif Pipe + + if (Init(g)) + return true; + + if (Jcp->GetMethodId(g, Mode)) + return true; + + if (Mode == MODE_DELETE && !Next) { + // Delete all documents + if (!Jcp->MakeCursor(g, this, "all", Filter, false)) + if (Jcp->DocDelete(g, true) == RC_OK) + return false; + + return true; + } // endif Mode + + if (Mode == MODE_INSERT) + Jcp->MakeColumnGroups(g, this); + + if (Mode != MODE_UPDATE) + return Jcp->MakeCursor(g, this, Options, Filter, Pipe); + + return false; +} // end of OpenDB + +/***********************************************************************/ +/* Data Base indexed read routine for ODBC access method. */ +/***********************************************************************/ +bool TDBJMG::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) +{ + strcpy(g->Message, "MONGO tables are not indexable"); + return true; +} // end of ReadKey + +/***********************************************************************/ +/* ReadDB: Get next document from a collection. */ +/***********************************************************************/ +int TDBJMG::ReadDB(PGLOBAL g) +{ + int rc = RC_OK; + + if (!N && Mode == MODE_UPDATE) + if (Jcp->MakeCursor(g, this, Options, Filter, Pipe)) + return RC_FX; + + if (++CurNum >= Rbuf) { + Rbuf = Jcp->Fetch(); + Curpos = Fpos + 1; + CurNum = 0; + N++; + } // endif CurNum + + rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX; + + return rc; +} // end of ReadDB + +/***********************************************************************/ +/* WriteDB: Data Base write routine for DOS access method. */ +/***********************************************************************/ +int TDBJMG::WriteDB(PGLOBAL g) +{ + int rc = RC_OK; + + if (Mode == MODE_INSERT) { + rc = Jcp->DocWrite(g); + } else if (Mode == MODE_DELETE) { + rc = Jcp->DocDelete(g, false); + } else if (Mode == MODE_UPDATE) { + rc = Jcp->DocUpdate(g, this); + } // endif Mode + + return rc; +} // end of WriteDB + +/***********************************************************************/ +/* Data Base delete line routine for ODBC access method. */ +/***********************************************************************/ +int TDBJMG::DeleteDB(PGLOBAL g, int irc) +{ + return (irc == RC_OK) ? WriteDB(g) : RC_OK; +} // end of DeleteDB + +/***********************************************************************/ +/* Table close routine for MONGO tables. */ +/***********************************************************************/ +void TDBJMG::CloseDB(PGLOBAL g) +{ + Jcp->Close(); + Done = false; +} // end of CloseDB + +/* ----------------------------- JMGCOL ------------------------------ */ + +/***********************************************************************/ +/* JMGCOL public constructor. */ +/***********************************************************************/ +JMGCOL::JMGCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) + : EXTCOL(cdp, tdbp, cprec, i, "MGO") +{ + Tmgp = (PTDBJMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); + Jpath = cdp->GetFmt() ? cdp->GetFmt() : cdp->GetName(); +//Mbuf = NULL; +} // end of JMGCOL constructor + +/***********************************************************************/ +/* JMGCOL constructor used for copying columns. */ +/* tdbp is the pointer to the new table descriptor. */ +/***********************************************************************/ +JMGCOL::JMGCOL(JMGCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp) +{ + Tmgp = col1->Tmgp; + Jpath = col1->Jpath; +//Mbuf = col1->Mbuf; +} // end of JMGCOL copy constructor + +/***********************************************************************/ +/* Get path when proj is false or projection path when proj is true. */ +/***********************************************************************/ +PSZ JMGCOL::GetJpath(PGLOBAL g, bool proj) +{ + if (Jpath) { + if (proj) { + char *p1, *p2, *projpath = PlugDup(g, Jpath); + int i = 0; + + for (p1 = p2 = projpath; *p1; p1++) + if (*p1 == '.') { + if (!i) + *p2++ = *p1; + + i = 1; + } else if (i) { + if (!isdigit(*p1)) { + *p2++ = *p1; + i = 0; + } // endif p1 + + } else + *p2++ = *p1; + + *p2 = 0; + return projpath; + } else + return Jpath; + + } else + return Name; + +} // end of GetJpath + +#if 0 +/***********************************************************************/ +/* Mini: used to suppress blanks to json strings. */ +/***********************************************************************/ +char *JMGCOL::Mini(PGLOBAL g, const bson_t *bson, bool b) +{ + char *s, *str = NULL; + int i, k = 0; + bool ok = true; + + if (b) + s = str = bson_array_as_json(bson, NULL); + else + s = str = bson_as_json(bson, NULL); + + for (i = 0; i < Long && s[i]; i++) { + switch (s[i]) { + case ' ': + if (ok) continue; + case '"': + ok = !ok; + default: + break; + } // endswitch s[i] + + Mbuf[k++] = s[i]; + } // endfor i + + bson_free(str); + + if (i >= Long) { + sprintf(g->Message, "Value too long for column %s", Name); + throw (int)TYPE_AM_MGO; + } // endif i + + Mbuf[k] = 0; + return Mbuf; +} // end of Mini +#endif // 0 + +/***********************************************************************/ +/* ReadColumn: */ +/***********************************************************************/ +void JMGCOL::ReadColumn(PGLOBAL g) +{ + Value->SetValue_psz(Tmgp->Jcp->GetColumnValue(Jpath)); +} // end of ReadColumn + +/***********************************************************************/ +/* WriteColumn: */ +/***********************************************************************/ +void JMGCOL::WriteColumn(PGLOBAL g) +{ + // Check whether this node must be written + if (Value != To_Val) + Value->SetValue_pval(To_Val, FALSE); // Convert the updated value + +} // end of WriteColumn + +#if 0 +/***********************************************************************/ +/* AddValue: Add column value to the document to insert or update. */ +/***********************************************************************/ +bool JMGCOL::AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd) +{ + bool rc = false; + + if (Value->IsNull()) { + if (upd) + rc = BSON_APPEND_NULL(doc, key); + else + return false; + + } else switch (Buf_Type) { + case TYPE_STRING: + rc = BSON_APPEND_UTF8(doc, key, Value->GetCharValue()); + break; + case TYPE_INT: + case TYPE_SHORT: + rc = BSON_APPEND_INT32(doc, key, Value->GetIntValue()); + break; + case TYPE_TINY: + rc = BSON_APPEND_BOOL(doc, key, Value->GetIntValue()); + break; + case TYPE_BIGINT: + rc = BSON_APPEND_INT64(doc, key, Value->GetBigintValue()); + break; + case TYPE_DOUBLE: + rc = BSON_APPEND_DOUBLE(doc, key, Value->GetFloatValue()); + break; + case TYPE_DECIM: + {bson_decimal128_t dec; + + if (bson_decimal128_from_string(Value->GetCharValue(), &dec)) + rc = BSON_APPEND_DECIMAL128(doc, key, &dec); + + } break; + case TYPE_DATE: + rc = BSON_APPEND_DATE_TIME(doc, key, Value->GetBigintValue() * 1000); + break; + default: + sprintf(g->Message, "Type %d not supported yet", Buf_Type); + return true; + } // endswitch Buf_Type + + if (!rc) { + strcpy(g->Message, "Adding value failed"); + return true; + } else + return false; + +} // end of AddValue +#endif // 0 + +/* -------------------------- TDBJGL class --------------------------- */ + +/***********************************************************************/ +/* TDBJGL class constructor. */ +/***********************************************************************/ +TDBJGL::TDBJGL(PMGODEF tdp) : TDBCAT(tdp) +{ + Topt = tdp->GetTopt(); + Uri = tdp->Uri; + Db = tdp->GetTabschema(); +} // end of TDBJCL constructor + + /***********************************************************************/ + /* GetResult: Get the list the JSON file columns. */ + /***********************************************************************/ +PQRYRES TDBJGL::GetResult(PGLOBAL g) +{ + return JSONColumns(g, Db, Uri, Topt, false); +} // end of GetResult + + /* -------------------------- End of mongo --------------------------- */ diff --git a/storage/connect/tabjmg.h b/storage/connect/tabjmg.h new file mode 100644 index 0000000000000..323fc0bba48c7 --- /dev/null +++ b/storage/connect/tabjmg.h @@ -0,0 +1,121 @@ +/**************** tabjmg H Declares Source Code File (.H) **************/ +/* Name: tabjmg.h Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the MongoDB classes using the Java Driver. */ +/***********************************************************************/ +#include "mongo.h" +#include "jmgoconn.h" +#include "jdbccat.h" + +/* -------------------------- TDBJMG class --------------------------- */ + +/***********************************************************************/ +/* This is the MongoDB Table Type using the Java Driver. */ +/* The table is a collection, each record being a document. */ +/***********************************************************************/ +class DllExport TDBJMG : public TDBEXT { + friend class JMGCOL; + friend class MGODEF; + friend class MGODISC; + friend class JAVAConn; + friend PQRYRES MGOColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool); +public: + // Constructor + TDBJMG(PMGODEF tdp); + TDBJMG(TDBJMG *tdbp); + + // Implementation + virtual AMT GetAmType(void) { return TYPE_AM_MGO; } + virtual PTDB Duplicate(PGLOBAL g) { return (PTDB)new(g) TDBJMG(this); } + + // Methods + virtual PTDB Clone(PTABS t); + virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual PCOL InsertSpecialColumn(PCOL colp); +//virtual void SetFilter(PFIL fp); + virtual int RowNumber(PGLOBAL g, bool b = FALSE) { return N; } + + // Database routines + virtual int Cardinality(PGLOBAL g); + virtual int GetMaxSize(PGLOBAL g); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + virtual int WriteDB(PGLOBAL g); + virtual int DeleteDB(PGLOBAL g, int irc); + virtual void CloseDB(PGLOBAL g); + virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr); + +protected: + bool Init(PGLOBAL g); + + // Members + JMgoConn *Jcp; // Points to a Mongo connection class +//JMGCOL *Cnp; // Points to count(*) column + JDBCPARM Ops; // Additional parameters + PCSZ Uri; + PCSZ Db_name; + PCSZ Coll_name; + PCSZ Options; // The MongoDB options + PCSZ Filter; // The filtering query + PSZ Wrapname; // Java wrapper name + int Fpos; // The current row index + int N; // The current Rownum + int B; // Array index base + bool Done; // Init done + bool Pipe; // True for pipeline +}; // end of class TDBJMG + +/* --------------------------- JMGCOL class -------------------------- */ + +/***********************************************************************/ +/* Class JMGCOL: MongoDB access method column descriptor. */ +/***********************************************************************/ +class DllExport JMGCOL : public EXTCOL { + friend class TDBJMG; + friend class FILTER; +public: + // Constructors + JMGCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); + JMGCOL(JMGCOL *colp, PTDB tdbp); // Constructor used in copy process + + // Implementation + virtual int GetAmType(void) {return Tmgp->GetAmType();} + + // Methods + //virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); + virtual PSZ GetJpath(PGLOBAL g, bool proj); + virtual void ReadColumn(PGLOBAL g); + virtual void WriteColumn(PGLOBAL g); +//bool AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd); + +protected: + // Default constructor not to be used + JMGCOL(void) {} +//char *GetProjPath(PGLOBAL g); +//char *Mini(PGLOBAL g, const bson_t *bson, bool b); + + // Members + TDBJMG *Tmgp; // To the MGO table block + char *Jpath; // The json path +//char *Mbuf; // The Mini buffer +}; // end of class JMGCOL + +/***********************************************************************/ +/* This is the class declaration for the MONGO catalog table. */ +/***********************************************************************/ +class DllExport TDBJGL : public TDBCAT { +public: + // Constructor + TDBJGL(PMGODEF tdp); + +protected: + // Specific routines + virtual PQRYRES GetResult(PGLOBAL g); + + // Members + PTOS Topt; + PCSZ Uri; + PCSZ Db; +}; // end of class TDBGOL diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 063115c7a60f8..823c82b9ceb54 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -31,6 +31,12 @@ #if defined(ZIP_SUPPORT) #include "filamzip.h" #endif // ZIP_SUPPORT +#if defined(JDBC_SUPPORT) +#include "jmgfam.h" +#endif // JDBC_SUPPORT +#if defined(MONGO_SUPPORT) +#include "mongofam.h" +#endif // MONGO_SUPPORT #include "tabmul.h" #include "checklvl.h" #include "resource.h" @@ -44,9 +50,11 @@ #define USE_G 1 /* Use recoverable memory if 1 */ /***********************************************************************/ -/* External function. */ +/* External functions. */ /***********************************************************************/ USETEMP UseTemp(void); +bool IsNum(PSZ s); +char *NextChr(PSZ s, char sep); typedef struct _jncol { struct _jncol *Next; @@ -63,16 +71,18 @@ typedef struct _jncol { /* JSONColumns: construct the result blocks containing the description */ /* of all the columns of a table contained inside a JSON file. */ /***********************************************************************/ -PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) +PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) { static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT}; static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0}; - char colname[65], fmt[129]; + char *p, colname[65], fmt[129]; int i, j, lvl, n = 0; int ncol = sizeof(buftyp) / sizeof(int); + bool mgo = (GetTypeID(topt->type) == TAB_MONGO); + PCSZ sep, level; PVAL valp; JCOL jcol; PJCL jcp, fjcp = NULL, pjcp = NULL; @@ -102,8 +112,15 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) /*********************************************************************/ /* Open the input file. */ /*********************************************************************/ - lvl = GetIntegerTableOption(g, topt, "Level", 0); - lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl; + level = GetStringTableOption(g, topt, "Level", NULL); + + if (level) { + lvl = atoi(level); + lvl = (lvl > 16) ? 16 : lvl; + } else + lvl = 0; + + sep = GetStringTableOption(g, topt, "Separator", "."); tdp = new(g) JSONDEF; #if defined(ZIP_SUPPORT) @@ -112,22 +129,41 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) #endif // ZIP_SUPPORT tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); - if (!tdp->Fn) { - strcpy(g->Message, MSG(MISSING_FNAME)); - return NULL; - } // endif Fn - if (!(tdp->Database = SetPath(g, db))) return NULL; tdp->Objname = GetStringTableOption(g, topt, "Object", NULL); tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2); + tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL); + tdp->Uri = (dsn && *dsn ? dsn : NULL); - if (trace) + if (!tdp->Fn && !tdp->Uri) { + strcpy(g->Message, MSG(MISSING_FNAME)); + return NULL; + } // endif Fn + + if (trace) htrc("File %s objname=%s pretty=%d lvl=%d\n", tdp->Fn, tdp->Objname, tdp->Pretty, lvl); + if (tdp->Uri) { +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + tdp->Collname = GetStringTableOption(g, topt, "Name", NULL); + tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname); + tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test"); + tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all"); + tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false); + tdp->Version = GetIntegerTableOption(g, topt, "Version", 3); + tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper", + (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface"); + tdp->Pretty = 0; +#else // !MONGO_SUPPORT || JDBC_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return NULL; +#endif // !MONGO_SUPPORT || JDBC_SUPPORT + } // endif Uri + if (tdp->Pretty == 2) { if (tdp->Zipped) { #if defined(ZIP_SUPPORT) @@ -144,10 +180,12 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL; } else { - if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) { - sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); - return NULL; - } // endif lrecl + if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) + if (!mgo) { + sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); + return NULL; + } else + tdp->Lrecl = 8192; // Should be enough tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); @@ -158,6 +196,22 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); return NULL; #endif // !ZIP_SUPPORT + } else if (tdp->Uri) { +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) +#if !defined(JDBC_SUPPORT) + tjnp = new(g) TDBJSN(tdp, new(g) MGOFAM(tdp)); +#elif !defined(MONGO_SUPPORT) + tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); +#else + if (tdp->Driver && toupper(*tdp->Driver) == 'C') + tjnp = new(g) TDBJSN(tdp, new(g) MGOFAM(tdp)); + else + tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); +#endif +#else // !MONGO_SUPPORT && !JDBC_SUPPORT + sprintf(g->Message, "No MongoDB support"); + return NULL; +#endif // MONGO_SUPPORT || JDBC_SUPPORT } else tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); @@ -199,7 +253,15 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) jcol.Found = true; colname[64] = 0; fmt[128] = 0; - jrp = (PJPR*)PlugSubAlloc(g, NULL, sizeof(PJPR) * lvl); + + if (!tdp->Uri) { + *fmt = '$'; + fmt[1] = '.'; + p = fmt + 2; + } else + p = fmt; + + jrp = (PJPR*)PlugSubAlloc(g, NULL, sizeof(PJPR) * MY_MAX(lvl, 0)); /*********************************************************************/ /* Analyse the JSON tree and define columns. */ @@ -211,7 +273,7 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) more: strncpy(colname, jpp->GetKey(), 64); - *fmt = 0; + *p = 0; j = 0; jvp = jpp->GetVal(); @@ -226,8 +288,8 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) jcol.Len = jcol.Scale = 0; jcol.Cbn = true; } else if (j < lvl) { - if (!*fmt) - strcpy(fmt, colname); + if (!*p) + strcat(fmt, colname); jsp = jvp->GetJson(); @@ -236,13 +298,24 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) if (!jrp[j]) jrp[j] = jsp->GetFirst(); - strncat(strncat(fmt, ":", 128), jrp[j]->GetKey(), 128); - strncat(strncat(colname, "_", 64), jrp[j]->GetKey(), 64); - jvp = jrp[j]->GetVal(); - j++; + if (*jrp[j]->GetKey() != '$') { + strncat(strncat(fmt, sep, 128), jrp[j]->GetKey(), 128); + strncat(strncat(colname, "_", 64), jrp[j]->GetKey(), 64); + } // endif Key + + jvp = jrp[j]->GetVal(); + j++; break; case TYPE_JAR: - strncat(fmt, ":", 128); + if (!tdp->Xcol || stricmp(tdp->Xcol, colname)) { + if (tdp->Uri) + strncat(strncat(fmt, sep, 128), "0", 128); + else + strncat(fmt, "[0]", 128); + + } else + strncat(fmt, (tdp->Uri ? sep : "[]"), 128); + jvp = jsp->GetValue(0); break; default: @@ -251,12 +324,13 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) } // endswitch jsp goto retry; - } else { + } else if (lvl >= 0) { jcol.Type = TYPE_STRING; jcol.Len = 256; jcol.Scale = 0; jcol.Cbn = true; - } // endif's + } else + continue; // Check whether this column was already found for (jcp = fjcp; jcp; jcp = jcp->Next) @@ -272,10 +346,10 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) } // endif Type - if (*fmt && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) { + if (*p && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) { jcp->Fmt = PlugDup(g, fmt); length[7] = MY_MAX(length[7], strlen(fmt)); - } // endif *fmt + } // endif fmt jcp->Len = MY_MAX(jcp->Len, jcol.Len); jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale); @@ -289,7 +363,7 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) jcp->Name = PlugDup(g, colname); length[0] = MY_MAX(length[0], strlen(colname)); - if (*fmt) { + if (*p) { jcp->Fmt = PlugDup(g, fmt); length[7] = MY_MAX(length[7], strlen(fmt)); } else @@ -411,6 +485,17 @@ JSONDEF::JSONDEF(void) Limit = 1; Base = 0; Strict = false; + Sep = '.'; +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + Uri = NULL; + Collname = Schema = Options = Filter = NULL; + Pipe = false; + Driver = NULL; + Version = 0; +#if defined(JDBC_SUPPORT) + Wrapname = NULL; +#endif // JDBC_SUPPORT +#endif // !MONGO_SUPPORT && !JDBC_SUPPORT } // end of JSONDEF constructor /***********************************************************************/ @@ -424,7 +509,33 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR, int poff) Pretty = GetIntCatInfo("Pretty", 2); Limit = GetIntCatInfo("Limit", 10); Base = GetIntCatInfo("Base", 0) ? 1 : 0; - return DOSDEF::DefineAM(g, "DOS", poff); + Sep = *GetStringCatInfo(g, "Separator", "."); + + if (Uri = GetStringCatInfo(g, "Connect", NULL)) { +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + Collname = GetStringCatInfo(g, "Name", + (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); + Collname = GetStringCatInfo(g, "Tabname", Collname); + Schema = GetStringCatInfo(g, "Dbname", "test"); + Options = GetStringCatInfo(g, "Colist", NULL); + Filter = GetStringCatInfo(g, "Filter", NULL); + Pipe = GetBoolCatInfo("Pipeline", false); + Driver = GetStringCatInfo(g, "Driver", NULL); + Version = GetIntCatInfo("Version", 3); + Pretty = 0; +#if defined(JDBC_SUPPORT) + if (Version == 2) + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface"); + else + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface"); +#endif // JDBC_SUPPORT +#else // !MONGO_SUPPORT && !JDBC_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return true; +#endif // !MONGO_SUPPORT && !JDBC_SUPPORT + } // endif Uri + + return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff); } // end of DefineAM /***********************************************************************/ @@ -446,7 +557,20 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) !(tmp == TMP_FORCE && (m == MODE_UPDATE || m == MODE_DELETE)); - if (Zipped) { + if (Uri) { +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) +#if !defined(JDBC_SUPPORT) + txfp = new(g) MGOFAM(this); +#elif !defined(MONGO_SUPPORT) + txfp = new(g) JMGFAM(this); +#else + if (Driver && toupper(*Driver) == 'C') + txfp = new(g) MGOFAM(this); + else + txfp = new(g) JMGFAM(this); +#endif +#endif // MONGO_SUPPORT || JDBC_SUPPORT + } else if (Zipped) { #if defined(ZIP_SUPPORT) if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { txfp = new(g) UNZFAM(this); @@ -479,14 +603,19 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) tdbp = new(g) TDBJSN(this, txfp); #if USE_G - // Allocate the parse work memory - PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); - memset(G, 0, sizeof(GLOBAL)); - G->Sarea_Size = Lrecl * 10; - G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); - PlugSubSet(G, G->Sarea, G->Sarea_Size); - G->jump_level = 0; - ((TDBJSN*)tdbp)->G = G; + if (Lrecl) { + // Allocate the parse work memory + PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); + memset(G, 0, sizeof(GLOBAL)); + G->Sarea_Size = Lrecl * 10; + G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); + PlugSubSet(G, G->Sarea, G->Sarea_Size); + G->jump_level = 0; + ((TDBJSN*)tdbp)->G = G; + } else { + strcpy(g->Message, "LRECL is not defined"); + return NULL; + } // endif Lrecl #else ((TDBJSN*)tdbp)->G = g; #endif @@ -538,6 +667,7 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) Limit = tdp->Limit; Pretty = tdp->Pretty; B = tdp->Base ? 1 : 0; + Sep = tdp->Sep; Strict = tdp->Strict; } else { Jmode = MODE_OBJECT; @@ -546,6 +676,7 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) Limit = 1; Pretty = 0; B = 0; + Sep = '.'; Strict = false; } // endif tdp @@ -575,6 +706,7 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp) SameRow = tdbp->SameRow; Xval = tdbp->Xval; B = tdbp->B; + Sep = tdbp->Sep; Pretty = tdbp->Pretty; Strict = tdbp->Strict; Comma = tdbp->Comma; @@ -657,21 +789,27 @@ PJSON TDBJSN::FindRow(PGLOBAL g) PJSON jsp = Row; PJVAL val = NULL; - for (objpath = PlugDup(g, Objname); jsp && objpath; objpath = p) { - if ((p = strchr(objpath, ':'))) - *p++ = 0; + for (objpath = PlugDup(g, Objname); jsp && objpath; objpath = p) { + if ((p = strchr(objpath, Sep))) + *p++ = 0; + + if (*objpath != '[' && !IsNum(objpath)) { // objpass is a key + val = (jsp->GetType() == TYPE_JOB) ? + jsp->GetObject()->GetValue(objpath) : NULL; + } else { + if (*objpath == '[') { + if (objpath[strlen(objpath) - 1] == ']') + objpath++; + else + return NULL; + } // endif [ - if (*objpath != '[') { // objpass is a key - val = (jsp->GetType() == TYPE_JOB) ? - jsp->GetObject()->GetValue(objpath) : NULL; - } else if (objpath[strlen(objpath)-1] == ']') { - val = (jsp->GetType() == TYPE_JAR) ? - jsp->GetArray()->GetValue(atoi(objpath+1) - B) : NULL; - } else - val = NULL; + val = (jsp->GetType() == TYPE_JAR) ? + jsp->GetArray()->GetValue(atoi(objpath) - B) : NULL; + } // endif objpath - jsp = (val) ? val->GetJson() : NULL; - } // endfor objpath + jsp = (val) ? val->GetJson() : NULL; + } // endfor objpath return jsp; } // end of FindRow @@ -702,13 +840,16 @@ bool TDBJSN::OpenDB(PGLOBAL g) return true; } // endswitch Jmode - if (Xcol && Txfp->GetAmType() != TYPE_AM_MGO) - To_Filter = NULL; // Imcompatible - } // endif Use - return TDBDOS::OpenDB(g); - } // end of OpenDB + if (TDBDOS::OpenDB(g)) + return true; + + if (Xcol) + To_Filter = NULL; // Imcompatible + + return false; +} // end of OpenDB /***********************************************************************/ /* SkipHeader: Physically skip first header line if applicable. */ @@ -790,63 +931,70 @@ int TDBJSN::ReadDB(PGLOBAL g) /* Make the top tree from the object path. */ /***********************************************************************/ int TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp) - { - if (Objname) { - if (!Val) { - // Parse and allocate Objname item(s) - char *p; - char *objpath = PlugDup(g, Objname); - int i; - PJOB objp; - PJAR arp; - PJVAL val = NULL; - - Top = NULL; - - for (; objpath; objpath = p) { - if ((p = strchr(objpath, ':'))) - *p++ = 0; - - if (*objpath != '[') { - objp = new(g) JOBJECT; - - if (!Top) - Top = objp; - - if (val) - val->SetValue(objp); - - val = new(g) JVALUE; - objp->SetValue(g, val, objpath); - } else if (objpath[strlen(objpath)-1] == ']') { - arp = new(g) JARRAY; +{ + if (Objname) { + if (!Val) { + // Parse and allocate Objname item(s) + char *p; + char *objpath = PlugDup(g, Objname); + int i; + PJOB objp; + PJAR arp; + PJVAL val = NULL; - if (!Top) - Top = arp; - - if (val) - val->SetValue(arp); - - val = new(g) JVALUE; - i = atoi(objpath+1) - B; - arp->SetValue(g, val, i); - arp->InitArray(g); - } else { - sprintf(g->Message, "Invalid Table path %s", Objname); - return RC_FX; - } // endif objpath - - } // endfor p + Top = NULL; - Val = val; - } // endif Val + for (; objpath; objpath = p) { + if ((p = strchr(objpath, Sep))) + *p++ = 0; - Val->SetValue(jsp); - } else - Top = jsp; + if (*objpath != '[' && !IsNum(objpath)) { + objp = new(g) JOBJECT; - return RC_OK; - } // end of MakeTopTree + if (!Top) + Top = objp; + + if (val) + val->SetValue(objp); + + val = new(g) JVALUE; + objp->SetValue(g, val, objpath); + } else { + if (*objpath == '[') { + // Old style + if (objpath[strlen(objpath) - 1] != ']') { + sprintf(g->Message, "Invalid Table path %s", Objname); + return RC_FX; + } else + objpath++; + + } // endif objpath + + arp = new(g) JARRAY; + + if (!Top) + Top = arp; + + if (val) + val->SetValue(arp); + + val = new(g) JVALUE; + i = atoi(objpath) - B; + arp->SetValue(g, val, i); + arp->InitArray(g); + } // endif objpath + + } // endfor p + + Val = val; + } // endif Val + + Val->SetValue(jsp); + } else + Top = jsp; + + return RC_OK; +} // end of MakeTopTree /***********************************************************************/ /* PrepareWriting: Prepare the line for WriteDB. */ @@ -903,6 +1051,7 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) MulVal = NULL; Nodes = NULL; Nod = 0; + Sep = Tjp->Sep; Xnod = -1; Xpd = false; Parsed = false; @@ -920,7 +1069,8 @@ JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) MulVal = col1->MulVal; Nodes = col1->Nodes; Nod = col1->Nod; - Xnod = col1->Xnod; + Sep = col1->Sep; + Xnod = col1->Xnod; Xpd = col1->Xpd; Parsed = col1->Parsed; } // end of JSONCOL copy constructor @@ -963,125 +1113,132 @@ bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b) /* Analyse array processing options. */ /***********************************************************************/ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) - { - int n = (int)strlen(p); - bool dg = true, b = false; - PJNODE jnp = &Nodes[i]; - - if (*p) { - if (p[--n] == ']') { - p[n--] = 0; - p++; - } else { - // Wrong array specification - sprintf(g->Message, - "Invalid array specification %s for %s", p, Name); - return true; - } // endif p - - } else - b = true; - - // To check whether a numeric Rank was specified - for (int k = 0; dg && p[k]; k++) - dg = isdigit(p[k]) > 0; - - if (!n) { - // Default specifications - if (CheckExpand(g, i, nm, false)) - return true; - else if (jnp->Op != OP_EXP) { - if (b) { - // Return 1st value (B is the index base) - jnp->Rank = Tjp->B; - jnp->Op = OP_EQ; - } else if (!Value->IsTypeNum()) { - jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING); - jnp->Op = OP_CNC; - } else - jnp->Op = OP_ADD; - - } // endif OP - - } else if (dg) { - // Return nth value - jnp->Rank = atoi(p) - Tjp->B; - jnp->Op = OP_EQ; - } else if (n == 1) { - // Set the Op value; - switch (*p) { - case '+': jnp->Op = OP_ADD; break; - case '*': jnp->Op = OP_MULT; break; - case '>': jnp->Op = OP_MAX; break; - case '<': jnp->Op = OP_MIN; 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_EXP; - Tjp->Xval = i; - Tjp->Xcol = nm; - } else if (CheckExpand(g, i, nm, true)) - return true; - - break; - default: - sprintf(g->Message, - "Invalid function specification %c for %s", *p, Name); - return true; - } // endswitch *p - - } else if (*p == '"' && p[n - 1] == '"') { - // This is a concat specification - jnp->Op = OP_CNC; - - if (n > 2) { - // Set concat intermediate string - p[n - 1] = 0; - jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING); - } // endif n - - } else { - sprintf(g->Message, "Wrong array specification for %s", Name); - 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, 0, 2); - - 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); +{ + int n; + bool dg = true, b = false; + PJNODE jnp = &Nodes[i]; + + //if (*p == '[') p++; // Old syntax .[ or :[ + n = (int)strlen(p); + + if (*p) { + if (p[n - 1] == ']') { + p[--n] = 0; + } else if (!IsNum(p)) { + // Wrong array specification + sprintf(g->Message, "Invalid array specification %s for %s", p, Name); + return true; + } // endif p - break; - default: - break; - } // endswitch Op + } else + b = true; + + // To check whether a numeric Rank was specified + dg = IsNum(p); + + if (!n) { + // Default specifications + if (CheckExpand(g, i, nm, false)) + return true; + else if (jnp->Op != OP_EXP) { + if (b) { + // Return 1st value (B is the index base) + jnp->Rank = Tjp->B; + jnp->Op = OP_EQ; + } else if (!Value->IsTypeNum()) { + jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING); + jnp->Op = OP_CNC; + } else + jnp->Op = OP_ADD; + + } // endif OP + + } else if (dg) { + // Return nth value + jnp->Rank = atoi(p) - Tjp->B; + jnp->Op = OP_EQ; + } else if (n == 1) { + // Set the Op value; + if (Sep == ':') + switch (*p) { + case '*': *p = 'x'; break; + case 'x': + case 'X': *p = '*'; break; // Expand this array + default: break; + } // endswitch p + + switch (*p) { + case '+': jnp->Op = OP_ADD; break; + case 'x': jnp->Op = OP_MULT; break; + case '>': jnp->Op = OP_MAX; break; + case '<': jnp->Op = OP_MIN; break; + case '!': jnp->Op = OP_SEP; break; // Average + case '#': jnp->Op = OP_NUM; break; + case '*': // Expand this array + if (!Tjp->Xcol && nm) { + Xpd = true; + jnp->Op = OP_EXP; + Tjp->Xval = i; + Tjp->Xcol = nm; + } else if (CheckExpand(g, i, nm, true)) + return true; + + break; + default: + sprintf(g->Message, + "Invalid function specification %c for %s", *p, Name); + return true; + } // endswitch *p + + } else if (*p == '"' && p[n - 1] == '"') { + // This is a concat specification + jnp->Op = OP_CNC; + + if (n > 2) { + // Set concat intermediate string + p[n - 1] = 0; + jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING); + } // endif n - if (jnp->Valp) - MulVal = AllocateValue(g, jnp->Valp); + } else { + sprintf(g->Message, "Wrong array specification for %s", Name); + 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, 0, 2); + + 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 + return false; +} // end of SetArrayOptions /***********************************************************************/ /* Parse the eventual passed Jpath information. */ @@ -1090,81 +1247,105 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) /* the node corresponding to that column. */ /***********************************************************************/ bool JSONCOL::ParseJpath(PGLOBAL g) - { - char *p, *p2 = NULL, *pbuf = NULL; - int i; - bool mul = false; - - if (Parsed) - return false; // Already done - else if (InitValue(g)) - return true; - else if (!Jpath) - Jpath = Name; - - if (To_Tdb->GetOrig()) { - // This is an updated column, get nodes from origin - for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp; - colp = (PJCOL)colp->GetNext()) - if (!stricmp(Name, colp->GetName())) { - Nod = colp->Nod; - Nodes = colp->Nodes; +{ + char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL; + int i; + bool a, mul = false; + + if (Parsed) + return false; // Already done + else if (InitValue(g)) + return true; + else if (!Jpath) + Jpath = Name; + + if (To_Tdb->GetOrig()) { + // This is an updated column, get nodes from origin + for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp; + colp = (PJCOL)colp->GetNext()) + if (!stricmp(Name, colp->GetName())) { + Nod = colp->Nod; + Nodes = colp->Nodes; Xpd = colp->Xpd; - goto fin; - } // endif Name - - sprintf(g->Message, "Cannot parse updated column %s", Name); - return true; - } // endif To_Orig - - pbuf = PlugDup(g, Jpath); - - // The Jpath must be analyzed - for (i = 0, p = pbuf; (p = strchr(p, ':')); i++, p++) - Nod++; // One path node found - - Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE)); - memset(Nodes, 0, (Nod) * sizeof(JNODE)); - - // Analyze the Jpath for this column - for (i = 0, p = pbuf; i < Nod; i++, p = (p2 ? p2 + 1 : p + strlen(p))) { - if ((p2 = strchr(p, ':'))) - *p2 = 0; - - // Jpath must be explicit - if (*p == 0 || *p == '[') { - // Analyse intermediate array processing - 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; - } // endif's - - } // endfor i, p - - fin: - MulVal = AllocateValue(g, Value); - Parsed = true; - return false; - } // end of ParseJpath + goto fin; + } // endif Name + + sprintf(g->Message, "Cannot parse updated column %s", Name); + return true; + } // endif To_Orig + + pbuf = PlugDup(g, Jpath); + if (*pbuf == '$') pbuf++; + if (*pbuf == Sep) pbuf++; + if (*pbuf == '[') p1 = pbuf++; + + // Estimate the required number of nodes + for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++) + Nod++; // One path node found + + Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE)); + memset(Nodes, 0, (Nod) * sizeof(JNODE)); + + // Analyze the Jpath for this column + for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) { + a = (p1 != NULL); + p1 = strchr(p, '['); + p2 = strchr(p, Sep); + + if (!p2) + p2 = p1; + else if (p1) { + if (p1 < p2) + p2 = p1; + else if (p1 == p2 + 1) + *p2++ = 0; // Old syntax .[ or :[ + else + p1 = NULL; + + } // endif p1 + + if (p2) + *p2++ = 0; + + // Jpath must be explicit + if (a || *p == 0 || *p == '[' || IsNum(p)) { + // Analyse intermediate array processing + 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; + } // endif's + + } // endfor i, p + + Nod = i; + +fin: + MulVal = AllocateValue(g, Value); + Parsed = true; + return false; +} // end of ParseJpath /***********************************************************************/ /* Get Jpath converted to Mongo path. */ /***********************************************************************/ -char *JSONCOL::GetJpath(PGLOBAL g, bool proj) +PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj) { if (Jpath) { char *p1, *p2, *mgopath; int i = 0; - if (strcmp(Jpath, "*")) - mgopath = PlugDup(g, Jpath); - else + if (strcmp(Jpath, "*")) { + p1 = Jpath; + if (*p1 == '$') p1++; + if (*p1 == '.') p1++; + mgopath = PlugDup(g, p1); + } else return NULL; for (p1 = p2 = mgopath; *p1; p1++) @@ -1173,27 +1354,42 @@ char *JSONCOL::GetJpath(PGLOBAL g, bool proj) if (!proj) *p2++ = *p1; - i = 2; - } else if (*p1 == ']' && i == 2) { - if (proj && *(p1 + 1) == ':') + } else if (*p1 == ']' && i == 1) { + if (proj && p1[1] == '.') p1++; i = 0; - } else if (proj) - i = 2; - else + } else if (*p1 == '.' && i == 2) { + if (!proj) + *p2++ = '.'; + + i = 0; + } else if (!proj) return NULL; } else switch (*p1) { - case ':': *p2++ = '.'; break; - case '[': i = 1; break; + case ':': + case '.': + if (isdigit(p1[1])) + i = 2; + + *p2++ = '.'; + break; + case '[': + if (*(p2 - 1) != '.') + *p2++ = '.'; + + i = 1; + break; case '*': if (*(p2 - 1) == '.' && !*(p1 + 1)) { p2--; // Suppress last :* break; } // endif p2 - default: *p2++ = *p1; break; + default: + *p2++ = *p1; + break; } // endswitch p1; *p2 = 0; @@ -1228,7 +1424,7 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n) case TYPE_INTG: case TYPE_BINT: case TYPE_DBL: - case TYPE_DATE: + case TYPE_DTM: vp->SetValue_pval(val->GetValue()); break; case TYPE_BOOL: @@ -1404,8 +1600,9 @@ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n) } else SetJsonValue(g, MulVal, jvp, n); - if (!MulVal->IsZero()) { - switch (op) { +// if (!MulVal->IsZero()) { + if (!MulVal->IsNull()) { + switch (op) { case OP_CNC: if (Nodes[n].CncVal) { val[0] = Nodes[n].CncVal; @@ -1430,7 +1627,7 @@ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n) if (err) vp->Reset(); - } // endif Zero + } // endif Null } while (Tjp->NextSame > nextsame); @@ -1717,54 +1914,66 @@ int TDBJSON::MakeDocument(PGLOBAL g) if (!jsp && g->Message[0]) return RC_FX; - objpath = PlugDup(g, Objname); + if ((objpath = PlugDup(g, Objname))) { + if (*objpath == '$') objpath++; + if (*objpath == '.') objpath++; + + /*********************************************************************/ + /* Find the table in the tree structure. */ + /*********************************************************************/ + for (; jsp && objpath; objpath = p) { + if ((p = strchr(objpath, Sep))) + *p++ = 0; + + if (*objpath != '[' && !IsNum(objpath)) { + // objpass is a key + if (jsp->GetType() != TYPE_JOB) { + strcpy(g->Message, "Table path does not match the json file"); + return RC_FX; + } // endif Type - /*********************************************************************/ - /* Find the table in the tree structure. */ - /*********************************************************************/ - for (; jsp && objpath; objpath = p) { - if ((p = strchr(objpath, ':'))) - *p++ = 0; - - if (*objpath != '[') { // objpass is a key - if (jsp->GetType() != TYPE_JOB) { - strcpy(g->Message, "Table path does not match the json file"); - return RC_FX; - } // endif Type - - key = objpath; - objp = jsp->GetObject(); - arp = NULL; - val = objp->GetValue(key); - - if (!val || !(jsp = val->GetJson())) { - sprintf(g->Message, "Cannot find object key %s", key); - return RC_FX; - } // endif val - - } else if (objpath[strlen(objpath)-1] == ']') { - if (jsp->GetType() != TYPE_JAR) { - strcpy(g->Message, "Table path does not match the json file"); - return RC_FX; - } // endif Type - - arp = jsp->GetArray(); - objp = NULL; - i = atoi(objpath+1) - B; - val = arp->GetValue(i); - - if (!val) { - sprintf(g->Message, "Cannot find array value %d", i); - return RC_FX; - } // endif val + key = objpath; + objp = jsp->GetObject(); + arp = NULL; + val = objp->GetValue(key); - } else { - sprintf(g->Message, "Invalid Table path %s", Objname); - return RC_FX; - } // endif objpath + if (!val || !(jsp = val->GetJson())) { + sprintf(g->Message, "Cannot find object key %s", key); + return RC_FX; + } // endif val + + } else { + if (*objpath == '[') { + // Old style + if (objpath[strlen(objpath) - 1] != ']') { + sprintf(g->Message, "Invalid Table path %s", Objname); + return RC_FX; + } else + objpath++; + + } // endif objpath + + if (jsp->GetType() != TYPE_JAR) { + strcpy(g->Message, "Table path does not match the json file"); + return RC_FX; + } // endif Type + + arp = jsp->GetArray(); + objp = NULL; + i = atoi(objpath) - B; + val = arp->GetValue(i); + + if (!val) { + sprintf(g->Message, "Cannot find array value %d", i); + return RC_FX; + } // endif val + + } // endif + + jsp = val->GetJson(); + } // endfor objpath - jsp = val->GetJson(); - } // endfor objpath + } // endif objpath if (jsp && jsp->GetType() == TYPE_JAR) Doc = jsp->GetArray(); @@ -2047,7 +2256,8 @@ void TDBJSON::CloseDB(PGLOBAL g) TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp) { Topt = tdp->GetTopt(); - Db = (char*)tdp->GetDB(); + Db = tdp->GetDB(); + Dsn = tdp->Uri; } // end of TDBJCL constructor /***********************************************************************/ @@ -2055,7 +2265,7 @@ TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp) /***********************************************************************/ PQRYRES TDBJCL::GetResult(PGLOBAL g) { - return JSONColumns(g, Db, Topt, false); + return JSONColumns(g, Db, Dsn, Topt, false); } // end of GetResult /* --------------------------- End of json --------------------------- */ diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index c16cf6846b661..6cdd2993e1fbb 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -36,7 +36,13 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */ friend class TDBJSON; friend class TDBJSN; friend class TDBJCL; - friend PQRYRES JSONColumns(PGLOBAL, char*, PTOS, bool); +#if defined(JDBC_SUPPORT) + friend class JMGFAM; +#endif // JDBC_SUPPORT +#if defined(MONGO_SUPPORT) + friend class MGOFAM; +#endif // MONGO_SUPPORT + friend PQRYRES JSONColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool); public: // Constructor JSONDEF(void); @@ -58,6 +64,20 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */ int Level; /* Used for catalog table */ int Base; /* The array index base */ bool Strict; /* Strict syntax checking */ + char Sep; /* The Jpath separator */ + const char *Uri; /* MongoDB connection URI */ +#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT) + PCSZ Collname; /* External collection name */ + PCSZ Schema; /* External schema (DB) name */ + PSZ Options; /* Colist ; Pipe */ + PSZ Filter; /* Filter */ + PSZ Driver; /* MongoDB Driver (C or JAVA) */ + bool Pipe; /* True if Colist is a pipeline */ + int Version; /* Driver version */ +#if defined(JDBC_SUPPORT) + PSZ Wrapname; /* MongoDB java wrapper name */ +#endif // JDBC_SUPPORT +#endif // MONGO_SUPPORT || JDBC_SUPPORT }; // end of JSONDEF /* -------------------------- TDBJSN class --------------------------- */ @@ -69,6 +89,12 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */ class DllExport TDBJSN : public TDBDOS { friend class JSONCOL; friend class JSONDEF; +#if defined(JDBC_SUPPORT) + friend class JMGFAM; +#endif // JDBC_SUPPORT +#if defined(MONGO_SUPPORT) + friend class MGOFAM; +#endif // MONGO_SUPPORT public: // Constructor TDBJSN(PJDEF tdp, PTXF txfp); @@ -120,6 +146,7 @@ class DllExport TDBJSN : public TDBDOS { int SameRow; // Same row nb int Xval; // Index of expandable array int B; // Array index base + char Sep; // The Jpath separator bool Strict; // Strict syntax checking bool Comma; // Row has final comma }; // end of class TDBJSN @@ -132,8 +159,13 @@ class DllExport TDBJSN : public TDBDOS { class DllExport JSONCOL : public DOSCOL { friend class TDBJSN; friend class TDBJSON; +#if defined(JDBC_SUPPORT) + friend class JMGFAM; +#endif // JDBC_SUPPORT +#if defined(MONGO_SUPPORT) friend class MGOFAM; - public: +#endif // MONGO_SUPPORT +public: // Constructors JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); JSONCOL(JSONCOL *colp, PTDB tdbp); // Constructor used in copy process @@ -144,7 +176,7 @@ class DllExport JSONCOL : public DOSCOL { // Methods virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); bool ParseJpath(PGLOBAL g); - char *GetJpath(PGLOBAL g, bool proj); + virtual PSZ GetJpath(PGLOBAL g, bool proj); virtual void ReadColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g); @@ -169,7 +201,8 @@ class DllExport JSONCOL : public DOSCOL { JNODE *Nodes; // The intermediate objects int Nod; // The number of intermediate objects int Xnod; // Index of multiple values - bool Xpd; // True for expandable column + char Sep; // The Jpath separator + bool Xpd; // True for expandable column bool Parsed; // True when parsed }; // end of class JSONCOL @@ -235,7 +268,7 @@ class DllExport TDBJCL : public TDBCAT { virtual PQRYRES GetResult(PGLOBAL g); // Members - PTOS Topt; - char *Db; - char *Dsn; + PTOS Topt; + PCSZ Db; + PCSZ Dsn; }; // end of class TDBJCL diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp index d39837a7b5a10..61aefc930821f 100644 --- a/storage/connect/table.cpp +++ b/storage/connect/table.cpp @@ -319,12 +319,12 @@ void TDB::Printf(PGLOBAL g, FILE *f, uint n) } /* endfor tp */ - } // end of Print + } // end of Printf void TDB::Prints(PGLOBAL, char *ps, uint) { sprintf(ps, "R%d.%s", Tdb_No, Name); - } // end of Print + } // end of Prints /* -------------------------- class TDBASE --------------------------- */ diff --git a/storage/connect/tabmgo.cpp b/storage/connect/tabmgo.cpp new file mode 100644 index 0000000000000..810785ede804d --- /dev/null +++ b/storage/connect/tabmgo.cpp @@ -0,0 +1,678 @@ +/************** tabmgo C++ Program Source Code File (.CPP) *************/ +/* PROGRAM NAME: tabmgo Version 1.0 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* This program are the MongoDB class DB execution routines. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the MariaDB header file. */ +/***********************************************************************/ +#include + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/* tdbdos.h is header containing the TDBDOS declarations. */ +/* json.h is header containing the JSON classes declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "xtable.h" +#include "maputil.h" +#include "filamtxt.h" +#include "tabext.h" +#include "tabmgo.h" +#include "tabmul.h" +#include "checklvl.h" +#include "resource.h" +#include "mycat.h" // for FNC_COL +#include "filter.h" + +/***********************************************************************/ +/* This should be an option. */ +/***********************************************************************/ +#define MAXCOL 200 /* Default max column nb in result */ +#define TYPE_UNKNOWN 12 /* Must be greater than other types */ + +bool IsNum(PSZ s); + +/***********************************************************************/ +/* MGOColumns: construct the result blocks containing the description */ +/* of all the columns of a document contained inside MongoDB. */ +/***********************************************************************/ +PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info) +{ + static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, + TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING}; + static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, + FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT}; + unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0}; + int ncol = sizeof(buftyp) / sizeof(int); + int i, n = 0; + PBCOL bcp; + MGODISC *mgd; + PQRYRES qrp; + PCOLRES crp; + + if (info) { + length[0] = 128; + length[7] = 256; + goto skipit; + } // endif info + + /*********************************************************************/ + /* Open MongoDB. */ + /*********************************************************************/ + mgd = new(g) MGODISC(g, (int*)length); + + if ((n = mgd->GetColumns(g, db, uri, topt)) < 0) + goto err; + +skipit: + if (trace) + htrc("MGOColumns: n=%d len=%d\n", n, length[0]); + + /*********************************************************************/ + /* Allocate the structures used to refer to the result set. */ + /*********************************************************************/ + qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, + buftyp, fldtyp, length, false, false); + + crp = qrp->Colresp->Next->Next->Next->Next->Next->Next; + crp->Name = "Nullable"; + crp->Next->Name = "Bpath"; + + if (info || !qrp) + return qrp; + + qrp->Nblin = n; + + /*********************************************************************/ + /* Now get the results into blocks. */ + /*********************************************************************/ + for (i = 0, bcp = mgd->fbcp; bcp; i++, bcp = bcp->Next) { + if (bcp->Type == TYPE_UNKNOWN) // Void column + bcp->Type = TYPE_STRING; + + crp = qrp->Colresp; // Column Name + crp->Kdata->SetValue(bcp->Name, i); + crp = crp->Next; // Data Type + crp->Kdata->SetValue(bcp->Type, i); + crp = crp->Next; // Type Name + crp->Kdata->SetValue(GetTypeName(bcp->Type), i); + crp = crp->Next; // Precision + crp->Kdata->SetValue(bcp->Len, i); + crp = crp->Next; // Length + crp->Kdata->SetValue(bcp->Len, i); + crp = crp->Next; // Scale (precision) + crp->Kdata->SetValue(bcp->Scale, i); + crp = crp->Next; // Nullable + crp->Kdata->SetValue(bcp->Cbn ? 1 : 0, i); + crp = crp->Next; // Field format + + if (crp->Kdata) + crp->Kdata->SetValue(bcp->Fmt, i); + + } // endfor i + + /*********************************************************************/ + /* Return the result pointer. */ + /*********************************************************************/ + return qrp; + +err: + if (mgd->tmgp) + mgd->tmgp->CloseDB(g); + + return NULL; +} // end of MGOColumns + +/***********************************************************************/ +/* Class used to get the columns of a mongo collection. */ +/***********************************************************************/ +// Constructor +MGODISC::MGODISC(PGLOBAL g, int *lg) { + length = lg; + fbcp = NULL; + pbcp = NULL; + tmgp = NULL; + n = k = lvl = 0; + all = false; +} // end of MGODISC constructor + +/***********************************************************************/ +/* Class used to get the columns of a mongo collection. */ +/***********************************************************************/ +int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt) +{ + PCSZ level; + bson_iter_t iter; + const bson_t *doc; + PMGODEF tdp; + TDBMGO *tmgp = NULL; + + level = GetStringTableOption(g, topt, "Level", NULL); + + if (level) { + lvl = atoi(level); + lvl = (lvl > 16) ? 16 : lvl; + } else + lvl = 0; + + all = GetBooleanTableOption(g, topt, "Fullarray", false); + + /*********************************************************************/ + /* Open the MongoDB collection. */ + /*********************************************************************/ + tdp = new(g) MGODEF; + tdp->Uri = uri; + tdp->Tabname = GetStringTableOption(g, topt, "Name", NULL); + tdp->Tabname = GetStringTableOption(g, topt, "Tabname", tdp->Tabname); + tdp->Tabschema = GetStringTableOption(g, topt, "Dbname", db); + tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; + tdp->Colist = GetStringTableOption(g, topt, "Colist", "all"); + tdp->Filter = GetStringTableOption(g, topt, "Filter", NULL); + tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false); + + if (trace) + htrc("Uri %s coll=%s db=%s colist=%s filter=%s lvl=%d\n", + tdp->Uri, tdp->Tabname, tdp->Tabschema, tdp->Colist, tdp->Filter, lvl); + + tmgp = new(g) TDBMGO(tdp); + tmgp->SetMode(MODE_READ); + + if (tmgp->OpenDB(g)) + return -1; + + bcol.Next = NULL; + bcol.Name = bcol.Fmt = NULL; + bcol.Type = TYPE_UNKNOWN; + bcol.Len = bcol.Scale = 0; + bcol.Found = true; + bcol.Cbn = false; + + /*********************************************************************/ + /* Analyse the BSON tree and define columns. */ + /*********************************************************************/ + for (int i = 1; ; i++) { + switch (tmgp->ReadDB(g)) { + case RC_EF: + return n; + case RC_FX: + return -1; + default: + doc = tmgp->Cmgp->Document; + } // endswitch ReadDB + + if (FindInDoc(g, &iter, doc, NULL, NULL, i, k, false)) + return -1; + + // Missing columns can be null + for (bcp = fbcp; bcp; bcp = bcp->Next) { + bcp->Cbn |= !bcp->Found; + bcp->Found = false; + } // endfor bcp + + } // endfor i + + return n; +} // end of GetColumns + +/*********************************************************************/ +/* Analyse passed document. */ +/*********************************************************************/ +bool MGODISC::FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc, + char *pcn, char *pfmt, int i, int k, bool b) +{ + if (!doc || bson_iter_init(iter, doc)) { + const char *key; + char colname[65]; + char fmt[129]; + bool newcol; + + while (bson_iter_next(iter)) { + key = bson_iter_key(iter); + newcol = true; + + if (pcn) { + strncpy(colname, pcn, 64); + colname[64] = 0; + strncat(strncat(colname, "_", 65), key, 65); + } else + strcpy(colname, key); + + if (pfmt) { + strncpy(fmt, pfmt, 128); + fmt[128] = 0; + strncat(strncat(fmt, ".", 129), key, 129); + } else + strcpy(fmt, key); + + bcol.Cbn = false; + + if (BSON_ITER_HOLDS_UTF8(iter)) { + bcol.Type = TYPE_STRING; + bcol.Len = strlen(bson_iter_utf8(iter, NULL)); + } else if (BSON_ITER_HOLDS_INT32(iter)) { + bcol.Type = TYPE_INT; + bcol.Len = 11; // bson_iter_int32(iter) + } else if (BSON_ITER_HOLDS_INT64(iter)) { + bcol.Type = TYPE_BIGINT; + bcol.Len = 22; // bson_iter_int64(iter) + } else if (BSON_ITER_HOLDS_DOUBLE(iter)) { + bcol.Type = TYPE_DOUBLE; + bcol.Len = 12; + bcol.Scale = 6; // bson_iter_double(iter) + } else if (BSON_ITER_HOLDS_DATE_TIME(iter)) { + bcol.Type = TYPE_DATE; + bcol.Len = 19; // bson_iter_date_time(iter) + } else if (BSON_ITER_HOLDS_BOOL(iter)) { + bcol.Type = TYPE_TINY; + bcol.Len = 1; + } else if (BSON_ITER_HOLDS_OID(iter)) { + bcol.Type = TYPE_STRING; + bcol.Len = 24; // bson_iter_oid(iter) + } else if (BSON_ITER_HOLDS_DECIMAL128(iter)) { + bcol.Type = TYPE_DECIM; + bcol.Len = 32; // bson_iter_decimal128(iter, &dec) + } else if (BSON_ITER_HOLDS_DOCUMENT(iter)) { + if (lvl < 0) + continue; + else if (lvl <= k) { + bcol.Type = TYPE_STRING; + bcol.Len = 512; + } else { + bson_iter_t child; + + if (bson_iter_recurse(iter, &child)) + if (FindInDoc(g, &child, NULL, colname, fmt, i, k + 1, false)) + return true; + + newcol = false; + } // endif lvl + + } else if (BSON_ITER_HOLDS_ARRAY(iter)) { + if (lvl < 0) + continue; + else if (lvl <= k) { + bcol.Type = TYPE_STRING; + bcol.Len = 512; + } else { + bson_t *arr; + bson_iter_t itar; + const uint8_t *data = NULL; + uint32_t len = 0; + + bson_iter_array(iter, &len, &data); + arr = bson_new_from_data(data, len); + + if (FindInDoc(g, &itar, arr, colname, fmt, i, k + 1, !all)) + return true; + + newcol = false; + } // endif lvl + + } // endif's + + if (newcol) { + // Check whether this column was already found + for (bcp = fbcp; bcp; bcp = bcp->Next) + if (!strcmp(colname, bcp->Name)) + break; + + if (bcp) { + if (bcp->Type != bcol.Type) + bcp->Type = TYPE_STRING; + + if (k && *fmt && (!bcp->Fmt || strlen(bcp->Fmt) < strlen(fmt))) { + bcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } // endif *fmt + + bcp->Len = MY_MAX(bcp->Len, bcol.Len); + bcp->Scale = MY_MAX(bcp->Scale, bcol.Scale); + bcp->Cbn |= bcol.Cbn; + bcp->Found = true; + } else { + // New column + bcp = (PBCOL)PlugSubAlloc(g, NULL, sizeof(BCOL)); + *bcp = bcol; + bcp->Cbn |= (i > 1); + bcp->Name = PlugDup(g, colname); + length[0] = MY_MAX(length[0], strlen(colname)); + + if (k) { + bcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } else + bcp->Fmt = NULL; + + if (pbcp) { + bcp->Next = pbcp->Next; + pbcp->Next = bcp; + } else + fbcp = bcp; + + n++; + } // endif jcp + + pbcp = bcp; + } // endif newcol + + if (b) + break; // Test only first element of arrays + + } // endwhile iter + + } // endif doc + + return false; +} // end of FindInDoc + +/* --------------------------- Class TDBMGO -------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBMGO class. */ +/***********************************************************************/ +TDBMGO::TDBMGO(MGODEF *tdp) : TDBEXT(tdp) +{ + Cmgp = NULL; + Cnd = NULL; + Pcg.Tdbp = this; + + if (tdp) { + Pcg.Uristr = tdp->Uri; + Pcg.Db_name = tdp->Tabschema; + Pcg.Coll_name = tdp->Tabname; + Pcg.Options = tdp->Colist; + Pcg.Filter = tdp->Filter; + Pcg.Pipe = tdp->Pipe && Options != NULL; + B = tdp->Base ? 1 : 0; + } else { + Pcg.Uristr = NULL; + Pcg.Db_name = NULL; + Pcg.Coll_name = NULL; + Pcg.Options = NULL; + Pcg.Filter = NULL; + Pcg.Pipe = false; + B = 0; + } // endif tdp + + Fpos = -1; + N = 0; + Done = false; +} // end of TDBMGO standard constructor + +TDBMGO::TDBMGO(TDBMGO *tdbp) : TDBEXT(tdbp) +{ + Cmgp = tdbp->Cmgp; + Cnd = tdbp->Cnd; + Pcg = tdbp->Pcg; + B = tdbp->B; + Fpos = tdbp->Fpos; + N = tdbp->N; + Done = tdbp->Done; +} // end of TDBMGO copy constructor + +// Used for update +PTDB TDBMGO::Clone(PTABS t) +{ + PTDB tp; + PMGOCOL cp1, cp2; + PGLOBAL g = t->G; + + tp = new(g) TDBMGO(this); + + for (cp1 = (PMGOCOL)Columns; cp1; cp1 = (PMGOCOL)cp1->GetNext()) + if (!cp1->IsSpecial()) { + cp2 = new(g) MGOCOL(cp1, tp); // Make a copy + NewPointer(t, cp1, cp2); + } // endif cp1 + + return tp; +} // end of Clone + +/***********************************************************************/ +/* Allocate JSN column description block. */ +/***********************************************************************/ +PCOL TDBMGO::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) +{ + PMGOCOL colp = new(g) MGOCOL(g, cdp, this, cprec, n); + + return colp; +} // end of MakeCol + +/***********************************************************************/ +/* InsertSpecialColumn: Put a special column ahead of the column list.*/ +/***********************************************************************/ +PCOL TDBMGO::InsertSpecialColumn(PCOL colp) +{ + if (!colp->IsSpecial()) + return NULL; + + colp->SetNext(Columns); + Columns = colp; + return colp; +} // end of InsertSpecialColumn + +/***********************************************************************/ +/* Init: initialize MongoDB processing. */ +/***********************************************************************/ +bool TDBMGO::Init(PGLOBAL g) +{ + if (Done) + return false; + + /*********************************************************************/ + /* Open an C connection for this table. */ + /*********************************************************************/ + if (!Cmgp) + Cmgp = new(g) CMgoConn(g, &Pcg); + else if (Cmgp->IsConnected()) + Cmgp->Close(); + + if (Cmgp->Connect(g)) + return true; + + Done = true; + return false; +} // end of Init + +/***********************************************************************/ +/* MONGO Cardinality: returns table size in number of rows. */ +/***********************************************************************/ +int TDBMGO::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + else if (Cardinal < 0) + Cardinal = (!Init(g)) ? Cmgp->CollSize(g) : 0; + + return Cardinal; +} // end of Cardinality + +/***********************************************************************/ +/* MONGO GetMaxSize: returns collection size estimate. */ +/***********************************************************************/ +int TDBMGO::GetMaxSize(PGLOBAL g) +{ + if (MaxSize < 0) + MaxSize = Cardinality(g); + + return MaxSize; +} // end of GetMaxSize + +/***********************************************************************/ +/* OpenDB: Data Base open routine for MONGO access method. */ +/***********************************************************************/ +bool TDBMGO::OpenDB(PGLOBAL g) +{ + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open replace it at its beginning. */ + /*******************************************************************/ + Cmgp->Rewind(); + Fpos = -1; + return false; + } // endif Use + + /*********************************************************************/ + /* First opening. */ + /*********************************************************************/ + if (Pcg.Pipe && Mode != MODE_READ) { + strcpy(g->Message, "Pipeline tables are read only"); + return true; + } // endif Pipe + + if (Init(g)) + return true; + + if (Mode == MODE_DELETE && !Next) + // Delete all documents + return Cmgp->DocDelete(g); + else if (Mode == MODE_INSERT) + Cmgp->MakeColumnGroups(g); + + return false; +} // end of OpenDB + +/***********************************************************************/ +/* Data Base indexed read routine for ODBC access method. */ +/***********************************************************************/ +bool TDBMGO::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) +{ + strcpy(g->Message, "MONGO tables are not indexable"); + return true; +} // end of ReadKey + +/***********************************************************************/ +/* ReadDB: Get next document from a collection. */ +/***********************************************************************/ +int TDBMGO::ReadDB(PGLOBAL g) +{ + return Cmgp->ReadNext(g); +} // end of ReadDB + +/***********************************************************************/ +/* WriteDB: Data Base write routine for MGO access method. */ +/***********************************************************************/ +int TDBMGO::WriteDB(PGLOBAL g) +{ + return Cmgp->Write(g); +} // end of WriteDB + +/***********************************************************************/ +/* Data Base delete line routine for MGO access method. */ +/***********************************************************************/ +int TDBMGO::DeleteDB(PGLOBAL g, int irc) +{ + return (irc == RC_OK) ? WriteDB(g) : RC_OK; +} // end of DeleteDB + +/***********************************************************************/ +/* Table close routine for MONGO tables. */ +/***********************************************************************/ +void TDBMGO::CloseDB(PGLOBAL g) +{ + Cmgp->Close(); + Done = false; +} // end of CloseDB + +/* ----------------------------- MGOCOL ------------------------------ */ + +/***********************************************************************/ +/* MGOCOL public constructor. */ +/***********************************************************************/ +MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) + : EXTCOL(cdp, tdbp, cprec, i, "MGO") +{ + Tmgp = (PTDBMGO)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); + Jpath = cdp->GetFmt() ? cdp->GetFmt() : cdp->GetName(); +} // end of MGOCOL constructor + +/***********************************************************************/ +/* MGOCOL constructor used for copying columns. */ +/* tdbp is the pointer to the new table descriptor. */ +/***********************************************************************/ +MGOCOL::MGOCOL(MGOCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp) +{ + Tmgp = col1->Tmgp; + Jpath = col1->Jpath; +} // end of MGOCOL copy constructor + +/***********************************************************************/ +/* Get path when proj is false or projection path when proj is true. */ +/***********************************************************************/ +PSZ MGOCOL::GetJpath(PGLOBAL g, bool proj) +{ + if (Jpath) { + if (proj) { + char *p1, *p2, *projpath = PlugDup(g, Jpath); + int i = 0; + + for (p1 = p2 = projpath; *p1; p1++) + if (*p1 == '.') { + if (!i) + *p2++ = *p1; + + i = 1; + } else if (i) { + if (!isdigit(*p1)) { + *p2++ = *p1; + i = 0; + } // endif p1 + + } else + *p2++ = *p1; + + *p2 = 0; + return projpath; + } else + return Jpath; + + } else + return Name; + +} // end of GetJpath + +/***********************************************************************/ +/* ReadColumn: */ +/***********************************************************************/ +void MGOCOL::ReadColumn(PGLOBAL g) +{ + Tmgp->Cmgp->GetColumnValue(g, this); +} // end of ReadColumn + +/***********************************************************************/ +/* WriteColumn: */ +/***********************************************************************/ +void MGOCOL::WriteColumn(PGLOBAL g) +{ + // Check whether this node must be written + if (Value != To_Val) + Value->SetValue_pval(To_Val, FALSE); // Convert the updated value + +} // end of WriteColumn + +/* ---------------------------TDBGOL class --------------------------- */ + +/***********************************************************************/ +/* TDBGOL class constructor. */ +/***********************************************************************/ +TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp) +{ + Topt = tdp->GetTopt(); + Uri = tdp->Uri; + Db = tdp->GetTabschema(); +} // end of TDBJCL constructor + +/***********************************************************************/ +/* GetResult: Get the list the JSON file columns. */ +/***********************************************************************/ +PQRYRES TDBGOL::GetResult(PGLOBAL g) +{ + return MGOColumns(g, Db, Uri, Topt, false); +} // end of GetResult + +/* -------------------------- End of mongo --------------------------- */ diff --git a/storage/connect/tabmgo.h b/storage/connect/tabmgo.h new file mode 100644 index 0000000000000..9a4e537eadfd8 --- /dev/null +++ b/storage/connect/tabmgo.h @@ -0,0 +1,129 @@ +/**************** tabmgo H Declares Source Code File (.H) **************/ +/* Name: tabmgo.h Version 1.1 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* */ +/* This file contains the MongoDB classes declares. */ +/***********************************************************************/ +#include "mongo.h" +#include "cmgoconn.h" + +/***********************************************************************/ +/* Class used to get the columns of a mongo collection. */ +/***********************************************************************/ +class MGODISC : public BLOCK { +public: + // Constructor + MGODISC(PGLOBAL g, int *lg); + + // Functions + int GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt); + bool FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc, + char *pcn, char *pfmt, int i, int k, bool b); + + // Members + BCOL bcol; + PBCOL bcp, fbcp, pbcp; + PMGODEF tdp; + TDBMGO *tmgp; + int *length; + int n, k, lvl; + bool all; +}; // end of MGODISC + +/* -------------------------- TDBMGO class --------------------------- */ + +/***********************************************************************/ +/* This is the MongoDB Table Type class declaration. */ +/* The table is a collection, each record being a document. */ +/***********************************************************************/ +class DllExport TDBMGO : public TDBEXT { + friend class MGOCOL; + friend class MGODEF; + friend class MGODISC; + friend PQRYRES MGOColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool); +public: + // Constructor + TDBMGO(MGODEF *tdp); + TDBMGO(TDBMGO *tdbp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_MGO;} + virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMGO(this);} + + // Methods + virtual PTDB Clone(PTABS t); + virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual PCOL InsertSpecialColumn(PCOL colp); + virtual int RowNumber(PGLOBAL g, bool b = FALSE) {return N;} + + // Database routines + virtual int Cardinality(PGLOBAL g); + virtual int GetMaxSize(PGLOBAL g); + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + virtual int WriteDB(PGLOBAL g); + virtual int DeleteDB(PGLOBAL g, int irc); + virtual void CloseDB(PGLOBAL g); + virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr); + +protected: + bool Init(PGLOBAL g); + + // Members + CMgoConn *Cmgp; // Points to a C Mongo connection class + CMGOPARM Pcg; // Parms passed to Cmgp + const Item *Cnd; // The first condition + int Fpos; // The current row index + int N; // The current Rownum + int B; // Array index base + bool Done; // Init done +}; // end of class TDBMGO + +/* --------------------------- MGOCOL class -------------------------- */ + +/***********************************************************************/ +/* Class MGOCOL: MongoDB access method column descriptor. */ +/***********************************************************************/ +class DllExport MGOCOL : public EXTCOL { + friend class TDBMGO; + friend class FILTER; +public: + // Constructors + MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); + MGOCOL(MGOCOL *colp, PTDB tdbp); // Constructor used in copy process + + // Implementation + virtual int GetAmType(void) { return Tmgp->GetAmType(); } + + // Methods + virtual PSZ GetJpath(PGLOBAL g, bool proj); + virtual void ReadColumn(PGLOBAL g); + virtual void WriteColumn(PGLOBAL g); + +protected: + // Default constructor not to be used + MGOCOL(void) {} + + // Members + TDBMGO *Tmgp; // To the MGO table block + char *Jpath; // The json path +}; // end of class MGOCOL + +/***********************************************************************/ +/* This is the class declaration for the MONGO catalog table. */ +/***********************************************************************/ +class DllExport TDBGOL : public TDBCAT { +public: + // Constructor + TDBGOL(PMGODEF tdp); + +protected: + // Specific routines + virtual PQRYRES GetResult(PGLOBAL g); + + // Members + PTOS Topt; + PCSZ Uri; + PCSZ Db; +}; // end of class TDBGOL diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 97ff7bc59f2d0..bdddcf64ca89a 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -124,7 +124,7 @@ bool MYSQLDEF::GetServerInfo(PGLOBAL g, const char *server_name) DBUG_RETURN(true); } // endif server - DBUG_PRINT("info", ("get_server_by_name returned server at %zx", + DBUG_PRINT("info", ("get_server_by_name returned server at %lx", (size_t) server)); // TODO: We need to examine which of these can really be NULL diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index 34711d584f191..56e5e72efd62f 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -273,7 +273,7 @@ PCSZ TDBODBC::GetFile(PGLOBAL g) /***********************************************************************/ /* Set DBQ and get the new file name into the connect string. */ /***********************************************************************/ -void TDBODBC::SetFile(PGLOBAL g, PSZ fn) +void TDBODBC::SetFile(PGLOBAL g, PCSZ fn) { if (MulConn) { int n = strlen(MulConn) + strlen(fn) - 1; @@ -289,7 +289,7 @@ void TDBODBC::SetFile(PGLOBAL g, PSZ fn) sprintf(Connect, MulConn, fn); } // endif MultConn - DBQ = fn; + DBQ = (PSZ)fn; } // end of SetFile /***********************************************************************/ diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index 0ca88b60858de..cedcf0f5f77f5 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -71,7 +71,7 @@ class TDBODBC : public TDBEXT { virtual PTDB Clone(PTABS t); virtual bool SetRecpos(PGLOBAL g, int recpos); virtual PCSZ GetFile(PGLOBAL g); - virtual void SetFile(PGLOBAL g, PSZ fn); + virtual void SetFile(PGLOBAL g, PCSZ fn); virtual void ResetSize(void); virtual PCSZ GetServer(void) {return "ODBC";} virtual int Indexable(void) {return 2;} @@ -187,7 +187,6 @@ class XSRCCOL : public ODBCCOL { // Methods virtual void ReadColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g); -// void Printf(PGLOBAL g, FILE *, uint); protected: // Members diff --git a/storage/connect/tabvir.cpp b/storage/connect/tabvir.cpp index 84b3dd1787b5b..c78a8f531f6e9 100644 --- a/storage/connect/tabvir.cpp +++ b/storage/connect/tabvir.cpp @@ -289,7 +289,7 @@ void VIRCOL::ReadColumn(PGLOBAL g) { // This should never be called sprintf(g->Message, "ReadColumn: Column %s is not virtual", Name); - throw TYPE_COLBLK; + throw (int)TYPE_COLBLK; } // end of ReadColumn /* ---------------------------TDBVICL class -------------------------- */ diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index 80d4395058e8f..6402f48e09042 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -1319,7 +1319,7 @@ void TDBXML::CloseDB(PGLOBAL g) Docp->CloseDoc(g, To_Xb); // This causes a crash in Diagnostics_area::set_error_status -// throw TYPE_AM_XML; +// throw (int)TYPE_AM_XML; } // endif DumpDoc } // endif Changed @@ -1642,7 +1642,7 @@ void XMLCOL::ReadColumn(PGLOBAL g) if (ValNode->GetType() != XML_ELEMENT_NODE && ValNode->GetType() != XML_ATTRIBUTE_NODE) { sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endif type // Get the Xname value from the XML file @@ -1653,7 +1653,7 @@ void XMLCOL::ReadColumn(PGLOBAL g) PushWarning(g, Tdbp); break; default: - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endswitch Value->SetValue_psz(Valbuf); @@ -1704,7 +1704,7 @@ void XMLCOL::WriteColumn(PGLOBAL g) /* For columns having an Xpath, the Clist must be updated. */ /*********************************************************************/ if (Tdbp->CheckRow(g, Nod || Tdbp->Colname)) - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; /*********************************************************************/ /* Null values are represented by no node. */ @@ -1776,7 +1776,7 @@ void XMLCOL::WriteColumn(PGLOBAL g) if (ColNode == NULL) { strcpy(g->Message, MSG(COL_ALLOC_ERR)); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endif ColNode } // endif ColNode @@ -1795,7 +1795,7 @@ void XMLCOL::WriteColumn(PGLOBAL g) if (ValNode == NULL && AttNode == NULL) { strcpy(g->Message, MSG(VAL_ALLOC_ERR)); - longjmp(g->jumper[g->jump_level], TYPE_AM_XML); + throw (int)TYPE_AM_XML; } // endif ValNode /*********************************************************************/ @@ -1805,7 +1805,7 @@ void XMLCOL::WriteColumn(PGLOBAL g) if (strlen(p) > (unsigned)Long) { sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } else strcpy(Valbuf, p); @@ -1855,7 +1855,7 @@ void XMULCOL::ReadColumn(PGLOBAL g) if (ValNode->GetType() != XML_ELEMENT_NODE && ValNode->GetType() != XML_ATTRIBUTE_NODE) { sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endif type // Get the Xname value from the XML file @@ -1866,7 +1866,7 @@ void XMULCOL::ReadColumn(PGLOBAL g) PushWarning(g, Tdbp); break; default: - longjmp(g->jumper[g->jump_level], TYPE_AM_XML); + throw (int)TYPE_AM_XML; } // endswitch if (!b) { @@ -1941,7 +1941,7 @@ void XMULCOL::WriteColumn(PGLOBAL g) /* For columns having an Xpath, the Clist must be updated. */ /*********************************************************************/ if (Tdbp->CheckRow(g, Nod)) - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; /*********************************************************************/ /* Find the column and value nodes to update or insert. */ @@ -1990,7 +1990,7 @@ void XMULCOL::WriteColumn(PGLOBAL g) if (len > 1 && !Tdbp->Xpand) { sprintf(g->Message, MSG(BAD_VAL_UPDATE), Name); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } else ValNode = Nlx->GetItem(g, Tdbp->Nsub, Vxnp); @@ -2032,7 +2032,7 @@ void XMULCOL::WriteColumn(PGLOBAL g) if (ColNode == NULL) { strcpy(g->Message, MSG(COL_ALLOC_ERR)); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endif ColNode } // endif ColNode @@ -2051,8 +2051,8 @@ void XMULCOL::WriteColumn(PGLOBAL g) if (ValNode == NULL && AttNode == NULL) { strcpy(g->Message, MSG(VAL_ALLOC_ERR)); - longjmp(g->jumper[g->jump_level], TYPE_AM_XML); - } // endif ValNode + throw (int)TYPE_AM_XML; + } // endif ValNode /*********************************************************************/ /* Get the string representation of Value according to column type. */ @@ -2061,7 +2061,7 @@ void XMULCOL::WriteColumn(PGLOBAL g) if (strlen(p) > (unsigned)Long) { sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } else strcpy(Valbuf, p); @@ -2093,7 +2093,7 @@ void XPOSCOL::ReadColumn(PGLOBAL g) if (Tdbp->Clist == NULL) { strcpy(g->Message, MSG(MIS_TAG_LIST)); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endif Clist if ((ValNode = Tdbp->Clist->GetItem(g, Rank, Vxnp))) { @@ -2105,7 +2105,7 @@ void XPOSCOL::ReadColumn(PGLOBAL g) PushWarning(g, Tdbp); break; default: - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endswitch Value->SetValue_psz(Valbuf); @@ -2156,14 +2156,14 @@ void XPOSCOL::WriteColumn(PGLOBAL g) /* For all columns the Clist must be updated. */ /*********************************************************************/ if (Tdbp->CheckRow(g, true)) - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; /*********************************************************************/ /* Find the column and value nodes to update or insert. */ /*********************************************************************/ if (Tdbp->Clist == NULL) { strcpy(g->Message, MSG(MIS_TAG_LIST)); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } // endif Clist n = Tdbp->Clist->GetLength(); @@ -2188,7 +2188,7 @@ void XPOSCOL::WriteColumn(PGLOBAL g) if (strlen(p) > (unsigned)Long) { sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long); - throw TYPE_AM_XML; + throw (int)TYPE_AM_XML; } else strcpy(Valbuf, p); diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index ca3557666a49f..32119c3490068 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2015 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ that is a connection with its personnal memory allocation. @note - + Author Olivier Bertrand */ /****************************************************************************/ @@ -144,9 +144,9 @@ void user_connect::SetHandler(ha_connect *hc) /****************************************************************************/ /* Check whether we begin a new query and if so cleanup the previous one. */ /****************************************************************************/ -bool user_connect::CheckCleanup(void) +bool user_connect::CheckCleanup(bool force) { - if (thdp->query_id > last_query_id) { + if (thdp->query_id > last_query_id || force) { uint worksize= GetWorkSize(); PlugCleanup(g, true); @@ -171,7 +171,7 @@ bool user_connect::CheckCleanup(void) g->Mrr = 0; last_query_id= thdp->query_id; - if (trace) + if (trace && !force) printf("=====> Begin new query %llu\n", last_query_id); return true; diff --git a/storage/connect/user_connect.h b/storage/connect/user_connect.h index a883eb85934ca..983d9adc47858 100644 --- a/storage/connect/user_connect.h +++ b/storage/connect/user_connect.h @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2011 +/* Copyright (C) MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ Declaration of the user_connect class. @note + Author Olivier Bertrand @see /sql/handler.h and /storage/connect/user_connect.cc @@ -53,7 +54,7 @@ class user_connect // Implementation bool user_init(); void SetHandler(ha_connect *hc); - bool CheckCleanup(void); + bool CheckCleanup(bool force = false); bool CheckQueryID(void) {return thdp->query_id > last_query_id;} bool CheckQuery(query_id_t vid) {return last_query_id > vid;} diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index b6c63bdadd327..6ec92d4de59f5 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -571,9 +571,9 @@ void VALUE::Printf(PGLOBAL g, FILE *f, uint n) if (Null) fprintf(f, "%s\n", m); else - fprintf(f, "%s%s%s", GetCharString(buf), "\n", m); + fprintf(f, "%s%s\n", m, GetCharString(buf)); -} /* end of Print */ +} /* end of Printf */ /***********************************************************************/ /* Make string output of an object value. */ @@ -588,7 +588,7 @@ void VALUE::Prints(PGLOBAL g, char *ps, uint z) p = GetCharString(buf); strncpy(ps, p, z); -} // end of Print +} // end of Prints /* -------------------------- Class TYPVAL ---------------------------- */ @@ -1451,7 +1451,7 @@ void TYPVAL::SetValue(uint n) if (k > Len) { sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); - longjmp(g->jumper[g->jump_level], 138); + throw 138; } else SetValue_psz(buf); @@ -1505,7 +1505,7 @@ void TYPVAL::SetValue(ulonglong n) if (k > Len) { sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len); - longjmp(g->jumper[g->jump_level], 138); + throw 138; } else SetValue_psz(buf); @@ -1655,14 +1655,17 @@ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) int i; for (i = 0; i < np; i++) - p[i] = vp[i]->GetCharString(val[i]); + if (vp[i]->IsNull()) + return false; + else + p[i] = vp[i]->GetCharString(val[i]); switch (op) { case OP_CNC: assert(np == 1 || np == 2); if (np == 2) - SetValue_psz(p[0]); + SetValue_psz(p[0]); if ((i = Len - (signed)strlen(Strp)) > 0) strncat(Strp, p[np - 1], i); @@ -1670,18 +1673,19 @@ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) break; case OP_MIN: assert(np == 2); - SetValue_psz((strcmp(p[0], p[1]) < 0) ? p[0] : p[1]); + SetValue_psz((strcmp(p[0], p[1]) < 0) ? p[0] : p[1]); break; case OP_MAX: assert(np == 2); - SetValue_psz((strcmp(p[0], p[1]) > 0) ? p[0] : p[1]); + SetValue_psz((strcmp(p[0], p[1]) > 0) ? p[0] : p[1]); break; default: -// sprintf(g->Message, MSG(BAD_EXP_OPER), op); + // sprintf(g->Message, MSG(BAD_EXP_OPER), op); strcpy(g->Message, "Function not supported"); return true; - } // endswitch op + } // endswitch op + Null = false; return false; } // end of Compute @@ -1719,7 +1723,7 @@ void TYPVAL::Prints(PGLOBAL g, char *ps, uint z) else strcat(strncat(strncpy(ps, "\"", z), Strp, z-2), "\""); -} // end of Print +} // end of Prints /* -------------------------- Class DECIMAL -------------------------- */ diff --git a/storage/connect/value.h b/storage/connect/value.h index 2754c7618151e..f771d33dc52f3 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -90,8 +90,8 @@ class DllExport VALUE : public BLOCK { virtual double GetFloatValue(void) = 0; virtual void *GetTo_Val(void) = 0; virtual void SetPrec(int prec) {Prec = prec;} - bool IsNull(void) {return Null;} - void SetNull(bool b) {Null = b;} + bool IsNull(void) {return (Nullable && Null);} + void SetNull(bool b) {Null = (Nullable ? b : false);} bool GetNullable(void) {return Nullable;} void SetNullable(bool b) {Nullable = b;} int GetType(void) {return Type;} diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp index 3e4db8080ae55..30dce3b7fefc5 100755 --- a/storage/connect/xindex.cpp +++ b/storage/connect/xindex.cpp @@ -188,7 +188,7 @@ void XXBASE::Printf(PGLOBAL, FILE *f, uint n) memset(m, ' ', n); // Make margin string m[n] = '\0'; fprintf(f, "%sXINDEX: Tbxp=%p Num=%d\n", m, Tbxp, Num_K); - } // end of Print + } // end of Printf /***********************************************************************/ /* Make string output of XINDEX contents. */ @@ -197,7 +197,7 @@ void XXBASE::Prints(PGLOBAL, char *ps, uint z) { *ps = '\0'; strncat(ps, "Xindex", z); - } // end of Print + } // end of Prints /* -------------------------- XINDEX Class --------------------------- */ @@ -3008,7 +3008,8 @@ KXYCOL::KXYCOL(PKXBASE kp) : To_Keys(Keys.Memp), /***********************************************************************/ bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln) { - int len = colp->GetLength(), prec = colp->GetScale(); + int len = colp->GetLength(), prec = colp->GetScale(); + bool un = colp->IsUnsigned(); // Currently no indexing on NULL columns if (colp->IsNullable() && kln) { @@ -3028,7 +3029,7 @@ bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln) // Allocate the Value object used when moving items Type = colp->GetResultType(); - if (!(Valp = AllocateValue(g, Type, len, prec, colp->IsUnsigned()))) + if (!(Valp = AllocateValue(g, Type, len, prec, un))) return true; Klen = Valp->GetClen(); @@ -3044,7 +3045,7 @@ bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln) // Currently we set it to true to be compatible with QRY blocks, // and the one before last is to enable length/type checking, set to // true if not a prefix key. - Kblp = AllocValBlock(g, To_Keys, Type, n, len, prec, !Prefix, true); + Kblp = AllocValBlock(g, To_Keys, Type, n, len, prec, !Prefix, true, un); Asc = sm; // Sort mode: Asc=true Desc=false Ndf = n; @@ -3064,7 +3065,8 @@ bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln) /***********************************************************************/ BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m) { - int len = colp->GetLength(), prec = colp->GetScale(); + int len = colp->GetLength(), prec = colp->GetScale(); + bool un = colp->IsUnsigned(); if (n[3] && colp->GetLength() > n[3] && colp->GetResultType() == TYPE_STRING) { @@ -3079,7 +3081,7 @@ BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m) this, colp, Type, n[0], len, m); // Allocate the Value object used when moving items - Valp = AllocateValue(g, Type, len, prec, colp->IsUnsigned()); + Valp = AllocateValue(g, Type, len, prec, un); Klen = Valp->GetClen(); if (n[2]) { @@ -3088,7 +3090,7 @@ BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m) Bkeys.Sub = true; // Allocate the Valblk containing initial block key values - Blkp = AllocValBlock(g, To_Bkeys, Type, n[2], len, prec, true, true); + Blkp = AllocValBlock(g, To_Bkeys, Type, n[2], len, prec, true, true, un); } // endif nb Keys.Size = n[0] * Klen; @@ -3099,7 +3101,7 @@ BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m) // by blanks (if true) or keep the zero ending char (if false). // Currently we set it to true to be compatible with QRY blocks, // and last one to enable type checking (no conversion). - Kblp = AllocValBlock(g, To_Keys, Type, n[0], len, prec, !Prefix, true); + Kblp = AllocValBlock(g, To_Keys, Type, n[0], len, prec, !Prefix, true, un); if (n[1]) { Koff.Size = n[1] * sizeof(int); diff --git a/storage/connect/xobject.cpp b/storage/connect/xobject.cpp index 205edc12d0ca4..85af377970196 100644 --- a/storage/connect/xobject.cpp +++ b/storage/connect/xobject.cpp @@ -84,7 +84,7 @@ double XOBJECT::GetFloatValue(void) CONSTANT::CONSTANT(PGLOBAL g, void *value, short type) { if (!(Value = AllocateValue(g, value, (int)type))) - throw TYPE_CONST; + throw (int)TYPE_CONST; Constant = true; } // end of CONSTANT constructor @@ -95,7 +95,7 @@ CONSTANT::CONSTANT(PGLOBAL g, void *value, short type) CONSTANT::CONSTANT(PGLOBAL g, int n) { if (!(Value = AllocateValue(g, &n, TYPE_INT))) - throw TYPE_CONST; + throw (int)TYPE_CONST; Constant = true; } // end of CONSTANT constructor @@ -117,7 +117,7 @@ void CONSTANT::Convert(PGLOBAL g, int newtype) { if (Value->GetType() != newtype) if (!(Value = AllocateValue(g, Value, newtype))) - throw TYPE_CONST; + throw (int)TYPE_CONST; } // end of Convert @@ -176,7 +176,7 @@ bool CONSTANT::Rephrase(PGLOBAL g, PSZ work) void CONSTANT::Printf(PGLOBAL g, FILE *f, uint n) { Value->Printf(g, f, n); - } /* end of Print */ + } /* end of Printf */ /***********************************************************************/ /* Make string output of a constant object. */ @@ -184,7 +184,7 @@ void CONSTANT::Printf(PGLOBAL g, FILE *f, uint n) void CONSTANT::Prints(PGLOBAL g, char *ps, uint z) { Value->Prints(g, ps, z); - } /* end of Print */ + } /* end of Prints */ /* -------------------------- Class STRING --------------------------- */ @@ -439,4 +439,3 @@ bool STRING::Resize(uint newsize) return newsize > Size; } // end of Resize -