Commit 94e5d7de authored by Olivier Bertrand's avatar Olivier Bertrand

- Add Support of the MongoDB Java Driver.

  modified:   storage/connect/CMakeLists.txt
  modified:   storage/connect/JavaWrappers.jar
  modified:   storage/connect/colblk.h
  modified:   storage/connect/filter.cpp
  modified:   storage/connect/filter.h
  modified:   storage/connect/ha_connect.cc
  modified:   storage/connect/ha_connect.h
  modified:   storage/connect/jdbccat.h
  modified:   storage/connect/jdbconn.cpp
  modified:   storage/connect/jdbconn.h
  modified:   storage/connect/mongofam.cpp
  modified:   storage/connect/mongofam.h
  modified:   storage/connect/mycat.cc
  modified:   storage/connect/mycat.h
  modified:   storage/connect/tabext.h
  modified:   storage/connect/tabjdbc.cpp
  modified:   storage/connect/tabjdbc.h
  modified:   storage/connect/tabjson.cpp
  modified:   storage/connect/tabjson.h
  modified:   storage/connect/tabmgo.cpp
  modified:   storage/connect/tabmgo.h
  created:    storage/connect/Mongo2Interface.java
  created:    storage/connect/Mongo3Interface.java
  created:    storage/connect/cmgoconn.cpp
  created:    storage/connect/cmgoconn.h
  created:    storage/connect/javaconn.cpp
  created:    storage/connect/javaconn.h
  created:    storage/connect/jmgfam.cpp
  created:    storage/connect/jmgfam.h
  created:    storage/connect/jmgoconn.cpp
  created:    storage/connect/jmgoconn.h
  created:    storage/connect/mongo.cpp
  created:    storage/connect/mongo.h
  created:    storage/connect/tabjmg.cpp
  created:    storage/connect/tabjmg.h

- tdbp not initialized when catched exception
in CntGetTDB (connect.cc line 188)
  modified:   storage/connect/connect.h

- CheckCleanup should sometimes doing cleanup on pure info
Sometimes MariaDB loops on info to get the size of all tables in a database.
This can sometimes fail by exhausted memory.
CheckCleanup now have a force boolean parameter (defaulting to false)
  modified:   storage/connect/ha_connect.cc
  modified:   storage/connect/user_connect.cc
  modified:   storage/connect/user_connect.h

Change the copyright of some source files
  modified:   storage/connect/connect.cc
  modified:   storage/connect/connect.h
  modified:   storage/connect/engmsg.h
  modified:   storage/connect/global.h
  modified:   storage/connect/ha_connect.cc
  modified:   storage/connect/ha_connect.h
  modified:   storage/connect/msgid.h
  modified:   storage/connect/mycat.cc
  modified:   storage/connect/mycat.h
  modified:   storage/connect/os.h
  modified:   storage/connect/osutil.c
  modified:   storage/connect/osutil.h
  modified:   storage/connect/user_connect.cc
  modified:   storage/connect/user_connect.h
