/***********************************************************************/ /* 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. */ /* tabodbc.h is header containing the TABODBC class declarations. */ /* odbconn.h is header containing ODBC connection declarations. */ /***********************************************************************/ #include"global.h" #include"plgdbsem.h" #include"mycat.h" #include"xtable.h" #include"tabext.h" #include"odbccat.h" #include"tabodbc.h" #include"tabmul.h" //#include "reldef.h" #include"tabcol.h" #include"valblk.h" #include"ha_connect.h"
TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBEXT(tdbp)
{
Ocp = tdbp->Ocp; // is that right ?
Cnp = tdbp->Cnp;
Connect = tdbp->Connect;
Ops = tdbp->Ops;
} // end of TDBODBC copy constructor
// Method
PTDB TDBODBC::Clone(PTABS t)
{
PTDB tp;
PODBCCOL cp1, cp2;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBODBC(this);
for (cp1 = (PODBCCOL)Columns; cp1; cp1 = (PODBCCOL)cp1->GetNext()) {
cp2 = new(g) ODBCCOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of CopyOne
/***********************************************************************/ /* Allocate ODBC column description block. */ /***********************************************************************/
PCOL TDBODBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{ returnnew(g) ODBCCOL(cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/ /* Extract the filename from connect string and return it. */ /* This used for Multiple(1) tables. Also prepare a connect string */ /* with a place holder to be used by SetFile. */ /***********************************************************************/
PCSZ TDBODBC::GetFile(PGLOBAL g)
{ if (Connect) { char *p1, *p2; int i;
size_t n;
if (p1) {
p1 += i; // Beginning of file name
p2 = strchr(p1, ';'); // End of file path/name
// Make the File path/name from the connect string
n = (p2) ? p2 - p1 : strlen(p1);
DBQ = (PSZ)PlugSubAlloc(g, NULL, n + 1);
memcpy(DBQ, p1, n);
DBQ[n] = '\0';
// Make the Format used to re-generate Connect (3 = "%s" + 1)
MulConn = (char*)PlugSubAlloc(g, NULL, strlen(Connect) - n + 3);
memcpy(MulConn, Connect, p1 - Connect);
MulConn[p1 - Connect] = '\0';
strcat(strcat(MulConn, "%s"), (p2) ? p2 : ";");
} // endif p1
} // endif Connect
return (DBQ) ? DBQ : (PSZ)"???";
} // end of GetFile
/***********************************************************************/ /* Set DBQ and get the new file name into the connect string. */ /***********************************************************************/ void TDBODBC::SetFile(PGLOBAL g, PCSZ fn)
{ if (MulConn) { int n = strlen(MulConn) + strlen(fn) - 1;
if (n > BufSize) { // Allocate a buffer larger than needed so the chance // of having to reallocate it is reduced.
BufSize = n + 6;
Connect = (char*)PlugSubAlloc(g, NULL, BufSize);
} // endif n
// Make the complete connect string
snprintf(Connect, BufSize, MulConn, fn);
} // endif MultConn
DBQ = PlugDup(g, fn);
} // end of SetFile
/***********************************************************************/ /* MakeInsert: make the Insert statement used with ODBC connection. */ /***********************************************************************/ bool TDBODBC::MakeInsert(PGLOBAL g)
{
PCSZ schmp = NULL; char *catp = NULL, buf[NAM_LEN * 3]; int len = 0; bool oom, b = false;
PCOL colp;
for (colp = Columns; colp; colp = colp->GetNext()) if (colp->IsSpecial()) {
strcpy(g->Message, MSG(NO_ODBC_SPECOL)); returntrue;
} else { // Column name can be encoded in UTF-8
Decode(colp->GetName(), buf, sizeof(buf));
len += (strlen(buf) + 6); // comma + quotes + valist
((PEXTCOL)colp)->SetRank(++Nparm);
} // endif colp
// Below 32 is enough to contain the fixed part of the query if (Catalog && *Catalog)
catp = Catalog;
if (catp)
len += strlen(catp) + 1;
if (Schema && *Schema)
schmp = Schema;
if (schmp)
len += strlen(schmp) + 1;
// Table name can be encoded in UTF-8
Decode(TableName, buf, sizeof(buf));
len += (strlen(buf) + 32);
Query = new(g) STRING(g, len, "INSERT INTO ");
if (catp) {
Query->Append(catp);
if (schmp) {
Query->Append('.');
Query->Append(schmp);
} // endif schmp
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
Query->Append(") VALUES (");
for (int i = 0; i < Nparm; i++)
Query->Append("?,");
if ((oom = Query->IsTruncated()))
strcpy(g->Message, "MakeInsert: Out of memory"); else
Query->RepLast(')');
if (*end) { for (int i = 0; end[i]; i++) if (end[i] == '`')
end[i] = *qc;
strcat(stmt, end);
} // endif end
return stmt;
} // end of MakeDelete #endif// 0
/***********************************************************************/ /* ResetSize: call by TDBMUL when calculating size estimate. */ /***********************************************************************/ void TDBODBC::ResetSize(void)
{
MaxSize = -1;
if (Ocp && Ocp->IsOpen())
Ocp->Close();
} // end of ResetSize
/***********************************************************************/ /* ODBC Cardinality: returns table size in number of rows. */ /***********************************************************************/ int TDBODBC::Cardinality(PGLOBAL g)
{ if (!g) return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) { // Info command, we must return the exact table row number char qry[96], tbn[64];
ODBConn *ocp = new(g) ODBConn(g, this);
if (ocp->Open(Connect, &Ops, Options) < 1) return -1;
// Table name can be encoded in UTF-8
Decode(TableName, tbn, sizeof(tbn));
strcpy(qry, "SELECT COUNT(*) FROM ");
if (Quote)
strcat(strcat(strcat(qry, Quote), tbn), Quote); else
strcat(qry, tbn);
// Allocate a Count(*) column (must not use the default constructor)
Cnp = new(g) ODBCCOL;
Cnp->InitValue(g);
if ((Cardinal = ocp->GetResultSize(qry, Cnp)) < 0) return -3;
ocp->Close();
} else
Cardinal = 10; // To make MySQL happy
return Cardinal;
} // end of Cardinality
/***********************************************************************/ /* ODBC 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 TDBODBC::OpenDB(PGLOBAL g)
{ bool rc = true;
if (Use == USE_OPEN) { /*******************************************************************/ /* Table already open, just replace it at its beginning. */ /*******************************************************************/ if (Memory == 1) { if ((Qrp = Ocp->AllocateResult(g)))
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 (Query && (Rbuf = Ocp->Rewind(Query->GetStr(), (PODBCCOL)Columns)) < 0) { if (Mode != MODE_READX) {
Ocp->Close(); returntrue;
} else {
Rbuf = 0;
}
}
} else {
Rbuf = Qrp->Nblin;
}
/*********************************************************************/ /* Open an ODBC 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 (!Ocp)
Ocp = new(g) ODBConn(g, this); elseif (Ocp->IsOpen())
Ocp->Close();
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) ODBCCOL;
Cnp->InitValue(g);
if ((Qrp = Ocp->AllocateResult(g)))
Memory = 2; // Must be filled else {
strcpy(g->Message, "Result set memory allocation failed"); returntrue;
} // endif n
} else// Void result
Memory = 0;
Ocp->m_Rows = 0;
} else returntrue;
} // endif Memory
if (!(rc = MakeSQL(g, false))) { for (PODBCCOL colp = (PODBCCOL)Columns; colp;
colp = (PODBCCOL)colp->GetNext()) if (!colp->IsSpecial())
colp->AllocateBuffers(g, Rows);
#if0 /***********************************************************************/ /* GetRecpos: return the position of last read record. */ /***********************************************************************/ int TDBODBC::GetRecpos(void)
{ return Fpos;
} // end of GetRecpos #endif// 0
/***********************************************************************/ /* SetRecpos: set the position of next read record. */ /***********************************************************************/ bool TDBODBC::SetRecpos(PGLOBAL g, int recpos)
{ if (Ocp->m_Full) {
Fpos = 0;
CurNum = recpos - 1;
} elseif (Memory == 3) {
Fpos = recpos;
CurNum = -1;
} elseif (Scrollable) { // Is new position in the current row set? if (recpos >= Curpos && recpos < Curpos + Rbuf) {
CurNum = recpos - Curpos;
Fpos = 0;
} else {
Fpos = recpos;
CurNum = 0;
} // endif recpos
} else {
strcpy(g->Message, "This action requires Memory setting or a scrollable cursor"); returntrue;
} // endif's
// Indicate the table position was externally set
Placed = true; returnfalse;
} // end of SetRecpos
/***********************************************************************/ /* Data Base indexed read routine for ODBC access method. */ /***********************************************************************/ bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
{ char c = Quote ? *Quote : 0; int oldlen = Query->GetLength();
PHC hc = To_Def->GetHandler();
if (!(kr || hc->end_range) || op == OP_NEXT ||
Mode == MODE_UPDATE || Mode == MODE_DELETE) { if (!kr && Mode == MODE_READX) { // This is a false indexed read
Rows = Ocp->ExecDirectSQL((char*)Query->GetStr(), (PODBCCOL)Columns);
Mode = MODE_READ; return (Rows < 0);
} // endif key
if (To_CondFil) if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
strcpy(g->Message, "Readkey: Out of memory"); returntrue;
} // endif Append
} // endif To_Condfil
Mode = MODE_READ;
} // endif's op
if (trace(33))
htrc("ODBC ReadKey: Query=%s\n", Query->GetStr());
Rows = Ocp->ExecDirectSQL((char*)Query->GetStr(), (PODBCCOL)Columns);
Query->Truncate(oldlen); return (Rows < 0);
} // end of ReadKey
/***********************************************************************/ /* VRDNDOS: Data Base read routine for odbc access method. */ /***********************************************************************/ int TDBODBC::ReadDB(PGLOBAL g)
{ int rc;
if (trace(2))
htrc("ODBC 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 if (!Ocp->ExecSQLcommand(Query->GetStr())) {
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_EF; // Nothing else to do
} else return RC_FX; // Error
} // endif Mode
/*********************************************************************/ /* Now start the reading process. */ /* Here is the place to fetch the line(s). */ /*********************************************************************/ if (Placed) { if (Fpos && CurNum >= 0)
Rbuf = Ocp->Fetch((Curpos = Fpos));
if (trace(2))
htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
return rc;
} // end of ReadDB
/***********************************************************************/ /* Data Base Insert write routine for ODBC access method. */ /***********************************************************************/ int TDBODBC::WriteDB(PGLOBAL g)
{ int n = Ocp->ExecuteSQL();
/***********************************************************************/ /* Data Base delete line routine for ODBC access method. */ /***********************************************************************/ int TDBODBC::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 (!Ocp->ExecSQLcommand(Query->GetStr())) {
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 ODBC access method. */ /***********************************************************************/ void TDBODBC::CloseDB(PGLOBAL g)
{ if (Ocp)
Ocp->Close();
if (trace(1))
htrc("ODBC CloseDB: closing %s\n", Name);
/***********************************************************************/ /* ODBCCOL constructor used for copying columns. */ /* tdbp is the pointer to the new table descriptor. */ /***********************************************************************/
ODBCCOL::ODBCCOL(ODBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
{
Slen = col1->Slen;
StrLen = col1->StrLen;
Sqlbuf = col1->Sqlbuf;
} // end of ODBCCOL copy constructor
/***********************************************************************/ /* ReadColumn: when SQLFetch is used there is nothing to do as the */ /* column buffer was bind to the record set. This is also the case */ /* when calculating MaxSize (Bufp is NULL even when Rows is not). */ /***********************************************************************/ void ODBCCOL::ReadColumn(PGLOBAL g)
{
PTDBODBC tdbp = (PTDBODBC)To_Tdb; int i = tdbp->Fpos - 1, n = tdbp->CurNum;
if (tdbp->Memory == 3) { // Get the value from the stored memory if (Crp->Nulls && Crp->Nulls[i] == '*') {
Value->Reset();
Value->SetNull(true);
} else {
Value->SetValue_pvblk(Crp->Kdata, i);
Value->SetNull(false);
} // endif Nulls
return;
} // endif Memory
if (StrLen[n] == SQL_NULL_DATA) { // Null value if (Nullable)
Value->SetNull(true);
/*********************************************************************/ /* Fill the allocated result structure. */ /*********************************************************************/ if (Value->IsNull()) { if (Crp->Nulls)
Crp->Nulls[i] = '*'; // Null value
/***********************************************************************/ /* AllocateBuffers: allocate the extended buffer for SQLExtendedFetch */ /* or Fetch. Note: we use Long+1 here because ODBC must have space */ /* for the ending null character. */ /***********************************************************************/ void ODBCCOL::AllocateBuffers(PGLOBAL g, int rows)
{ if (Buf_Type == TYPE_DATE)
Sqlbuf = (TIMESTAMP_STRUCT*)PlugSubAlloc(g, NULL, sizeof(TIMESTAMP_STRUCT));
/***********************************************************************/ /* Returns the buffer to use for Fetch or Extended Fetch. */ /***********************************************************************/ void *ODBCCOL::GetBuffer(DWORD rows)
{ if (rows && To_Tdb) {
assert(rows == (DWORD)((TDBODBC*)To_Tdb)->Rows); return Bufp;
} else return (Buf_Type == TYPE_DATE) ? Sqlbuf : Value->GetTo_Val();
} // end of GetBuffer
/***********************************************************************/ /* Returns the buffer length to use for Fetch or Extended Fetch. */ /***********************************************************************/
SWORD ODBCCOL::GetBuflen(void)
{
SWORD flen;
switch (Buf_Type) { case TYPE_DATE:
flen = (SWORD)sizeof(TIMESTAMP_STRUCT); break; case TYPE_STRING: case TYPE_DECIM:
flen = (SWORD)Value->GetClen() + 1; break; default:
flen = (SWORD)Value->GetClen();
} // endswitch Buf_Type
return flen;
} // end of GetBuflen
/***********************************************************************/ /* WriteColumn: make sure the bind buffer is updated. */ /***********************************************************************/ void ODBCCOL::WriteColumn(PGLOBAL g)
{ /*********************************************************************/ /* Do convert the column value if necessary. */ /*********************************************************************/ if (Value != To_Val)
Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
returnfalse;
} // end of BindParameters #endif// 0
/***********************************************************************/ /* XDBC GetMaxSize: returns table size (not always one row). */ /***********************************************************************/ int TDBXDBC::GetMaxSize(PGLOBAL g)
{ if (MaxSize < 0)
MaxSize = 10; // Just a guess
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/ /* ODBC 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 TDBXDBC::OpenDB(PGLOBAL g)
{ if (trace(1))
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n", this, Tdb_No, Use, Mode);
if (Use == USE_OPEN) {
strcpy(g->Message, "Multiple execution is not allowed"); returntrue;
} // endif use
/*********************************************************************/ /* Open an ODBC 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 (!Ocp) {
Ocp = new(g) ODBConn(g, this);
} elseif (Ocp->IsOpen())
Ocp->Close();
if (Ocp->Open(Connect, &Ops, Options) < 1) returntrue;
Use = USE_OPEN; // Do it now in case we are recursively called
if (Mode != MODE_READ && Mode != MODE_READX) {
strcpy(g->Message, "No INSERT/DELETE/UPDATE of XDBC tables"); returntrue;
} // endif Mode
/*********************************************************************/ /* Get the command to execute. */ /*********************************************************************/ if (!(Cmdlist = MakeCMD(g))) { // Next lines commented out because of CHECK TABLE //Ocp->Close(); //return true;
} // endif Cmdlist
Rows = 1; returnfalse;
} // end of OpenDB
/***********************************************************************/ /* ReadDB: Data Base read routine for xdbc access method. */ /***********************************************************************/ int TDBXDBC::ReadDB(PGLOBAL g)
{ if (Cmdlist) { if (!Query)
Query = new(g)STRING(g, 0, Cmdlist->Cmd); else
Query->Set(Cmdlist->Cmd);
if (Ocp->ExecSQLcommand(Query->GetStr()))
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 XDBC access method. */ /***********************************************************************/ int TDBXDBC::WriteDB(PGLOBAL g)
{
strcpy(g->Message, "Execsrc tables are read only"); return RC_FX;
} // end of DeleteDB
/***********************************************************************/ /* Data Base delete line routine for XDBC access method. */ /***********************************************************************/ int TDBXDBC::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(NO_ODBC_DELETE)); return RC_FX;
} // end of DeleteDB
/***********************************************************************/ /* XSRCCOL public constructor. */ /***********************************************************************/
XSRCCOL::XSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
: ODBCCOL(cdp, tdbp, cprec, i, am)
{ // Set additional ODBC access method information for column.
Flag = cdp->GetOffset();
} // end of XSRCCOL constructor
/***********************************************************************/ /* XSRCCOL constructor used for copying columns. */ /* tdbp is the pointer to the new table descriptor. */ /***********************************************************************/
XSRCCOL::XSRCCOL(XSRCCOL *col1, PTDB tdbp) : ODBCCOL(col1, tdbp)
{
Flag = col1->Flag;
} // end of XSRCCOL copy constructor
/***********************************************************************/ /* ReadColumn: set column value according to Flag. */ /***********************************************************************/ void XSRCCOL::ReadColumn(PGLOBAL g)
{
PTDBXDBC tdbp = (PTDBXDBC)To_Tdb;
/***********************************************************************/ /* WriteColumn: Should never be called. */ /***********************************************************************/ void XSRCCOL::WriteColumn(PGLOBAL g)
{ // Should never be called
} // end of WriteColumn
/* ---------------------------TDBDRV class --------------------------- */
/***********************************************************************/ /* GetResult: Get the list of ODBC drivers. */ /***********************************************************************/
PQRYRES TDBDRV::GetResult(PGLOBAL g)
{ return ODBCDrivers(g, Maxres, false);
} // end of GetResult
/* ---------------------------TDBSRC class --------------------------- */
/***********************************************************************/ /* GetResult: Get the list of ODBC data sources. */ /***********************************************************************/
PQRYRES TDBSRC::GetResult(PGLOBAL g)
{ return ODBCDataSources(g, Maxres, false);
} // end of GetResult
/* ---------------------------TDBOTB class --------------------------- */
/***********************************************************************/ /* GetResult: Get the list of ODBC tables. */ /***********************************************************************/
PQRYRES TDBOTB::GetResult(PGLOBAL g)
{ return ODBCTables(g, Dsn, Schema, Tab, Tabtyp, Maxres, false, &Ops);
} // end of GetResult
/* ---------------------------TDBOCL class --------------------------- */
/***********************************************************************/ /* TDBOCL class constructor. */ /***********************************************************************/
TDBOCL::TDBOCL(PODEF tdp) : TDBOTB(tdp)
{
Colpat = tdp->Colpat;
} // end of TDBOTB constructor
/***********************************************************************/ /* GetResult: Get the list of ODBC table columns. */ /***********************************************************************/
PQRYRES TDBOCL::GetResult(PGLOBAL g)
{ return ODBCColumns(g, Dsn, Schema, Tab, Colpat, Maxres, false, &Ops);
} // end of GetResult
/* ------------------------ End of Tabodbc --------------------------- */
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.25Bemerkung:
(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.