/***********************************************************************/ /* Include application header files: */ /* global.h is header containing all global declarations. */ /* plgdbsem.h is header containing the DB application declarations. */ /* kindex.h is kindex header that also includes tabdos.h. */ /* tabJDBC.h is header containing the TABJDBC class declarations. */ /* JDBConn.h is header containing JDBC connection declarations. */ /***********************************************************************/ #include"global.h" #include"plgdbsem.h" #include"mycat.h" #include"xtable.h" #include"tabext.h" #include"tabjdbc.h" #include"tabmul.h" #include"tabcol.h" #include"valblk.h" #include"ha_connect.h"
/* -------------------------- Class JDBCDEF -------------------------- */
/***********************************************************************/ /* Constructor. */ /***********************************************************************/
JDBCDEF::JDBCDEF(void)
{
Driver = Url = Wrapname = NULL;
} // end of JDBCDEF constructor
/***********************************************************************/ /* Called on table construction. */ /***********************************************************************/ bool JDBCDEF::SetParms(PJPARM sjp)
{
sjp->Url= Url;
sjp->User= Username;
sjp->Pwd= Password; //sjp->Properties = Prop; returntrue;
} // end of SetParms
/***********************************************************************/ /* Parse connection string */ /* */ /* SYNOPSIS */ /* ParseURL() */ /* Url The connection string to parse */ /* */ /* DESCRIPTION */ /* This is used to set the Url in case a wrapper server as been */ /* specified. This is rather experimental yet. */ /* */ /* RETURN VALUE */ /* RC_OK Url was a true URL */ /* RC_NF Url was a server name/table */ /* RC_FX Error */ /* */ /***********************************************************************/ int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b)
{ if (strncmp(url, "jdbc:", 5)) {
PSZ p;
// No "jdbc:" in connection string. Must be a straight // "server" or "server/table" // ok, so we do a little parsing, but not completely! if ((p = strchr(url, '/'))) { // If there is a single '/' in the connection string, // this means the user is specifying a table name
*p++= '\0';
// there better not be any more '/'s ! if (strchr(p, '/')) return RC_FX;
Tabname = p;
} // endif
if (trace(1))
htrc("server: %s Tabname: %s", url, Tabname);
// Now make the required URL
FOREIGN_SERVER *server, server_buffer;
// get_server_by_name() clones the server if exists if (!(server= get_server_by_name(current_thd->mem_root, url, &server_buffer))) {
snprintf(g->Message, sizeof(g->Message), "Server %s does not exist!", url); return RC_FX;
} // endif server
#ifdefined(DEVELOPMENT) if (*server->host == '@') {
Url = GetUserVariable(g, (const uchar*)&server->host[1]);
} else #endif// 0 if (strncmp(server->host, "jdbc:", 5)) { // Now make the required URL
Url = (PSZ)PlugSubAlloc(g, NULL, 0);
strcat(strcpy(Url, "jdbc:"), server->scheme);
strcat(strcat(Url, "://"), server->host);
// Url was a JDBC URL, nothing to do return RC_OK;
} // end of ParseURL
/***********************************************************************/ /* DefineAM: define specific AM block values from JDBC file. */ /***********************************************************************/ bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{ int rc = RC_OK;
// Default values may have been set in ParseURL
Memory = GetIntCatInfo("Memory", Memory);
Driver = GetStringCatInfo(g, "Driver", Driver);
Wrapname = GetStringCatInfo(g, "Wrapper", Wrapname); returnfalse;
} // end of DefineAM
/***********************************************************************/ /* GetTable: makes a new Table Description Block. */ /***********************************************************************/
PTDB JDBCDEF::GetTable(PGLOBAL g, MODE m)
{
PTDB tdbp = NULL;
/*********************************************************************/ /* Allocate a TDB of the proper type. */ /* Column blocks will be allocated only when needed. */ /*********************************************************************/ if (Xsrc)
tdbp = new(g)TDBXJDC(this); elseswitch (Catfunc) { case FNC_COL:
tdbp = new(g)TDBJDBCL(this); break; #if0 case FNC_DSN:
tdbp = new(g)TDBJSRC(this); break; #endif// 0 case FNC_TABLE:
tdbp = new(g)TDBJTB(this); break; case FNC_DRIVER:
tdbp = new(g)TDBJDRV(this); break; default:
tdbp = new(g)TDBJDBC(this);
/***********************************************************************/ /* The MySQL and MariaDB JDBC drivers return by default a result set */ /* containing the entire result of the executed query. This can be an */ /* issue for big tables and memory error can occur. An alternative is */ /* to use streaming (reading one row at a time) but to specify this, */ /* a fetch size of the integer min value must be send to the driver. */ /***********************************************************************/ int JDBCPARM::CheckSize(int rows)
{ if (Url && rows == 1) { // Are we connected to a MySQL JDBC connector? bool b = (!strncmp(Url, "jdbc:mysql:", 11) ||
!strncmp(Url, "jdbc:mariadb:", 13)); return b ? INT_MIN32 : rows;
} else return rows;
} // end of CheckSize
/* -------------------------- Class TDBJDBC -------------------------- */
/***********************************************************************/ /* Implementation of the TDBJDBC class. */ /***********************************************************************/
TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBEXT(tdp)
{
Jcp = NULL;
Cnp = NULL;
if (Quote) { // Put table name between identifier quotes in case in contains blanks
Query->Append(Quote);
Query->Append(buf);
Query->Append(Quote);
} else
Query->Append(buf);
Query->Append('(');
for (colp = Columns; colp; colp = colp->GetNext()) { if (b)
Query->Append(", "); else
b = true;
// Column name can be in UTF-8 encoding
Decode(colp->GetName(), buf, sizeof(buf));
if (Quote) { // Put column name between identifier quotes in case in contains blanks
Query->Append(Quote);
Query->Append(buf);
Query->Append(Quote);
} else
Query->Append(buf);
} // endfor colp
if ((Query->Append(") VALUES ("))) {
safe_strcpy(g->Message, sizeof(g->Message), "MakeInsert: Out of memory"); returntrue;
} else// in case prepared statement fails
pos = Query->GetLength();
// Make prepared statement for (int i = 0; i < Nparm; i++)
Query->Append("?,");
if (Query->IsTruncated()) {
safe_strcpy(g->Message, sizeof(g->Message), "MakeInsert: Out of memory"); returntrue;
} else
Query->RepLast(')');
// Now see if we can use prepared statement if (Jcp->PrepareSQL(Query->GetStr()))
Query->Truncate(pos); // Restore query to not prepared else
Prepared = true;
if (trace(33))
htrc("Insert=%s\n", Query->GetStr());
// Allocate a Count(*) column (must not use the default constructor)
Cnp = new(g)JDBCCOL;
Cnp->InitValue(g);
if ((Cardinal = jcp->GetResultSize(qry, Cnp)) < 0) return -3;
jcp->Close();
} else #endif// 0
Cardinal = 10; // To make MariaDB happy
return Cardinal;
} // end of Cardinality
/***********************************************************************/ /* JDBC Access Method opening routine. */ /* New method now that this routine is called recursively (last table */ /* first in reverse order): index blocks are immediately linked to */ /* join block of next table if it exists or else are discarted. */ /***********************************************************************/ bool TDBJDBC::OpenDB(PGLOBAL g)
{ bool rc = true;
if (Use == USE_OPEN) { if (Mode == MODE_READ || Mode == MODE_READX) { /*****************************************************************/ /* Table already open, just replace it at its beginning. */ /*****************************************************************/ if (Memory == 1) { if ((Qrp = Jcp->AllocateResult(g, this)))
Memory = 2; // Must be filled else
Memory = 0; // Allocation failed, don't use it
} elseif (Memory == 2)
Memory = 3; // Ok to use memory result
if (Memory < 3) { // Method will depend on cursor type if ((Rbuf = Query ? Jcp->Rewind(Query->GetStr()) : 0) < 0)
{ if (Mode != MODE_READX) {
Jcp->Close(); returntrue;
} else
Rbuf = 0;
}
/*********************************************************************/ /* Open an JDBC connection for this table. */ /* Note: this may not be the proper way to do. Perhaps it is better */ /* to test whether a connection is already open for this datasource */ /* and if so to allocate just a new result set. But this only for */ /* drivers allowing concurency in getting results ??? */ /*********************************************************************/ if (!Jcp)
Jcp = new(g)JDBConn(g, Wrapname); elseif (Jcp->IsOpen())
Jcp->Close();
if (Jcp->Connect(&Ops)) returntrue; elseif (Quoted)
Quote = Jcp->GetQuoteChar();
if (Mode != MODE_READ && Mode != MODE_READX) if (Jcp->SetUUID(g, this))
PushWarning(g, this, 1);
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/ /* Make the command and allocate whatever is used for getting results*/ /*********************************************************************/ if (Mode == MODE_READ || Mode == MODE_READX) { if (Memory > 1 && !Srcdef) { int n;
if (!MakeSQL(g, true)) { // Allocate a Count(*) column
Cnp = new(g)JDBCCOL;
Cnp->InitValue(g);
#if0 /***********************************************************************/ /* GetRecpos: return the position of last read record. */ /***********************************************************************/ int TDBJDBC::GetRecpos(void)
{ return Fpos;
} // end of GetRecpos #endif// 0
/***********************************************************************/ /* SetRecpos: set the position of next read record. */ /***********************************************************************/ bool TDBJDBC::SetRecpos(PGLOBAL g, int recpos)
{ if (Jcp->m_Full) {
Fpos = 0;
CurNum = 1;
} elseif (Memory == 3) {
Fpos = 0;
CurNum = recpos;
} elseif (Ops.Scrollable) { // Is new position in the current row set? if (recpos > 0 && recpos <= Rbuf) {
CurNum = recpos;
Fpos = recpos;
} else {
safe_strcpy(g->Message, sizeof(g->Message), "Scrolling out of row set NIY"); returntrue;
} // endif recpos
if (To_CondFil) if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
safe_strcpy(g->Message, sizeof(g->Message), "Readkey: Out of memory"); returntrue;
} // endif Append
} // endif To_Condfil
Mode = MODE_READ;
} // endif's op
if (trace(33))
htrc("JDBC ReadKey: Query=%s\n", Query->GetStr());
rc = Jcp->ExecuteQuery((char*)Query->GetStr());
Query->Truncate(oldlen);
Rows = 1; // ??? return (rc != RC_OK);
} // end of ReadKey
/***********************************************************************/ /* Data Base read routine for JDBC access method. */ /***********************************************************************/ int TDBJDBC::ReadDB(PGLOBAL g)
{ int rc;
if (trace(2))
htrc("JDBC ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) { if (!Query && MakeCommand(g)) return RC_FX;
// Send the UPDATE/DELETE command to the remote table
rc = Jcp->ExecuteUpdate(Query->GetStr());
if (rc == RC_OK) {
AftRows = Jcp->m_Aff; return RC_EF; // Nothing else to do
} else {
Werr = true; return RC_FX;
} // endif rc
} // endif Mode
/*********************************************************************/ /* Now start the reading process. */ /* Here is the place to fetch the line(s). */ /*********************************************************************/ if (Placed) { if (Fpos && CurNum >= 0)
Rbuf = Jcp->Fetch((Curpos = Fpos)); else
Fpos = CurNum;
if (trace(2))
htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
return rc;
} // end of ReadDB
/***********************************************************************/ /* Data Base Insert write routine for JDBC access method. */ /***********************************************************************/ int TDBJDBC::WriteDB(PGLOBAL g)
{ int rc;
// Statement was not prepared, we must construct and execute // an insert query for each line to insert
uint len = Query->GetLength(); char buf[64];
// Make the Insert command value list for (PCOL colp = Columns; colp; colp = colp->GetNext()) { if (!colp->GetValue()->IsNull()) { char *s = colp->GetValue()->GetCharString(buf);
/***********************************************************************/ /* Data Base delete line routine for JDBC access method. */ /***********************************************************************/ int TDBJDBC::DeleteDB(PGLOBAL g, int irc)
{ if (irc == RC_FX) { if (!Query && MakeCommand(g)) return RC_FX;
// Send the DELETE (all) command to the remote table if (Jcp->ExecuteUpdate(Query->GetStr()) == RC_OK) {
AftRows = Jcp->m_Aff;
snprintf(g->Message, sizeof(g->Message), "%s: %d affected rows", TableName, AftRows);
if (trace(1))
htrc("%s\n", g->Message);
PushWarning(g, this, 0); // 0 means a Note return RC_OK; // This is a delete all
} else return RC_FX; // Error
} else return RC_OK; // Ignore
} // end of DeleteDB
/***********************************************************************/ /* Data Base close routine for JDBC access method. */ /***********************************************************************/ void TDBJDBC::CloseDB(PGLOBAL g)
{ if (Jcp)
Jcp->Close();
if (trace(1))
htrc("JDBC CloseDB: closing %s\n", Name);
/***********************************************************************/ /* JDBCCOL public constructor. */ /***********************************************************************/
JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
: EXTCOL(cdp, tdbp, cprec, i, am)
{
uuid = false;
} // end of JDBCCOL constructor
/***********************************************************************/ /* JDBCCOL private constructor. */ /***********************************************************************/
JDBCCOL::JDBCCOL(void) : EXTCOL()
{
uuid = false;
} // end of JDBCCOL constructor
/***********************************************************************/ /* JDBCCOL constructor used for copying columns. */ /* tdbp is the pointer to the new table descriptor. */ /***********************************************************************/
JDBCCOL::JDBCCOL(JDBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
{
uuid = col1->uuid;
} // end of JDBCCOL copy constructor
/***********************************************************************/ /* ReadColumn: retrieve the column value via the JDBC driver. */ /***********************************************************************/ void JDBCCOL::ReadColumn(PGLOBAL g)
{
PTDBJDBC tdbp = (PTDBJDBC)To_Tdb; int i = tdbp->Fpos - 1;
if (tdbp->Memory == 3) { // Get the value from the stored memory if (Crp->Nulls && Crp->Nulls[i] == '*') {
Value->Reset();
Value->SetNull(true);
} else {
Value->SetValue_pvblk(Crp->Kdata, i);
Value->SetNull(false);
} // endif Nulls
return;
} // endif Memory
/*********************************************************************/ /* Get the column value. */ /*********************************************************************/
tdbp->Jcp->SetColumnValue(Rank, Name, Value);
if (tdbp->Memory != 2) return;
/*********************************************************************/ /* Fill the allocated result structure. */ /*********************************************************************/ if (Value->IsNull()) { if (Crp->Nulls)
Crp->Nulls[i] = '*'; // Null value
/***********************************************************************/ /* WriteColumn: Convert if necessary. */ /***********************************************************************/ void JDBCCOL::WriteColumn(PGLOBAL g)
{ /*********************************************************************/ /* Do convert the column value if necessary. */ /*********************************************************************/ if (Value != To_Val)
Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
} // end of WriteColumn
/* -------------------------- Class TDBXJDC -------------------------- */
/***********************************************************************/ /* Implementation of the TDBXJDC class. */ /***********************************************************************/
TDBXJDC::TDBXJDC(PJDBCDEF tdp) : TDBJDBC(tdp)
{
Cmdlist = NULL;
Cmdcol = NULL;
Mxr = tdp->Maxerr;
Nerr = 0;
} // end of TDBXJDC constructor
/***********************************************************************/ /* XDBC GetMaxSize: returns table size (not always one row). */ /***********************************************************************/ int TDBXJDC::GetMaxSize(PGLOBAL g)
{ if (MaxSize < 0)
MaxSize = 2; // Just a guess
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/ /* JDBC Access Method opening routine. */ /* New method now that this routine is called recursively (last table */ /* first in reverse order): index blocks are immediately linked to */ /* join block of next table if it exists or else are discarted. */ /***********************************************************************/ bool TDBXJDC::OpenDB(PGLOBAL g)
{ if (trace(1))
htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n", this, Tdb_No, Use, Mode);
if (Use == USE_OPEN) {
safe_strcpy(g->Message, sizeof(g->Message), "Multiple execution is not allowed"); returntrue;
} // endif use
/*********************************************************************/ /* Open an JDBC connection for this table. */ /* Note: this may not be the proper way to do. Perhaps it is better */ /* to test whether a connection is already open for this datasource */ /* and if so to allocate just a new result set. But this only for */ /* drivers allowing concurency in getting results ??? */ /*********************************************************************/ if (!Jcp) {
Jcp = new(g) JDBConn(g, Wrapname);
} elseif (Jcp->IsOpen())
Jcp->Close();
if (Jcp->Connect(&Ops)) returntrue;
Use = USE_OPEN; // Do it now in case we are recursively called
if (Mode != MODE_READ && Mode != MODE_READX) {
safe_strcpy(g->Message, sizeof(g->Message), "No INSERT/DELETE/UPDATE of XJDBC tables"); returntrue;
} // endif Mode
/*********************************************************************/ /* Get the command to execute. */ /*********************************************************************/ if (!(Cmdlist = MakeCMD(g))) { // Next lines commented out because of CHECK TABLE //Jcp->Close(); //return true;
} // endif Query
Rows = 1; returnfalse;
} // end of OpenDB
/***********************************************************************/ /* ReadDB: Data Base read routine for xdbc access method. */ /***********************************************************************/ int TDBXJDC::ReadDB(PGLOBAL g)
{ if (Cmdlist) { int rc;
if (!Query)
Query = new(g) STRING(g, 0, Cmdlist->Cmd); else
Query->Set(Cmdlist->Cmd);
if ((rc = Jcp->ExecuteCommand(Query->GetStr())) == RC_FX)
Nerr++;
Fpos++; // Used for progress info
Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next; return RC_OK;
} else {
PushWarning(g, this, 1); return RC_EF;
} // endif Cmdlist
} // end of ReadDB
/***********************************************************************/ /* Data Base write line routine for JDBC access method. */ /***********************************************************************/ int TDBXJDC::WriteDB(PGLOBAL g)
{
safe_strcpy(g->Message, sizeof(g->Message), "Execsrc tables are read only"); return RC_FX;
} // end of DeleteDB
/***********************************************************************/ /* Data Base delete line routine for JDBC access method. */ /***********************************************************************/ int TDBXJDC::DeleteDB(PGLOBAL g, int irc)
{
safe_strcpy(g->Message, sizeof(g->Message), "NO_XJDBC_DELETE"); return RC_FX;
} // end of DeleteDB
/***********************************************************************/ /* JSRCCOL public constructor. */ /***********************************************************************/
JSRCCOL::JSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
: JDBCCOL(cdp, tdbp, cprec, i, am)
{ // Set additional JDBC access method information for column.
Flag = cdp->GetOffset();
} // end of JSRCCOL constructor
/***********************************************************************/ /* ReadColumn: set column value according to Flag. */ /***********************************************************************/ void JSRCCOL::ReadColumn(PGLOBAL g)
{
PTDBXJDC tdbp = (PTDBXJDC)To_Tdb;
/***********************************************************************/ /* WriteColumn: Should never be called. */ /***********************************************************************/ void JSRCCOL::WriteColumn(PGLOBAL g)
{ // Should never be called
} // end of WriteColumn
/* ---------------------------TDBJDRV class -------------------------- */
/***********************************************************************/ /* GetResult: Get the list of JDBC drivers. */ /***********************************************************************/
PQRYRES TDBJDRV::GetResult(PGLOBAL g)
{ return JDBCDrivers(g, Maxres, false);
} // end of GetResult
/* ---------------------------TDBJTB class --------------------------- */
/***********************************************************************/ /* GetResult: Get the list of JDBC tables. */ /***********************************************************************/
PQRYRES TDBJTB::GetResult(PGLOBAL g)
{ return JDBCTables(g, Schema, Tab, Tabtype, Maxres, false, &Ops);
} // end of GetResult
/* --------------------------TDBJDBCL class -------------------------- */
/***********************************************************************/ /* TDBJDBCL class constructor. */ /***********************************************************************/
TDBJDBCL::TDBJDBCL(PJDBCDEF tdp) : TDBJTB(tdp)
{
Colpat = tdp->Colpat;
} // end of TDBJDBCL constructor
/***********************************************************************/ /* GetResult: Get the list of JDBC table columns. */ /***********************************************************************/
PQRYRES TDBJDBCL::GetResult(PGLOBAL g)
{ return JDBCColumns(g, Schema, Tab, Colpat, Maxres, false, &Ops);
} // end of GetResult
Messung V0.5 in Prozent
¤ 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.0.24Bemerkung:
(vorverarbeitet am 2026-10-08)
¤
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.