mariadb/storage/connect/jdbconn.cpp
2022-10-02 22:14:21 +02:00

1691 lines
50 KiB
C++

/************ Jdbconn C++ Functions Source Code File (.CPP) ************/
/* Name: JDBCONN.CPP Version 1.2 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2016-2018 */
/* */
/* This file contains the JDBC connection classes functions. */
/***********************************************************************/
#if defined(_WIN32)
// This is needed for RegGetValue
#define _WINVER 0x0601
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0601
#endif // _WIN32
/***********************************************************************/
/* Include relevant MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
#include <m_string.h>
#if defined(_WIN32)
//nclude <io.h>
//nclude <fcntl.h>
#include <direct.h> // for getcwd
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif // __BORLANDC__
//#include <windows.h>
#else // !_WIN32
#if defined(UNIX)
#include <errno.h>
#else // !UNIX
//nclude <io.h>
#endif // !UNIX
#include <stdio.h>
#include <stdlib.h> // for getenv
//nclude <fcntl.h>
#define NODW
#endif // !_WIN32
/***********************************************************************/
/* Required objects includes. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "xobject.h"
#include "xtable.h"
#include "tabext.h"
#include "tabjdbc.h"
//#include "jdbconn.h"
#include "resource.h"
#include "valblk.h"
#include "osutil.h"
//#if defined(_WIN32)
//extern "C" HINSTANCE s_hModule; // Saved module handle
//#endif // _WIN32
#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
/***********************************************************************/
/* 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
// To avoid gcc warning
int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v);
/***********************************************************************/
/* GetJDBCType: returns the SQL_TYPE corresponding to a PLG type. */
/***********************************************************************/
static short GetJDBCType(int type)
{
short tp = 0; // NULL
switch (type) {
case TYPE_STRING: tp = 12; break; // VARCHAR
case TYPE_SHORT: tp = 5; break; // SMALLINT
case TYPE_INT: tp = 4; break; // INTEGER
case TYPE_DATE: tp = 93; break; // DATE
//case TYPE_TIME: tp = 92; break; // TIME
//case TYPE_TIMESTAMP: tp = 93; break; // TIMESTAMP
case TYPE_BIGINT: tp = -5; break; // BIGINT
case TYPE_DOUBLE: tp = 8; break; // DOUBLE
case TYPE_TINY: tp = -6; break; // TINYINT
case TYPE_DECIM: tp = 3; break; // DECIMAL
} // endswitch type
return tp;
} // end of GetJDBCType
/***********************************************************************/
/* TranslateJDBCType: translate a JDBC Type to a PLG type. */
/***********************************************************************/
int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v)
{
int type;
switch (stp) {
case -1: // LONGVARCHAR, TEXT
case -16: // LONGNVARCHAR, NTEXT (unicode)
if (GetTypeConv() != TPC_YES)
return TYPE_ERROR;
else
len = MY_MIN(abs(len), GetConvSize());
/* fall through */
case 12: // VARCHAR
if (tn && !stricmp(tn, "TEXT"))
// Postgresql returns 12 for TEXT
if (GetTypeConv() == TPC_NO)
return TYPE_ERROR;
// Postgresql can return this
if (len == 0x7FFFFFFF)
len = GetConvSize();
/* fall through */
case -9: // NVARCHAR (unicode)
// Postgresql can return this when size is unknown
if (len == 0x7FFFFFFF)
len = GetConvSize();
v = 'V';
/* fall through */
case 1: // CHAR
case -15: // NCHAR (unicode)
case -8: // ROWID
type = TYPE_STRING;
break;
case 2: // NUMERIC
case 3: // DECIMAL
case -3: // VARBINARY
type = TYPE_DECIM;
break;
case 4: // INTEGER
type = TYPE_INT;
break;
case 5: // SMALLINT
type = TYPE_SHORT;
break;
case -6: // TINYINT
case -7: // BIT
case 16: // BOOLEAN
type = TYPE_TINY;
break;
case 6: // FLOAT
case 7: // REAL
case 8: // DOUBLE
type = TYPE_DOUBLE;
break;
case 93: // TIMESTAMP, DATETIME
type = TYPE_DATE;
len = 19 + ((prec) ? (prec+1) : 0);
v = (tn && toupper(tn[0]) == 'T') ? 'S' : 'E';
break;
case 91: // DATE, YEAR
type = TYPE_DATE;
if (!tn || toupper(tn[0]) != 'Y') {
len = 10;
v = 'D';
} else {
len = 4;
v = 'Y';
} // endif len
break;
case 92: // TIME
type = TYPE_DATE;
len = 8 + ((prec) ? (prec + 1) : 0);
v = 'T';
break;
case -5: // BIGINT
type = TYPE_BIGINT;
break;
case 1111: // UNKNOWN or UUID
if (!tn || !stricmp(tn, "UUID")) {
type = TYPE_STRING;
len = 36;
break;
} // endif tn
/* fall through */
case 0: // NULL
case -2: // BINARY
case -4: // LONGVARBINARY
case 70: // DATALINK
case 2000: // JAVA_OBJECT
case 2001: // DISTINCT
case 2002: // STRUCT
case 2003: // ARRAY
case 2004: // BLOB
case 2005: // CLOB
case 2006: // REF
case 2009: // SQLXML
case 2011: // NCLOB
default:
type = TYPE_ERROR;
len = 0;
} // endswitch type
return type;
} // end of TranslateJDBCType
/***********************************************************************/
/* A helper class to split an optionally qualified table name into */
/* components. */
/* These formats are understood: */
/* "CatalogName.SchemaName.TableName" */
/* "SchemaName.TableName" */
/* "TableName" */
/***********************************************************************/
class SQLQualifiedName {
static const uint max_parts = 3; // Catalog.Schema.Table
MYSQL_LEX_STRING m_part[max_parts];
char m_buf[512];
void lex_string_set(MYSQL_LEX_STRING *S, char *str, size_t length)
{
S->str = str;
S->length = length;
} // end of lex_string_set
void lex_string_shorten_down(MYSQL_LEX_STRING *S, size_t offs)
{
DBUG_ASSERT(offs <= S->length);
S->str += offs;
S->length -= offs;
} // end of lex_string_shorten_down
/*********************************************************************/
/* Find the rightmost '.' delimiter and return the length */
/* of the qualifier, including the rightmost '.' delimier. */
/* For example, for the string {"a.b.c",5} it will return 4, */
/* which is the length of the qualifier "a.b." */
/*********************************************************************/
size_t lex_string_find_qualifier(MYSQL_LEX_STRING *S)
{
size_t i;
for (i = S->length; i > 0; i--)
{
if (S->str[i - 1] == '.')
{
S->str[i - 1] = '\0';
return i;
}
}
return 0;
} // end of lex_string_find_qualifier
public:
/*********************************************************************/
/* Initialize to the given optionally qualified name. */
/* NULL pointer in "name" is supported. */
/* name qualifier has precedence over schema. */
/*********************************************************************/
SQLQualifiedName(JCATPARM *cap)
{
const char *name = (const char *)cap->Tab;
char *db = (char *)cap->DB;
size_t len, i;
// Initialize the parts
for (i = 0; i < max_parts; i++)
lex_string_set(&m_part[i], NULL, 0);
if (name) {
// Initialize the first (rightmost) part
lex_string_set(&m_part[0], m_buf,
strmake(m_buf, name, sizeof(m_buf) - 1) - m_buf);
// Initialize the other parts, if exist.
for (i = 1; i < max_parts; i++) {
if (!(len = lex_string_find_qualifier(&m_part[i - 1])))
break;
lex_string_set(&m_part[i], m_part[i - 1].str, len - 1);
lex_string_shorten_down(&m_part[i - 1], len);
} // endfor i
} // endif name
// If it was not specified, set schema as the passed db name
if (db && !m_part[1].length)
lex_string_set(&m_part[1], db, strlen(db));
} // end of SQLQualifiedName
char *ptr(uint i)
{
DBUG_ASSERT(i < max_parts);
return (char *)(m_part[i].length ? m_part[i].str : NULL);
} // end of ptr
size_t length(uint i)
{
DBUG_ASSERT(i < max_parts);
return m_part[i].length;
} // end of length
}; // end of class SQLQualifiedName
/***********************************************************************/
/* 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 ((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
/***********************************************************************/
/* JDBCColumns: constructs the result blocks containing all columns */
/* of a JDBC table that will be retrieved by GetData commands. */
/***********************************************************************/
PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat,
int maxres, bool info, PJPARM sjp)
{
int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT,
TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_TABNAME, FLD_NAME,
FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH,
FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM};
unsigned int length[] = {0, 0, 0, 0, 6, 0, 10, 10, 6, 6, 6, 0};
bool b[] = {true, true, false, false, false, false, false, false, true, true, false, true};
int i, n, ncol = 12;
PCOLRES crp;
PQRYRES qrp;
JCATPARM *cap;
JDBConn *jcp = NULL;
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
if (!info) {
jcp = new(g)JDBConn(g, NULL);
if (jcp->Connect(sjp)) // openReadOnly + noJDBCdialog
return NULL;
if (table && !strchr(table, '%')) {
// We fix a MySQL limit because some data sources return 32767
n = jcp->GetMaxValue(1); // MAX_COLUMNS_IN_TABLE)
maxres = (n > 0) ? MY_MIN(n, 4096) : 4096;
} else if (!maxres)
maxres = 20000;
// n = jcp->GetMaxValue(2); MAX_CATALOG_NAME_LEN
// length[0] = (n) ? (n + 1) : 0;
// n = jcp->GetMaxValue(3); MAX_SCHEMA_NAME_LEN
// length[1] = (n) ? (n + 1) : 0;
// n = jcp->GetMaxValue(4); MAX_TABLE_NAME_LEN
// length[2] = (n) ? (n + 1) : 0;
n = jcp->GetMaxValue(5); // MAX_COLUMN_NAME_LEN
length[3] = (n > 0) ? (n + 1) : 128;
} else { // Info table
maxres = 0;
length[0] = 128;
length[1] = 128;
length[2] = 128;
length[3] = 128;
length[5] = 30;
length[11] = 255;
} // endif jcp
if (trace(1))
htrc("JDBCColumns: max=%d len=%d,%d,%d,%d\n",
maxres, length[0], length[1], length[2], length[3]);
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS,
buftyp, fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
if (b[i])
crp->Kdata->SetNullable(true);
if (info || !qrp) // Info table
return qrp;
if (trace(1))
htrc("Getting col results ncol=%d\n", qrp->Nbcol);
if (!(cap = AllocCatInfo(g, JCAT_COL, db, table, qrp)))
return NULL;
// Colpat cannot be null or empty for some drivers
cap->Pat = (colpat && *colpat) ? colpat : PlugDup(g, "%");
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
if ((n = jcp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n;
// ResetNullValues(cap);
if (trace(1))
htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/* Cleanup */
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCColumns
/**************************************************************************/
/* JDBCSrcCols: constructs the result blocks containing the */
/* description of all the columns of a Srcdef option. */
/**************************************************************************/
PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sjp)
{
char *sqry;
PQRYRES qrp;
JDBConn *jcp = new(g)JDBConn(g, NULL);
if (jcp->Connect(sjp))
return NULL;
if (strstr(src, "%s")) {
// Place holder for an eventual where clause
size_t sqry_size = strlen(src) + 2;
sqry = (char*)PlugSubAlloc(g, NULL, sqry_size);
// Function PlugSubAlloc(...) recalculate string size
// while allocate memory - it rounds size up size to multiple of 8
// we need to know the real allocated size
// to use it in sprintf(...)
const int sqry_real_allocated_size = ROUNDUP_TO_8(sqry_size);
snprintf(sqry, sqry_real_allocated_size, src, "1=1"); // dummy where clause
} else
sqry = (char*)src;
qrp = jcp->GetMetaData(g, sqry);
jcp->Close();
return qrp;
} // end of JDBCSrcCols
/**************************************************************************/
/* JDBCTables: constructs the result blocks containing all tables in */
/* an JDBC database that will be retrieved by GetData commands. */
/**************************************************************************/
PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp,
int maxres, bool info, PJPARM sjp)
{
int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING};
XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_NAME, FLD_TYPE, FLD_REM};
unsigned int length[] = {0, 0, 0, 16, 0};
bool b[] = {true, true, false, false, true};
int i, n, ncol = 5;
PCOLRES crp;
PQRYRES qrp;
JCATPARM *cap;
JDBConn *jcp = NULL;
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
if (!info) {
/**********************************************************************/
/* Open the connection with the JDBC data source. */
/**********************************************************************/
jcp = new(g)JDBConn(g, NULL);
if (jcp->Connect(sjp))
return NULL;
if (!maxres)
maxres = 10000; // This is completely arbitrary
n = jcp->GetMaxValue(2); // Max catalog name length
// if (n < 0)
// return NULL;
length[0] = (n > 0) ? (n + 1) : 0;
n = jcp->GetMaxValue(3); // Max schema name length
length[1] = (n > 0) ? (n + 1) : 0;
n = jcp->GetMaxValue(4); // Max table name length
length[2] = (n > 0) ? (n + 1) : 128;
} else {
maxres = 0;
length[0] = 128;
length[1] = 128;
length[2] = 128;
length[4] = 255;
} // endif info
if (trace(1))
htrc("JDBCTables: max=%d len=%d,%d\n", maxres, length[0], length[1]);
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, buftyp,
fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
if (b[i])
crp->Kdata->SetNullable(true);
if (info || !qrp)
return qrp;
// Tabpat cannot be null or empty for some drivers
if (!(cap = AllocCatInfo(g, JCAT_TAB, db,
(tabpat && *tabpat) ? tabpat : PlugDup(g, "%"), qrp)))
return NULL;
cap->Pat = tabtyp;
if (trace(1))
htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
if ((n = jcp->GetCatInfo(cap)) >= 0) {
qrp->Nblin = n;
// ResetNullValues(cap);
if (trace(1))
htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
} else
qrp = NULL;
/************************************************************************/
/* Close any local connection. */
/************************************************************************/
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCTables
/*************************************************************************/
/* JDBCDrivers: constructs the result blocks containing all JDBC */
/* drivers available on the local host. */
/* Called with info=true to have result column names. */
/*************************************************************************/
PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info)
{
int buftyp[] ={TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING};
XFLD fldtyp[] ={FLD_NAME, FLD_EXTRA, FLD_DEFAULT, FLD_REM };
unsigned int length[] ={ 128, 32, 4, 256 };
bool b[] ={ false, false, false, true };
int i, ncol = 4;
PCOLRES crp;
PQRYRES qrp;
JDBConn *jcp = NULL;
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
if (!info) {
jcp = new(g) JDBConn(g, NULL);
if (jcp->Open(g) != RC_OK)
return NULL;
if (!maxres)
maxres = 256; // Estimated max number of drivers
} else
maxres = 0;
if (trace(1))
htrc("JDBCDrivers: max=%d len=%d\n", maxres, length[0]);
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, 0, buftyp, fldtyp, length, false, true);
for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) {
if (b[i])
crp->Kdata->SetNullable(true);
switch (i) {
case 0: crp->Name = "Name"; break;
case 1: crp->Name = "Version"; break;
case 2: crp->Name = "Compliant"; break;
case 3: crp->Name = "Description"; break;
} // endswitch
} // endfor i
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
if (!info && qrp && jcp->GetDrivers(qrp))
qrp = NULL;
if (!info)
jcp->Close();
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of JDBCDrivers
/***********************************************************************/
/* JDBConn construction/destruction. */
/***********************************************************************/
JDBConn::JDBConn(PGLOBAL g, PCSZ wrapper) : JAVAConn(g, wrapper)
{
xqid = xuid = xid = grs = readid = fetchid = typid = errid = nullptr;
prepid = xpid = pcid = nullptr;
chrfldid = intfldid = dblfldid = fltfldid = bigfldid = nullptr;
objfldid = datfldid = timfldid = tspfldid = uidfldid = nullptr;
DiscFunc = "JdbcDisconnect";
m_Ncol = 0;
m_Aff = 0;
//m_Rows = 0;
m_Fetch = 0;
m_RowsetSize = 0;
m_Updatable = true;
m_Transact = false;
m_Scrollable = false;
m_Full = false;
m_Opened = false;
m_IDQuoteChar[0] = '"';
m_IDQuoteChar[1] = 0;
} // end of JDBConn
/***********************************************************************/
/* Search for UUID columns. */
/***********************************************************************/
bool JDBConn::SetUUID(PGLOBAL g, PTDBJDBC tjp)
{
int ncol, ctyp;
bool brc = true;
PCSZ fnc = "GetColumns";
PCOL colp;
JCATPARM *cap;
//jint jtyp;
jboolean rc = false;
jobjectArray parms;
jmethodID catid = nullptr;
if (gmID(g, catid, fnc, "([Ljava/lang/String;)I"))
return true;
else if (gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I"))
return true;
else if (gmID(g, readid, "ReadNext", "()I"))
return true;
cap = AllocCatInfo(g, JCAT_COL, tjp->Schema, tjp->TableName, NULL);
SQLQualifiedName name(cap);
// Build the java string array
parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL);
env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2)));
env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1)));
env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0)));
for (colp = tjp->GetColumns(); colp; colp = colp->GetNext()) {
env->SetObjectArrayElement(parms, 3, env->NewStringUTF(colp->GetName()));
ncol = env->CallIntMethod(job, catid, parms);
if (Check(ncol)) {
snprintf(g->Message, sizeof(g->Message), "%s: %s", fnc, Msg);
goto err;
} // endif Check
rc = env->CallBooleanMethod(job, readid);
if (Check(rc)) {
snprintf(g->Message, sizeof(g->Message), "ReadNext: %s", Msg);
goto err;
} else if (rc == 0) {
snprintf(g->Message, sizeof(g->Message), "table %s does not exist", tjp->TableName);
goto err;
} // endif rc
// Should return 666 is case of error (not done yet)
ctyp = (int)env->CallIntMethod(job, intfldid, 5, nullptr);
//if (Check((ctyp == 666) ? -1 : 1)) {
// snprintf(g->Message, sizeof(g->Message), "Getting ctyp: %s", Msg);
// goto err;
//} // endif ctyp
if (ctyp == 1111)
((PJDBCCOL)colp)->uuid = true;
} // endfor colp
// All is Ok
brc = false;
err:
// Not used anymore
env->DeleteLocalRef(parms);
return brc;
} // end of SetUUID
/***********************************************************************/
/* Utility routine. */
/***********************************************************************/
int JDBConn::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
/***********************************************************************/
/* AddJars: add some jar file to the Class path. */
/***********************************************************************/
void JDBConn::AddJars(PSTRG jpop, char sep)
{
#if defined(DEVELOPMENT)
jpop->Append(
";C:/Jconnectors/postgresql-9.4.1208.jar"
";C:/Oracle/ojdbc7.jar"
";C:/Apache/commons-dbcp2-2.1.1/commons-dbcp2-2.1.1.jar"
";C:/Apache/commons-pool2-2.4.2/commons-pool2-2.4.2.jar"
";C:/Apache/commons-logging-1.2/commons-logging-1.2.jar"
";C:/Jconnectors/mysql-connector-java-6.0.2-bin.jar"
";C:/Jconnectors/mariadb-java-client-2.0.1.jar"
";C:/Jconnectors/sqljdbc42.jar");
#endif // DEVELOPMENT
} // end of AddJars
/***********************************************************************/
/* Connect: connect to a data source. */
/***********************************************************************/
bool JDBConn::Connect(PJPARM sop)
{
bool err = false;
jint rc;
PGLOBAL& g = m_G;
/*******************************************************************/
/* Create or attach a JVM. */
/*******************************************************************/
if (Open(g))
return true;
if (!sop) // DRIVER catalog table
return false;
jmethodID cid = nullptr;
if (gmID(g, cid, "JdbcConnect", "([Ljava/lang/String;IZ)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;
//m_LoginTimeout = sop->Cto;
//m_QueryTimeout = sop->Qto;
//m_UseCnc = sop->UseCnc;
// change some elements
if (sop->Driver)
env->SetObjectArrayElement(parms, 0, env->NewStringUTF(sop->Driver));
if (sop->Url)
env->SetObjectArrayElement(parms, 1, env->NewStringUTF(sop->Url));
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, m_RowsetSize, m_Scrollable);
err = Check(rc);
env->DeleteLocalRef(parms); // Not used anymore
if (err) {
snprintf(g->Message, sizeof(g->Message), "Connecting: %s rc=%d", Msg, (int)rc);
return true;
} // endif Msg
jmethodID qcid = nullptr;
if (!gmID(g, qcid, "GetQuoteString", "()Ljava/lang/String;")) {
jstring s = (jstring)env->CallObjectMethod(job, qcid);
if (s != nullptr) {
char *qch = GetUTFString(s);
m_IDQuoteChar[0] = *qch;
} else {
s = (jstring)env->CallObjectMethod(job, errid);
Msg = GetUTFString(s);
} // endif s
} // endif qcid
if (gmID(g, typid, "ColumnType", "(ILjava/lang/String;)I"))
return true;
else
m_Connected = true;
return false;
} // end of Connect
/***********************************************************************/
/* Execute an SQL command. */
/***********************************************************************/
int JDBConn::ExecuteCommand(PCSZ sql)
{
int rc;
jint n;
jstring qry;
PGLOBAL& g = m_G;
// Get the methods used to execute a query and get the result
if (gmID(g, xid, "Execute", "(Ljava/lang/String;)I") ||
gmID(g, grs, "GetResult", "()I"))
return RC_FX;
qry = env->NewStringUTF(sql);
n = env->CallIntMethod(job, xid, qry);
env->DeleteLocalRef(qry);
if (Check(n)) {
snprintf(g->Message, sizeof(g->Message), "Execute: %s", Msg);
return RC_FX;
} // endif n
m_Ncol = env->CallIntMethod(job, grs);
if (Check(m_Ncol)) {
snprintf(g->Message, sizeof(g->Message), "GetResult: %s", Msg);
rc = RC_FX;
} else if (m_Ncol) {
strcpy(g->Message, "Result set column number");
rc = RC_OK; // A result set was returned
} else {
m_Aff = (int)n; // Affected rows
strcpy(g->Message, "Affected rows");
rc = RC_NF;
} // endif ncol
return rc;
} // end of ExecuteCommand
/***********************************************************************/
/* Fetch next row. */
/***********************************************************************/
int JDBConn::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 rc;
rc = env->CallBooleanMethod(job, readid);
if (!Check(rc)) {
if (rc == 0)
m_Full = (m_Fetch == 1);
else
m_Fetch++;
m_Rows += (int)rc;
} else
snprintf(g->Message, sizeof(g->Message), "Fetch: %s", Msg);
} // endif pos
return (int)rc;
} // end of Fetch
/***********************************************************************/
/* Restart from beginning of result set */
/***********************************************************************/
int JDBConn::Rewind(PCSZ sql)
{
int rbuf = -1;
if (m_Full)
rbuf = m_Rows; // No need to "rewind"
else if (m_Scrollable) {
if (gmID(m_G, fetchid, "Fetch", "(I)Z"))
return -1;
(void) env->CallBooleanMethod(job, fetchid, 0);
rbuf = m_Rows;
} else if (ExecuteCommand(sql) != RC_FX)
rbuf = 0;
return rbuf;
} // end of Rewind
/***********************************************************************/
/* Retrieve and set the column value from the result set. */
/***********************************************************************/
void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
{
const char *field;
PGLOBAL& g = m_G;
jint ctyp;
jstring cn, jn = nullptr;
jobject jb = nullptr;
if (rank == 0)
if (!name || (jn = env->NewStringUTF(name)) == nullptr) {
snprintf(g->Message, sizeof(g->Message), "Fail to allocate jstring %s", SVP(name));
throw (int)TYPE_AM_JDBC;
} // endif name
// Returns 666 is case of error
ctyp = env->CallIntMethod(job, typid, rank, jn);
if (Check((ctyp == 666) ? -1 : 1)) {
snprintf(g->Message, sizeof(g->Message), "Getting ctyp: %s", Msg);
throw (int)TYPE_AM_JDBC;
} // endif Check
if (val->GetNullable())
if (!gmID(g, objfldid, "ObjectField", "(ILjava/lang/String;)Ljava/lang/Object;")) {
jb = env->CallObjectMethod(job, objfldid, (jint)rank, jn);
if (Check(0)) {
snprintf(g->Message, sizeof(g->Message), "Getting jp: %s", Msg);
throw (int)TYPE_AM_JDBC;
} // endif Check
if (jb == nullptr) {
val->Reset();
val->SetNull(true);
goto chk;
} // endif job
} // endif objfldid
switch (ctyp) {
case 12: // VARCHAR
case -9: // NVARCHAR
case -1: // LONGVARCHAR, TEXT
case 1: // CHAR
case -15: // NCHAR
case -16: // LONGNVARCHAR, NTEXT
case 3: // DECIMAL
case -8: // ROWID
if (jb && ctyp != 3)
cn = (jstring)jb;
else if (!gmID(g, chrfldid, "StringField", "(ILjava/lang/String;)Ljava/lang/String;"))
cn = (jstring)env->CallObjectMethod(job, chrfldid, (jint)rank, jn);
else
cn = nullptr;
if (cn) {
field = GetUTFString(cn);
val->SetValue_psz((PSZ)field);
} else
val->Reset();
break;
case 4: // INTEGER
case 5: // SMALLINT
case -6: // TINYINT
case 16: // BOOLEAN
case -7: // BIT
if (!gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I"))
val->SetValue((int)env->CallIntMethod(job, intfldid, rank, jn));
else
val->Reset();
break;
case 8: // DOUBLE
case 2: // NUMERIC
//case 3: // DECIMAL
if (!gmID(g, dblfldid, "DoubleField", "(ILjava/lang/String;)D"))
val->SetValue((double)env->CallDoubleMethod(job, dblfldid, rank, jn));
else
val->Reset();
break;
case 7: // REAL
case 6: // FLOAT
if (!gmID(g, fltfldid, "FloatField", "(ILjava/lang/String;)F"))
val->SetValue((float)env->CallFloatMethod(job, fltfldid, rank, jn));
else
val->Reset();
break;
case 91: // DATE
if (!gmID(g, datfldid, "DateField", "(ILjava/lang/String;)I")) {
val->SetValue((int)env->CallIntMethod(job, datfldid, (jint)rank, jn));
} else
val->Reset();
break;
case 92: // TIME
if (!gmID(g, timfldid, "TimeField", "(ILjava/lang/String;)I")) {
val->SetValue((int)env->CallIntMethod(job, timfldid, (jint)rank, jn));
} else
val->Reset();
break;
case 93: // TIMESTAMP
if (!gmID(g, tspfldid, "TimestampField", "(ILjava/lang/String;)I")) {
val->SetValue((int)env->CallIntMethod(job, tspfldid, (jint)rank, jn));
} else
val->Reset();
break;
case -5: // BIGINT
if (!gmID(g, bigfldid, "BigintField", "(ILjava/lang/String;)J"))
val->SetValue((long long)env->CallLongMethod(job, bigfldid, (jint)rank, jn));
else
val->Reset();
break;
/* case java.sql.Types.SMALLINT:
System.out.print(jdi.IntField(i));
break;
case java.sql.Types.BOOLEAN:
System.out.print(jdi.BooleanField(i)); */
case 1111: // UUID
if (!gmID(g, uidfldid, "UuidField", "(ILjava/lang/String;)Ljava/lang/String;"))
cn = (jstring)env->CallObjectMethod(job, uidfldid, (jint)rank, jn);
else
cn = nullptr;
if (cn) {
val->SetValue_psz((PSZ)GetUTFString(cn));
} else
val->Reset();
break;
case 0: // NULL
val->SetNull(true);
/* fall through */
default:
val->Reset();
} // endswitch Type
chk:
if (Check()) {
if (rank == 0)
env->DeleteLocalRef(jn);
snprintf(g->Message, sizeof(g->Message), "SetColumnValue: %s rank=%d ctyp=%d", Msg, rank, (int)ctyp);
throw (int)TYPE_AM_JDBC;
} // endif Check
if (rank == 0)
env->DeleteLocalRef(jn);
} // end of SetColumnValue
/***********************************************************************/
/* Prepare an SQL statement for insert. */
/***********************************************************************/
bool JDBConn::PrepareSQL(PCSZ sql)
{
bool b = true;
PGLOBAL& g = m_G;
if (!gmID(g, prepid, "CreatePrepStmt", "(Ljava/lang/String;)I")) {
// Create the prepared statement
jstring qry = env->NewStringUTF(sql);
if (Check(env->CallBooleanMethod(job, prepid, qry)))
snprintf(g->Message, sizeof(g->Message), "CreatePrepStmt: %s", Msg);
else
b = false;
env->DeleteLocalRef(qry);
} // endif prepid
return b;
} // end of PrepareSQL
/***********************************************************************/
/* Execute an SQL query that returns a result set. */
/***********************************************************************/
int JDBConn::ExecuteQuery(PCSZ sql)
{
int rc = RC_FX;
jint ncol;
jstring qry;
PGLOBAL& g = m_G;
// Get the methods used to execute a query and get the result
if (!gmID(g, xqid, "ExecuteQuery", "(Ljava/lang/String;)I")) {
qry = env->NewStringUTF(sql);
ncol = env->CallIntMethod(job, xqid, qry);
if (!Check(ncol)) {
m_Ncol = (int)ncol;
m_Aff = 0; // Affected rows
rc = RC_OK;
} else
snprintf(g->Message, sizeof(g->Message), "ExecuteQuery: %s", Msg);
env->DeleteLocalRef(qry);
} // endif xqid
return rc;
} // end of ExecuteQuery
/***********************************************************************/
/* Execute an SQL query and get the affected rows. */
/***********************************************************************/
int JDBConn::ExecuteUpdate(PCSZ sql)
{
int rc = RC_FX;
jint n;
jstring qry;
PGLOBAL& g = m_G;
// Get the methods used to execute a query and get the affected rows
if (!gmID(g, xuid, "ExecuteUpdate", "(Ljava/lang/String;)I")) {
qry = env->NewStringUTF(sql);
n = env->CallIntMethod(job, xuid, qry);
if (!Check(n)) {
m_Ncol = 0;
m_Aff = (int)n; // Affected rows
rc = RC_OK;
} else
snprintf(g->Message, sizeof(g->Message), "ExecuteUpdate: %s n=%d", Msg, n);
env->DeleteLocalRef(qry);
} // endif xuid
return rc;
} // end of ExecuteUpdate
/***********************************************************************/
/* Get the number of lines of the result set. */
/***********************************************************************/
int JDBConn::GetResultSize(PCSZ sql, PCOL colp)
{
int rc;
if ((rc = ExecuteQuery(sql)) != RC_OK)
return -1;
if ((rc = Fetch()) > 0) {
try {
SetColumnValue(1, NULL, colp->GetValue());
} catch (...) {
return -4;
} // end catch
} else
return -2;
if ((rc = Fetch()) != 0)
return -3;
m_Full = false;
return colp->GetIntValue();
} // end of GetResultSize
/***********************************************************************/
/* Execute a prepared statement. */
/***********************************************************************/
int JDBConn::ExecuteSQL(void)
{
int rc = RC_FX;
PGLOBAL& g = m_G;
// Get the methods used to execute a prepared statement
if (!gmID(g, xpid, "ExecutePrep", "()I")) {
jint n = env->CallIntMethod(job, xpid);
if (n == -3)
strcpy(g->Message, "SQL statement is not prepared");
else if (Check(n))
snprintf(g->Message, sizeof(g->Message), "ExecutePrep: %s", Msg);
else {
m_Aff = (int)n;
rc = RC_OK;
} // endswitch n
} // endif xpid
return rc;
} // end of ExecuteSQL
/***********************************************************************/
/* Set a parameter for inserting. */
/***********************************************************************/
bool JDBConn::SetParam(JDBCCOL *colp)
{
PGLOBAL& g = m_G;
bool rc = false;
PVAL val = colp->GetValue();
jint n, jrc = 0, i = (jint)colp->GetRank();
jshort s;
jlong lg;
//jfloat f;
jdouble d;
jclass dat;
jobject datobj;
jstring jst = nullptr;
jmethodID dtc, setid = nullptr;
if (val->GetNullable() && val->IsNull()) {
if (gmID(g, setid, "SetNullParm", "(II)I"))
return true;
jrc = env->CallIntMethod(job, setid, i,
(colp->uuid ? 1111 : (jint)GetJDBCType(val->GetType())));
} else if (colp->uuid) {
if (gmID(g, setid, "SetUuidParm", "(ILjava/lang/String;)V"))
return true;
jst = env->NewStringUTF(val->GetCharValue());
env->CallVoidMethod(job, setid, i, jst);
} else switch (val->GetType()) {
case TYPE_STRING:
if (gmID(g, setid, "SetStringParm", "(ILjava/lang/String;)V"))
return true;
jst = env->NewStringUTF(val->GetCharValue());
env->CallVoidMethod(job, setid, i, jst);
break;
case TYPE_INT:
if (gmID(g, setid, "SetIntParm", "(II)V"))
return true;
n = (jint)val->GetIntValue();
env->CallVoidMethod(job, setid, i, n);
break;
case TYPE_TINY:
case TYPE_SHORT:
if (gmID(g, setid, "SetShortParm", "(IS)V"))
return true;
s = (jshort)val->GetShortValue();
env->CallVoidMethod(job, setid, i, s);
break;
case TYPE_BIGINT:
if (gmID(g, setid, "SetBigintParm", "(IJ)V"))
return true;
lg = (jlong)val->GetBigintValue();
env->CallVoidMethod(job, setid, i, lg);
break;
case TYPE_DOUBLE:
case TYPE_DECIM:
if (gmID(g, setid, "SetDoubleParm", "(ID)V"))
return true;
d = (jdouble)val->GetFloatValue();
env->CallVoidMethod(job, setid, i, d);
break;
case TYPE_DATE:
if ((dat = env->FindClass("java/sql/Timestamp")) == nullptr) {
strcpy(g->Message, "Cannot find Timestamp class");
return true;
} else if (!(dtc = env->GetMethodID(dat, "<init>", "(J)V"))) {
strcpy(g->Message, "Cannot find Timestamp class constructor");
return true;
} // endif's
lg = (jlong)val->GetBigintValue() * 1000;
if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) {
strcpy(g->Message, "Cannot make Timestamp object");
return true;
} else if (gmID(g, setid, "SetTimestampParm", "(ILjava/sql/Timestamp;)V"))
return true;
env->CallVoidMethod(job, setid, i, datobj);
break;
default:
snprintf(g->Message, sizeof(g->Message), "Parm type %d not supported", val->GetType());
return true;
} // endswitch Type
if (Check(jrc)) {
snprintf(g->Message, sizeof(g->Message), "SetParam: col=%s msg=%s", colp->GetName(), Msg);
rc = true;
} // endif msg
if (jst)
env->DeleteLocalRef(jst);
return rc;
} // end of SetParam
/***********************************************************************/
/* Get the list of Drivers and set it in qrp. */
/***********************************************************************/
bool JDBConn::GetDrivers(PQRYRES qrp)
{
PSZ sval;
int i, n, size;
PCOLRES crp;
jstring js;
jmethodID gdid = nullptr;
if (gmID(m_G, gdid, "GetDrivers", "([Ljava/lang/String;I)I"))
return true;
// Build the java string array
jobjectArray s = env->NewObjectArray(4 * qrp->Maxres,
env->FindClass("java/lang/String"), NULL);
size = env->CallIntMethod(job, gdid, s, qrp->Maxres);
for (i = 0, n = 0; i < size; i++) {
crp = qrp->Colresp;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = GetUTFString(js);
crp->Kdata->SetValue(sval, i);
crp = crp->Next;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = GetUTFString(js);
crp->Kdata->SetValue(sval, i);
crp = crp->Next;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = GetUTFString(js);
crp->Kdata->SetValue(sval, i);
crp = crp->Next;
js = (jstring)env->GetObjectArrayElement(s, n++);
sval = GetUTFString(js);
crp->Kdata->SetValue(sval, i);
} // endfor i
// Not used anymore
env->DeleteLocalRef(s);
qrp->Nblin = size;
return false;
} // end of GetDrivers
/**************************************************************************/
/* GetMetaData: constructs the result blocks containing the */
/* description of all the columns of an SQL command. */
/**************************************************************************/
PQRYRES JDBConn::GetMetaData(PGLOBAL g, PCSZ src)
{
static int buftyp[] = {TYPE_STRING, TYPE_INT, TYPE_INT,
TYPE_INT, TYPE_INT};
static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_PREC,
FLD_SCALE, FLD_NULL };
static unsigned int length[] = {0, 6, 10, 6, 6};
const char *name;
int len, qcol = 5;
PQRYRES qrp = NULL;
PCOLRES crp;
ushort i;
jint *n = nullptr;
jstring label;
jmethodID colid = nullptr;
int rc = ExecuteCommand(src);
if (rc == RC_NF) {
strcpy(g->Message, "Srcdef is not returning a result set");
return NULL;
} else if ((rc) == RC_FX) {
return NULL;
} else if (m_Ncol == 0) {
strcpy(g->Message, "Invalid Srcdef");
return NULL;
} // endif's
if (gmID(g, colid, "ColumnDesc", "(I[I)Ljava/lang/String;"))
return NULL;
// Get max column name length
len = GetMaxValue(5);
length[0] = (len > 0) ? len + 1 : 128;
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
if (!(qrp = PlgAllocResult(g, qcol, m_Ncol, IDS_COLUMNS + 3,
buftyp, fldtyp, length, false, true)))
return NULL;
// Some columns must be renamed
for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
switch (++i) {
case 3: crp->Name = "Precision"; break;
case 4: crp->Name = "Scale"; break;
case 5: crp->Name = "Nullable"; break;
} // endswitch i
// Build the java int array
jintArray val = env->NewIntArray(4);
if (val == nullptr) {
strcpy(m_G->Message, "Cannot allocate jint array");
return NULL;
} // endif colid
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
for (i = 0; i < m_Ncol; i++) {
if (!(label = (jstring)env->CallObjectMethod(job, colid, i + 1, val))) {
if (Check())
snprintf(g->Message, sizeof(g->Message), "ColumnDesc: %s", Msg);
else
strcpy(g->Message, "No result metadata");
env->ReleaseIntArrayElements(val, n, 0);
return NULL;
} // endif label
name = GetUTFString(label);
crp = qrp->Colresp; // Column_Name
crp->Kdata->SetValue((char*)name, i);
n = env->GetIntArrayElements(val, 0);
crp = crp->Next; // Data_Type
crp->Kdata->SetValue((int)n[0], i);
crp = crp->Next; // Precision (length)
crp->Kdata->SetValue((int)n[1], i);
crp = crp->Next; // Scale
crp->Kdata->SetValue((int)n[2], i);
crp = crp->Next; // Nullable
crp->Kdata->SetValue((int)n[3], i);
qrp->Nblin++;
} // endfor i
/* Cleanup */
env->ReleaseIntArrayElements(val, n, 0);
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of GetMetaData
/***********************************************************************/
/* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
/***********************************************************************/
int JDBConn::GetCatInfo(JCATPARM *cap)
{
PGLOBAL& g = m_G;
// void *buffer;
int i, ncol;
PCSZ fnc = "Unknown";
uint n;
short len, tp;
PQRYRES qrp = cap->Qrp;
PCOLRES crp;
jboolean rc = false;
// HSTMT hstmt = NULL;
// SQLLEN *vl, *vlen = NULL;
PVAL *pval = NULL;
char* *pbuf = NULL;
jobjectArray parms;
jmethodID catid = nullptr;
if (qrp->Maxres <= 0)
return 0; // 0-sized result"
SQLQualifiedName name(cap);
// Build the java string array
parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL);
env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2)));
env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1)));
env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0)));
env->SetObjectArrayElement(parms, 3, env->NewStringUTF((const char*)cap->Pat));
// Now do call the proper JDBC API
switch (cap->Id) {
case JCAT_COL:
fnc = "GetColumns";
break;
case JCAT_TAB:
fnc = "GetTables";
break;
#if 0
case JCAT_KEY:
fnc = "SQLPrimaryKeys";
rc = SQLPrimaryKeys(hstmt, name.ptr(2), name.length(2),
name.ptr(1), name.length(1),
name.ptr(0), name.length(0));
break;
#endif // 0
default:
snprintf(g->Message, sizeof(g->Message), "Invalid SQL function id");
return -1;
} // endswitch infotype
if (gmID(g, catid, fnc, "([Ljava/lang/String;)I"))
return -1;
// call method
ncol = env->CallIntMethod(job, catid, parms);
if (Check(ncol)) {
snprintf(g->Message, sizeof(g->Message), "%s: %s", fnc, Msg);
env->DeleteLocalRef(parms);
return -1;
} // endif Check
// Not used anymore
env->DeleteLocalRef(parms);
if (trace(1))
htrc("Method %s returned %d columns\n", fnc, ncol);
// n because we no more ignore the first column
if ((n = qrp->Nbcol) > (uint)ncol) {
strcpy(g->Message, MSG(COL_NUM_MISM));
return -1;
} // endif n
// Unconditional to handle STRBLK's
pval = (PVAL *)PlugSubAlloc(g, NULL, n * sizeof(PVAL));
// vlen = (SQLLEN *)PlugSubAlloc(g, NULL, n * sizeof(SQLLEN));
pbuf = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
// Prepare retrieving column values
for (n = 0, crp = qrp->Colresp; crp; crp = crp->Next) {
if (!(tp = GetJDBCType(crp->Type))) {
snprintf(g->Message, sizeof(g->Message), MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
return -1;
} // endif tp
if (!(len = GetTypeSize(crp->Type, crp->Length))) {
len = 255; // for STRBLK's
((STRBLK*)crp->Kdata)->SetSorted(true);
} // endif len
pval[n] = AllocateValue(g, crp->Type, len);
pval[n]->SetNullable(true);
if (crp->Type == TYPE_STRING) {
pbuf[n] = (char*)PlugSubAlloc(g, NULL, len);
// buffer = pbuf[n];
} // endif Type
// } else
// buffer = pval[n]->GetTo_Val();
n++;
} // endfor n
// Now fetch the result
for (i = 0; i < qrp->Maxres; i++) {
if (Check(rc = Fetch(0))) {
snprintf(g->Message, sizeof(g->Message), "Fetch: %s", Msg);
return -1;
} if (rc == 0) {
if (trace(1))
htrc("End of fetches i=%d\n", i);
break;
} // endif rc
for (n = 0, crp = qrp->Colresp; crp; n++, crp = crp->Next) {
SetColumnValue(n + 1, nullptr, pval[n]);
crp->Kdata->SetValue(pval[n], i);
} // endfor n
} // endfor i
if (rc > 0)
qrp->Truncated = true;
return i;
} // end of GetCatInfo
/***********************************************************************/
/* Allocate a CONNECT result structure from the JDBC result. */
/***********************************************************************/
PQRYRES JDBConn::AllocateResult(PGLOBAL g, PTDB tdbp)
{
bool uns;
PCOL colp;
PCOLRES *pcrp, crp;
PQRYRES qrp;
if (!m_Rows) {
strcpy(g->Message, "Void result");
return NULL;
} // endif m_Rows
/*********************************************************************/
/* Allocate the result storage for future retrieval. */
/*********************************************************************/
qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
pcrp = &qrp->Colresp;
qrp->Continued = FALSE;
qrp->Truncated = FALSE;
qrp->Info = FALSE;
qrp->Suball = TRUE;
qrp->BadLines = 0;
qrp->Maxsize = m_Rows;
qrp->Maxres = m_Rows;
qrp->Nbcol = 0;
qrp->Nblin = 0;
qrp->Cursor = 0;
for (colp = tdbp->GetColumns(); colp; colp = colp->GetNext())
if (!colp->IsSpecial()) {
*pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
crp = *pcrp;
pcrp = &crp->Next;
memset(crp, 0, sizeof(COLRES));
crp->Ncol = ++qrp->Nbcol;
crp->Name = colp->GetName();
crp->Type = colp->GetResultType();
crp->Prec = colp->GetScale();
crp->Length = colp->GetLength();
crp->Clen = colp->GetValue()->GetClen();
uns = colp->IsUnsigned();
if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
crp->Clen, 0, FALSE, TRUE, uns))) {
snprintf(g->Message, sizeof(g->Message), MSG(INV_RESULT_TYPE),
GetFormatType(crp->Type));
return NULL;
} // endif Kdata
if (!colp->IsNullable())
crp->Nulls = NULL;
else {
crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
memset(crp->Nulls, ' ', m_Rows);
} // endelse Nullable
((EXTCOL*)colp)->SetCrp(crp);
} // endif colp
*pcrp = NULL;
return qrp;
} // end of AllocateResult