parent c51548d6
...@@ -245,7 +245,7 @@ int main() { ...@@ -245,7 +245,7 @@ int main() {
ENDIF(CONNECT_WITH_ODBC) ENDIF(CONNECT_WITH_ODBC)
# #
# JDBC # JDBC and MongoDB Java Driver
# #
IF(APPLE) IF(APPLE)
OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine without JDBC support" OFF) OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine without JDBC support" OFF)
...@@ -262,9 +262,13 @@ IF(CONNECT_WITH_JDBC) ...@@ -262,9 +262,13 @@ IF(CONNECT_WITH_JDBC)
INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH2}) INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH2})
# SET(JDBC_LIBRARY ${JAVA_JVM_LIBRARY}) will be dynamically linked # SET(JDBC_LIBRARY ${JAVA_JVM_LIBRARY}) will be dynamically linked
SET(CONNECT_SOURCES ${CONNECT_SOURCES} 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 JdbcInterface.java ApacheInterface.java MariadbInterface.java
MysqlInterface.java OracleInterface.java PostgresqlInterface.java MysqlInterface.java OracleInterface.java PostgresqlInterface.java
Mongo2Interface.java Mongo3Interface.java
JavaWrappers.jar) JavaWrappers.jar)
# TODO: Find how to compile and install the java wrapper classes # TODO: Find how to compile and install the java wrapper classes
# Find required libraries and include directories # Find required libraries and include directories
...@@ -292,7 +296,7 @@ IF(CONNECT_WITH_ZIP) ...@@ -292,7 +296,7 @@ IF(CONNECT_WITH_ZIP)
ENDIF(CONNECT_WITH_ZIP) ENDIF(CONNECT_WITH_ZIP)
# #
# MONGO (CMAKE NOT YET WORKING) # MONGO C Driver (CMAKE NOT YET WORKING)
# #
#OPTION(CONNECT_WITH_MONGO "Compile CONNECT storage engine with MONGO support" ON) #OPTION(CONNECT_WITH_MONGO "Compile CONNECT storage engine with MONGO support" ON)
...@@ -311,7 +315,12 @@ ENDIF(CONNECT_WITH_ZIP) ...@@ -311,7 +315,12 @@ ENDIF(CONNECT_WITH_ZIP)
# IF (MONGO_FOUND) # IF (MONGO_FOUND)
# INCLUDE_DIRECTORIES(${MONGO_INCLUDE_DIR}) # INCLUDE_DIRECTORIES(${MONGO_INCLUDE_DIR})
# SET(MONGO_LIBRARY ${MONGO_LIBRARIES}) # SET(MONGO_LIBRARY ${MONGO_LIBRARIES})
# SET(CONNECT_SOURCES ${CONNECT_SOURCES} mongofam.cpp mongofam.h) # 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) # add_definitions(-DMONGO_SUPPORT)
# ENDIF(MONGO_FOUND) # ENDIF(MONGO_FOUND)
#ENDIF(CONNECT_WITH_MONGO) #ENDIF(CONNECT_WITH_MONGO)
...@@ -339,3 +348,4 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES} ...@@ -339,3 +348,4 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY} LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY}
${ODBC_LIBRARY} ${JDBC_LIBRARY} ${IPHLPAPI_LIBRARY}) ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${IPHLPAPI_LIBRARY})
This diff was suppressed by a .gitattributes entry.
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<String> Colnames = null;
Cursor cursor = null;
MongoClient client = null;
DB db = null;
DBCollection coll = null;
BasicDBObject doc = null;
BasicDBObject dbq = null;
BasicDBObject dbf = null;
List<DBObject> 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<DBObject>) 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<String> 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
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<String> Colnames = null;
MongoClient client = null;
MongoDatabase db = null;
MongoCollection<BsonDocument> coll = null;
FindIterable<BsonDocument> finditer = null;
AggregateIterable<BsonDocument> aggiter = null;
MongoCursor<BsonDocument> 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<? extends Bson>) 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<String> 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
/************ 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 <my_global.h>
/***********************************************************************/
/* 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
/***********************************************************************/
/* CMgoConn.h : header file for the MongoDB connection classes. */
/***********************************************************************/
/***********************************************************************/
/* Include MongoDB library header files. */
/***********************************************************************/
#include <bson.h>
#include <bcon.h>
#include <mongoc.h>
// 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
...@@ -38,6 +38,7 @@ class DllExport COLBLK : public XOBJECT { ...@@ -38,6 +38,7 @@ class DllExport COLBLK : public XOBJECT {
virtual PTDB GetTo_Tdb(void) {return To_Tdb;} virtual PTDB GetTo_Tdb(void) {return To_Tdb;}
virtual int GetClustered(void) {return 0;} virtual int GetClustered(void) {return 0;}
virtual int IsClustered(void) {return FALSE;} virtual int IsClustered(void) {return FALSE;}
virtual PSZ GetJpath(PGLOBAL g, bool proj) {return NULL;}
PCOL GetNext(void) {return Next;} PCOL GetNext(void) {return Next;}
PSZ GetName(void) {return Name;} PSZ GetName(void) {return Name;}
int GetIndex(void) {return Index;} int GetIndex(void) {return Index;}
......
/* Copyright (C) Olivier Bertrand 2004 - 2017 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -185,7 +185,7 @@ bool CntInfo(PGLOBAL g, PTDB tp, PXF info) ...@@ -185,7 +185,7 @@ bool CntInfo(PGLOBAL g, PTDB tp, PXF info)
/***********************************************************************/ /***********************************************************************/
PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h) PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h)
{ {
PTDB tdbp; PTDB tdbp = NULL;
PTABLE tabp; PTABLE tabp;
PDBUSER dup = PlgGetUser(g); PDBUSER dup = PlgGetUser(g);
volatile PCATLG cat = (dup) ? dup->Catalog : NULL; // Safe over throw volatile PCATLG cat = (dup) ? dup->Catalog : NULL; // Safe over throw
......
/* Copyright (C) Olivier Bertrand 2004 - 2011 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
/**************** Cnt H Declares Source Code File (.H) *****************/ /**************** Cnt H Declares Source Code File (.H) *****************/
/* Name: CONNECT.H Version 2.4 */ /* Name: CONNECT.H Version 2.4 */
/* Author Olivier BERTRAND bertrandop@gmail.com */
/* This file contains the some based classes declares. */ /* This file contains the some based classes declares. */
/***********************************************************************/ /***********************************************************************/
#include "filamtxt.h" #include "filamtxt.h"
......
/* Copyright (C) MariaDB Corporation Ab */
#define MSG_ACCESS_VIOLATN "Access violation" #define MSG_ACCESS_VIOLATN "Access violation"
#define MSG_ADD_BAD_TYPE "Array add value type mismatch (%s -> %s)" #define MSG_ADD_BAD_TYPE "Array add value type mismatch (%s -> %s)"
#define MSG_ALLOC_ERROR "Error allocating %s" #define MSG_ALLOC_ERROR "Error allocating %s"
......
...@@ -33,18 +33,11 @@ ...@@ -33,18 +33,11 @@
#include "tabcol.h" #include "tabcol.h"
#include "xtable.h" #include "xtable.h"
#include "array.h" #include "array.h"
//#include "subquery.h"
#include "filter.h" #include "filter.h"
//#include "token.h"
//#include "select.h"
#include "xindex.h" #include "xindex.h"
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
#include "filamtxt.h"
#include "tabdos.h"
#include "tabjson.h"
#include "tabext.h" #include "tabext.h"
#include "tabmgo.h" #endif // MONGO_SUPPORT || JDBC_SUPPORT
#endif // MONGO_SUPPORT
/***********************************************************************/ /***********************************************************************/
/* Utility routines. */ /* Utility routines. */
...@@ -1412,11 +1405,11 @@ PFIL FILTER::Copy(PTABS t) ...@@ -1412,11 +1405,11 @@ PFIL FILTER::Copy(PTABS t)
} // end of Copy } // end of Copy
#endif // 0 #endif // 0
#if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
/***********************************************************************/ /***********************************************************************/
/* Make selector json representation for Mongo tables. */ /* Make selector json representation for Mongo tables. */
/***********************************************************************/ /***********************************************************************/
#if defined(MONGO_SUPPORT) bool FILTER::MakeSelector(PGLOBAL g, PSTRG s)
bool FILTER::MakeSelector(PGLOBAL g, PSTRG s, bool m)
{ {
s->Append('{'); s->Append('{');
...@@ -1428,29 +1421,21 @@ bool FILTER::MakeSelector(PGLOBAL g, PSTRG s, bool m) ...@@ -1428,29 +1421,21 @@ bool FILTER::MakeSelector(PGLOBAL g, PSTRG s, bool m)
s->Append(Opc == OP_AND ? "and" : "or"); s->Append(Opc == OP_AND ? "and" : "or");
s->Append("\":["); s->Append("\":[");
if (((PFIL)Arg(0))->MakeSelector(g, s, m)) if (((PFIL)Arg(0))->MakeSelector(g, s))
return true; return true;
s->Append(','); s->Append(',');
if (((PFIL)Arg(1))->MakeSelector(g, s, m)) if (((PFIL)Arg(1))->MakeSelector(g, s))
return true; return true;
s->Append(']'); s->Append(']');
} else { } else {
char *pth, buf[501];
if (GetArgType(0) != TYPE_COLBLK) if (GetArgType(0) != TYPE_COLBLK)
return true; return true;
s->Append('"'); s->Append('"');
s->Append(((PCOL)Arg(0))->GetJpath(g, false));
if (m)
pth = ((PMGOCOL)Arg(0))->Jpath;
else if (!(pth = ((PJCOL)Arg(0))->GetJpath(g, false)))
return true;
s->Append(pth);
s->Append("\":{\"$"); s->Append("\":{\"$");
switch (Opc) { switch (Opc) {
...@@ -1472,33 +1457,33 @@ bool FILTER::MakeSelector(PGLOBAL g, PSTRG s, bool m) ...@@ -1472,33 +1457,33 @@ bool FILTER::MakeSelector(PGLOBAL g, PSTRG s, bool m)
case OP_LE: case OP_LE:
s->Append("lte"); s->Append("lte");
break; break;
//case OP_NULL: case OP_NULL:
// s->Append("ne"); case OP_LIKE:
// break; case OP_EXIST:
//case OP_LIKE:
// s->Append("ne");
// break;
//case OP_EXIST:
// s->Append("ne");
// break;
default: default:
return true; return true;
} // endswitch Opc } // endswitch Opc
s->Append("\":"); s->Append("\":");
if (GetArgType(1) == TYPE_COLBLK) if (GetArgType(1) == TYPE_COLBLK) {
return true; s->Append("\"$");
s->Append(((PEXTCOL)Arg(1))->GetJpath(g, false));
s->Append('"');
} else {
char buf[501];
Arg(1)->Prints(g, buf, 500); Arg(1)->Prints(g, buf, 500);
s->Append(buf); s->Append(buf);
} // endif Type
s->Append('}'); s->Append('}');
} // endif Opc } // endif Opc
s->Append('}'); s->Append('}');
return false; return false;
} // end of MakeSelector } // end of MakeSelector
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT || JDBC_SUPPORT
/*********************************************************************/ /*********************************************************************/
/* Make file output of FILTER contents. */ /* Make file output of FILTER contents. */
......
/*************** Filter H Declares Source Code File (.H) ***************/ /*************** 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. */ /* This file contains the FILTER and derived classes declares. */
/***********************************************************************/ /***********************************************************************/
...@@ -61,9 +61,9 @@ class DllExport FILTER : public XOBJECT { /* Filter description block */ ...@@ -61,9 +61,9 @@ class DllExport FILTER : public XOBJECT { /* Filter description block */
//virtual PXOB CheckSubQuery(PGLOBAL, PSQL); //virtual PXOB CheckSubQuery(PGLOBAL, PSQL);
//virtual bool CheckLocal(PTDB); //virtual bool CheckLocal(PTDB);
//virtual int CheckSpcCol(PTDB tdbp, int n); //virtual int CheckSpcCol(PTDB tdbp, int n);
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
bool MakeSelector(PGLOBAL g, PSTRG s, bool m); bool MakeSelector(PGLOBAL g, PSTRG s);
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT || JDBC_SUPPORT
virtual void Printf(PGLOBAL g, FILE *f, uint n); virtual void Printf(PGLOBAL g, FILE *f, uint n);
virtual void Prints(PGLOBAL g, char *ps, uint z); virtual void Prints(PGLOBAL g, char *ps, uint z);
// PFIL Linearize(bool nosep); // PFIL Linearize(bool nosep);
......
/***********************************************************************/ /***********************************************************************/
/* GLOBAL.H: Declaration file used by all CONNECT implementations. */ /* 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 */
/***********************************************************************/ /***********************************************************************/
/***********************************************************************/ /***********************************************************************/
......
/* Copyright (C) Olivier Bertrand 2004 - 2017 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -98,8 +98,7 @@ ...@@ -98,8 +98,7 @@
rnd_next signals that it has reached the end of its data. Calls to 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. ha_connect::extra() are hints as to what will be occuring to the request.
Happy use!<br> Author Olivier Bertrand
-Olivier
*/ */
#ifdef USE_PRAGMA_IMPLEMENTATION #ifdef USE_PRAGMA_IMPLEMENTATION
...@@ -209,10 +208,10 @@ pthread_mutex_t parmut = PTHREAD_MUTEX_INITIALIZER; ...@@ -209,10 +208,10 @@ pthread_mutex_t parmut = PTHREAD_MUTEX_INITIALIZER;
/***********************************************************************/ /***********************************************************************/
PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
PQRYRES VirColumns(PGLOBAL g, bool info); PQRYRES VirColumns(PGLOBAL g, bool info);
PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, 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); PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info);
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT)
PQRYRES MGOColumns(PGLOBAL g, char *db, PTOS topt, bool info); PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ url, PTOS topt, bool info);
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT
int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v); int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v);
void PushWarning(PGLOBAL g, THD *thd, int level); void PushWarning(PGLOBAL g, THD *thd, int level);
...@@ -701,7 +700,7 @@ static int connect_init_func(void *p) ...@@ -701,7 +700,7 @@ static int connect_init_func(void *p)
DTVAL::SetTimeShift(); // Initialize time zone shift once for all DTVAL::SetTimeShift(); // Initialize time zone shift once for all
BINCOL::SetEndian(); // Initialize host endian setting BINCOL::SetEndian(); // Initialize host endian setting
#if defined(JDBC_SUPPORT) #if defined(JDBC_SUPPORT)
JDBConn::SetJVM(); JAVAConn::SetJVM();
#endif // JDBC_SUPPORT #endif // JDBC_SUPPORT
DBUG_RETURN(0); DBUG_RETURN(0);
} // end of connect_init_func } // end of connect_init_func
...@@ -726,7 +725,7 @@ static int connect_done_func(void *) ...@@ -726,7 +725,7 @@ static int connect_done_func(void *)
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT
#ifdef JDBC_SUPPORT #ifdef JDBC_SUPPORT
JDBConn::ResetJVM(); JAVAConn::ResetJVM();
#endif // JDBC_SUPPORT #endif // JDBC_SUPPORT
#if defined(__WIN__) #if defined(__WIN__)
...@@ -4081,7 +4080,7 @@ int ha_connect::info(uint flag) ...@@ -4081,7 +4080,7 @@ int ha_connect::info(uint flag)
if (xmod == MODE_ANY || xmod == MODE_ALTER) { if (xmod == MODE_ANY || xmod == MODE_ALTER) {
// Pure info, not a query // Pure info, not a query
pure= true; pure= true;
xp->CheckCleanup(); xp->CheckCleanup(xmod == MODE_ANY && valid_query_id == 0);
} // endif xmod } // endif xmod
// This is necessary for getting file length // This is necessary for getting file length
...@@ -4094,8 +4093,10 @@ int ha_connect::info(uint flag) ...@@ -4094,8 +4093,10 @@ int ha_connect::info(uint flag)
} else } else
DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen
if (!(tdbp= GetTDB(g))) if (!(tdbp = GetTDB(g))) {
DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
} // endif tdbp
valid_info = false; valid_info = false;
} // endif tdbp } // endif tdbp
...@@ -5299,16 +5300,18 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5299,16 +5300,18 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
POPARM sop= NULL; POPARM sop= NULL;
PCSZ ucnc= NULL; PCSZ ucnc= NULL;
PCSZ tabtyp = NULL;
bool cnc= false; bool cnc= false;
int cto= -1, qto= -1; int cto= -1, qto= -1;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
#if defined(JDBC_SUPPORT) #if defined(JDBC_SUPPORT)
PJPARM sjp= NULL; PJPARM sjp= NULL;
#endif // JDBC_SUPPORT
#if defined(JDBC_SUPPORT) || defined(MONGO_SUPPORT)
PCSZ driver= NULL; PCSZ driver= NULL;
char *url= NULL; char *url= NULL;
//char *prop= NULL; //char *prop= NULL;
PCSZ tabtyp= NULL; #endif // JDBC_SUPPORT || MONGO_SUPPORT
#endif // JDBC_SUPPORT
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
bool bif, ok= false, dbf= false; bool bif, ok= false, dbf= false;
TABTYPE ttp= TAB_UNDEF; TABTYPE ttp= TAB_UNDEF;
...@@ -5361,6 +5364,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5361,6 +5364,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
#endif // __WIN__ #endif // __WIN__
port= atoi(GetListOption(g, "port", topt->oplist, "0")); port= atoi(GetListOption(g, "port", topt->oplist, "0"));
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL);
mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0")); mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1")); cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1"));
qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1")); qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1"));
...@@ -5368,12 +5372,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5368,12 +5372,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if ((ucnc= GetListOption(g, "UseDSN", topt->oplist))) if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0); cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
#endif #endif
#if defined(JDBC_SUPPORT) #if defined(JDBC_SUPPORT) || defined(MONGO_SUPPORT)
driver= GetListOption(g, "Driver", topt->oplist, NULL); driver= GetListOption(g, "Driver", topt->oplist, NULL);
// url= GetListOption(g, "URL", topt->oplist, NULL); #endif // JDBC_SUPPORT || MONGO_SUPPORT
// prop = GetListOption(g, "Properties", topt->oplist, NULL);
tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL);
#endif // JDBC_SUPPORT
#if defined(PROMPT_OK) #if defined(PROMPT_OK)
cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0")); cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
#endif // PROMPT_OK #endif // PROMPT_OK
...@@ -5585,14 +5586,14 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5585,14 +5586,14 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
ok = true; ok = true;
break; break;
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
case TAB_MONGO: case TAB_MONGO:
if (!topt->tabname) if (!topt->tabname)
topt->tabname = tab; topt->tabname = tab;
ok = true; ok = true;
break; break;
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT || JDBC_SUPPORT
case TAB_VIR: case TAB_VIR:
ok = true; ok = true;
break; break;
...@@ -5733,13 +5734,36 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5733,13 +5734,36 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
qrp = VirColumns(g, fnc == FNC_COL); qrp = VirColumns(g, fnc == FNC_COL);
break; break;
case TAB_JSON: case TAB_JSON:
qrp = JSONColumns(g, (char*)db, dsn, topt, fnc == FNC_COL); qrp = JSONColumns(g, db, dsn, topt, fnc == FNC_COL);
break; break;
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
case TAB_MONGO: case TAB_MONGO:
qrp = MGOColumns(g, (char*)db, topt, fnc == FNC_COL); 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; break;
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT || JDBC_SUPPORT
#if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT) #if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT)
case TAB_XML: case TAB_XML:
qrp = XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL); qrp = XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL);
......
/* Copyright (C) Olivier Bertrand 2004 - 2015 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
/** @file ha_connect.h /** @file ha_connect.h
Author Olivier Bertrand
@brief @brief
The ha_connect engine is a prototype storage engine to access external data. The ha_connect engine is a prototype storage engine to access external data.
......
/************ 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 <my_global.h>
#include <m_string.h>
#if defined(__WIN__)
#include <direct.h> // for getcwd
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif // __BORLANDC__
#else // !__WIN__
#if defined(UNIX)
#include <errno.h>
#else // !UNIX
#endif // !UNIX
#include <stdio.h>
#include <stdlib.h> // 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, "<init>", "(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
/***********************************************************************/
/* 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 <jni.h>
/***********************************************************************/
/* 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
#ifndef __JDBCCAT_H
#define __JDBCCAT_H
// Timeout and net wait defaults // Timeout and net wait defaults
#define DEFAULT_LOGIN_TIMEOUT -1 // means do not set #define DEFAULT_LOGIN_TIMEOUT -1 // means do not set
#define DEFAULT_QUERY_TIMEOUT -1 // means do not set #define DEFAULT_QUERY_TIMEOUT -1 // means do not set
...@@ -8,9 +11,9 @@ typedef struct jdbc_parms { ...@@ -8,9 +11,9 @@ typedef struct jdbc_parms {
PCSZ Url; // Driver URL PCSZ Url; // Driver URL
PCSZ User; // User connect info PCSZ User; // User connect info
PCSZ Pwd; // Password connect info PCSZ Pwd; // Password connect info
//char *Properties; // Connection property list
//int Cto; // Connect timeout //int Cto; // Connect timeout
//int Qto; // Query timeout //int Qto; // Query timeout
int Version; // Driver version
int Fsize; // Fetch size int Fsize; // Fetch size
bool Scrollable; // Scrollable cursor bool Scrollable; // Scrollable cursor
} JDBCPARM, *PJPARM; } JDBCPARM, *PJPARM;
...@@ -28,3 +31,5 @@ PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sop); ...@@ -28,3 +31,5 @@ PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sop);
PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat,
PCSZ tabtyp, int maxres, bool info, PJPARM sop); PCSZ tabtyp, int maxres, bool info, PJPARM sop);
PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info); PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info);
#endif // __JDBCCAT_H
...@@ -53,38 +53,28 @@ ...@@ -53,38 +53,28 @@
#include "osutil.h" #include "osutil.h"
#if defined(__WIN__) //#if defined(__WIN__)
extern "C" HINSTANCE s_hModule; // Saved module handle //extern "C" HINSTANCE s_hModule; // Saved module handle
#endif // __WIN__ //#endif // __WIN__
#define nullptr 0 //#define nullptr 0
TYPCONV GetTypeConv(); TYPCONV GetTypeConv();
int GetConvSize(); int GetConvSize();
extern char *JvmPath; // The connect_jvm_path global variable value //extern char *JvmPath; // The connect_jvm_path global variable value
extern char *ClassPath; // The connect_class_path global variable value //extern char *ClassPath; // The connect_class_path global variable value
char *GetJavaWrapper(void); // The connect_java_wrapper 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
/***********************************************************************/ /***********************************************************************/
/* Some macro's (should be defined elsewhere to be more accessible) */ /* Some macro's (should be defined elsewhere to be more accessible) */
/***********************************************************************/ /***********************************************************************/
#if defined(_DEBUG) //#if defined(_DEBUG)
#define ASSERT(f) assert(f) //#define ASSERT(f) assert(f)
#define DEBUG_ONLY(f) (f) //#define DEBUG_ONLY(f) (f)
#else // !_DEBUG //#else // !_DEBUG
#define ASSERT(f) ((void)0) //#define ASSERT(f) ((void)0)
#define DEBUG_ONLY(f) ((void)0) //#define DEBUG_ONLY(f) ((void)0)
#endif // !_DEBUG //#endif // !_DEBUG
// To avoid gcc warning // To avoid gcc warning
int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v); int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v);
...@@ -251,7 +241,7 @@ PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat, ...@@ -251,7 +241,7 @@ PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat,
if (!info) { if (!info) {
jcp = new(g)JDBConn(g, NULL); jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(sjp) != RC_OK) // openReadOnly + noJDBCdialog if (jcp->Connect(sjp)) // openReadOnly + noJDBCdialog
return NULL; return NULL;
if (table && !strchr(table, '%')) { if (table && !strchr(table, '%')) {
...@@ -337,7 +327,7 @@ PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sjp) ...@@ -337,7 +327,7 @@ PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sjp)
PQRYRES qrp; PQRYRES qrp;
JDBConn *jcp = new(g)JDBConn(g, NULL); JDBConn *jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(sjp)) if (jcp->Connect(sjp))
return NULL; return NULL;
if (strstr(src, "%s")) { if (strstr(src, "%s")) {
...@@ -379,7 +369,7 @@ PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp, ...@@ -379,7 +369,7 @@ PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp,
/**********************************************************************/ /**********************************************************************/
jcp = new(g)JDBConn(g, NULL); jcp = new(g)JDBConn(g, NULL);
if (jcp->Open(sjp) == RC_FX) if (jcp->Connect(sjp))
return NULL; return NULL;
if (!maxres) if (!maxres)
...@@ -523,37 +513,16 @@ PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info) ...@@ -523,37 +513,16 @@ PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info)
/***********************************************************************/ /***********************************************************************/
/* JDBConn construction/destruction. */ /* 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; xqid = xuid = xid = grs = readid = fetchid = typid = errid = nullptr;
prepid = xpid = pcid = nullptr; prepid = xpid = pcid = nullptr;
chrfldid = intfldid = dblfldid = fltfldid = bigfldid = nullptr; chrfldid = intfldid = dblfldid = fltfldid = bigfldid = nullptr;
objfldid = datfldid = timfldid = tspfldid = nullptr; objfldid = datfldid = timfldid = tspfldid = nullptr;
//m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT; DiscFunc = "JdbcDisconnect";
//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;
m_Ncol = 0; m_Ncol = 0;
m_Aff = 0; m_Aff = 0;
m_Rows = 0; //m_Rows = 0;
m_Fetch = 0; m_Fetch = 0;
m_RowsetSize = 0; m_RowsetSize = 0;
m_Updatable = true; m_Updatable = true;
...@@ -563,7 +532,6 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp) ...@@ -563,7 +532,6 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp)
m_Opened = false; m_Opened = false;
m_IDQuoteChar[0] = '"'; m_IDQuoteChar[0] = '"';
m_IDQuoteChar[1] = 0; m_IDQuoteChar[1] = 0;
//*m_ErrMsg = '\0';
} // end of JDBConn } // end of JDBConn
//JDBConn::~JDBConn() //JDBConn::~JDBConn()
...@@ -573,55 +541,6 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp) ...@@ -573,55 +541,6 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp)
// } // end of ~JDBConn // } // 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. */ /* Utility routine. */
/***********************************************************************/ /***********************************************************************/
...@@ -641,381 +560,52 @@ int JDBConn::GetMaxValue(int n) ...@@ -641,381 +560,52 @@ int JDBConn::GetMaxValue(int n)
} // end of GetMaxValue } // end of GetMaxValue
/***********************************************************************/ /***********************************************************************/
/* Reset the JVM library. */ /* AddJars: add some jar file to the Class path. */
/***********************************************************************/
void JDBConn::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 JDBConn::GetJVM(PGLOBAL g) void JDBConn::AddJars(PSTRG jpop, char sep)
{ {
int ntry; #if defined(DEVELOPMENT)
jpop->Append(
if (!LibJvm) { ";C:/Jconnectors/postgresql-9.4.1208.jar"
char soname[512]; ";C:/Oracle/ojdbc7.jar"
";C:/Apache/commons-dbcp2-2.1.1/commons-dbcp2-2.1.1.jar"
#if defined(__WIN__) ";C:/Apache/commons-pool2-2.4.2/commons-pool2-2.4.2.jar"
for (ntry = 0; !LibJvm && ntry < 3; ntry++) { ";C:/Apache/commons-logging-1.2/commons-logging-1.2.jar"
if (!ntry && JvmPath) { ";C:/Jconnectors/mysql-connector-java-6.0.2-bin.jar"
strcat(strcpy(soname, JvmPath), "\\jvm.dll"); ";C:/Jconnectors/mariadb-java-client-2.0.1.jar"
ntry = 3; // No other try ";C:/Jconnectors/sqljdbc42.jar");
} else if (ntry < 2 && getenv("JAVA_HOME")) { #endif // DEVELOPMENT
strcpy(soname, getenv("JAVA_HOME")); } // end of AddJars
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. */ /* Connect: connect to a data source. */
/***********************************************************************/ /***********************************************************************/
int JDBConn::Open(PJPARM sop) bool JDBConn::Connect(PJPARM sop)
{ {
int irc = RC_FX; int irc = RC_FX;
bool err = false; bool err = false;
jint rc;
jboolean jt = (trace > 0); jboolean jt = (trace > 0);
PGLOBAL& g = m_G; 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 */ /* Create or attach a JVM. */
/*******************************************************************/ /*******************************************************************/
PSTRG jpop = new(g)STRING(g, 512, "-Djava.class.path=."); if (Open(g))
char *cp = NULL; return true;
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, "<init>", "(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
if (!sop) // DRIVER catalog table if (!sop) // DRIVER catalog table
return RC_OK; return false;
jmethodID cid = nullptr; jmethodID cid = nullptr;
if (gmID(g, cid, "JdbcConnect", "([Ljava/lang/String;IZ)I")) if (gmID(g, cid, "JdbcConnect", "([Ljava/lang/String;IZ)I"))
return RC_FX; return true;
// Build the java string array // Build the java string array
jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4 jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4
env->FindClass("java/lang/String"), NULL); // Strings 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_Scrollable = sop->Scrollable;
m_RowsetSize = sop->Fsize; m_RowsetSize = sop->Fsize;
//m_LoginTimeout = sop->Cto; //m_LoginTimeout = sop->Cto;
...@@ -1035,9 +625,6 @@ int JDBConn::Open(PJPARM sop) ...@@ -1035,9 +625,6 @@ int JDBConn::Open(PJPARM sop)
if (sop->Pwd) if (sop->Pwd)
env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd)); env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd));
//if (sop->Properties)
// env->SetObjectArrayElement(parms, 4, env->NewStringUTF(sop->Properties));
// call method // call method
rc = env->CallIntMethod(job, cid, parms, m_RowsetSize, m_Scrollable); rc = env->CallIntMethod(job, cid, parms, m_RowsetSize, m_Scrollable);
err = Check(rc); err = Check(rc);
...@@ -1045,7 +632,7 @@ int JDBConn::Open(PJPARM sop) ...@@ -1045,7 +632,7 @@ int JDBConn::Open(PJPARM sop)
if (err) { if (err) {
sprintf(g->Message, "Connecting: %s rc=%d", Msg, (int)rc); sprintf(g->Message, "Connecting: %s rc=%d", Msg, (int)rc);
return RC_FX; return true;
} // endif Msg } // endif Msg
jmethodID qcid = nullptr; jmethodID qcid = nullptr;
...@@ -1064,17 +651,18 @@ int JDBConn::Open(PJPARM sop) ...@@ -1064,17 +651,18 @@ int JDBConn::Open(PJPARM sop)
} // endif qcid } // endif qcid
if (gmID(g, typid, "ColumnType", "(ILjava/lang/String;)I")) if (gmID(g, typid, "ColumnType", "(ILjava/lang/String;)I"))
return RC_FX; return true;
else else
m_Opened = true; m_Opened = true;
return RC_OK; return false;
} // end of Open } // end of Connect
/***********************************************************************/ /***********************************************************************/
/* Execute an SQL command. */ /* Execute an SQL command. */
/***********************************************************************/ /***********************************************************************/
int JDBConn::ExecSQLcommand(PCSZ sql) int JDBConn::ExecuteCommand(PCSZ sql)
{ {
int rc; int rc;
jint n; jint n;
...@@ -1110,7 +698,7 @@ int JDBConn::ExecSQLcommand(PCSZ sql) ...@@ -1110,7 +698,7 @@ int JDBConn::ExecSQLcommand(PCSZ sql)
} // endif ncol } // endif ncol
return rc; return rc;
} // end of ExecSQLcommand } // end of ExecuteCommand
/***********************************************************************/ /***********************************************************************/
/* Fetch next row. */ /* Fetch next row. */
...@@ -1170,38 +758,12 @@ int JDBConn::Rewind(PCSZ sql) ...@@ -1170,38 +758,12 @@ int JDBConn::Rewind(PCSZ sql)
jboolean b = env->CallBooleanMethod(job, fetchid, 0); jboolean b = env->CallBooleanMethod(job, fetchid, 0);
rbuf = m_Rows; rbuf = m_Rows;
} else if (ExecSQLcommand(sql) != RC_FX) } else if (ExecuteCommand(sql) != RC_FX)
rbuf = 0; rbuf = 0;
return rbuf; return rbuf;
} // end of Rewind } // 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. */ /* Retrieve and set the column value from the result set. */
/***********************************************************************/ /***********************************************************************/
...@@ -1424,7 +986,7 @@ int JDBConn::ExecuteUpdate(PCSZ sql) ...@@ -1424,7 +986,7 @@ int JDBConn::ExecuteUpdate(PCSZ sql)
/***********************************************************************/ /***********************************************************************/
/* Get the number of lines of the result set. */ /* 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; int rc, n = 0;
...@@ -1565,53 +1127,6 @@ bool JDBConn::SetParam(JDBCCOL *colp) ...@@ -1565,53 +1127,6 @@ bool JDBConn::SetParam(JDBCCOL *colp)
return rc; return rc;
} // end of SetParam } // 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. */ /* Get the list of Drivers and set it in qrp. */
/***********************************************************************/ /***********************************************************************/
...@@ -1677,7 +1192,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) ...@@ -1677,7 +1192,7 @@ bool JDBConn::SetParam(JDBCCOL *colp)
jint *n = nullptr; jint *n = nullptr;
jstring label; jstring label;
jmethodID colid = nullptr; jmethodID colid = nullptr;
int rc = ExecSQLcommand(src); int rc = ExecuteCommand(src);
if (rc == RC_NF) { if (rc == RC_NF) {
strcpy(g->Message, "Srcdef is not returning a result set"); strcpy(g->Message, "Srcdef is not returning a result set");
...@@ -2002,10 +1517,10 @@ bool JDBConn::SetParam(JDBCCOL *colp) ...@@ -2002,10 +1517,10 @@ bool JDBConn::SetParam(JDBCCOL *colp)
/***********************************************************************/ /***********************************************************************/
/* Allocate a CONNECT result structure from the JDBC result. */ /* Allocate a CONNECT result structure from the JDBC result. */
/***********************************************************************/ /***********************************************************************/
PQRYRES JDBConn::AllocateResult(PGLOBAL g) PQRYRES JDBConn::AllocateResult(PGLOBAL g, PTDB tdbp)
{ {
bool uns; bool uns;
PJDBCCOL colp; PCOL colp;
PCOLRES *pcrp, crp; PCOLRES *pcrp, crp;
PQRYRES qrp; PQRYRES qrp;
...@@ -2030,8 +1545,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) ...@@ -2030,8 +1545,7 @@ bool JDBConn::SetParam(JDBCCOL *colp)
qrp->Nblin = 0; qrp->Nblin = 0;
qrp->Cursor = 0; qrp->Cursor = 0;
for (colp = (PJDBCCOL)m_Tdb->Columns; colp; for (colp = tdbp->GetColumns(); colp; colp = colp->GetNext())
colp = (PJDBCCOL)colp->GetNext())
if (!colp->IsSpecial()) { if (!colp->IsSpecial()) {
*pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
crp = *pcrp; crp = *pcrp;
...@@ -2059,10 +1573,9 @@ bool JDBConn::SetParam(JDBCCOL *colp) ...@@ -2059,10 +1573,9 @@ bool JDBConn::SetParam(JDBCCOL *colp)
memset(crp->Nulls, ' ', m_Rows); memset(crp->Nulls, ' ', m_Rows);
} // endelse Nullable } // endelse Nullable
colp->SetCrp(crp); ((EXTCOL*)colp)->SetCrp(crp);
} // endif colp } // endif colp
*pcrp = NULL; *pcrp = NULL;
//qrp->Nblin = n;
return qrp; return qrp;
} // end of AllocateResult } // end of AllocateResult
/***********************************************************************/ /***********************************************************************/
/* JDBConn.h : header file for the JDBC connection classes. */ /* JDBConn.h : header file for the JDBC connection classes. */
/***********************************************************************/ /***********************************************************************/
//nclude <windows.h> /* Windows include file */ #include "javaconn.h"
//nclude <windowsx.h> /* Message crackers */
/***********************************************************************/
/* Included C-definition files required by the interface. */
/***********************************************************************/
#include "block.h"
/***********************************************************************/
/* JDBC interface. */
/***********************************************************************/
#include <jni.h>
/***********************************************************************/
/* 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
// JDBC connection to a data source // JDBC connection to a data source
class TDBJDBC; class TDBJDBC;
...@@ -66,7 +12,7 @@ class TDBXJDC; ...@@ -66,7 +12,7 @@ class TDBXJDC;
/***********************************************************************/ /***********************************************************************/
/* JDBConn class. */ /* JDBConn class. */
/***********************************************************************/ /***********************************************************************/
class JDBConn : public BLOCK { class JDBConn : public JAVAConn {
friend class TDBJDBC; friend class TDBJDBC;
friend class TDBXJDC; friend class TDBXJDC;
//friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&); //friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
...@@ -74,86 +20,51 @@ class JDBConn : public BLOCK { ...@@ -74,86 +20,51 @@ class JDBConn : public BLOCK {
JDBConn(); // Standard (unused) constructor JDBConn(); // Standard (unused) constructor
public: public:
JDBConn(PGLOBAL g, TDBJDBC *tdbp); // Constructor
JDBConn(PGLOBAL g, PCSZ wrapper);
int Open(PJPARM sop); virtual void AddJars(PSTRG jpop, char sep);
int Rewind(PCSZ sql); PQRYRES AllocateResult(PGLOBAL g, PTDB tdbp);
void Close(void);
PQRYRES AllocateResult(PGLOBAL g);
// Attributes // Attributes
public: public:
char *GetQuoteChar(void) { return m_IDQuoteChar; } char *GetQuoteChar(void) { return m_IDQuoteChar; }
// Database successfully opened? virtual int GetMaxValue(int infotype);
bool IsOpen(void) { return m_Opened; }
//PSZ GetStringInfo(ushort infotype);
int GetMaxValue(int infotype);
//PSZ GetConnect(void) { return m_Connect; }
public: public:
// Operations // Operations
//void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;} virtual bool Connect(PJPARM sop);
//void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;} virtual bool MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options,
//void SetUserName(PSZ user) {m_User = user;} PCSZ filter, bool pipe) {return true;}
//void SetUserPwd(PSZ pwd) {m_Pwd = pwd;} virtual int GetResultSize(PCSZ sql, PCOL colp);
int GetResultSize(PCSZ sql, JDBCCOL *colp); virtual int ExecuteCommand(PCSZ sql);
int ExecuteQuery(PCSZ sql); virtual int ExecuteQuery(PCSZ sql);
int ExecuteUpdate(PCSZ sql); virtual int ExecuteUpdate(PCSZ sql);
int Fetch(int pos = 0); virtual int Fetch(int pos = 0);
virtual void SetColumnValue(int rank, PSZ name, PVAL val);
// Jdbc operations
bool PrepareSQL(PCSZ sql); bool PrepareSQL(PCSZ sql);
int ExecuteSQL(void); int ExecuteSQL(void); // Prepared statement
bool SetParam(JDBCCOL *colp); bool SetParam(JDBCCOL *colp);
int ExecSQLcommand(PCSZ sql);
void SetColumnValue(int rank, PSZ name, PVAL val);
int GetCatInfo(JCATPARM *cap); int GetCatInfo(JCATPARM *cap);
//bool GetDataSources(PQRYRES qrp);
bool GetDrivers(PQRYRES qrp); bool GetDrivers(PQRYRES qrp);
PQRYRES GetMetaData(PGLOBAL g, PCSZ src); PQRYRES GetMetaData(PGLOBAL g, PCSZ src);
int Rewind(PCSZ sql);
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);
// Implementation // Implementation
public: public:
//virtual ~JDBConn(); //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: protected:
// Members // Members
#if defined(__WIN__) #if 0
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) JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine)
JNIEnv *env; // Pointer to native interface JNIEnv *env; // Pointer to native interface
jclass jdi; // Pointer to the java wrapper class jclass jdi; // Pointer to the java wrapper class
jobject job; // The java wrapper class object jobject job; // The java wrapper class object
jmethodID errid; // The GetErrmsg method ID
#endif // 0
jmethodID xqid; // The ExecuteQuery method ID jmethodID xqid; // The ExecuteQuery method ID
jmethodID xuid; // The ExecuteUpdate method ID jmethodID xuid; // The ExecuteUpdate method ID
jmethodID xid; // The Execute method ID jmethodID xid; // The Execute method ID
...@@ -164,7 +75,6 @@ class JDBConn : public BLOCK { ...@@ -164,7 +75,6 @@ class JDBConn : public BLOCK {
jmethodID prepid; // The CreatePrepStmt method ID jmethodID prepid; // The CreatePrepStmt method ID
jmethodID xpid; // The ExecutePrep method ID jmethodID xpid; // The ExecutePrep method ID
jmethodID pcid; // The ClosePrepStmt method ID jmethodID pcid; // The ClosePrepStmt method ID
jmethodID errid; // The GetErrmsg method ID
jmethodID objfldid; // The ObjectField method ID jmethodID objfldid; // The ObjectField method ID
jmethodID chrfldid; // The StringField method ID jmethodID chrfldid; // The StringField method ID
jmethodID intfldid; // The IntField method ID jmethodID intfldid; // The IntField method ID
...@@ -174,18 +84,16 @@ class JDBConn : public BLOCK { ...@@ -174,18 +84,16 @@ class JDBConn : public BLOCK {
jmethodID timfldid; // The TimeField method ID jmethodID timfldid; // The TimeField method ID
jmethodID tspfldid; // The TimestampField method ID jmethodID tspfldid; // The TimestampField method ID
jmethodID bigfldid; // The BigintField method ID jmethodID bigfldid; // The BigintField method ID
PCSZ Msg; // PCSZ Msg;
char *m_Wrap; // PCSZ m_Wrap;
char m_IDQuoteChar[2]; char m_IDQuoteChar[2];
PCSZ m_Pwd; PCSZ m_Pwd;
int m_Ncol; int m_Ncol;
int m_Aff; int m_Aff;
int m_Rows;
int m_Fetch; int m_Fetch;
int m_RowsetSize; int m_RowsetSize;
jboolean m_Updatable; jboolean m_Updatable;
jboolean m_Transact; jboolean m_Transact;
jboolean m_Scrollable; jboolean m_Scrollable;
bool m_Opened;
bool m_Full; bool m_Full;
}; // end of JDBConn class definition }; // end of JDBConn class definition
/************ 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 <io.h>
//#include <fcntl.h>
//#include <errno.h>
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif // __BORLANDC__
//#include <windows.h>
#else // !__WIN__
#if defined(UNIX) || defined(UNIV_LINUX)
//#include <errno.h>
#include <unistd.h>
//#if !defined(sun) // Sun has the ftruncate fnc.
//#define USETEMP // Force copy mode for DELETE
//#endif // !sun
#else // !UNIX
//#include <io.h>
#endif // !UNIX
//#include <fcntl.h>
#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
/************** 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
/************ 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 <my_global.h>
/***********************************************************************/
/* 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, "<init>", "(I)V");
val = env->NewObject(cls, cns, valp->GetIntValue());
break;
case TYPE_TINY:
cls = env->FindClass("java/lang/Boolean");
cns = env->GetMethodID(cls, "<init>", "(Z)V");
val = env->NewObject(cls, cns, (valp->GetIntValue() != 0));
break;
case TYPE_BIGINT:
cls = env->FindClass("java/lang/Long");
cns = env->GetMethodID(cls, "<init>", "(J)V");
val = env->NewObject(cls, cns, valp->GetBigintValue());
break;
case TYPE_DOUBLE:
cls = env->FindClass("java/lang/Double");
cns = env->GetMethodID(cls, "<init>", "(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
/***********************************************************************/
/* 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
/************** 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 <my_global.h>
/***********************************************************************/
/* 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
strcpy(g->Message, "No column find for Java Mongo yet");
return NULL;
} // 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
/**************** 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 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
/************ MONGO FAM C++ Program Source Code File (.CPP) ************/ /************ MONGO FAM C++ Program Source Code File (.CPP) ************/
/* PROGRAM NAME: mongofam.cpp */ /* PROGRAM NAME: mongofam.cpp */
/* ------------- */ /* ------------- */
/* Version 1.1 */ /* Version 1.3 */
/* */ /* */
/* COPYRIGHT: */ /* COPYRIGHT: */
/* ---------- */ /* ---------- */
...@@ -17,26 +17,6 @@ ...@@ -17,26 +17,6 @@
/* Include relevant sections of the System header files. */ /* Include relevant sections of the System header files. */
/***********************************************************************/ /***********************************************************************/
#include "my_global.h" #include "my_global.h"
#if defined(__WIN__)
//#include <io.h>
//#include <fcntl.h>
//#include <errno.h>
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif // __BORLANDC__
//#include <windows.h>
#else // !__WIN__
#if defined(UNIX) || defined(UNIV_LINUX)
//#include <errno.h>
#include <unistd.h>
//#if !defined(sun) // Sun has the ftruncate fnc.
//#define USETEMP // Force copy mode for DELETE
//#endif // !sun
#else // !UNIX
//#include <io.h>
#endif // !UNIX
//#include <fcntl.h>
#endif // !__WIN__
/***********************************************************************/ /***********************************************************************/
/* Include application header files: */ /* Include application header files: */
...@@ -54,20 +34,8 @@ ...@@ -54,20 +34,8 @@
#if defined(UNIX) || defined(UNIV_LINUX) #if defined(UNIX) || defined(UNIV_LINUX)
#include "osutil.h" #include "osutil.h"
//#define _fileno fileno
//#define _O_RDONLY O_RDONLY
#endif #endif
// Required to initialize libmongoc's internals
void mongo_init(bool init)
{
if (init)
mongoc_init();
else
mongoc_cleanup();
} // end of mongo_init
/* --------------------------- Class MGOFAM -------------------------- */ /* --------------------------- Class MGOFAM -------------------------- */
/***********************************************************************/ /***********************************************************************/
...@@ -75,88 +43,39 @@ void mongo_init(bool init) ...@@ -75,88 +43,39 @@ void mongo_init(bool init)
/***********************************************************************/ /***********************************************************************/
MGOFAM::MGOFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL) MGOFAM::MGOFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL)
{ {
Client = NULL; Cmgp = NULL;
Database = NULL; Pcg.Tdbp = NULL;
Collection = NULL;
Cursor = NULL; if (tdp) {
Query = NULL; Pcg.Uristr = tdp->Uri;
Opts = NULL; 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; To_Fbt = NULL;
Mode = MODE_ANY; Mode = MODE_ANY;
Uristr = tdp->Uri;
Db_name = tdp->Schema;
Coll_name = tdp->Collname;
Options = tdp->Options;
Filter = tdp->Filter;
Done = false; Done = false;
Pipe = tdp->Pipe;
Lrecl = tdp->Lrecl + tdp->Ending; Lrecl = tdp->Lrecl + tdp->Ending;
} // end of MGOFAM standard constructor } // end of MGOFAM standard constructor
MGOFAM::MGOFAM(PMGOFAM tdfp) : DOSFAM(tdfp) MGOFAM::MGOFAM(PMGOFAM tdfp) : DOSFAM(tdfp)
{ {
Client = tdfp->Client; Pcg = tdfp->Pcg;
Database = NULL;
Collection = tdfp->Collection;
Cursor = tdfp->Cursor;
Query = tdfp->Query;
Opts = tdfp->Opts;
To_Fbt = tdfp->To_Fbt; To_Fbt = tdfp->To_Fbt;
Mode = tdfp->Mode; Mode = tdfp->Mode;
Uristr = tdfp->Uristr;
Db_name = tdfp->Db_name;
Coll_name = tdfp->Coll_name;
Options = tdfp->Options;
Filter = NULL;
Done = tdfp->Done; Done = tdfp->Done;
Pipe = tdfp->Pipe;
} // end of MGOFAM copy constructor } // end of MGOFAM copy constructor
#if 0
void *MGOFAM::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 *MGOFAM::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 *MGOFAM::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
/***********************************************************************/ /***********************************************************************/
/* Reset: reset position values at the beginning of file. */ /* Reset: reset position values at the beginning of file. */
/***********************************************************************/ /***********************************************************************/
...@@ -175,47 +94,16 @@ int MGOFAM::GetFileLength(PGLOBAL g) ...@@ -175,47 +94,16 @@ int MGOFAM::GetFileLength(PGLOBAL g)
} // end of GetFileLength } // end of GetFileLength
/***********************************************************************/ /***********************************************************************/
/* Cardinality: returns table cardinality in number of rows. */ /* Cardinality: returns the number of documents in the collection. */
/* This function can be called with a null argument to test the */ /* This function can be called with a null argument to test the */
/* availability of Cardinality implementation (1 yes, 0 no). */ /* availability of Cardinality implementation (1 yes, 0 no). */
/***********************************************************************/ /***********************************************************************/
int MGOFAM::Cardinality(PGLOBAL g) int MGOFAM::Cardinality(PGLOBAL g)
{ {
if (g) { if (!g)
if (!Init(g)) {
bson_t *query;
const char *jf = NULL;
if (Pipe)
return 10;
else if (Filter)
jf = 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();
int64_t card = (int)mongoc_collection_count(Collection,
MONGOC_QUERY_NONE, query, 0, 0, NULL, &Error);
if (card < 0)
sprintf(g->Message, "Collection count: %s", Error.message);
bson_destroy(query);
return card;
} else
return -1;
} else
return 1; return 1;
return (!Init(g)) ? Cmgp->CollSize(g) : 0;
} // end of Cardinality } // end of Cardinality
/***********************************************************************/ /***********************************************************************/
...@@ -234,268 +122,22 @@ bool MGOFAM::Init(PGLOBAL g) ...@@ -234,268 +122,22 @@ bool MGOFAM::Init(PGLOBAL g)
if (Done) if (Done)
return false; return false;
Uri = mongoc_uri_new(Uristr); /*********************************************************************/
/* Open an C connection for this table. */
if (!Uri) { /*********************************************************************/
sprintf(g->Message, "Failed to parse URI: \"%s\"", Uristr); if (!Cmgp) {
return true; Pcg.Tdbp = Tdbp;
} // endif Uri Cmgp = new(g) CMgoConn(g, &Pcg);
} else if (Cmgp->IsConnected())
// Create a new client pool instance Cmgp->Close();
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);
//Client = mongoc_client_new(uristr);
if (!Client) {
sprintf(g->Message, "Failed to get Client");
return true;
} // endif Client
//mongoc_client_set_error_api(Client, 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_set_appname(Client, "Connect");
// Get a handle on the database Db_name and collection Coll_name if (Cmgp->Connect(g))
// Database = mongoc_client_get_database(Client, Db_name);
// Collection = mongoc_database_get_collection(Database, Coll_name);
Collection = mongoc_client_get_collection(Client, Db_name, Coll_name);
if (!Collection) {
sprintf(g->Message, "Failed to get Collection %s.%s", Db_name, Coll_name);
return true; return true;
} // endif Collection
Done = true; Done = true;
return false; return false;
} // end of Init } // end of Init
/***********************************************************************/
/* OpenDB: Data Base open routine for MONGO access method. */
/***********************************************************************/
bool MGOFAM::MakeCursor(PGLOBAL g)
{
const char *p;
bool b = false, id = (Mode != MODE_READ), all = false;
uint len;
PSZ jp;
PCOL cp;
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)
all = true;
if (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);
len = s->GetLength();
if (Tdbp->GetFilter()) {
s->Append(",{\"$match\":");
if (!Tdbp->GetFilter()->MakeSelector(g, s, false)) {
s->Append('}');
Tdbp->SetFilter(NULL); // Not needed anymore
} else {
if (((TDBJSN*)Tdbp)->Xcol)
Tdbp->SetFilter(NULL); // Incompatible
htrc("Failed making selector\n");
s->Truncate(len);
} // endif Selector
} // endif To_Filter
if (!all) {
// Project list
len = s->GetLength();
if (Tdbp->GetColumns()) {
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 = ((PJCOL)cp)->GetJpath(g, true)))
s->Append(jp);
else {
s->Truncate(len);
goto nop;
} // endif Jpath
s->Append("\":1");
} // endfor cp
} else
s->Append(",{\"$project\":{\"_id\":1}}");
s->Append("}}");
} // endif all
nop:
s->Append("]}");
s->Resize(s->GetLength() + 1);
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 cursor
} 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, false)) {
if (((TDBJSN*)Tdbp)->Xcol)
Tdbp->SetFilter(NULL); // Incompatible
htrc("Cannot make selector\n");
s->Truncate(len);
} else
Tdbp->SetFilter(NULL); // Not needed anymore
} // endif To_Filter
if (trace)
htrc("selector: %s\n", s->GetStr());
s->Resize(s->GetLength() + 1);
if (s->GetLength()) {
Query = bson_new_from_json((const uint8_t *)s->GetStr(), -1, &Error);
if (!Query) {
sprintf(g->Message, "Wrong filter: %s", Error.message);
return true;
} // endif Query
} else
Query = bson_new();
} else
Query = bson_new();
if (!all) {
if (Options && *Options) {
if (trace)
htrc("options=%s\n", Options);
p = Options;
} else if (Tdbp->GetColumns()) {
// Projection list
if (s)
s->Set("{\"projection\":{\"");
else
s = new(g) STRING(g, 511, "{\"projection\":{\"");
if (!id)
s->Append("_id\":0,\"");
for (PCOL cp = Tdbp->GetColumns(); cp; cp = cp->GetNext()) {
if (b)
s->Append(",\"");
else
b = true;
if ((jp = ((PJCOL)cp)->GetJpath(g, true)))
s->Append(jp);
else {
s->Reset();
s->Resize(0);
goto nope;
} // endif Jpath
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 true;
} // endif Opts
} // endif all
nope:
Cursor = mongoc_collection_find_with_opts(Collection, Query, Opts, NULL);
} // endif Pipe
return false;
} // end of MakeCursor
/***********************************************************************/ /***********************************************************************/
/* OpenTableFile: Open a MongoDB table. */ /* OpenTableFile: Open a MongoDB table. */
/***********************************************************************/ /***********************************************************************/
...@@ -503,7 +145,7 @@ bool MGOFAM::OpenTableFile(PGLOBAL g) ...@@ -503,7 +145,7 @@ bool MGOFAM::OpenTableFile(PGLOBAL g)
{ {
Mode = Tdbp->GetMode(); Mode = Tdbp->GetMode();
if (Pipe && Mode != MODE_READ) { if (Pcg.Pipe && Mode != MODE_READ) {
strcpy(g->Message, "Pipeline tables are read only"); strcpy(g->Message, "Pipeline tables are read only");
return true; return true;
} // endif Pipe } // endif Pipe
...@@ -511,20 +153,11 @@ bool MGOFAM::OpenTableFile(PGLOBAL g) ...@@ -511,20 +153,11 @@ bool MGOFAM::OpenTableFile(PGLOBAL g)
if (Init(g)) if (Init(g))
return true; return true;
if (Mode == MODE_DELETE && !Tdbp->GetNext()) { if (Mode == MODE_DELETE && !Tdbp->GetNext())
// Store the number of deleted lines
DelRows = Cardinality(g);
// Delete all documents // Delete all documents
if (!mongoc_collection_remove(Collection, MONGOC_REMOVE_NONE, return Cmgp->DocDelete(g);
Query, NULL, &Error)) { else if (Mode == MODE_INSERT)
sprintf(g->Message, "Remove all: %s", Error.message); Cmgp->MakeColumnGroups(g);
return true;
} // endif remove
} else if (Mode != MODE_INSERT)
if (MakeCursor(g))
return true;
return false; return false;
} // end of OpenTableFile } // end of OpenTableFile
...@@ -589,91 +222,18 @@ int MGOFAM::SkipRecord(PGLOBAL g, bool header) ...@@ -589,91 +222,18 @@ int MGOFAM::SkipRecord(PGLOBAL g, bool header)
return RC_OK; // Dummy return RC_OK; // Dummy
} // end of SkipRecord } // end of SkipRecord
/***********************************************************************/
/* Use to trace restaurants document contains. */
/***********************************************************************/
void MGOFAM::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
/***********************************************************************/ /***********************************************************************/
/* ReadBuffer: Get next document from a collection. */ /* ReadBuffer: Get next document from a collection. */
/***********************************************************************/ /***********************************************************************/
int MGOFAM::ReadBuffer(PGLOBAL g) int MGOFAM::ReadBuffer(PGLOBAL g)
{ {
int rc = RC_OK; int rc = Cmgp->ReadNext(g);
if (mongoc_cursor_next(Cursor, &Document)) {
char *str = bson_as_json(Document, NULL);
if (trace > 1) {
bson_iter_t iter;
ShowDocument(&iter, Document, "");
} else if (trace == 1)
htrc("%s\n", str);
strncpy(Tdbp->GetLine(), str, Lrecl);
bson_free(str);
} else if (mongoc_cursor_error(Cursor, &Error)) {
sprintf(g->Message, "Mongo Cursor Failure: %s", Error.message);
rc = RC_FX;
} else {
//mongoc_cursor_destroy(Cursor);
rc = RC_EF;
} // endif's Cursor
if (rc != RC_OK)
return rc; return rc;
strncpy(Tdbp->GetLine(), Cmgp->GetDocument(g), Lrecl);
return RC_OK;
} // end of ReadBuffer } // end of ReadBuffer
/***********************************************************************/ /***********************************************************************/
...@@ -681,84 +241,7 @@ int MGOFAM::ReadBuffer(PGLOBAL g) ...@@ -681,84 +241,7 @@ int MGOFAM::ReadBuffer(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
int MGOFAM::WriteBuffer(PGLOBAL g) int MGOFAM::WriteBuffer(PGLOBAL g)
{ {
int rc = RC_OK; return Cmgp->Write(g);
bson_t *doc;
//if (Mode == MODE_INSERT && !Collection) {
// if ((Database = mongoc_client_get_database(Client, db_name)))
// Collection = mongoc_database_create_collection(Database, coll_name,
// NULL, &Error);
// if (!Collection)
// if (Database) {
// sprintf(g->Message, "Create collection: %s", Error.message);
// return RC_FX;
// } else {
// sprintf(g->Message, "Fail to get database %s", db_name);
// return RC_FX;
// } // endif Database
//} // endif Collection
if (!(doc = bson_new_from_json((const uint8_t *)Tdbp->GetLine(),
-1, &Error))) {
sprintf(g->Message, "Wrong document: %s", Error.message);
return RC_FX;
} // endif doc
if (Mode != MODE_INSERT) {
bool b = false;
bson_iter_t iter;
bson_t *selector = bson_new();
bson_iter_init(&iter, Document);
if (bson_iter_find(&iter, "_id")) {
if (BSON_ITER_HOLDS_OID(&iter))
b = BSON_APPEND_OID(selector, "_id", bson_iter_oid(&iter));
else if (BSON_ITER_HOLDS_INT32(&iter))
b = BSON_APPEND_INT32(selector, "_id", bson_iter_int32(&iter));
else if (BSON_ITER_HOLDS_INT64(&iter))
b = BSON_APPEND_INT64(selector, "_id", bson_iter_int64(&iter));
else if (BSON_ITER_HOLDS_DOUBLE(&iter))
b = BSON_APPEND_DOUBLE(selector, "_id", bson_iter_double(&iter));
else if (BSON_ITER_HOLDS_UTF8(&iter))
b = BSON_APPEND_UTF8(selector, "_id", bson_iter_utf8(&iter, NULL));
} // endif iter
if (!b) {
strcpy(g->Message, "Cannot find _id");
return RC_FX;
} // endif oid
if (Mode == MODE_DELETE) {
if (!mongoc_collection_remove(Collection, MONGOC_REMOVE_NONE,
selector, NULL, &Error)) {
sprintf(g->Message, "Remove: %s", Error.message);
bson_destroy(selector);
return RC_FX;
} // endif remove
} else {
if (!mongoc_collection_update(Collection, MONGOC_UPDATE_NONE,
selector, doc, NULL, &Error)) {
sprintf(g->Message, "Update: %s", Error.message);
bson_destroy(selector);
return RC_FX;
} // endif remove
} // endif Mode
bson_destroy(selector);
} else if (!mongoc_collection_insert(Collection, MONGOC_INSERT_NONE,
doc, NULL, &Error)) {
sprintf(g->Message, "Inserting: %s", Error.message);
rc = RC_FX;
} // endif insert
bson_destroy(doc);
return rc;
} // end of WriteBuffer } // end of WriteBuffer
/***********************************************************************/ /***********************************************************************/
...@@ -774,18 +257,7 @@ int MGOFAM::DeleteRecords(PGLOBAL g, int irc) ...@@ -774,18 +257,7 @@ int MGOFAM::DeleteRecords(PGLOBAL g, int irc)
/***********************************************************************/ /***********************************************************************/
void MGOFAM::CloseTableFile(PGLOBAL g, bool) void MGOFAM::CloseTableFile(PGLOBAL g, bool)
{ {
if (Query) bson_destroy(Query); Cmgp->Close();
if (Opts) bson_destroy(Opts);
if (Cursor) mongoc_cursor_destroy(Cursor);
if (Collection) mongoc_collection_destroy(Collection);
// mongoc_database_destroy(Database);
// mongoc_client_destroy(Client);
if (Client) mongoc_client_pool_push(Pool, Client);
if (Pool) mongoc_client_pool_destroy(Pool);
if (Uri) mongoc_uri_destroy(Uri);
//bson_mem_restore_vtable();
//mongoc_cleanup();
//G = NULL;
Done = false; Done = false;
} // end of CloseTableFile } // end of CloseTableFile
...@@ -794,9 +266,6 @@ void MGOFAM::CloseTableFile(PGLOBAL g, bool) ...@@ -794,9 +266,6 @@ void MGOFAM::CloseTableFile(PGLOBAL g, bool)
/***********************************************************************/ /***********************************************************************/
void MGOFAM::Rewind(void) void MGOFAM::Rewind(void)
{ {
mongoc_cursor_t *cursor = mongoc_cursor_clone(Cursor); Cmgp->Rewind();
mongoc_cursor_destroy(Cursor);
Cursor = cursor;
} // end of Rewind } // end of Rewind
/************** MongoFam H Declares Source Code File (.H) **************/ /************** MongoFam H Declares Source Code File (.H) **************/
/* Name: mongofam.h Version 1.3 */ /* Name: mongofam.h Version 1.4 */
/* */ /* */
/* (C) Copyright to the author Olivier BERTRAND 2017 */ /* (C) Copyright to the author Olivier BERTRAND 2017 */
/* */ /* */
/* This file contains the MongoDB access method classes declares. */ /* This file contains the MongoDB access method classes declares. */
/***********************************************************************/ /***********************************************************************/
#pragma once #include "cmgoconn.h"
/***********************************************************************/
/* Include MongoDB library header files. */
/***********************************************************************/
#include <bson.h>
#include <bcon.h>
#include <mongoc.h>
#include "block.h"
//#include "array.h"
typedef class TXTFAM *PTXF; typedef class TXTFAM *PTXF;
typedef class MGOFAM *PMGOFAM; typedef class MGOFAM *PMGOFAM;
...@@ -37,6 +27,7 @@ class DllExport MGOFAM : public DOSFAM { ...@@ -37,6 +27,7 @@ class DllExport MGOFAM : public DOSFAM {
virtual bool GetUseTemp(void) { return false; } virtual bool GetUseTemp(void) { return false; }
virtual int GetPos(void); virtual int GetPos(void);
virtual int GetNextPos(void); virtual int GetNextPos(void);
void SetTdbp(PTDBDOS tdbp) { Tdbp = tdbp; }
virtual PTXF Duplicate(PGLOBAL g) { return (PTXF)new(g) MGOFAM(this); } virtual PTXF Duplicate(PGLOBAL g) { return (PTXF)new(g) MGOFAM(this); }
void SetLrecl(int lrecl) { Lrecl = lrecl; } void SetLrecl(int lrecl) { Lrecl = lrecl; }
...@@ -63,35 +54,12 @@ class DllExport MGOFAM : public DOSFAM { ...@@ -63,35 +54,12 @@ class DllExport MGOFAM : public DOSFAM {
virtual int RenameTempFile(PGLOBAL g) { return RC_OK; } virtual int RenameTempFile(PGLOBAL g) { return RC_OK; }
virtual int InitDelete(PGLOBAL g, int fpos, int spos); virtual int InitDelete(PGLOBAL g, int fpos, int spos);
bool Init(PGLOBAL g); bool Init(PGLOBAL g);
bool MakeCursor(PGLOBAL g);
void ShowDocument(bson_iter_t *i, const bson_t *b, const char *k);
//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 *) {}
// Members // Members
//static PGLOBAL G; CMgoConn *Cmgp; // Points to a C Mongo connection class
mongoc_uri_t *Uri; CMGOPARM Pcg; // Parms passed to Cmgp
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_mem_vtable_t Vtable;
bson_t *Query; // MongoDB cursor filter
bson_t *Opts; // MongoDB cursor options
bson_error_t Error;
PFBLOCK To_Fbt; // Pointer to temp file block PFBLOCK To_Fbt; // Pointer to temp file block
MODE Mode; MODE Mode;
const char *Uristr;
const char *Db_name;
const char *Coll_name;
const char *Options;
const char *Filter;
bool Done; // Init done bool Done; // Init done
bool Pipe;
}; // end of class MGOFAM }; // end of class MGOFAM
/* Copyright (C) MariaDB Corporation Ab */
#define MSG_ACCESS_VIOLATN 200 #define MSG_ACCESS_VIOLATN 200
#define MSG_ADD_BAD_TYPE 201 #define MSG_ADD_BAD_TYPE 201
#define MSG_ALLOC_ERROR 202 #define MSG_ALLOC_ERROR 202
......
/* Copyright (C) Olivier Bertrand 2004 - 2017 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
#if defined(JDBC_SUPPORT) #if defined(JDBC_SUPPORT)
#define NJDBC #define NJDBC
#include "tabjdbc.h" #include "tabjdbc.h"
#endif // ODBC_SUPPORT #endif // JDBC_SUPPORT
#if defined(PIVOT_SUPPORT) #if defined(PIVOT_SUPPORT)
#include "tabpivot.h" #include "tabpivot.h"
#endif // PIVOT_SUPPORT #endif // PIVOT_SUPPORT
...@@ -96,9 +96,9 @@ ...@@ -96,9 +96,9 @@
#if defined(XML_SUPPORT) #if defined(XML_SUPPORT)
#include "tabxml.h" #include "tabxml.h"
#endif // XML_SUPPORT #endif // XML_SUPPORT
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
#include "tabmgo.h" #include "mongo.h"
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT || JDBC_SUPPORT
#if defined(ZIP_SUPPORT) #if defined(ZIP_SUPPORT)
#include "tabzip.h" #include "tabzip.h"
#endif // ZIP_SUPPORT #endif // ZIP_SUPPORT
...@@ -133,21 +133,21 @@ TABTYPE GetTypeID(const char *type) ...@@ -133,21 +133,21 @@ TABTYPE GetTypeID(const char *type)
: (!stricmp(type, "CSV")) ? TAB_CSV : (!stricmp(type, "CSV")) ? TAB_CSV
: (!stricmp(type, "FMT")) ? TAB_FMT : (!stricmp(type, "FMT")) ? TAB_FMT
: (!stricmp(type, "DBF")) ? TAB_DBF : (!stricmp(type, "DBF")) ? TAB_DBF
#ifdef XML_SUPPORT #if defined(XML_SUPPORT)
: (!stricmp(type, "XML")) ? TAB_XML : (!stricmp(type, "XML")) ? TAB_XML
#endif #endif
: (!stricmp(type, "INI")) ? TAB_INI : (!stricmp(type, "INI")) ? TAB_INI
: (!stricmp(type, "VEC")) ? TAB_VEC : (!stricmp(type, "VEC")) ? TAB_VEC
#ifdef ODBC_SUPPORT #if defined(ODBC_SUPPORT)
: (!stricmp(type, "ODBC")) ? TAB_ODBC : (!stricmp(type, "ODBC")) ? TAB_ODBC
#endif #endif
#ifdef JDBC_SUPPORT #if defined(JDBC_SUPPORT)
: (!stricmp(type, "JDBC")) ? TAB_JDBC : (!stricmp(type, "JDBC")) ? TAB_JDBC
#endif #endif
: (!stricmp(type, "MYSQL")) ? TAB_MYSQL : (!stricmp(type, "MYSQL")) ? TAB_MYSQL
: (!stricmp(type, "MYPRX")) ? TAB_MYSQL : (!stricmp(type, "MYPRX")) ? TAB_MYSQL
: (!stricmp(type, "DIR")) ? TAB_DIR : (!stricmp(type, "DIR")) ? TAB_DIR
#ifdef __WIN__ #if defined(__WIN__)
: (!stricmp(type, "MAC")) ? TAB_MAC : (!stricmp(type, "MAC")) ? TAB_MAC
: (!stricmp(type, "WMI")) ? TAB_WMI : (!stricmp(type, "WMI")) ? TAB_WMI
#endif #endif
...@@ -156,15 +156,15 @@ TABTYPE GetTypeID(const char *type) ...@@ -156,15 +156,15 @@ TABTYPE GetTypeID(const char *type)
: (!stricmp(type, "OCCUR")) ? TAB_OCCUR : (!stricmp(type, "OCCUR")) ? TAB_OCCUR
: (!stricmp(type, "CATLG")) ? TAB_PRX // Legacy : (!stricmp(type, "CATLG")) ? TAB_PRX // Legacy
: (!stricmp(type, "PROXY")) ? TAB_PRX : (!stricmp(type, "PROXY")) ? TAB_PRX
#ifdef PIVOT_SUPPORT #if defined(PIVOT_SUPPORT)
: (!stricmp(type, "PIVOT")) ? TAB_PIVOT : (!stricmp(type, "PIVOT")) ? TAB_PIVOT
#endif #endif
: (!stricmp(type, "VIR")) ? TAB_VIR : (!stricmp(type, "VIR")) ? TAB_VIR
: (!stricmp(type, "JSON")) ? TAB_JSON : (!stricmp(type, "JSON")) ? TAB_JSON
#ifdef ZIP_SUPPORT #if defined(ZIP_SUPPORT)
: (!stricmp(type, "ZIP")) ? TAB_ZIP : (!stricmp(type, "ZIP")) ? TAB_ZIP
#endif #endif
#ifdef MONGO_SUPPORT #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
: (!stricmp(type, "MONGO")) ? TAB_MONGO : (!stricmp(type, "MONGO")) ? TAB_MONGO
#endif #endif
: (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY; : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY;
...@@ -557,9 +557,9 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) ...@@ -557,9 +557,9 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am)
#endif // PIVOT_SUPPORT #endif // PIVOT_SUPPORT
case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_VIR: tdp= new(g) VIRDEF; break;
case TAB_JSON: tdp= new(g) JSONDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break;
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
case TAB_MONGO: tdp = new(g) MGODEF; break; case TAB_MONGO: tdp = new(g) MGODEF; break;
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT || JDBC_SUPPORT
#if defined(ZIP_SUPPORT) #if defined(ZIP_SUPPORT)
case TAB_ZIP: tdp= new(g) ZIPDEF; break; case TAB_ZIP: tdp= new(g) ZIPDEF; break;
#endif // ZIP_SUPPORT #endif // ZIP_SUPPORT
......
/* Copyright (C) Olivier Bertrand 2004 - 2015 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
/**************** MYCAT H Declares Source Code File (.H) ***************/ /**************** MYCAT H Declares Source Code File (.H) ***************/
/* Name: MYCAT.H Version 2.3 */ /* Name: MYCAT.H Version 2.3 */
/* */ /* Author: Olivier Bertrand */
/* This file contains the CONNECT plugin MYCAT class definitions. */ /* This file contains the CONNECT plugin MYCAT class definitions. */
/***********************************************************************/ /***********************************************************************/
#ifndef __MYCAT__H #ifndef __MYCAT__H
......
/* Copyright (C) MariaDB Corporation Ab */
#ifndef _OS_H_INCLUDED #ifndef _OS_H_INCLUDED
#define _OS_H_INCLUDED #define _OS_H_INCLUDED
......
/* Copyright (C) MariaDB Corporation Ab */
#include "my_global.h" #include "my_global.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
......
/* Copyright (C) MariaDB Corporation Ab */
#ifndef __OSUTIL_H__ #ifndef __OSUTIL_H__
#define __OSUTIL_H__ #define __OSUTIL_H__
......
...@@ -138,11 +138,11 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ ...@@ -138,11 +138,11 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_VIR = 171, /* Virtual tables am type no */ TYPE_AM_VIR = 171, /* Virtual tables am type no */
TYPE_AM_DMY = 172, /* DMY Dummy 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_SET = 180, /* SET Set tables am type no */
TYPE_AM_MYSQL = 192, /* MYSQL access method type no */ TYPE_AM_MYSQL = 190, /* MYSQL access method type no */
TYPE_AM_MYX = 193, /* MYSQL EXEC access method type */ TYPE_AM_MYX = 191, /* MYSQL EXEC access method type */
TYPE_AM_CAT = 195, /* Catalog access method type no */ TYPE_AM_CAT = 192, /* Catalog access method type no */
TYPE_AM_ZIP = 198, /* ZIP access method type no */ TYPE_AM_ZIP = 193, /* ZIP access method type no */
TYPE_AM_MGO = 199, /* MGO access method type no */ TYPE_AM_MGO = 194, /* MGO access method type no */
TYPE_AM_OUT = 200}; /* Output relations (storage) */ TYPE_AM_OUT = 200}; /* Output relations (storage) */
enum RECFM {RECFM_NAF = -2, /* Not a file */ enum RECFM {RECFM_NAF = -2, /* Not a file */
......
...@@ -104,6 +104,8 @@ class DllExport EXTDEF : public TABDEF { /* EXT table */ ...@@ -104,6 +104,8 @@ class DllExport EXTDEF : public TABDEF { /* EXT table */
/* This is the base class for all external tables. */ /* This is the base class for all external tables. */
/***********************************************************************/ /***********************************************************************/
class DllExport TDBEXT : public TDB { class DllExport TDBEXT : public TDB {
friend class JAVAConn;
friend class JMgoConn;
public: public:
// Constructors // Constructors
TDBEXT(EXTDEF *tdp); TDBEXT(EXTDEF *tdp);
...@@ -164,7 +166,7 @@ class DllExport TDBEXT : public TDB { ...@@ -164,7 +166,7 @@ class DllExport TDBEXT : public TDB {
}; // end of class TDBEXT }; // end of class TDBEXT
/***********************************************************************/ /***********************************************************************/
/* Virual class EXTCOL: external column. */ /* Virtual class EXTCOL: external column. */
/***********************************************************************/ /***********************************************************************/
class DllExport EXTCOL : public COLBLK { class DllExport EXTCOL : public COLBLK {
friend class TDBEXT; friend class TDBEXT;
......
...@@ -223,10 +223,10 @@ bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) ...@@ -223,10 +223,10 @@ bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
} // endif Connect } // endif Connect
if (Url) if (Url)
rc = ParseURL(g, Url); if ((rc = ParseURL(g, Url)) == RC_FX) {
sprintf(g->Message, "Wrong JDBC URL %s", Url);
if (rc == RC_FX) // Error
return true; return true;
} // endif rc
Wrapname = GetStringCatInfo(g, "Wrapper", NULL); Wrapname = GetStringCatInfo(g, "Wrapper", NULL);
return false; return false;
...@@ -305,12 +305,12 @@ TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBEXT(tdp) ...@@ -305,12 +305,12 @@ TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBEXT(tdp)
if (tdp) { if (tdp) {
Ops.Driver = tdp->Driver; Ops.Driver = tdp->Driver;
Ops.Url = tdp->Url; Ops.Url = tdp->Url;
WrapName = tdp->Wrapname; Wrapname = tdp->Wrapname;
Ops.User = tdp->Username; Ops.User = tdp->Username;
Ops.Pwd = tdp->Password; Ops.Pwd = tdp->Password;
Ops.Scrollable = tdp->Scrollable; Ops.Scrollable = tdp->Scrollable;
} else { } else {
WrapName = NULL; Wrapname = NULL;
Ops.Driver = NULL; Ops.Driver = NULL;
Ops.Url = NULL; Ops.Url = NULL;
Ops.User = NULL; Ops.User = NULL;
...@@ -328,7 +328,7 @@ TDBJDBC::TDBJDBC(PTDBJDBC tdbp) : TDBEXT(tdbp) ...@@ -328,7 +328,7 @@ TDBJDBC::TDBJDBC(PTDBJDBC tdbp) : TDBEXT(tdbp)
{ {
Jcp = tdbp->Jcp; // is that right ? Jcp = tdbp->Jcp; // is that right ?
Cnp = tdbp->Cnp; Cnp = tdbp->Cnp;
WrapName = tdbp->WrapName; Wrapname = tdbp->Wrapname;
Ops = tdbp->Ops; Ops = tdbp->Ops;
Prepared = tdbp->Prepared; Prepared = tdbp->Prepared;
Werr = tdbp->Werr; Werr = tdbp->Werr;
...@@ -562,7 +562,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g) ...@@ -562,7 +562,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g)
/* Table already open, just replace it at its beginning. */ /* Table already open, just replace it at its beginning. */
/*******************************************************************/ /*******************************************************************/
if (Memory == 1) { if (Memory == 1) {
if ((Qrp = Jcp->AllocateResult(g))) if ((Qrp = Jcp->AllocateResult(g, this)))
Memory = 2; // Must be filled Memory = 2; // Must be filled
else else
Memory = 0; // Allocation failed, don't use it Memory = 0; // Allocation failed, don't use it
...@@ -596,11 +596,11 @@ bool TDBJDBC::OpenDB(PGLOBAL g) ...@@ -596,11 +596,11 @@ bool TDBJDBC::OpenDB(PGLOBAL g)
/* drivers allowing concurency in getting results ??? */ /* drivers allowing concurency in getting results ??? */
/*********************************************************************/ /*********************************************************************/
if (!Jcp) if (!Jcp)
Jcp = new(g)JDBConn(g, this); Jcp = new(g)JDBConn(g, Wrapname);
else if (Jcp->IsOpen()) else if (Jcp->IsOpen())
Jcp->Close(); Jcp->Close();
if (Jcp->Open(&Ops) == RC_FX) if (Jcp->Connect(&Ops))
return true; return true;
else if (Quoted) else if (Quoted)
Quote = Jcp->GetQuoteChar(); Quote = Jcp->GetQuoteChar();
...@@ -608,7 +608,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g) ...@@ -608,7 +608,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g)
Use = USE_OPEN; // Do it now in case we are recursively called 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 (Mode == MODE_READ || Mode == MODE_READX) {
if (Memory > 1 && !Srcdef) { if (Memory > 1 && !Srcdef) {
...@@ -625,7 +625,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g) ...@@ -625,7 +625,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g)
} else if (n) { } else if (n) {
Jcp->m_Rows = n; Jcp->m_Rows = n;
if ((Qrp = Jcp->AllocateResult(g))) if ((Qrp = Jcp->AllocateResult(g, this)))
Memory = 2; // Must be filled Memory = 2; // Must be filled
else { else {
strcpy(g->Message, "Result set memory allocation failed"); strcpy(g->Message, "Result set memory allocation failed");
...@@ -1134,11 +1134,11 @@ bool TDBXJDC::OpenDB(PGLOBAL g) ...@@ -1134,11 +1134,11 @@ bool TDBXJDC::OpenDB(PGLOBAL g)
/* drivers allowing concurency in getting results ??? */ /* drivers allowing concurency in getting results ??? */
/*********************************************************************/ /*********************************************************************/
if (!Jcp) { if (!Jcp) {
Jcp = new(g) JDBConn(g, this); Jcp = new(g) JDBConn(g, Wrapname);
} else if (Jcp->IsOpen()) } else if (Jcp->IsOpen())
Jcp->Close(); Jcp->Close();
if (Jcp->Open(&Ops) == RC_FX) if (Jcp->Connect(&Ops))
return true; return true;
Use = USE_OPEN; // Do it now in case we are recursively called Use = USE_OPEN; // Do it now in case we are recursively called
...@@ -1173,7 +1173,7 @@ int TDBXJDC::ReadDB(PGLOBAL g) ...@@ -1173,7 +1173,7 @@ int TDBXJDC::ReadDB(PGLOBAL g)
else else
Query->Set(Cmdlist->Cmd); Query->Set(Cmdlist->Cmd);
if ((rc = Jcp->ExecSQLcommand(Query->GetStr())) == RC_FX) if ((rc = Jcp->ExecuteCommand(Query->GetStr())) == RC_FX)
Nerr++; Nerr++;
if (rc == RC_NF) if (rc == RC_NF)
......
...@@ -41,7 +41,7 @@ class DllExport JDBCDEF : public EXTDEF { /* Logical table description */ ...@@ -41,7 +41,7 @@ class DllExport JDBCDEF : public EXTDEF { /* Logical table description */
// Members // Members
PSZ Driver; /* JDBC driver */ PSZ Driver; /* JDBC driver */
PSZ Url; /* JDBC driver URL */ PSZ Url; /* JDBC driver URL */
PSZ Wrapname; /* Java wrapper name */ PSZ Wrapname; /* Java driver name */
}; // end of JDBCDEF }; // end of JDBCDEF
#if !defined(NJDBC) #if !defined(NJDBC)
...@@ -89,7 +89,7 @@ class TDBJDBC : public TDBEXT { ...@@ -89,7 +89,7 @@ class TDBJDBC : public TDBEXT {
JDBConn *Jcp; // Points to a JDBC connection class JDBConn *Jcp; // Points to a JDBC connection class
JDBCCOL *Cnp; // Points to count(*) column JDBCCOL *Cnp; // Points to count(*) column
JDBCPARM Ops; // Additional parameters 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 Prepared; // True when using prepared statement
bool Werr; // Write error bool Werr; // Write error
bool Rerr; // Rewind error bool Rerr; // Rewind error
......
/************** 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 <my_global.h>
/***********************************************************************/
/* 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 */
/* --------------------------- 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
/* ---------------------------TDBGOL class --------------------------- */
/***********************************************************************/
/* TDBGOL class constructor. */
/***********************************************************************/
TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp)
{
Topt = tdp->GetTopt();
Db = (char*)tdp->GetTabschema();
} // end of TDBJCL constructor
/***********************************************************************/
/* GetResult: Get the list the JSON file columns. */
/***********************************************************************/
PQRYRES TDBGOL::GetResult(PGLOBAL g)
{
return MGOColumns(g, Db, Topt, false);
} // end of GetResult
#endif // 0
/* -------------------------- End of mongo --------------------------- */
/**************** 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
#if 0
/***********************************************************************/
/* 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;
char *Db;
}; // end of class TDBGOL
#endif 0
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
#if defined(ZIP_SUPPORT) #if defined(ZIP_SUPPORT)
#include "filamzip.h" #include "filamzip.h"
#endif // ZIP_SUPPORT #endif // ZIP_SUPPORT
#if defined(JDBC_SUPPORT)
#include "jmgfam.h"
#endif // JDBC_SUPPORT
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT)
#include "mongofam.h" #include "mongofam.h"
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT
...@@ -68,7 +71,7 @@ typedef struct _jncol { ...@@ -68,7 +71,7 @@ typedef struct _jncol {
/* JSONColumns: construct the result blocks containing the description */ /* JSONColumns: construct the result blocks containing the description */
/* of all the columns of a table contained inside a JSON file. */ /* of all the columns of a table contained inside a JSON file. */
/***********************************************************************/ /***********************************************************************/
PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, 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, static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING}; TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
...@@ -78,7 +81,8 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -78,7 +81,8 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
char *p, colname[65], fmt[129]; char *p, colname[65], fmt[129];
int i, j, lvl, n = 0; int i, j, lvl, n = 0;
int ncol = sizeof(buftyp) / sizeof(int); int ncol = sizeof(buftyp) / sizeof(int);
PCSZ sep; bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
PCSZ sep, level;
PVAL valp; PVAL valp;
JCOL jcol; JCOL jcol;
PJCL jcp, fjcp = NULL, pjcp = NULL; PJCL jcp, fjcp = NULL, pjcp = NULL;
...@@ -108,8 +112,14 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -108,8 +112,14 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
/*********************************************************************/ /*********************************************************************/
/* Open the input file. */ /* Open the input file. */
/*********************************************************************/ /*********************************************************************/
lvl = GetIntegerTableOption(g, topt, "Level", 0); level = GetStringTableOption(g, topt, "Level", NULL);
lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl;
if (level) {
lvl = atoi(level);
lvl = (lvl > 16) ? 16 : lvl;
} else
lvl = 0;
sep = GetStringTableOption(g, topt, "Separator", "."); sep = GetStringTableOption(g, topt, "Separator", ".");
tdp = new(g) JSONDEF; tdp = new(g) JSONDEF;
...@@ -119,11 +129,6 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -119,11 +129,6 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
#endif // ZIP_SUPPORT #endif // ZIP_SUPPORT
tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
if (!tdp->Fn && !dsn) {
strcpy(g->Message, MSG(MISSING_FNAME));
return NULL;
} // endif Fn
if (!(tdp->Database = SetPath(g, db))) if (!(tdp->Database = SetPath(g, db)))
return NULL; return NULL;
...@@ -133,22 +138,30 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -133,22 +138,30 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL); tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL);
tdp->Uri = (dsn && *dsn ? dsn : NULL); tdp->Uri = (dsn && *dsn ? dsn : NULL);
if (!tdp->Fn && !tdp->Uri) {
strcpy(g->Message, MSG(MISSING_FNAME));
return NULL;
} // endif Fn
if (trace) if (trace)
htrc("File %s objname=%s pretty=%d lvl=%d\n", htrc("File %s objname=%s pretty=%d lvl=%d\n",
tdp->Fn, tdp->Objname, tdp->Pretty, lvl); tdp->Fn, tdp->Objname, tdp->Pretty, lvl);
if (tdp->Uri) { if (tdp->Uri) {
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
tdp->Collname = GetStringTableOption(g, topt, "Name", NULL); tdp->Collname = GetStringTableOption(g, topt, "Name", NULL);
tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname); tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname);
tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test"); tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test");
tdp->Options = PlugDup(g, "all"); tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all");
// tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false); 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; tdp->Pretty = 0;
#else // !MONGO_SUPPORT #else // !MONGO_SUPPORT || JDBC_SUPPORT
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
return NULL; return NULL;
#endif // !MONGO_SUPPORT #endif // !MONGO_SUPPORT || JDBC_SUPPORT
} // endif Uri } // endif Uri
if (tdp->Pretty == 2) { if (tdp->Pretty == 2) {
...@@ -167,10 +180,12 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -167,10 +180,12 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL; jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL;
} else { } else {
if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) { if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))
if (!mgo) {
sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
return NULL; return NULL;
} // endif lrecl } else
tdp->Lrecl = 8192; // Should be enough
tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF);
...@@ -182,12 +197,21 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -182,12 +197,21 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
return NULL; return NULL;
#endif // !ZIP_SUPPORT #endif // !ZIP_SUPPORT
} else if (tdp->Uri) { } else if (tdp->Uri) {
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
#if !defined(JDBC_SUPPORT)
tjnp = new(g) TDBJSN(tdp, new(g) MGOFAM(tdp)); tjnp = new(g) TDBJSN(tdp, new(g) MGOFAM(tdp));
#else // !MONGO_SUPPORT #elif !defined(MONGO_SUPPORT)
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); 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; return NULL;
#endif // !MONGO_SUPPORT #endif // MONGO_SUPPORT || JDBC_SUPPORT
} else } else
tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp));
...@@ -229,15 +253,15 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -229,15 +253,15 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
jcol.Found = true; jcol.Found = true;
colname[64] = 0; colname[64] = 0;
fmt[128] = 0; fmt[128] = 0;
*fmt = '$';
if (!tdp->Uri) { if (!tdp->Uri) {
*fmt = '$';
fmt[1] = '.'; fmt[1] = '.';
p = fmt + 2; p = fmt + 2;
} else } else
p = fmt + 1; p = fmt;
jrp = (PJPR*)PlugSubAlloc(g, NULL, sizeof(PJPR) * lvl); jrp = (PJPR*)PlugSubAlloc(g, NULL, sizeof(PJPR) * MY_MAX(lvl, 0));
/*********************************************************************/ /*********************************************************************/
/* Analyse the JSON tree and define columns. */ /* Analyse the JSON tree and define columns. */
...@@ -300,12 +324,13 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info) ...@@ -300,12 +324,13 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, char *dsn, PTOS topt, bool info)
} // endswitch jsp } // endswitch jsp
goto retry; goto retry;
} else { } else if (lvl >= 0) {
jcol.Type = TYPE_STRING; jcol.Type = TYPE_STRING;
jcol.Len = 256; jcol.Len = 256;
jcol.Scale = 0; jcol.Scale = 0;
jcol.Cbn = true; jcol.Cbn = true;
} // endif's } else
continue;
// Check whether this column was already found // Check whether this column was already found
for (jcp = fjcp; jcp; jcp = jcp->Next) for (jcp = fjcp; jcp; jcp = jcp->Next)
...@@ -461,11 +486,16 @@ JSONDEF::JSONDEF(void) ...@@ -461,11 +486,16 @@ JSONDEF::JSONDEF(void)
Base = 0; Base = 0;
Strict = false; Strict = false;
Sep = '.'; Sep = '.';
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
Uri = NULL; Uri = NULL;
Collname = Schema = Options = Filter = NULL; Collname = Schema = Options = Filter = NULL;
Pipe = false; Pipe = false;
#endif // MONGO_SUPPORT Driver = NULL;
Version = 0;
#if defined(JDBC_SUPPORT)
Wrapname = NULL;
#endif // JDBC_SUPPORT
#endif // !MONGO_SUPPORT && !JDBC_SUPPORT
} // end of JSONDEF constructor } // end of JSONDEF constructor
/***********************************************************************/ /***********************************************************************/
...@@ -482,7 +512,7 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR, int poff) ...@@ -482,7 +512,7 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
Sep = *GetStringCatInfo(g, "Separator", "."); Sep = *GetStringCatInfo(g, "Separator", ".");
if (Uri = GetStringCatInfo(g, "Connect", NULL)) { if (Uri = GetStringCatInfo(g, "Connect", NULL)) {
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
Collname = GetStringCatInfo(g, "Name", Collname = GetStringCatInfo(g, "Name",
(Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
Collname = GetStringCatInfo(g, "Tabname", Collname); Collname = GetStringCatInfo(g, "Tabname", Collname);
...@@ -490,11 +520,19 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR, int poff) ...@@ -490,11 +520,19 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
Options = GetStringCatInfo(g, "Colist", NULL); Options = GetStringCatInfo(g, "Colist", NULL);
Filter = GetStringCatInfo(g, "Filter", NULL); Filter = GetStringCatInfo(g, "Filter", NULL);
Pipe = GetBoolCatInfo("Pipeline", false); Pipe = GetBoolCatInfo("Pipeline", false);
Driver = GetStringCatInfo(g, "Driver", NULL);
Version = GetIntCatInfo("Version", 3);
Pretty = 0; Pretty = 0;
#else // !MONGO_SUPPORT #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"); sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
return true; return true;
#endif // !MONGO_SUPPORT #endif // !MONGO_SUPPORT && !JDBC_SUPPORT
} // endif Uri } // endif Uri
return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff); return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff);
...@@ -520,12 +558,18 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ...@@ -520,12 +558,18 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
(m == MODE_UPDATE || m == MODE_DELETE)); (m == MODE_UPDATE || m == MODE_DELETE));
if (Uri) { if (Uri) {
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
#if !defined(JDBC_SUPPORT)
txfp = new(g) MGOFAM(this); txfp = new(g) MGOFAM(this);
#else // !MONGO_SUPPORT #elif !defined(MONGO_SUPPORT)
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); txfp = new(g) JMGFAM(this);
return NULL; #else
#endif // !MONGO_SUPPORT 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) { } else if (Zipped) {
#if defined(ZIP_SUPPORT) #if defined(ZIP_SUPPORT)
if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
...@@ -559,6 +603,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ...@@ -559,6 +603,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
tdbp = new(g) TDBJSN(this, txfp); tdbp = new(g) TDBJSN(this, txfp);
#if USE_G #if USE_G
if (Lrecl) {
// Allocate the parse work memory // Allocate the parse work memory
PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
memset(G, 0, sizeof(GLOBAL)); memset(G, 0, sizeof(GLOBAL));
...@@ -567,6 +612,10 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ...@@ -567,6 +612,10 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
PlugSubSet(G, G->Sarea, G->Sarea_Size); PlugSubSet(G, G->Sarea, G->Sarea_Size);
G->jump_level = 0; G->jump_level = 0;
((TDBJSN*)tdbp)->G = G; ((TDBJSN*)tdbp)->G = G;
} else {
strcpy(g->Message, "LRECL is not defined");
return NULL;
} // endif Lrecl
#else #else
((TDBJSN*)tdbp)->G = g; ((TDBJSN*)tdbp)->G = g;
#endif #endif
...@@ -791,13 +840,16 @@ bool TDBJSN::OpenDB(PGLOBAL g) ...@@ -791,13 +840,16 @@ bool TDBJSN::OpenDB(PGLOBAL g)
return true; return true;
} // endswitch Jmode } // endswitch Jmode
if (Xcol && Txfp->GetAmType() != TYPE_AM_MGO)
To_Filter = NULL; // Imcompatible
} // endif Use } // endif Use
return TDBDOS::OpenDB(g); if (TDBDOS::OpenDB(g))
} // end of OpenDB return true;
if (Xcol)
To_Filter = NULL; // Imcompatible
return false;
} // end of OpenDB
/***********************************************************************/ /***********************************************************************/
/* SkipHeader: Physically skip first header line if applicable. */ /* SkipHeader: Physically skip first header line if applicable. */
...@@ -1282,7 +1334,7 @@ bool JSONCOL::ParseJpath(PGLOBAL g) ...@@ -1282,7 +1334,7 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
/* Get Jpath converted to Mongo path. */ /* Get Jpath converted to Mongo path. */
/***********************************************************************/ /***********************************************************************/
char *JSONCOL::GetJpath(PGLOBAL g, bool proj) PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj)
{ {
if (Jpath) { if (Jpath) {
char *p1, *p2, *mgopath; char *p1, *p2, *mgopath;
...@@ -2204,8 +2256,8 @@ void TDBJSON::CloseDB(PGLOBAL g) ...@@ -2204,8 +2256,8 @@ void TDBJSON::CloseDB(PGLOBAL g)
TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp) TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp)
{ {
Topt = tdp->GetTopt(); Topt = tdp->GetTopt();
Db = (char*)tdp->GetDB(); Db = tdp->GetDB();
Dsn = (char*)tdp->Uri; Dsn = tdp->Uri;
} // end of TDBJCL constructor } // end of TDBJCL constructor
/***********************************************************************/ /***********************************************************************/
......
...@@ -36,10 +36,13 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */ ...@@ -36,10 +36,13 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */
friend class TDBJSON; friend class TDBJSON;
friend class TDBJSN; friend class TDBJSN;
friend class TDBJCL; friend class TDBJCL;
friend PQRYRES JSONColumns(PGLOBAL, char*, char*, PTOS, bool); #if defined(JDBC_SUPPORT)
friend class JMGFAM;
#endif // JDBC_SUPPORT
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT)
friend class MGOFAM; friend class MGOFAM;
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT
friend PQRYRES JSONColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
public: public:
// Constructor // Constructor
JSONDEF(void); JSONDEF(void);
...@@ -63,13 +66,18 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */ ...@@ -63,13 +66,18 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */
bool Strict; /* Strict syntax checking */ bool Strict; /* Strict syntax checking */
char Sep; /* The Jpath separator */ char Sep; /* The Jpath separator */
const char *Uri; /* MongoDB connection URI */ const char *Uri; /* MongoDB connection URI */
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT) || defined(JDBC_SUPPORT)
PCSZ Collname; /* External collection name */ PCSZ Collname; /* External collection name */
PCSZ Schema; /* External schema (DB) name */ PCSZ Schema; /* External schema (DB) name */
PSZ Options; /* Colist ; Pipe */ PSZ Options; /* Colist ; Pipe */
PSZ Filter; /* Filter */ PSZ Filter; /* Filter */
PSZ Driver; /* MongoDB Driver (C or JAVA) */
bool Pipe; /* True if Colist is a pipeline */ bool Pipe; /* True if Colist is a pipeline */
#endif // MONGO_SUPPORT 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 }; // end of JSONDEF
/* -------------------------- TDBJSN class --------------------------- */ /* -------------------------- TDBJSN class --------------------------- */
...@@ -81,6 +89,9 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */ ...@@ -81,6 +89,9 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */
class DllExport TDBJSN : public TDBDOS { class DllExport TDBJSN : public TDBDOS {
friend class JSONCOL; friend class JSONCOL;
friend class JSONDEF; friend class JSONDEF;
#if defined(JDBC_SUPPORT)
friend class JMGFAM;
#endif // JDBC_SUPPORT
#if defined(MONGO_SUPPORT) #if defined(MONGO_SUPPORT)
friend class MGOFAM; friend class MGOFAM;
#endif // MONGO_SUPPORT #endif // MONGO_SUPPORT
...@@ -148,8 +159,13 @@ class DllExport TDBJSN : public TDBDOS { ...@@ -148,8 +159,13 @@ class DllExport TDBJSN : public TDBDOS {
class DllExport JSONCOL : public DOSCOL { class DllExport JSONCOL : public DOSCOL {
friend class TDBJSN; friend class TDBJSN;
friend class TDBJSON; friend class TDBJSON;
#if defined(JDBC_SUPPORT)
friend class JMGFAM;
#endif // JDBC_SUPPORT
#if defined(MONGO_SUPPORT)
friend class MGOFAM; friend class MGOFAM;
public: #endif // MONGO_SUPPORT
public:
// Constructors // Constructors
JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
JSONCOL(JSONCOL *colp, PTDB tdbp); // Constructor used in copy process JSONCOL(JSONCOL *colp, PTDB tdbp); // Constructor used in copy process
...@@ -160,7 +176,7 @@ class DllExport JSONCOL : public DOSCOL { ...@@ -160,7 +176,7 @@ class DllExport JSONCOL : public DOSCOL {
// Methods // Methods
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
bool ParseJpath(PGLOBAL g); bool ParseJpath(PGLOBAL g);
char *GetJpath(PGLOBAL g, bool proj); virtual PSZ GetJpath(PGLOBAL g, bool proj);
virtual void ReadColumn(PGLOBAL g); virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g);
...@@ -253,6 +269,6 @@ class DllExport TDBJCL : public TDBCAT { ...@@ -253,6 +269,6 @@ class DllExport TDBJCL : public TDBCAT {
// Members // Members
PTOS Topt; PTOS Topt;
char *Db; PCSZ Db;
char *Dsn; PCSZ Dsn;
}; // end of class TDBJCL }; // end of class TDBJCL
...@@ -35,11 +35,13 @@ ...@@ -35,11 +35,13 @@
#define MAXCOL 200 /* Default max column nb in result */ #define MAXCOL 200 /* Default max column nb in result */
#define TYPE_UNKNOWN 12 /* Must be greater than other types */ #define TYPE_UNKNOWN 12 /* Must be greater than other types */
bool IsNum(PSZ s);
/***********************************************************************/ /***********************************************************************/
/* MGOColumns: construct the result blocks containing the description */ /* MGOColumns: construct the result blocks containing the description */
/* of all the columns of a document contained inside MongoDB. */ /* of all the columns of a document contained inside MongoDB. */
/***********************************************************************/ /***********************************************************************/
PQRYRES MGOColumns(PGLOBAL g, char *db, PTOS topt, bool info) PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info)
{ {
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING}; TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
...@@ -64,7 +66,7 @@ PQRYRES MGOColumns(PGLOBAL g, char *db, PTOS topt, bool info) ...@@ -64,7 +66,7 @@ PQRYRES MGOColumns(PGLOBAL g, char *db, PTOS topt, bool info)
/*********************************************************************/ /*********************************************************************/
mgd = new(g) MGODISC(g, (int*)length); mgd = new(g) MGODISC(g, (int*)length);
if ((n = mgd->GetColumns(g, db, topt)) < 0) if ((n = mgd->GetColumns(g, db, uri, topt)) < 0)
goto err; goto err;
skipit: skipit:
...@@ -142,7 +144,7 @@ MGODISC::MGODISC(PGLOBAL g, int *lg) { ...@@ -142,7 +144,7 @@ MGODISC::MGODISC(PGLOBAL g, int *lg) {
/***********************************************************************/ /***********************************************************************/
/* Class used to get the columns of a mongo collection. */ /* Class used to get the columns of a mongo collection. */
/***********************************************************************/ /***********************************************************************/
int MGODISC::GetColumns(PGLOBAL g, char *db, PTOS topt) int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt)
{ {
PCSZ level; PCSZ level;
bson_iter_t iter; bson_iter_t iter;
...@@ -164,7 +166,7 @@ int MGODISC::GetColumns(PGLOBAL g, char *db, PTOS topt) ...@@ -164,7 +166,7 @@ int MGODISC::GetColumns(PGLOBAL g, char *db, PTOS topt)
/* Open the MongoDB collection. */ /* Open the MongoDB collection. */
/*********************************************************************/ /*********************************************************************/
tdp = new(g) MGODEF; tdp = new(g) MGODEF;
tdp->Uri = GetStringTableOption(g, topt, "Connect", "mongodb://localhost:27017"); tdp->Uri = uri;
tdp->Tabname = GetStringTableOption(g, topt, "Name", NULL); tdp->Tabname = GetStringTableOption(g, topt, "Name", NULL);
tdp->Tabname = GetStringTableOption(g, topt, "Tabname", tdp->Tabname); tdp->Tabname = GetStringTableOption(g, topt, "Tabname", tdp->Tabname);
tdp->Tabschema = GetStringTableOption(g, topt, "Dbname", db); tdp->Tabschema = GetStringTableOption(g, topt, "Dbname", db);
...@@ -200,7 +202,7 @@ int MGODISC::GetColumns(PGLOBAL g, char *db, PTOS topt) ...@@ -200,7 +202,7 @@ int MGODISC::GetColumns(PGLOBAL g, char *db, PTOS topt)
case RC_FX: case RC_FX:
return -1; return -1;
default: default:
doc = tmgp->Document; doc = tmgp->Cmgp->Document;
} // endswitch ReadDB } // endswitch ReadDB
if (FindInDoc(g, &iter, doc, NULL, NULL, i, k, false)) if (FindInDoc(g, &iter, doc, NULL, NULL, i, k, false))
...@@ -368,140 +370,33 @@ bool MGODISC::FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc, ...@@ -368,140 +370,33 @@ bool MGODISC::FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc,
return false; return false;
} // end of FindInDoc } // end of FindInDoc
/* -------------------------- Class MGODEF --------------------------- */
MGODEF::MGODEF(void)
{
Uri = NULL;
Colist = NULL;
Filter = NULL;
Level = 0;
Base = 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", "*");
Uri = GetStringCatInfo(g, "Connect", "mongodb://localhost:27017");
Colist = GetStringCatInfo(g, "Colist", NULL);
Filter = GetStringCatInfo(g, "Filter", NULL);
Base = GetIntCatInfo("Base", 0) ? 1 : 0;
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)
return new(g)TDBGOL(this);
return new(g) TDBMGO(this);
} // end of GetTable
/* --------------------------- 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;
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 = '.';
icp->AddCol(g, colp, p + 1);
} 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 TDBMGO -------------------------- */ /* --------------------------- Class TDBMGO -------------------------- */
/***********************************************************************/ /***********************************************************************/
/* Implementation of the TDBMGO class. */ /* Implementation of the TDBMGO class. */
/***********************************************************************/ /***********************************************************************/
TDBMGO::TDBMGO(PMGODEF tdp) : TDBEXT(tdp) TDBMGO::TDBMGO(MGODEF *tdp) : TDBEXT(tdp)
{ {
G = NULL; Cmgp = NULL;
Uri = NULL;
Pool = NULL;
Client = NULL;
Database = NULL;
Collection = NULL;
Cursor = NULL;
Query = NULL;
Opts = NULL;
Fpc = NULL;
Cnd = NULL; Cnd = NULL;
Pcg.Tdbp = this;
if (tdp) { if (tdp) {
Uristr = tdp->Uri; Pcg.Uristr = tdp->Uri;
Db_name = tdp->Tabschema; Pcg.Db_name = tdp->Tabschema;
Coll_name = tdp->Tabname; Pcg.Coll_name = tdp->Tabname;
Options = tdp->Colist; Pcg.Options = tdp->Colist;
Filter = tdp->Filter; Pcg.Filter = tdp->Filter;
Pcg.Pipe = tdp->Pipe && Options != NULL;
B = tdp->Base ? 1 : 0; B = tdp->Base ? 1 : 0;
Pipe = tdp->Pipe && Options != NULL;
} else { } else {
Uristr = NULL; Pcg.Uristr = NULL;
Db_name = NULL; Pcg.Db_name = NULL;
Coll_name = NULL; Pcg.Coll_name = NULL;
Options = NULL; Pcg.Options = NULL;
Filter = NULL; Pcg.Filter = NULL;
Pcg.Pipe = false;
B = 0; B = 0;
Pipe = false;
} // endif tdp } // endif tdp
Fpos = -1; Fpos = -1;
...@@ -511,27 +406,13 @@ TDBMGO::TDBMGO(PMGODEF tdp) : TDBEXT(tdp) ...@@ -511,27 +406,13 @@ TDBMGO::TDBMGO(PMGODEF tdp) : TDBEXT(tdp)
TDBMGO::TDBMGO(TDBMGO *tdbp) : TDBEXT(tdbp) TDBMGO::TDBMGO(TDBMGO *tdbp) : TDBEXT(tdbp)
{ {
G = tdbp->G; Cmgp = tdbp->Cmgp;
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; Cnd = tdbp->Cnd;
Uristr = tdbp->Uristr; Pcg = tdbp->Pcg;
Db_name = tdbp->Db_name;;
Coll_name = tdbp->Coll_name;
Options = tdbp->Options;
Filter = tdbp->Filter;
B = tdbp->B; B = tdbp->B;
Fpos = tdbp->Fpos; Fpos = tdbp->Fpos;
N = tdbp->N; N = tdbp->N;
Done = tdbp->Done; Done = tdbp->Done;
Pipe = tdbp->Pipe;
} // end of TDBMGO copy constructor } // end of TDBMGO copy constructor
// Used for update // Used for update
...@@ -559,9 +440,7 @@ PCOL TDBMGO::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) ...@@ -559,9 +440,7 @@ PCOL TDBMGO::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{ {
PMGOCOL colp = new(g) MGOCOL(g, cdp, this, cprec, n); PMGOCOL colp = new(g) MGOCOL(g, cdp, this, cprec, n);
colp->Mbuf = (char*)PlugSubAlloc(g, NULL, colp->Long + 1);
return colp; return colp;
//return (colp->ParseJpath(g)) ? NULL : colp;
} // end of MakeCol } // end of MakeCol
/***********************************************************************/ /***********************************************************************/
...@@ -577,60 +456,6 @@ PCOL TDBMGO::InsertSpecialColumn(PCOL colp) ...@@ -577,60 +456,6 @@ PCOL TDBMGO::InsertSpecialColumn(PCOL colp)
return colp; return colp;
} // end of InsertSpecialColumn } // end of InsertSpecialColumn
/***********************************************************************/
/* MONGO Cardinality: returns table size in number of rows. */
/***********************************************************************/
int TDBMGO::Cardinality(PGLOBAL g)
{
if (!g)
return 1;
else if (Cardinal < 0)
if (!Init(g)) {
bson_t *query;
const char *jf = NULL;
if (Pipe)
return 10;
else if (Filter)
jf = 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();
Cardinal = (int)mongoc_collection_count(Collection,
MONGOC_QUERY_NONE, query, 0, 0, NULL, &Error);
if (Cardinal < 0) {
htrc("Collection count: %s", Error.message);
Cardinal = 10;
} // endif Cardinal
bson_destroy(query);
} else
return 10;
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
/***********************************************************************/ /***********************************************************************/
/* Init: initialize MongoDB processing. */ /* Init: initialize MongoDB processing. */
/***********************************************************************/ /***********************************************************************/
...@@ -639,257 +464,44 @@ bool TDBMGO::Init(PGLOBAL g) ...@@ -639,257 +464,44 @@ bool TDBMGO::Init(PGLOBAL g)
if (Done) if (Done)
return false; return false;
G = g; /*********************************************************************/
/* Open an C connection for this table. */
Uri = mongoc_uri_new(Uristr); /*********************************************************************/
if (!Cmgp)
if (!Uri) { Cmgp = new(g) CMgoConn(g, &Pcg);
sprintf(g->Message, "Failed to parse URI: \"%s\"", Uristr); else if (Cmgp->IsConnected())
return true; Cmgp->Close();
} // 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);
//Client = mongoc_client_new(uristr);
if (!Client) {
sprintf(g->Message, "Failed to get Client");
return true;
} // endif Client
//mongoc_client_set_error_api(Client, 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_set_appname(Client, "Connect");
// Get a handle on the database Db_name and collection Coll_name
// Database = mongoc_client_get_database(Client, Db_name);
// Collection = mongoc_database_get_collection(Database, Coll_name);
Collection = mongoc_client_get_collection(Client, Db_name, Coll_name);
if (!Collection) { if (Cmgp->Connect(g))
sprintf(g->Message, "Failed to get Collection %s.%s", Db_name, Coll_name);
return true; return true;
} // endif Collection
Done = true; Done = true;
return false; return false;
} // end of Init } // end of Init
/***********************************************************************/ /***********************************************************************/
/* On update the filter can be made by Cond_Push after MakeCursor. */ /* MONGO Cardinality: returns table size in number of rows. */
/***********************************************************************/ /***********************************************************************/
void TDBMGO::SetFilter(PFIL fp) int TDBMGO::Cardinality(PGLOBAL g)
{ {
To_Filter = fp; if (!g)
return 1;
if (fp && Cursor && Cnd != Cond) { else if (Cardinal < 0)
mongoc_cursor_t *cursor = MakeCursor(G); Cardinal = (!Init(g)) ? Cmgp->CollSize(g) : 0;
if (cursor) {
mongoc_cursor_destroy(Cursor);
Cursor = cursor;
} else
htrc("SetFilter: %s\n", G->Message);
} // endif Cursor
} // end of SetFilter return Cardinal;
} // end of Cardinality
/***********************************************************************/ /***********************************************************************/
/* OpenDB: Data Base open routine for MONGO access method. */ /* MONGO GetMaxSize: returns collection size estimate. */
/***********************************************************************/ /***********************************************************************/
mongoc_cursor_t *TDBMGO::MakeCursor(PGLOBAL g) int TDBMGO::GetMaxSize(PGLOBAL g)
{ {
const char *p; if (MaxSize < 0)
bool b = false, id = (Mode != MODE_READ), all = false; MaxSize = Cardinality(g);
mongoc_cursor_t *cursor;
PCOL cp;
PSTRG s = NULL;
if (Options && !stricmp(Options, "all")) {
Options = NULL;
all = true;
} // endif Options
for (cp = Columns; cp; cp = cp->GetNext())
if (!strcmp(cp->GetName(), "_id"))
id = true;
else if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && !Options)
all = true;
if (Pipe) {
if (trace)
htrc("Pipeline: %s\n", Options);
p = strrchr(Options, ']');
if (!p) {
strcpy(g->Message, "Missing ] in pipeline");
return NULL;
} else
*(char*)p = 0;
s = new(g) STRING(g, 1023, (PSZ)Options);
if (To_Filter) {
s->Append(",{\"$match\":");
if (To_Filter->MakeSelector(g, s, true)) {
strcpy(g->Message, "Failed making selector");
return NULL;
} else
s->Append('}');
To_Filter = NULL; // Not needed anymore
} // endif To_Filter
if (!all) {
// Project list
if (Columns) {
s->Append(",{\"$project\":{\"");
if (!id)
s->Append("_id\":0,\"");
for (cp = Columns; cp; cp = cp->GetNext()) {
if (b)
s->Append(",\"");
else
b = true;
s->Append(((PMGOCOL)cp)->GetProjPath(g));
s->Append("\":1");
} // endfor cp
s->Append("}}");
} else
s->Append(",{\"$project\":{\"_id\":1}}");
} // endif all
s->Append("]}");
s->Resize(s->GetLength() + 1);
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 NULL;
} // 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 NULL;
} // endif cursor
} else {
if (Filter || To_Filter) {
if (trace) {
if (Filter)
htrc("Filter: %s\n", Filter);
if (To_Filter) {
char buf[512];
To_Filter->Prints(g, buf, 511);
htrc("To_Filter: %s\n", buf);
} // endif To_Filter
} // endif trace
s = new(g) STRING(g, 1023, (PSZ)Filter);
if (To_Filter) {
if (Filter)
s->Append(',');
if (To_Filter->MakeSelector(g, s, true)) {
strcpy(g->Message, "Failed making selector");
return NULL;
} // endif Selector
To_Filter = 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 (Columns) {
// Projection list
if (s)
s->Set("{\"projection\":{\"");
else
s = new(g) STRING(g, 511, "{\"projection\":{\"");
if (!id)
s->Append("_id\":0,\"");
for (cp = Columns; cp; cp = cp->GetNext()) {
if (b)
s->Append(",\"");
else
b = true;
s->Append(((PMGOCOL)cp)->GetProjPath(g));
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 cursor; return MaxSize;
} // end of MakeCursor } // end of GetMaxSize
/***********************************************************************/ /***********************************************************************/
/* OpenDB: Data Base open routine for MONGO access method. */ /* OpenDB: Data Base open routine for MONGO access method. */
...@@ -900,10 +512,7 @@ bool TDBMGO::OpenDB(PGLOBAL g) ...@@ -900,10 +512,7 @@ bool TDBMGO::OpenDB(PGLOBAL g)
/*******************************************************************/ /*******************************************************************/
/* Table already open replace it at its beginning. */ /* Table already open replace it at its beginning. */
/*******************************************************************/ /*******************************************************************/
mongoc_cursor_t *cursor = mongoc_cursor_clone(Cursor); Cmgp->Rewind();
mongoc_cursor_destroy(Cursor);
Cursor = cursor;
Fpos = -1; Fpos = -1;
return false; return false;
} // endif Use } // endif Use
...@@ -911,7 +520,7 @@ bool TDBMGO::OpenDB(PGLOBAL g) ...@@ -911,7 +520,7 @@ bool TDBMGO::OpenDB(PGLOBAL g)
/*********************************************************************/ /*********************************************************************/
/* First opening. */ /* First opening. */
/*********************************************************************/ /*********************************************************************/
if (Pipe && Mode != MODE_READ) { if (Pcg.Pipe && Mode != MODE_READ) {
strcpy(g->Message, "Pipeline tables are read only"); strcpy(g->Message, "Pipeline tables are read only");
return true; return true;
} // endif Pipe } // endif Pipe
...@@ -919,20 +528,11 @@ bool TDBMGO::OpenDB(PGLOBAL g) ...@@ -919,20 +528,11 @@ bool TDBMGO::OpenDB(PGLOBAL g)
if (Init(g)) if (Init(g))
return true; return true;
if (Mode == MODE_DELETE && !Next) { if (Mode == MODE_DELETE && !Next)
// Delete all documents // Delete all documents
Query = bson_new(); return Cmgp->DocDelete(g);
else if (Mode == MODE_INSERT)
if (!mongoc_collection_remove(Collection, MONGOC_REMOVE_NONE, Cmgp->MakeColumnGroups(g);
Query, NULL, &Error)) {
sprintf(g->Message, "Mongo remove all: %s", Error.message);
return true;
} // endif remove
} else if (Mode == MODE_INSERT)
MakeColumnGroups(g);
else if (!(Cursor = MakeCursor(g)))
return true;
return false; return false;
} // end of OpenDB } // end of OpenDB
...@@ -951,211 +551,19 @@ bool TDBMGO::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) ...@@ -951,211 +551,19 @@ bool TDBMGO::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
/***********************************************************************/ /***********************************************************************/
int TDBMGO::ReadDB(PGLOBAL g) int TDBMGO::ReadDB(PGLOBAL g)
{ {
int rc = RC_OK; return Cmgp->ReadNext(g);
if (mongoc_cursor_next(Cursor, &Document)) {
if (trace > 1) {
bson_iter_t iter;
ShowDocument(&iter, Document, "");
} else if (trace == 1) {
char *str = bson_as_json(Document, NULL);
htrc("%s\n", str);
bson_free(str);
} // endif trace
} else if (mongoc_cursor_error(Cursor, &Error)) {
sprintf(g->Message, "Mongo Cursor Failure: %s", Error.message);
rc = RC_FX;
} else {
//mongoc_cursor_destroy(Cursor);
rc = RC_EF;
} // endif's Cursor
return rc;
} // end of ReadDB } // end of ReadDB
/***********************************************************************/ /***********************************************************************/
/* Use to trace restaurants document contains. */ /* WriteDB: Data Base write routine for MGO access method. */
/***********************************************************************/
void TDBMGO::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 TDBMGO::MakeColumnGroups(PGLOBAL g)
{
Fpc = new(g) INCOL;
for (PCOL colp = Columns; colp; colp = colp->GetNext())
if (!colp->IsSpecial())
Fpc->AddCol(g, colp, ((PMGOCOL)colp)->Jpath);
} // end of MakeColumnGroups
/***********************************************************************/
/* DocWrite. */
/***********************************************************************/
bool TDBMGO::DocWrite(PGLOBAL g, PINCOL icp)
{
for (PKC kp = icp->Klist; kp; kp = kp->Next)
if (kp->Incolp) {
BSON_APPEND_DOCUMENT_BEGIN(&icp->Child, kp->Key, &kp->Incolp->Child);
if (DocWrite(g, kp->Incolp))
return true;
bson_append_document_end(&icp->Child, &kp->Incolp->Child);
} else if (((PMGOCOL)kp->Colp)->AddValue(g, &icp->Child, kp->Key, false))
return true;
return false;
} // end of DocWrite
/***********************************************************************/
/* WriteDB: Data Base write routine for DOS access method. */
/***********************************************************************/ /***********************************************************************/
int TDBMGO::WriteDB(PGLOBAL g) int TDBMGO::WriteDB(PGLOBAL g)
{ {
int rc = RC_OK; return Cmgp->Write(g);
if (Mode == 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 (Mode == MODE_UPDATE) {
bson_t child;
bson_t *update = bson_new();
BSON_APPEND_DOCUMENT_BEGIN(update, "$set", &child);
for (PCOL colp = To_SetCols; colp; colp = colp->GetNext())
if (((PMGOCOL)colp)->AddValue(g, &child, ((PMGOCOL)colp)->Jpath, 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 WriteDB } // end of WriteDB
/***********************************************************************/ /***********************************************************************/
/* Data Base delete line routine for ODBC access method. */ /* Data Base delete line routine for MGO access method. */
/***********************************************************************/ /***********************************************************************/
int TDBMGO::DeleteDB(PGLOBAL g, int irc) int TDBMGO::DeleteDB(PGLOBAL g, int irc)
{ {
...@@ -1167,15 +575,7 @@ int TDBMGO::DeleteDB(PGLOBAL g, int irc) ...@@ -1167,15 +575,7 @@ int TDBMGO::DeleteDB(PGLOBAL g, int irc)
/***********************************************************************/ /***********************************************************************/
void TDBMGO::CloseDB(PGLOBAL g) void TDBMGO::CloseDB(PGLOBAL g)
{ {
if (Query) bson_destroy(Query); Cmgp->Close();
if (Opts) bson_destroy(Opts);
if (Cursor) mongoc_cursor_destroy(Cursor);
if (Collection) mongoc_collection_destroy(Collection);
// mongoc_database_destroy(Database);
// mongoc_client_destroy(Client);
if (Client) mongoc_client_pool_push(Pool, Client);
if (Pool) mongoc_client_pool_destroy(Pool);
if (Uri) mongoc_uri_destroy(Uri);
Done = false; Done = false;
} // end of CloseDB } // end of CloseDB
...@@ -1189,7 +589,6 @@ MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) ...@@ -1189,7 +589,6 @@ MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
{ {
Tmgp = (PTDBMGO)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); Tmgp = (PTDBMGO)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
Jpath = cdp->GetFmt() ? cdp->GetFmt() : cdp->GetName(); Jpath = cdp->GetFmt() ? cdp->GetFmt() : cdp->GetName();
Mbuf = NULL;
} // end of MGOCOL constructor } // end of MGOCOL constructor
/***********************************************************************/ /***********************************************************************/
...@@ -1200,15 +599,15 @@ MGOCOL::MGOCOL(MGOCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp) ...@@ -1200,15 +599,15 @@ MGOCOL::MGOCOL(MGOCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
{ {
Tmgp = col1->Tmgp; Tmgp = col1->Tmgp;
Jpath = col1->Jpath; Jpath = col1->Jpath;
Mbuf = col1->Mbuf;
} // end of MGOCOL copy constructor } // end of MGOCOL copy constructor
/***********************************************************************/ /***********************************************************************/
/* Get projection path. */ /* Get path when proj is false or projection path when proj is true. */
/***********************************************************************/ /***********************************************************************/
char *MGOCOL::GetProjPath(PGLOBAL g) PSZ MGOCOL::GetJpath(PGLOBAL g, bool proj)
{ {
if (Jpath) { if (Jpath) {
if (proj) {
char *p1, *p2, *projpath = PlugDup(g, Jpath); char *p1, *p2, *projpath = PlugDup(g, Jpath);
int i = 0; int i = 0;
...@@ -1230,143 +629,19 @@ char *MGOCOL::GetProjPath(PGLOBAL g) ...@@ -1230,143 +629,19 @@ char *MGOCOL::GetProjPath(PGLOBAL g)
*p2 = 0; *p2 = 0;
return projpath; return projpath;
} else } else
return NULL; return Jpath;
} // end of GetProjPath
/***********************************************************************/
/* Mini: used to suppress blanks to json strings. */
/***********************************************************************/
char *MGOCOL::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); } else
return Name;
if (i >= Long) {
sprintf(g->Message, "Value too long for column %s", Name);
throw (int)TYPE_AM_MGO;
} // endif i
Mbuf[k] = 0; } // end of GetJpath
return Mbuf;
} // end of Mini
/***********************************************************************/ /***********************************************************************/
/* ReadColumn: */ /* ReadColumn: */
/***********************************************************************/ /***********************************************************************/
void MGOCOL::ReadColumn(PGLOBAL g) void MGOCOL::ReadColumn(PGLOBAL g)
{ {
Tmgp->Cmgp->GetColumnValue(g, this);
if (!strcmp(Jpath, "*")) {
Value->SetValue_psz(Mini(g, Tmgp->Document, false));
} else if (bson_iter_init(&Iter, Tmgp->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_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, doc, false));
bson_destroy(doc);
} else
Value->Reset();
} 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, 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, doc, false));
bson_destroy(doc);
} else {
//strcpy(g->Message, "bson_iter_array failed (data is null)");
//throw (int)TYPE_AM_MGO;
Value->Reset();
} // endif data
} // endif data
} else
Value->Reset();
} else
Value->Reset();
// Set null when applicable
if (Nullable)
Value->SetNull(Value->IsZero());
} // end of ReadColumn } // end of ReadColumn
/***********************************************************************/ /***********************************************************************/
...@@ -1380,59 +655,6 @@ void MGOCOL::WriteColumn(PGLOBAL g) ...@@ -1380,59 +655,6 @@ void MGOCOL::WriteColumn(PGLOBAL g)
} // end of WriteColumn } // end of WriteColumn
/***********************************************************************/
/* AddValue: Add column value to the document to insert or update. */
/***********************************************************************/
bool MGOCOL::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
/* ---------------------------TDBGOL class --------------------------- */ /* ---------------------------TDBGOL class --------------------------- */
/***********************************************************************/ /***********************************************************************/
...@@ -1441,7 +663,8 @@ bool MGOCOL::AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd) ...@@ -1441,7 +663,8 @@ bool MGOCOL::AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd)
TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp) TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp)
{ {
Topt = tdp->GetTopt(); Topt = tdp->GetTopt();
Db = (char*)tdp->GetTabschema(); Uri = tdp->Uri;
Db = tdp->GetTabschema();
} // end of TDBJCL constructor } // end of TDBJCL constructor
/***********************************************************************/ /***********************************************************************/
...@@ -1449,7 +672,7 @@ TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp) ...@@ -1449,7 +672,7 @@ TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp)
/***********************************************************************/ /***********************************************************************/
PQRYRES TDBGOL::GetResult(PGLOBAL g) PQRYRES TDBGOL::GetResult(PGLOBAL g)
{ {
return MGOColumns(g, Db, Topt, false); return MGOColumns(g, Db, Uri, Topt, false);
} // end of GetResult } // end of GetResult
/* -------------------------- End of mongo --------------------------- */ /* -------------------------- End of mongo --------------------------- */
/**************** tabmgo H Declares Source Code File (.H) **************/ /**************** tabmgo H Declares Source Code File (.H) **************/
/* Name: tabmgo.h Version 1.0 */ /* Name: tabmgo.h Version 1.1 */
/* */ /* */
/* (C) Copyright to the author Olivier BERTRAND 2017 */ /* (C) Copyright to the author Olivier BERTRAND 2017 */
/* */ /* */
/* This file contains the MongoDB classes declares. */ /* This file contains the MongoDB classes declares. */
/***********************************************************************/ /***********************************************************************/
#include "osutil.h" #include "mongo.h"
#include "block.h" #include "cmgoconn.h"
#include "colblk.h"
/***********************************************************************/
/* Include MongoDB library header files. */
/***********************************************************************/
#include <bson.h>
#include <bcon.h>
#include <mongoc.h>
typedef class MGODEF *PMGODEF;
typedef class TDBMGO *PTDBMGO;
typedef class MGOCOL *PMGOCOL;
typedef class INCOL *PINCOL;
typedef struct _bncol {
struct _bncol *Next;
char *Name;
char *Fmt;
int Type;
int Len;
int Scale;
bool Cbn;
bool Found;
} BCOL, *PBCOL;
typedef struct KEYCOL {
KEYCOL *Next;
PINCOL Incolp;
PCOL Colp;
char *Key;
} *PKC;
/***********************************************************************/ /***********************************************************************/
/* Class used to get the columns of a mongo collection. */ /* Class used to get the columns of a mongo collection. */
...@@ -48,7 +17,7 @@ class MGODISC : public BLOCK { ...@@ -48,7 +17,7 @@ class MGODISC : public BLOCK {
MGODISC(PGLOBAL g, int *lg); MGODISC(PGLOBAL g, int *lg);
// Functions // Functions
int GetColumns(PGLOBAL g, char *db, PTOS topt); int GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt);
bool FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc, bool FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc,
char *pcn, char *pfmt, int i, int k, bool b); char *pcn, char *pfmt, int i, int k, bool b);
...@@ -62,52 +31,7 @@ class MGODISC : public BLOCK { ...@@ -62,52 +31,7 @@ class MGODISC : public BLOCK {
bool all; bool all;
}; // end of MGODISC }; // end of MGODISC
/***********************************************************************/ /* -------------------------- TDBMGO class --------------------------- */
/* MongoDB table. */
/***********************************************************************/
class DllExport MGODEF : public EXTDEF { /* Table description */
friend class TDBMGO;
friend class MGOFAM;
friend class MGODISC;
friend PQRYRES MGOColumns(PGLOBAL, char *, 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 Uri; /* MongoDB connection URI */
PCSZ Colist; /* Options list */
PCSZ Filter; /* Filtering query */
int Level; /* Used for catalog table */
int Base; /* The array index base */
bool Pipe; /* True is Colist is a pipeline */
}; // end of MGODEF
/* ------------------------- TDBMGO classes -------------------------- */
/***********************************************************************/
/* Used when inserting values in a MongoDB collection. */
/***********************************************************************/
class INCOL : public BLOCK {
public:
// Constructor
INCOL(void) { Klist = NULL; }
// Methods
void AddCol(PGLOBAL g, PCOL colp, char *jp);
//Members
bson_t Child;
PKC Klist;
}; // end of INCOL;
/***********************************************************************/ /***********************************************************************/
/* This is the MongoDB Table Type class declaration. */ /* This is the MongoDB Table Type class declaration. */
...@@ -117,10 +41,10 @@ class DllExport TDBMGO : public TDBEXT { ...@@ -117,10 +41,10 @@ class DllExport TDBMGO : public TDBEXT {
friend class MGOCOL; friend class MGOCOL;
friend class MGODEF; friend class MGODEF;
friend class MGODISC; friend class MGODISC;
friend PQRYRES MGOColumns(PGLOBAL, char *, PTOS, bool); friend PQRYRES MGOColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
public: public:
// Constructor // Constructor
TDBMGO(PMGODEF tdp); TDBMGO(MGODEF *tdp);
TDBMGO(TDBMGO *tdbp); TDBMGO(TDBMGO *tdbp);
// Implementation // Implementation
...@@ -131,7 +55,6 @@ class DllExport TDBMGO : public TDBEXT { ...@@ -131,7 +55,6 @@ class DllExport TDBMGO : public TDBEXT {
virtual PTDB Clone(PTABS t); virtual PTDB Clone(PTABS t);
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
virtual PCOL InsertSpecialColumn(PCOL colp); virtual PCOL InsertSpecialColumn(PCOL colp);
virtual void SetFilter(PFIL fp);
virtual int RowNumber(PGLOBAL g, bool b = FALSE) {return N;} virtual int RowNumber(PGLOBAL g, bool b = FALSE) {return N;}
// Database routines // Database routines
...@@ -146,35 +69,15 @@ class DllExport TDBMGO : public TDBEXT { ...@@ -146,35 +69,15 @@ class DllExport TDBMGO : public TDBEXT {
protected: protected:
bool Init(PGLOBAL g); bool Init(PGLOBAL g);
mongoc_cursor_t *MakeCursor(PGLOBAL g);
void ShowDocument(bson_iter_t *i, const bson_t *b, const char *k);
void MakeColumnGroups(PGLOBAL g);
bool DocWrite(PGLOBAL g, PINCOL icp);
// Members // Members
PGLOBAL G; // Needed by SetFilter CMgoConn *Cmgp; // Points to a C Mongo connection class
mongoc_uri_t *Uri; CMGOPARM Pcg; // Parms passed to Cmgp
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;
PINCOL Fpc; // To insert INCOL classes
const Item *Cnd; // The first condition const Item *Cnd; // The first condition
const char *Uristr;
const char *Db_name;
const char *Coll_name;
const char *Options; // The MongoDB options
const char *Filter; // The filtering query
int Fpos; // The current row index int Fpos; // The current row index
int N; // The current Rownum int N; // The current Rownum
int B; // Array index base int B; // Array index base
bool Done; // Init done bool Done; // Init done
bool Pipe; // True for pipeline
}; // end of class TDBMGO }; // end of class TDBMGO
/* --------------------------- MGOCOL class -------------------------- */ /* --------------------------- MGOCOL class -------------------------- */
...@@ -194,23 +97,17 @@ class DllExport MGOCOL : public EXTCOL { ...@@ -194,23 +97,17 @@ class DllExport MGOCOL : public EXTCOL {
virtual int GetAmType(void) { return Tmgp->GetAmType(); } virtual int GetAmType(void) { return Tmgp->GetAmType(); }
// Methods // 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 ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g);
bool AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd);
protected: protected:
// Default constructor not to be used // Default constructor not to be used
MGOCOL(void) {} MGOCOL(void) {}
char *GetProjPath(PGLOBAL g);
char *Mini(PGLOBAL g, const bson_t *bson, bool b);
// Members // Members
TDBMGO *Tmgp; // To the MGO table block TDBMGO *Tmgp; // To the MGO table block
bson_iter_t Iter; // Used to retrieve column value
bson_iter_t Desc; // Descendant iter
char *Jpath; // The json path char *Jpath; // The json path
char *Mbuf; // The Mini buffer
}; // end of class MGOCOL }; // end of class MGOCOL
/***********************************************************************/ /***********************************************************************/
...@@ -227,5 +124,6 @@ class DllExport TDBGOL : public TDBCAT { ...@@ -227,5 +124,6 @@ class DllExport TDBGOL : public TDBCAT {
// Members // Members
PTOS Topt; PTOS Topt;
char *Db; PCSZ Uri;
PCSZ Db;
}; // end of class TDBGOL }; // end of class TDBGOL
/* Copyright (C) Olivier Bertrand 2004 - 2015 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
that is a connection with its personnal memory allocation. that is a connection with its personnal memory allocation.
@note @note
Author Olivier Bertrand
*/ */
/****************************************************************************/ /****************************************************************************/
...@@ -144,9 +144,9 @@ void user_connect::SetHandler(ha_connect *hc) ...@@ -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. */ /* 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(); uint worksize= GetWorkSize();
PlugCleanup(g, true); PlugCleanup(g, true);
...@@ -171,7 +171,7 @@ bool user_connect::CheckCleanup(void) ...@@ -171,7 +171,7 @@ bool user_connect::CheckCleanup(void)
g->Mrr = 0; g->Mrr = 0;
last_query_id= thdp->query_id; last_query_id= thdp->query_id;
if (trace) if (trace && !force)
printf("=====> Begin new query %llu\n", last_query_id); printf("=====> Begin new query %llu\n", last_query_id);
return true; return true;
......
/* Copyright (C) Olivier Bertrand 2004 - 2011 /* Copyright (C) MariaDB Corporation Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
Declaration of the user_connect class. Declaration of the user_connect class.
@note @note
Author Olivier Bertrand
@see @see
/sql/handler.h and /storage/connect/user_connect.cc /sql/handler.h and /storage/connect/user_connect.cc
...@@ -53,7 +54,7 @@ class user_connect ...@@ -53,7 +54,7 @@ class user_connect
// Implementation // Implementation
bool user_init(); bool user_init();
void SetHandler(ha_connect *hc); void SetHandler(ha_connect *hc);
bool CheckCleanup(void); bool CheckCleanup(bool force = false);
bool CheckQueryID(void) {return thdp->query_id > last_query_id;} bool CheckQueryID(void) {return thdp->query_id > last_query_id;}
bool CheckQuery(query_id_t vid) {return last_query_id > vid;} bool CheckQuery(query_id_t vid) {return last_query_id > vid;}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment