mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 13:32:33 +01:00
5ae2656b69
commit c545d544378483bf68c4fb713cd4ec872d0df2c4 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Tue Mar 27 23:13:14 2018 +0200 - Fix MDEV-15577 CONNECT engine JDBC remote index prevents UPDATE Fixed in TDBJDBC::OpenDB because query can be null for updates modified: storage/connect/tabjdbc.cpp commit c4f1fe2e8e74566e9c3296f435448d9f5c718b23 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Wed Mar 14 12:21:17 2018 +0100 - Fix MDEV-15429 CONNECT engine JDBC handling Postgresql UUID type Also handle Postgresql sending type VARCHAR for TEXT column and setting length to b x7FFFFFF when the length is unknown. modified: storage/connect/Client.java modified: storage/connect/JavaWrappers.jar modified: storage/connect/JdbcInterface.java modified: storage/connect/PostgresqlInterface.java modified: storage/connect/global.h modified: storage/connect/ha_connect.cc modified: storage/connect/jdbconn.cpp modified: storage/connect/jdbconn.h modified: storage/connect/mysql-test/connect/r/jdbc_postgresql.result modified: storage/connect/mysql-test/connect/t/jdbc_postgresql.test modified: storage/connect/mysql-test/connect/t/jdbconn.inc modified: storage/connect/plgdbsem.h modified: storage/connect/tabjdbc.cpp modified: storage/connect/tabjdbc.h added: storage/connect/mysql-test/connect/std_data/JavaWrappers.jar commit 3068bb4882a316c6c32c624609db2bf24ae3ad40 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Mon Feb 26 19:40:27 2018 +0100 Revert to old cmake file to avoid compile error commit da8c1c0bd6a327fd03bd321be3170f468122ef67 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Mon Feb 26 16:13:39 2018 +0100 - Remove warning on not used tabtyp variable in connect_assisted_discovery modified: storage/connect/ha_connect.cc - Fix a bug causing CONNECT to loop when expanding a JSON column when the expanded column value is null or void array. - Adding the FullArray option to JSON tables. - Skipping expanded JSON lines when the expanded column value is null. modified: storage/connect/connect.cc modified: storage/connect/tabdos.h modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h - Fix MDEV-13353 No file privilege for ODBC, JDBC, MONGO, MAC, WMI file types. modified: storage/connect/ha_connect.cc - Make some Json UDFs to accept a non JSON item as 1st parameter. modified: storage/connect/json.cpp modified: storage/connect/json.h modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h - Update Json UDF tests to cope with above changes. modified: storage/connect/mysql-test/connect/r/json_udf.result modified: storage/connect/mysql-test/connect/r/json_udf_bin.result modified: storage/connect/mysql-test/connect/r/vcol.result modified: storage/connect/mysql-test/connect/t/json_udf.test modified: storage/connect/mysql-test/connect/t/vcol.test - Fix some compiler warning treated as error PlugSubAlloc no more exported because it does throw. modified: storage/connect/global.h modified: storage/connect/ha_connect.cc modified: storage/connect/jsonudf.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h - Other files modified (?) when going back to wrong merge modified: storage/connect/CMakeLists.txt modified: storage/connect/array.cpp modified: storage/connect/colblk.cpp modified: storage/connect/connect.cc modified: storage/connect/csort.cpp modified: storage/connect/domdoc.cpp modified: storage/connect/filamap.cpp modified: storage/connect/filamgz.cpp modified: storage/connect/filamtxt.cpp modified: storage/connect/filamzip.cpp modified: storage/connect/filter.cpp modified: storage/connect/fmdlex.c modified: storage/connect/jdbconn.cpp modified: storage/connect/macutil.cpp modified: storage/connect/myconn.cpp modified: storage/connect/odbconn.cpp modified: storage/connect/plgdbutl.cpp modified: storage/connect/plugutil.cpp modified: storage/connect/preparse.h modified: storage/connect/rcmsg.c modified: storage/connect/rcmsg.h modified: storage/connect/reldef.cpp modified: storage/connect/tabdos.cpp modified: storage/connect/tabfmt.cpp modified: storage/connect/tabmac.cpp modified: storage/connect/tabmul.cpp modified: storage/connect/tabmysql.cpp modified: storage/connect/tabmysql.h modified: storage/connect/tabodbc.cpp modified: storage/connect/tabtbl.cpp modified: storage/connect/tabxml.cpp modified: storage/connect/value.cpp modified: storage/connect/xobject.cpp commit 5095628b31ed8c94bd7c794c6b0162894a9040b1 Author: Olivier Bertrand <bertrandop@gmail.com> Date: Tue Feb 13 14:29:00 2018 +0100 - Fix a bug causing CONNECT to loop when expanding a JSON column when the expanded column value is null or void array. - Adding the FullArray option to JSON tables. - Skipping expanded JSON lines when the expanded column value is null. modified: storage/connect/connect.cc modified: storage/connect/tabdos.h modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h commit 9896174328da42016735630c893fd09eb128b48e Author: Olivier Bertrand <bertrandop@gmail.com> Date: Fri Feb 2 15:48:57 2018 +0100 - Remove warning on not used tabtyp variable in connect_assisted_discovery modified: storage/connect/ha_connect.cc commit d7e254c05f88173eb04d8dafc813013eb42ccdbe Author: Olivier Bertrand <bertrandop@gmail.com> Date: Wed Jan 31 14:42:45 2018 +0100 - Use delayed load for the MongoDB C Drive on Windows modified: storage/connect/CMakeLists.txt modified: storage/connect/cmgoconn.cpp modified: storage/connect/ha_connect.cc - Add FORCE to the connect_type_conv enum values This will translate binary values to TYPE_STRING modified: storage/connect/checklvl.h modified: storage/connect/ha_connect.cc modified: storage/connect/odbconn.cpp - Change the connect_xtrace variable to from int to set modified: storage/connect/array.cpp modified: storage/connect/blkfil.cpp modified: storage/connect/block.h modified: storage/connect/cmgoconn.cpp modified: storage/connect/colblk.cpp modified: storage/connect/connect.cc modified: storage/connect/filamap.cpp modified: storage/connect/filamdbf.cpp modified: storage/connect/filamfix.cpp modified: storage/connect/filamgz.cpp modified: storage/connect/filamtxt.cpp modified: storage/connect/filamvct.cpp modified: storage/connect/filamzip.cpp modified: storage/connect/filter.cpp modified: storage/connect/global.h modified: storage/connect/ha_connect.cc modified: storage/connect/inihandl.cpp modified: storage/connect/javaconn.cpp modified: storage/connect/jdbconn.cpp modified: storage/connect/jmgfam.cpp modified: storage/connect/jmgoconn.cpp modified: storage/connect/json.cpp modified: storage/connect/jsonudf.cpp modified: storage/connect/libdoc.cpp modified: storage/connect/mongo.cpp modified: storage/connect/mycat.cc modified: storage/connect/myconn.cpp modified: storage/connect/odbconn.cpp modified: storage/connect/plgdbutl.cpp modified: storage/connect/plugutil.cpp modified: storage/connect/reldef.cpp modified: storage/connect/tabcol.cpp modified: storage/connect/tabdos.cpp modified: storage/connect/tabext.cpp modified: storage/connect/tabfix.cpp modified: storage/connect/tabfmt.cpp modified: storage/connect/tabjdbc.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/table.cpp modified: storage/connect/tabmul.cpp modified: storage/connect/tabmysql.cpp modified: storage/connect/tabodbc.cpp modified: storage/connect/tabpivot.cpp modified: storage/connect/tabsys.cpp modified: storage/connect/tabtbl.cpp modified: storage/connect/tabutil.cpp modified: storage/connect/tabvct.cpp modified: storage/connect/tabwmi.cpp modified: storage/connect/tabxml.cpp modified: storage/connect/user_connect.cc modified: storage/connect/valblk.cpp modified: storage/connect/value.cpp modified: storage/connect/xindex.cpp - Restore connect_enable_mongo variable (but undocumented) modified: storage/connect/ha_connect.cc modified: storage/connect/mycat.cc modified: storage/connect/mysql-test/connect/r/json_java_2.result modified: storage/connect/mysql-test/connect/r/json_java_3.result modified: storage/connect/mysql-test/connect/r/json_mongo_c.result modified: storage/connect/mysql-test/connect/r/mongo_c.result modified: storage/connect/mysql-test/connect/r/mongo_java_2.result modified: storage/connect/mysql-test/connect/r/mongo_java_3.result modified: storage/connect/mysql-test/connect/r/tbl_thread.result modified: storage/connect/mysql-test/connect/t/mongo.inc modified: storage/connect/mysql-test/connect/t/mongo_test.inc modified: storage/connect/mysql-test/connect/t/tbl_thread.test
1303 lines
40 KiB
C++
1303 lines
40 KiB
C++
/************* TabJDBC C++ Program Source Code File (.CPP) *************/
|
|
/* PROGRAM NAME: TABJDBC */
|
|
/* ------------- */
|
|
/* Version 1.2 */
|
|
/* */
|
|
/* COPYRIGHT: */
|
|
/* ---------- */
|
|
/* (C) Copyright to the author Olivier BERTRAND 2016-2017 */
|
|
/* */
|
|
/* WHAT THIS PROGRAM DOES: */
|
|
/* ----------------------- */
|
|
/* This program are the TABJDBC class DB execution routines. */
|
|
/* */
|
|
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
|
/* -------------------------------------- */
|
|
/* */
|
|
/* REQUIRED FILES: */
|
|
/* --------------- */
|
|
/* TABJDBC.CPP - Source code */
|
|
/* PLGDBSEM.H - DB application declaration file */
|
|
/* TABJDBC.H - TABJDBC classes declaration file */
|
|
/* GLOBAL.H - Global declaration file */
|
|
/* */
|
|
/* REQUIRED LIBRARIES: */
|
|
/* ------------------- */
|
|
/* Large model C library */
|
|
/* */
|
|
/* REQUIRED PROGRAMS: */
|
|
/* ------------------ */
|
|
/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
|
|
/* */
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
/* Include relevant MariaDB header file. */
|
|
/***********************************************************************/
|
|
#define MYSQL_SERVER 1
|
|
#include "my_global.h"
|
|
#include "sql_class.h"
|
|
#include "sql_servers.h"
|
|
#if defined(__WIN__)
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#if defined(__BORLANDC__)
|
|
#define __MFC_COMPAT__ // To define min/max as macro
|
|
#endif
|
|
//#include <windows.h>
|
|
#include <sqltypes.h>
|
|
#else
|
|
#if defined(UNIX)
|
|
#include <errno.h>
|
|
#define NODW
|
|
#include "osutil.h"
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
/***********************************************************************/
|
|
/* Include application header files: */
|
|
/* global.h is header containing all global declarations. */
|
|
/* plgdbsem.h is header containing the DB application declarations. */
|
|
/* kindex.h is kindex header that also includes tabdos.h. */
|
|
/* tabJDBC.h is header containing the TABJDBC class declarations. */
|
|
/* JDBConn.h is header containing JDBC connection declarations. */
|
|
/***********************************************************************/
|
|
#include "global.h"
|
|
#include "plgdbsem.h"
|
|
#include "mycat.h"
|
|
#include "xtable.h"
|
|
#include "tabext.h"
|
|
#include "tabjdbc.h"
|
|
#include "tabmul.h"
|
|
//#include "reldef.h"
|
|
#include "tabcol.h"
|
|
#include "valblk.h"
|
|
#include "ha_connect.h"
|
|
|
|
#include "sql_string.h"
|
|
|
|
/***********************************************************************/
|
|
/* DB static variables. */
|
|
/***********************************************************************/
|
|
// int num_read, num_there, num_eq[2], num_nf; // Statistics
|
|
extern int num_read, num_there, num_eq[2]; // Statistics
|
|
|
|
/***********************************************************************/
|
|
/* External function. */
|
|
/***********************************************************************/
|
|
bool ExactInfo(void);
|
|
|
|
/* -------------------------- Class JDBCDEF -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* Constructor. */
|
|
/***********************************************************************/
|
|
JDBCDEF::JDBCDEF(void)
|
|
{
|
|
Driver = Url = Wrapname = NULL;
|
|
} // end of JDBCDEF constructor
|
|
|
|
/***********************************************************************/
|
|
/* Called on table construction. */
|
|
/***********************************************************************/
|
|
bool JDBCDEF::SetParms(PJPARM sjp)
|
|
{
|
|
sjp->Url= Url;
|
|
sjp->User= Username;
|
|
sjp->Pwd= Password;
|
|
//sjp->Properties = Prop;
|
|
return true;
|
|
} // end of SetParms
|
|
|
|
/***********************************************************************/
|
|
/* Parse connection string */
|
|
/* */
|
|
/* SYNOPSIS */
|
|
/* ParseURL() */
|
|
/* Url The connection string to parse */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* This is used to set the Url in case a wrapper server as been */
|
|
/* specified. This is rather experimental yet. */
|
|
/* */
|
|
/* RETURN VALUE */
|
|
/* RC_OK Url was a true URL */
|
|
/* RC_NF Url was a server name/table */
|
|
/* RC_FX Error */
|
|
/* */
|
|
/***********************************************************************/
|
|
int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b)
|
|
{
|
|
if (strncmp(url, "jdbc:", 5)) {
|
|
PSZ p;
|
|
|
|
// No "jdbc:" in connection string. Must be a straight
|
|
// "server" or "server/table"
|
|
// ok, so we do a little parsing, but not completely!
|
|
if ((p = strchr(url, '/'))) {
|
|
// If there is a single '/' in the connection string,
|
|
// this means the user is specifying a table name
|
|
*p++= '\0';
|
|
|
|
// there better not be any more '/'s !
|
|
if (strchr(p, '/'))
|
|
return RC_FX;
|
|
|
|
Tabname = p;
|
|
// } else if (b) {
|
|
// // Otherwise, straight server name,
|
|
// Tabname = GetStringCatInfo(g, "Name", NULL);
|
|
// Tabname = GetStringCatInfo(g, "Tabname", Tabname);
|
|
} // endif
|
|
|
|
if (trace(1))
|
|
htrc("server: %s Tabname: %s", url, Tabname);
|
|
|
|
// Now make the required URL
|
|
FOREIGN_SERVER *server, server_buffer;
|
|
|
|
// get_server_by_name() clones the server if exists
|
|
if (!(server= get_server_by_name(current_thd->mem_root, url, &server_buffer))) {
|
|
sprintf(g->Message, "Server %s does not exist!", url);
|
|
return RC_FX;
|
|
} // endif server
|
|
|
|
if (strncmp(server->host, "jdbc:", 5)) {
|
|
// Now make the required URL
|
|
Url = (PSZ)PlugSubAlloc(g, NULL, 0);
|
|
strcat(strcpy(Url, "jdbc:"), server->scheme);
|
|
strcat(strcat(Url, "://"), server->host);
|
|
|
|
if (server->port) {
|
|
char buf[16];
|
|
|
|
sprintf(buf, "%ld", server->port);
|
|
strcat(strcat(Url, ":"), buf);
|
|
} // endif port
|
|
|
|
if (server->db)
|
|
strcat(strcat(Url, "/"), server->db);
|
|
|
|
PlugSubAlloc(g, NULL, strlen(Url) + 1);
|
|
} else // host is a URL
|
|
Url = PlugDup(g, server->host);
|
|
|
|
if (server->username)
|
|
Username = PlugDup(g, server->username);
|
|
|
|
if (server->password)
|
|
Password = PlugDup(g, server->password);
|
|
|
|
return RC_NF;
|
|
} // endif
|
|
|
|
// Url was a JDBC URL, nothing to do
|
|
return RC_OK;
|
|
} // end of ParseURL
|
|
|
|
/***********************************************************************/
|
|
/* DefineAM: define specific AM block values from JDBC file. */
|
|
/***********************************************************************/
|
|
bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
|
{
|
|
int rc = RC_OK;
|
|
|
|
if (EXTDEF::DefineAM(g, am, poff))
|
|
return true;
|
|
|
|
Driver = GetStringCatInfo(g, "Driver", NULL);
|
|
Desc = Url = GetStringCatInfo(g, "Connect", NULL);
|
|
|
|
if (!Url && !Catfunc) {
|
|
// Look in the option list (deprecated)
|
|
Url = GetStringCatInfo(g, "Url", NULL);
|
|
|
|
if (!Url) {
|
|
sprintf(g->Message, "Missing URL for JDBC table %s", Name);
|
|
return true;
|
|
} // endif Url
|
|
|
|
} // endif Connect
|
|
|
|
if (Url)
|
|
if ((rc = ParseURL(g, Url)) == RC_FX) {
|
|
sprintf(g->Message, "Wrong JDBC URL %s", Url);
|
|
return true;
|
|
} // endif rc
|
|
|
|
Wrapname = GetStringCatInfo(g, "Wrapper", NULL);
|
|
return false;
|
|
} // end of DefineAM
|
|
|
|
/***********************************************************************/
|
|
/* GetTable: makes a new Table Description Block. */
|
|
/***********************************************************************/
|
|
PTDB JDBCDEF::GetTable(PGLOBAL g, MODE m)
|
|
{
|
|
PTDB tdbp = NULL;
|
|
|
|
/*********************************************************************/
|
|
/* Allocate a TDB of the proper type. */
|
|
/* Column blocks will be allocated only when needed. */
|
|
/*********************************************************************/
|
|
if (Xsrc)
|
|
tdbp = new(g)TDBXJDC(this);
|
|
else switch (Catfunc) {
|
|
case FNC_COL:
|
|
tdbp = new(g)TDBJDBCL(this);
|
|
break;
|
|
#if 0
|
|
case FNC_DSN:
|
|
tdbp = new(g)TDBJSRC(this);
|
|
break;
|
|
#endif // 0
|
|
case FNC_TABLE:
|
|
tdbp = new(g)TDBJTB(this);
|
|
break;
|
|
case FNC_DRIVER:
|
|
tdbp = new(g)TDBJDRV(this);
|
|
break;
|
|
default:
|
|
tdbp = new(g)TDBJDBC(this);
|
|
|
|
if (Multiple == 1)
|
|
tdbp = new(g)TDBMUL(tdbp);
|
|
else if (Multiple == 2)
|
|
strcpy(g->Message, "NO_JDBC_MUL");
|
|
|
|
} // endswitch Catfunc
|
|
|
|
return tdbp;
|
|
} // end of GetTable
|
|
|
|
/***********************************************************************/
|
|
/* The MySQL and MariaDB JDBC drivers return by default a result set */
|
|
/* containing the entire result of the executed query. This can be an */
|
|
/* issue for big tables and memory error can occur. An alternative is */
|
|
/* to use streaming (reading one row at a time) but to specify this, */
|
|
/* a fech size of the integer min value must be send to the driver. */
|
|
/***********************************************************************/
|
|
int JDBCPARM::CheckSize(int rows)
|
|
{
|
|
if (Url && rows == 1) {
|
|
// Are we connected to a MySQL JDBC connector?
|
|
bool b = (!strncmp(Url, "jdbc:mysql:", 11) ||
|
|
!strncmp(Url, "jdbc:mariadb:", 13));
|
|
return b ? INT_MIN32 : rows;
|
|
} else
|
|
return rows;
|
|
|
|
} // end of CheckSize
|
|
|
|
/* -------------------------- Class TDBJDBC -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* Implementation of the TDBJDBC class. */
|
|
/***********************************************************************/
|
|
TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBEXT(tdp)
|
|
{
|
|
Jcp = NULL;
|
|
Cnp = NULL;
|
|
|
|
if (tdp) {
|
|
Ops.Driver = tdp->Driver;
|
|
Ops.Url = tdp->Url;
|
|
Wrapname = tdp->Wrapname;
|
|
Ops.User = tdp->Username;
|
|
Ops.Pwd = tdp->Password;
|
|
Ops.Scrollable = tdp->Scrollable;
|
|
} else {
|
|
Wrapname = NULL;
|
|
Ops.Driver = NULL;
|
|
Ops.Url = NULL;
|
|
Ops.User = NULL;
|
|
Ops.Pwd = NULL;
|
|
Ops.Scrollable = false;
|
|
} // endif tdp
|
|
|
|
Prepared = false;
|
|
Werr = false;
|
|
Rerr = false;
|
|
Ops.Fsize = Ops.CheckSize(Rows);
|
|
} // end of TDBJDBC standard constructor
|
|
|
|
TDBJDBC::TDBJDBC(PTDBJDBC tdbp) : TDBEXT(tdbp)
|
|
{
|
|
Jcp = tdbp->Jcp; // is that right ?
|
|
Cnp = tdbp->Cnp;
|
|
Wrapname = tdbp->Wrapname;
|
|
Ops = tdbp->Ops;
|
|
Prepared = tdbp->Prepared;
|
|
Werr = tdbp->Werr;
|
|
Rerr = tdbp->Rerr;
|
|
} // end of TDBJDBC copy constructor
|
|
|
|
// Method
|
|
PTDB TDBJDBC::Clone(PTABS t)
|
|
{
|
|
PTDB tp;
|
|
PJDBCCOL cp1, cp2;
|
|
PGLOBAL g = t->G; // Is this really useful ???
|
|
|
|
tp = new(g)TDBJDBC(this);
|
|
|
|
for (cp1 = (PJDBCCOL)Columns; cp1; cp1 = (PJDBCCOL)cp1->GetNext()) {
|
|
cp2 = new(g)JDBCCOL(cp1, tp); // Make a copy
|
|
NewPointer(t, cp1, cp2);
|
|
} // endfor cp1
|
|
|
|
return tp;
|
|
} // end of Clone
|
|
|
|
/***********************************************************************/
|
|
/* Allocate JDBC column description block. */
|
|
/***********************************************************************/
|
|
PCOL TDBJDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
|
{
|
|
return new(g)JDBCCOL(cdp, this, cprec, n);
|
|
} // end of MakeCol
|
|
|
|
/***********************************************************************/
|
|
/* MakeInsert: make the Insert statement used with JDBC connection. */
|
|
/***********************************************************************/
|
|
bool TDBJDBC::MakeInsert(PGLOBAL g)
|
|
{
|
|
PCSZ schmp = NULL;
|
|
char *catp = NULL, buf[NAM_LEN * 3];
|
|
int len = 0;
|
|
uint pos;
|
|
bool b = false;
|
|
PTABLE tablep = To_Table;
|
|
PCOL colp;
|
|
|
|
for (colp = Columns; colp; colp = colp->GetNext())
|
|
if (colp->IsSpecial()) {
|
|
strcpy(g->Message, "No JDBC special columns");
|
|
return true;
|
|
} else {
|
|
// Column name can be encoded in UTF-8
|
|
Decode(colp->GetName(), buf, sizeof(buf));
|
|
len += (strlen(buf) + 6); // comma + quotes + valist
|
|
((PEXTCOL)colp)->SetRank(++Nparm);
|
|
} // endif colp
|
|
|
|
// Below 32 is enough to contain the fixed part of the query
|
|
if (Catalog && *Catalog)
|
|
catp = Catalog;
|
|
|
|
if (catp)
|
|
len += strlen(catp) + 1;
|
|
|
|
//if (tablep->GetSchema())
|
|
// schmp = (char*)tablep->GetSchema();
|
|
//else
|
|
if (Schema && *Schema)
|
|
schmp = Schema;
|
|
|
|
if (schmp)
|
|
len += strlen(schmp) + 1;
|
|
|
|
// Table name can be encoded in UTF-8
|
|
Decode(TableName, buf, sizeof(buf));
|
|
len += (strlen(buf) + 32);
|
|
Query = new(g)STRING(g, len, "INSERT INTO ");
|
|
|
|
if (catp) {
|
|
Query->Append(catp);
|
|
|
|
if (schmp) {
|
|
Query->Append('.');
|
|
Query->Append(schmp);
|
|
} // endif schmp
|
|
|
|
Query->Append('.');
|
|
} else if (schmp) {
|
|
Query->Append(schmp);
|
|
Query->Append('.');
|
|
} // endif schmp
|
|
|
|
if (Quote) {
|
|
// Put table name between identifier quotes in case in contains blanks
|
|
Query->Append(Quote);
|
|
Query->Append(buf);
|
|
Query->Append(Quote);
|
|
} else
|
|
Query->Append(buf);
|
|
|
|
Query->Append('(');
|
|
|
|
for (colp = Columns; colp; colp = colp->GetNext()) {
|
|
if (b)
|
|
Query->Append(", ");
|
|
else
|
|
b = true;
|
|
|
|
// Column name can be in UTF-8 encoding
|
|
Decode(colp->GetName(), buf, sizeof(buf));
|
|
|
|
if (Quote) {
|
|
// Put column name between identifier quotes in case in contains blanks
|
|
Query->Append(Quote);
|
|
Query->Append(buf);
|
|
Query->Append(Quote);
|
|
} else
|
|
Query->Append(buf);
|
|
|
|
} // endfor colp
|
|
|
|
if ((Query->Append(") VALUES ("))) {
|
|
strcpy(g->Message, "MakeInsert: Out of memory");
|
|
return true;
|
|
} else // in case prepared statement fails
|
|
pos = Query->GetLength();
|
|
|
|
// Make prepared statement
|
|
for (int i = 0; i < Nparm; i++)
|
|
Query->Append("?,");
|
|
|
|
if (Query->IsTruncated()) {
|
|
strcpy(g->Message, "MakeInsert: Out of memory");
|
|
return true;
|
|
} else
|
|
Query->RepLast(')');
|
|
|
|
// Now see if we can use prepared statement
|
|
if (Jcp->PrepareSQL(Query->GetStr()))
|
|
Query->Truncate(pos); // Restore query to not prepared
|
|
else
|
|
Prepared = true;
|
|
|
|
if (trace(33))
|
|
htrc("Insert=%s\n", Query->GetStr());
|
|
|
|
return false;
|
|
} // end of MakeInsert
|
|
|
|
/***********************************************************************/
|
|
/* JDBC Set Parameter function. */
|
|
/***********************************************************************/
|
|
bool TDBJDBC::SetParameters(PGLOBAL g)
|
|
{
|
|
PJDBCCOL colp;
|
|
|
|
for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next)
|
|
if (Jcp->SetParam(colp))
|
|
return true;
|
|
|
|
return false;
|
|
} // end of SetParameters
|
|
|
|
/***********************************************************************/
|
|
/* ResetSize: call by TDBMUL when calculating size estimate. */
|
|
/***********************************************************************/
|
|
void TDBJDBC::ResetSize(void)
|
|
{
|
|
MaxSize = -1;
|
|
|
|
if (Jcp && Jcp->IsOpen())
|
|
Jcp->Close();
|
|
|
|
} // end of ResetSize
|
|
|
|
/***********************************************************************/
|
|
/* JDBC Cardinality: returns table size in number of rows. */
|
|
/***********************************************************************/
|
|
int TDBJDBC::Cardinality(PGLOBAL g)
|
|
{
|
|
if (!g)
|
|
return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
|
|
|
|
#if 0
|
|
if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) {
|
|
// Info command, we must return the exact table row number
|
|
char qry[96], tbn[64];
|
|
JDBConn *jcp = new(g)JDBConn(g, this);
|
|
|
|
if (jcp->Open(&Ops) == RC_FX)
|
|
return -1;
|
|
|
|
// Table name can be encoded in UTF-8
|
|
Decode(TableName, tbn, sizeof(tbn));
|
|
strcpy(qry, "SELECT COUNT(*) FROM ");
|
|
|
|
if (Quote)
|
|
strcat(strcat(strcat(qry, Quote), tbn), Quote);
|
|
else
|
|
strcat(qry, tbn);
|
|
|
|
// Allocate a Count(*) column (must not use the default constructor)
|
|
Cnp = new(g)JDBCCOL;
|
|
Cnp->InitValue(g);
|
|
|
|
if ((Cardinal = jcp->GetResultSize(qry, Cnp)) < 0)
|
|
return -3;
|
|
|
|
jcp->Close();
|
|
} else
|
|
#endif // 0
|
|
Cardinal = 10; // To make MariaDB happy
|
|
|
|
return Cardinal;
|
|
} // end of Cardinality
|
|
|
|
/***********************************************************************/
|
|
/* JDBC Access Method opening routine. */
|
|
/* New method now that this routine is called recursively (last table */
|
|
/* first in reverse order): index blocks are immediately linked to */
|
|
/* join block of next table if it exists or else are discarted. */
|
|
/***********************************************************************/
|
|
bool TDBJDBC::OpenDB(PGLOBAL g)
|
|
{
|
|
bool rc = true;
|
|
|
|
if (trace(1))
|
|
htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
|
|
this, Tdb_No, Use, Mode);
|
|
|
|
if (Use == USE_OPEN) {
|
|
/*******************************************************************/
|
|
/* Table already open, just replace it at its beginning. */
|
|
/*******************************************************************/
|
|
if (Memory == 1) {
|
|
if ((Qrp = Jcp->AllocateResult(g, this)))
|
|
Memory = 2; // Must be filled
|
|
else
|
|
Memory = 0; // Allocation failed, don't use it
|
|
|
|
} else if (Memory == 2)
|
|
Memory = 3; // Ok to use memory result
|
|
|
|
if (Memory < 3) {
|
|
// Method will depend on cursor type
|
|
if ((Rbuf = Query ? Jcp->Rewind(Query->GetStr()) : 0) < 0)
|
|
if (Mode != MODE_READX) {
|
|
Jcp->Close();
|
|
return true;
|
|
} else
|
|
Rbuf = 0;
|
|
|
|
} else
|
|
Rbuf = Qrp->Nblin;
|
|
|
|
CurNum = 0;
|
|
Fpos = 0;
|
|
Curpos = 1;
|
|
return false;
|
|
} // endif use
|
|
|
|
/*********************************************************************/
|
|
/* 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)JDBConn(g, Wrapname);
|
|
else if (Jcp->IsOpen())
|
|
Jcp->Close();
|
|
|
|
if (Jcp->Connect(&Ops))
|
|
return true;
|
|
else if (Quoted)
|
|
Quote = Jcp->GetQuoteChar();
|
|
|
|
if (Mode != MODE_READ && Mode != MODE_READX)
|
|
if (Jcp->SetUUID(g, this))
|
|
PushWarning(g, this, 1);
|
|
|
|
Use = USE_OPEN; // Do it now in case we are recursively called
|
|
|
|
/*********************************************************************/
|
|
/* Make the command and allocate whatever is used for getting results*/
|
|
/*********************************************************************/
|
|
if (Mode == MODE_READ || Mode == MODE_READX) {
|
|
if (Memory > 1 && !Srcdef) {
|
|
int n;
|
|
|
|
if (!MakeSQL(g, true)) {
|
|
// Allocate a Count(*) column
|
|
Cnp = new(g)JDBCCOL;
|
|
Cnp->InitValue(g);
|
|
|
|
if ((n = Jcp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
|
|
sprintf(g->Message, "Cannot get result size rc=%d", n);
|
|
return true;
|
|
} else if (n) {
|
|
Jcp->m_Rows = n;
|
|
|
|
if ((Qrp = Jcp->AllocateResult(g, this)))
|
|
Memory = 2; // Must be filled
|
|
else {
|
|
strcpy(g->Message, "Result set memory allocation failed");
|
|
return true;
|
|
} // endif n
|
|
|
|
} else // Void result
|
|
Memory = 0;
|
|
|
|
Jcp->m_Rows = 0;
|
|
} else
|
|
return true;
|
|
|
|
} // endif Memory
|
|
|
|
if (!(rc = MakeSQL(g, false))) {
|
|
// for (PJDBCCOL colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->GetNext())
|
|
// if (!colp->IsSpecial())
|
|
// colp->AllocateBuffers(g, Rows);
|
|
|
|
rc = (Mode == MODE_READ)
|
|
? (Jcp->ExecuteQuery(Query->GetStr()) != RC_OK)
|
|
: false;
|
|
} // endif rc
|
|
|
|
} else if (Mode == MODE_INSERT) {
|
|
#if 0
|
|
if (!(rc = MakeInsert(g))) {
|
|
if (Nparm != Jcp->PrepareSQL(Query->GetStr())) {
|
|
strcpy(g->Message, MSG(PARM_CNT_MISS));
|
|
rc = true;
|
|
} else
|
|
rc = BindParameters(g);
|
|
|
|
} // endif rc
|
|
#endif // 0
|
|
rc = MakeInsert(g);
|
|
} else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
|
rc = false; // wait for CheckCond before calling MakeCommand(g);
|
|
} else
|
|
sprintf(g->Message, "Invalid mode %d", Mode);
|
|
|
|
if (rc) {
|
|
Jcp->Close();
|
|
return true;
|
|
} // endif rc
|
|
|
|
/*********************************************************************/
|
|
/* Reset statistics values. */
|
|
/*********************************************************************/
|
|
num_read = num_there = num_eq[0] = num_eq[1] = 0;
|
|
return false;
|
|
} // end of OpenDB
|
|
|
|
#if 0
|
|
/***********************************************************************/
|
|
/* GetRecpos: return the position of last read record. */
|
|
/***********************************************************************/
|
|
int TDBJDBC::GetRecpos(void)
|
|
{
|
|
return Fpos;
|
|
} // end of GetRecpos
|
|
#endif // 0
|
|
|
|
/***********************************************************************/
|
|
/* SetRecpos: set the position of next read record. */
|
|
/***********************************************************************/
|
|
bool TDBJDBC::SetRecpos(PGLOBAL g, int recpos)
|
|
{
|
|
if (Jcp->m_Full) {
|
|
Fpos = 0;
|
|
CurNum = 1;
|
|
} else if (Memory == 3) {
|
|
Fpos = 0;
|
|
CurNum = recpos;
|
|
} else if (Ops.Scrollable) {
|
|
// Is new position in the current row set?
|
|
if (recpos > 0 && recpos <= Rbuf) {
|
|
CurNum = recpos;
|
|
Fpos = recpos;
|
|
} else {
|
|
strcpy(g->Message, "Scrolling out of row set NIY");
|
|
return true;
|
|
} // endif recpos
|
|
|
|
} else {
|
|
strcpy(g->Message, "This action requires a scrollable cursor");
|
|
return true;
|
|
} // endif's
|
|
|
|
// Indicate the table position was externally set
|
|
Placed = true;
|
|
return false;
|
|
} // end of SetRecpos
|
|
|
|
/***********************************************************************/
|
|
/* Data Base indexed read routine for JDBC access method. */
|
|
/***********************************************************************/
|
|
bool TDBJDBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
|
|
{
|
|
char c = Quote ? *Quote : 0;
|
|
int rc, oldlen = Query->GetLength();
|
|
PHC hc = To_Def->GetHandler();
|
|
|
|
if (!(kr || hc->end_range) || op == OP_NEXT ||
|
|
Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
|
if (!kr && Mode == MODE_READX) {
|
|
// This is a false indexed read
|
|
rc = Jcp->ExecuteQuery((char*)Query->GetStr());
|
|
Mode = MODE_READ;
|
|
Rows = 1; // ???
|
|
return (rc != RC_OK);
|
|
} // endif key
|
|
|
|
return false;
|
|
} else {
|
|
if (hc->MakeKeyWhere(g, Query, op, c, kr))
|
|
return true;
|
|
|
|
if (To_CondFil) {
|
|
if (To_CondFil->Idx != hc->active_index) {
|
|
To_CondFil->Idx = hc->active_index;
|
|
To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
|
|
*To_CondFil->Body= 0;
|
|
|
|
if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond)))
|
|
PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
|
|
|
|
} // endif active_index
|
|
|
|
if (To_CondFil)
|
|
if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
|
|
strcpy(g->Message, "Readkey: Out of memory");
|
|
return true;
|
|
} // endif Append
|
|
|
|
} // endif To_Condfil
|
|
|
|
Mode = MODE_READ;
|
|
} // endif's op
|
|
|
|
if (trace(33))
|
|
htrc("JDBC ReadKey: Query=%s\n", Query->GetStr());
|
|
|
|
rc = Jcp->ExecuteQuery((char*)Query->GetStr());
|
|
Query->Truncate(oldlen);
|
|
Rows = 1; // ???
|
|
return (rc != RC_OK);
|
|
} // end of ReadKey
|
|
|
|
/***********************************************************************/
|
|
/* Data Base read routine for JDBC access method. */
|
|
/***********************************************************************/
|
|
int TDBJDBC::ReadDB(PGLOBAL g)
|
|
{
|
|
int rc;
|
|
|
|
if (trace(2))
|
|
htrc("JDBC ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
|
|
|
|
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
|
if (!Query && MakeCommand(g))
|
|
return RC_FX;
|
|
|
|
// Send the UPDATE/DELETE command to the remote table
|
|
rc = Jcp->ExecuteUpdate(Query->GetStr());
|
|
|
|
if (rc == RC_OK) {
|
|
AftRows = Jcp->m_Aff;
|
|
return RC_EF; // Nothing else to do
|
|
} else {
|
|
Werr = true;
|
|
return RC_FX;
|
|
} // endif rc
|
|
|
|
} // endif Mode
|
|
|
|
/*********************************************************************/
|
|
/* Now start the reading process. */
|
|
/* Here is the place to fetch the line(s). */
|
|
/*********************************************************************/
|
|
if (Placed) {
|
|
if (Fpos && CurNum >= 0)
|
|
Rbuf = Jcp->Fetch((Curpos = Fpos));
|
|
else
|
|
Fpos = CurNum;
|
|
|
|
rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
|
|
Placed = false;
|
|
} else {
|
|
if (Memory != 3) {
|
|
if (++CurNum >= Rbuf) {
|
|
Rbuf = Jcp->Fetch();
|
|
Curpos = Fpos + 1;
|
|
CurNum = 0;
|
|
} // endif CurNum
|
|
|
|
rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
|
|
} else // Getting result from memory
|
|
rc = (Fpos < Qrp->Nblin) ? RC_OK : RC_EF;
|
|
|
|
if (rc == RC_OK) {
|
|
if (Memory == 2)
|
|
Qrp->Nblin++;
|
|
|
|
Fpos++; // Used for memory and pos
|
|
} // endif rc
|
|
|
|
} // endif placed
|
|
|
|
if (trace(2))
|
|
htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
|
|
|
|
return rc;
|
|
} // end of ReadDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base Insert write routine for JDBC access method. */
|
|
/***********************************************************************/
|
|
int TDBJDBC::WriteDB(PGLOBAL g)
|
|
{
|
|
int rc;
|
|
|
|
if (Prepared) {
|
|
if (SetParameters(g)) {
|
|
Werr = true;
|
|
rc = RC_FX;
|
|
} else if ((rc = Jcp->ExecuteSQL()) == RC_OK)
|
|
AftRows += Jcp->m_Aff;
|
|
else
|
|
Werr = true;
|
|
|
|
return rc;
|
|
} // endif Prepared
|
|
|
|
// Statement was not prepared, we must construct and execute
|
|
// an insert query for each line to insert
|
|
uint len = Query->GetLength();
|
|
char buf[64];
|
|
|
|
// Make the Insert command value list
|
|
for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
|
|
if (!colp->GetValue()->IsNull()) {
|
|
char *s = colp->GetValue()->GetCharString(buf);
|
|
|
|
if (colp->GetResultType() == TYPE_STRING)
|
|
Query->Append_quoted(s);
|
|
else if (colp->GetResultType() == TYPE_DATE) {
|
|
DTVAL *dtv = (DTVAL*)colp->GetValue();
|
|
|
|
if (dtv->IsFormatted())
|
|
Query->Append_quoted(s);
|
|
else
|
|
Query->Append(s);
|
|
|
|
} else
|
|
Query->Append(s);
|
|
|
|
} else
|
|
Query->Append("NULL");
|
|
|
|
Query->Append(',');
|
|
} // endfor colp
|
|
|
|
if (unlikely(Query->IsTruncated())) {
|
|
strcpy(g->Message, "WriteDB: Out of memory");
|
|
return RC_FX;
|
|
} // endif Query
|
|
|
|
Query->RepLast(')');
|
|
|
|
if (trace(2))
|
|
htrc("Inserting: %s\n", Query->GetStr());
|
|
|
|
rc = Jcp->ExecuteUpdate(Query->GetStr());
|
|
Query->Truncate(len); // Restore query
|
|
|
|
if (rc == RC_OK)
|
|
AftRows += Jcp->m_Aff;
|
|
else
|
|
Werr = true;
|
|
|
|
return rc;
|
|
} // end of WriteDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base delete line routine for JDBC access method. */
|
|
/***********************************************************************/
|
|
int TDBJDBC::DeleteDB(PGLOBAL g, int irc)
|
|
{
|
|
if (irc == RC_FX) {
|
|
if (!Query && MakeCommand(g))
|
|
return RC_FX;
|
|
|
|
// Send the DELETE (all) command to the remote table
|
|
if (Jcp->ExecuteUpdate(Query->GetStr()) == RC_OK) {
|
|
AftRows = Jcp->m_Aff;
|
|
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
|
|
|
|
if (trace(1))
|
|
htrc("%s\n", g->Message);
|
|
|
|
PushWarning(g, this, 0); // 0 means a Note
|
|
return RC_OK; // This is a delete all
|
|
} else
|
|
return RC_FX; // Error
|
|
|
|
} else
|
|
return RC_OK; // Ignore
|
|
|
|
} // end of DeleteDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base close routine for JDBC access method. */
|
|
/***********************************************************************/
|
|
void TDBJDBC::CloseDB(PGLOBAL g)
|
|
{
|
|
if (Jcp)
|
|
Jcp->Close();
|
|
|
|
if (trace(1))
|
|
htrc("JDBC CloseDB: closing %s\n", Name);
|
|
|
|
if (!Werr &&
|
|
(Mode == MODE_INSERT || Mode == MODE_UPDATE || Mode == MODE_DELETE)) {
|
|
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
|
|
|
|
if (trace(1))
|
|
htrc("%s\n", g->Message);
|
|
|
|
PushWarning(g, this, 0); // 0 means a Note
|
|
} // endif Mode
|
|
|
|
Prepared = false;
|
|
} // end of CloseDB
|
|
|
|
/* --------------------------- JDBCCOL ------------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* JDBCCOL public constructor. */
|
|
/***********************************************************************/
|
|
JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
|
|
: EXTCOL(cdp, tdbp, cprec, i, am)
|
|
{
|
|
uuid = false;
|
|
} // end of JDBCCOL constructor
|
|
|
|
/***********************************************************************/
|
|
/* JDBCCOL private constructor. */
|
|
/***********************************************************************/
|
|
JDBCCOL::JDBCCOL(void) : EXTCOL()
|
|
{
|
|
uuid = false;
|
|
} // end of JDBCCOL constructor
|
|
|
|
/***********************************************************************/
|
|
/* JDBCCOL constructor used for copying columns. */
|
|
/* tdbp is the pointer to the new table descriptor. */
|
|
/***********************************************************************/
|
|
JDBCCOL::JDBCCOL(JDBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
|
|
{
|
|
uuid = col1->uuid;
|
|
} // end of JDBCCOL copy constructor
|
|
|
|
/***********************************************************************/
|
|
/* ReadColumn: retrieve the column value via the JDBC driver. */
|
|
/***********************************************************************/
|
|
void JDBCCOL::ReadColumn(PGLOBAL g)
|
|
{
|
|
PTDBJDBC tdbp = (PTDBJDBC)To_Tdb;
|
|
int i = tdbp->Fpos - 1, n = tdbp->CurNum;
|
|
|
|
if (tdbp->Memory == 3) {
|
|
// Get the value from the stored memory
|
|
if (Crp->Nulls && Crp->Nulls[i] == '*') {
|
|
Value->Reset();
|
|
Value->SetNull(true);
|
|
} else {
|
|
Value->SetValue_pvblk(Crp->Kdata, i);
|
|
Value->SetNull(false);
|
|
} // endif Nulls
|
|
|
|
return;
|
|
} // endif Memory
|
|
|
|
/*********************************************************************/
|
|
/* Get the column value. */
|
|
/*********************************************************************/
|
|
tdbp->Jcp->SetColumnValue(Rank, Name, Value);
|
|
|
|
if (tdbp->Memory != 2)
|
|
return;
|
|
|
|
/*********************************************************************/
|
|
/* Fill the allocated result structure. */
|
|
/*********************************************************************/
|
|
if (Value->IsNull()) {
|
|
if (Crp->Nulls)
|
|
Crp->Nulls[i] = '*'; // Null value
|
|
|
|
Crp->Kdata->Reset(i);
|
|
} else
|
|
Crp->Kdata->SetValue(Value, i);
|
|
|
|
} // end of ReadColumn
|
|
|
|
/***********************************************************************/
|
|
/* WriteColumn: Convert if necessary. */
|
|
/***********************************************************************/
|
|
void JDBCCOL::WriteColumn(PGLOBAL g)
|
|
{
|
|
/*********************************************************************/
|
|
/* Do convert the column value if necessary. */
|
|
/*********************************************************************/
|
|
if (Value != To_Val)
|
|
Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
|
|
|
|
} // end of WriteColumn
|
|
|
|
/* -------------------------- Class TDBXJDC -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* Implementation of the TDBXJDC class. */
|
|
/***********************************************************************/
|
|
TDBXJDC::TDBXJDC(PJDBCDEF tdp) : TDBJDBC(tdp)
|
|
{
|
|
Cmdlist = NULL;
|
|
Cmdcol = NULL;
|
|
Mxr = tdp->Maxerr;
|
|
Nerr = 0;
|
|
} // end of TDBXJDC constructor
|
|
|
|
/***********************************************************************/
|
|
/* Allocate XSRC column description block. */
|
|
/***********************************************************************/
|
|
PCOL TDBXJDC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
|
{
|
|
PJSRCCOL colp = new(g)JSRCCOL(cdp, this, cprec, n);
|
|
|
|
if (!colp->Flag)
|
|
Cmdcol = colp->GetName();
|
|
|
|
return colp;
|
|
} // end of MakeCol
|
|
|
|
/***********************************************************************/
|
|
/* MakeCMD: make the SQL statement to send to JDBC connection. */
|
|
/***********************************************************************/
|
|
PCMD TDBXJDC::MakeCMD(PGLOBAL g)
|
|
{
|
|
PCMD xcmd = NULL;
|
|
|
|
if (To_CondFil) {
|
|
if (Cmdcol) {
|
|
if (!stricmp(Cmdcol, To_CondFil->Body) &&
|
|
(To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
|
|
xcmd = To_CondFil->Cmds;
|
|
} else
|
|
strcpy(g->Message, "Invalid command specification filter");
|
|
|
|
} else
|
|
strcpy(g->Message, "No command column in select list");
|
|
|
|
} else if (!Srcdef)
|
|
strcpy(g->Message, "No Srcdef default command");
|
|
else
|
|
xcmd = new(g) CMD(g, Srcdef);
|
|
|
|
return xcmd;
|
|
} // end of MakeCMD
|
|
|
|
/***********************************************************************/
|
|
/* XDBC GetMaxSize: returns table size (not always one row). */
|
|
/***********************************************************************/
|
|
int TDBXJDC::GetMaxSize(PGLOBAL g)
|
|
{
|
|
if (MaxSize < 0)
|
|
MaxSize = 2; // Just a guess
|
|
|
|
return MaxSize;
|
|
} // end of GetMaxSize
|
|
|
|
/***********************************************************************/
|
|
/* JDBC Access Method opening routine. */
|
|
/* New method now that this routine is called recursively (last table */
|
|
/* first in reverse order): index blocks are immediately linked to */
|
|
/* join block of next table if it exists or else are discarted. */
|
|
/***********************************************************************/
|
|
bool TDBXJDC::OpenDB(PGLOBAL g)
|
|
{
|
|
bool rc = false;
|
|
|
|
if (trace(1))
|
|
htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
|
|
this, Tdb_No, Use, Mode);
|
|
|
|
if (Use == USE_OPEN) {
|
|
strcpy(g->Message, "Multiple execution is not allowed");
|
|
return true;
|
|
} // endif use
|
|
|
|
/*********************************************************************/
|
|
/* 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) JDBConn(g, Wrapname);
|
|
} else if (Jcp->IsOpen())
|
|
Jcp->Close();
|
|
|
|
if (Jcp->Connect(&Ops))
|
|
return true;
|
|
|
|
Use = USE_OPEN; // Do it now in case we are recursively called
|
|
|
|
if (Mode != MODE_READ && Mode != MODE_READX) {
|
|
strcpy(g->Message, "No INSERT/DELETE/UPDATE of XJDBC tables");
|
|
return true;
|
|
} // endif Mode
|
|
|
|
/*********************************************************************/
|
|
/* Get the command to execute. */
|
|
/*********************************************************************/
|
|
if (!(Cmdlist = MakeCMD(g))) {
|
|
Jcp->Close();
|
|
return true;
|
|
} // endif Query
|
|
|
|
Rows = 1;
|
|
return false;
|
|
} // end of OpenDB
|
|
|
|
/***********************************************************************/
|
|
/* ReadDB: Data Base read routine for xdbc access method. */
|
|
/***********************************************************************/
|
|
int TDBXJDC::ReadDB(PGLOBAL g)
|
|
{
|
|
if (Cmdlist) {
|
|
int rc;
|
|
|
|
if (!Query)
|
|
Query = new(g) STRING(g, 0, Cmdlist->Cmd);
|
|
else
|
|
Query->Set(Cmdlist->Cmd);
|
|
|
|
if ((rc = Jcp->ExecuteCommand(Query->GetStr())) == RC_FX)
|
|
Nerr++;
|
|
|
|
if (rc == RC_NF)
|
|
AftRows = Jcp->m_Aff;
|
|
else if (rc == RC_OK)
|
|
AftRows = Jcp->m_Ncol;
|
|
|
|
Fpos++; // Used for progress info
|
|
Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
|
|
return RC_OK;
|
|
} else
|
|
return RC_EF;
|
|
|
|
} // end of ReadDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base write line routine for JDBC access method. */
|
|
/***********************************************************************/
|
|
int TDBXJDC::WriteDB(PGLOBAL g)
|
|
{
|
|
strcpy(g->Message, "Execsrc tables are read only");
|
|
return RC_FX;
|
|
} // end of DeleteDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base delete line routine for JDBC access method. */
|
|
/***********************************************************************/
|
|
int TDBXJDC::DeleteDB(PGLOBAL g, int irc)
|
|
{
|
|
strcpy(g->Message, "NO_XJDBC_DELETE");
|
|
return RC_FX;
|
|
} // end of DeleteDB
|
|
|
|
/* --------------------------- JSRCCOL ------------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* JSRCCOL public constructor. */
|
|
/***********************************************************************/
|
|
JSRCCOL::JSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
|
|
: JDBCCOL(cdp, tdbp, cprec, i, am)
|
|
{
|
|
// Set additional JDBC access method information for column.
|
|
Flag = cdp->GetOffset();
|
|
} // end of JSRCCOL constructor
|
|
|
|
/***********************************************************************/
|
|
/* ReadColumn: set column value according to Flag. */
|
|
/***********************************************************************/
|
|
void JSRCCOL::ReadColumn(PGLOBAL g)
|
|
{
|
|
PTDBXJDC tdbp = (PTDBXJDC)To_Tdb;
|
|
|
|
switch (Flag) {
|
|
case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break;
|
|
case 1: Value->SetValue(tdbp->AftRows); break;
|
|
case 2: Value->SetValue_psz(g->Message); break;
|
|
default: Value->SetValue_psz("Invalid Flag"); break;
|
|
} // endswitch Flag
|
|
|
|
} // end of ReadColumn
|
|
|
|
/***********************************************************************/
|
|
/* WriteColumn: Should never be called. */
|
|
/***********************************************************************/
|
|
void JSRCCOL::WriteColumn(PGLOBAL g)
|
|
{
|
|
// Should never be called
|
|
} // end of WriteColumn
|
|
|
|
/* ---------------------------TDBJDRV class -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* GetResult: Get the list of JDBC drivers. */
|
|
/***********************************************************************/
|
|
PQRYRES TDBJDRV::GetResult(PGLOBAL g)
|
|
{
|
|
return JDBCDrivers(g, Maxres, false);
|
|
} // end of GetResult
|
|
|
|
/* ---------------------------TDBJTB class --------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* TDBJTB class constructor. */
|
|
/***********************************************************************/
|
|
TDBJTB::TDBJTB(PJDBCDEF tdp) : TDBJDRV(tdp)
|
|
{
|
|
Schema = tdp->Tabschema;
|
|
Tab = tdp->Tabname;
|
|
Tabtype = tdp->Tabtyp;
|
|
Ops.Driver = tdp->Driver;
|
|
Ops.Url = tdp->Url;
|
|
Ops.User = tdp->Username;
|
|
Ops.Pwd = tdp->Password;
|
|
Ops.Fsize = 0;
|
|
Ops.Scrollable = false;
|
|
} // end of TDBJTB constructor
|
|
|
|
/***********************************************************************/
|
|
/* GetResult: Get the list of JDBC tables. */
|
|
/***********************************************************************/
|
|
PQRYRES TDBJTB::GetResult(PGLOBAL g)
|
|
{
|
|
return JDBCTables(g, Schema, Tab, Tabtype, Maxres, false, &Ops);
|
|
} // end of GetResult
|
|
|
|
/* --------------------------TDBJDBCL class -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* TDBJDBCL class constructor. */
|
|
/***********************************************************************/
|
|
TDBJDBCL::TDBJDBCL(PJDBCDEF tdp) : TDBJTB(tdp)
|
|
{
|
|
Colpat = tdp->Colpat;
|
|
} // end of TDBJDBCL constructor
|
|
|
|
/***********************************************************************/
|
|
/* GetResult: Get the list of JDBC table columns. */
|
|
/***********************************************************************/
|
|
PQRYRES TDBJDBCL::GetResult(PGLOBAL g)
|
|
{
|
|
return JDBCColumns(g, Schema, Tab, Colpat, Maxres, false, &Ops);
|
|
} // end of GetResult
|