Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  jdbconn.cpp   Sprache: 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 (const char *p = strstr(src, "%s")) {
  // Place holder for an eventual where clause
  size_t sqry_size = strlen(src) + 3;
  sqry = (char*)PlugSubAlloc(g, NULL, sqry_size);
  snprintf(sqry, sqry_size, "%.*s1=1%s", (int) (p - src), src, p + 2); // 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) {
  snprintf(g->Message, sizeof(g->Message), "Result set column number");
  rc = RC_OK;      // A result set was returned
 } else {
  m_Aff = (int)n;     // Affected rows
  snprintf(g->Message, sizeof(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) {
   snprintf(g->Message, sizeof(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)
   snprintf(g->Message, sizeof(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) {
    snprintf(g->Message, sizeof(g->Message), "Cannot find Timestamp class");
    return true;
   } else if (!(dtc = env->GetMethodID(dat, "<init>", "(J)V"))) {
    snprintf(g->Message, sizeof(g->Message), "Cannot find Timestamp class constructor");
    return true;
   } // endif's

   lg = (jlong)val->GetBigintValue() * 1000;

   if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) {
    snprintf(g->Message, sizeof(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) {
   snprintf(g->Message, sizeof(g->Message), "Srcdef is not returning a result set");
   return NULL;
  } else if ((rc) == RC_FX) {
   return NULL;
  } else if (m_Ncol == 0) {
   snprintf(g->Message, sizeof(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
     snprintf(g->Message, sizeof(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) {
   snprintf(g->Message, sizeof(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) {
   snprintf(g->Message, sizeof(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

Messung V0.5 in Prozent
C=73 H=96 G=85

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet am  2026-10-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

letze Version des Elbe Quellennavigators


Jenseits des Üblichen ....
    

Besucher

Besucher

Statistik
#Sources=1126438
#Domains=1867298