Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  tabodbc.cpp   Sprache: C

 

/************* Tabodbc C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: TABODBC                                               */
/* -------------                                                       */
/*  Version 3.2                                                        */
/*                                                                     */
/* COPYRIGHT:                                                          */
/* ----------                                                          */
/*  (C) Copyright to the author Olivier BERTRAND          2000-2018    */
/*                                                                     */
/* WHAT THIS PROGRAM DOES:                                             */
/* -----------------------                                             */
/*  This program are the TABODBC class DB execution routines.          */
/*                                                                     */
/* WHAT YOU NEED TO COMPILE THIS PROGRAM:                              */
/* --------------------------------------                              */
/*                                                                     */
/*  REQUIRED FILES:                                                    */
/*  ---------------                                                    */
/*    TABODBC.CPP    - Source code                                     */
/*    PLGDBSEM.H     - DB application declaration file                 */
/*    TABODBC.H      - TABODBC classes declaration file                */
/*    GLOBAL.H       - Global declaration file                         */
/*                                                                     */
/*  REQUIRED LIBRARIES:                                                */
/*  -------------------                                                */
/*    Large model C library                                            */
/*                                                                     */
/*  REQUIRED PROGRAMS:                                                 */
/*  ------------------                                                 */
/*    IBM, Borland, GNU or Microsoft C++ Compiler and Linker           */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/*  Include relevant MariaDB header file.                              */
/***********************************************************************/
#include "my_global.h"
#include "sql_class.h"
#if defined(_WIN32)
#include <io.h>
#include <fcntl.h>
#if defined(__BORLANDC__)
#define __MFC_COMPAT__                   // To define min/max as macro
#endif
//#include <windows.h>
#include <sqltypes.h>
#else
#if defined(UNIX)
#include <errno.h>
#define NODW
#include "osutil.h"
#else
#include <io.h>
#endif
#include <fcntl.h>
#endif

/***********************************************************************/
/*  Include application header files:                                  */
/*  global.h    is header containing all global declarations.          */
/*  plgdbsem.h  is header containing the DB application declarations.  */
/*  kindex.h    is kindex header that also includes tabdos.h.          */
/*  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"

#include "sql_string.h"

/***********************************************************************/
/*  DB static variables.                                               */
/***********************************************************************/
//     int num_read, num_there, num_eq[2], num_nf;        // Statistics
extern int num_read, num_there, num_eq[2];                // Statistics

/***********************************************************************/
/*  External function.                                                 */
/***********************************************************************/
bool ExactInfo(void);

/* -------------------------- Class ODBCDEF -------------------------- */

/***********************************************************************/
/*  Constructor.                                                       */
/***********************************************************************/
ODBCDEF::ODBCDEF(void)
{
  Connect = NULL;
  Catver = 0;
  UseCnc = false;
}  // end of ODBCDEF constructor

/***********************************************************************/
/*  DefineAM: define specific AM block values from XDB file.           */
/***********************************************************************/
bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{
  Desc = Connect = GetStringCatInfo(g, "Connect", NULL);

  if (!Connect && !Catfunc) {
    snprintf(g->Message, sizeof(g->Message), "Missing connection for ODBC table %s", Name);
    return true;
  } // endif Connect

 if (EXTDEF::DefineAM(g, am, poff))
  return true;

  Catver = GetIntCatInfo("Catver", 2);
  Options = ODBConn::noOdbcDialog;
//Options = ODBConn::noOdbcDialog | ODBConn::useCursorLib;
  Cto= GetIntCatInfo("ConnectTimeout", DEFAULT_LOGIN_TIMEOUT);
  Qto= GetIntCatInfo("QueryTimeout", DEFAULT_QUERY_TIMEOUT);
 UseCnc = GetBoolCatInfo("UseDSN", false);
  return false;
} // end of DefineAM

/***********************************************************************/
/*  GetTable: makes a new Table Description Block.                     */
/***********************************************************************/
PTDB ODBCDEF::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) TDBXDBC(this);
  else switch (Catfunc) {
    case FNC_COL:
      tdbp = new(g) TDBOCL(this);
      break;
    case FNC_TABLE:
      tdbp = new(g) TDBOTB(this);
      break;
    case FNC_DSN:
      tdbp = new(g) TDBSRC(this);
      break;
    case FNC_DRIVER:
      tdbp = new(g) TDBDRV(this);
      break;
    default:
      tdbp = new(g) TDBODBC(this);
  
      if (Multiple == 1)
        tdbp = new(g) TDBMUL(tdbp);
      else if (Multiple == 2)
        strcpy(g->Message, MSG(NO_ODBC_MUL));
  } // endswitch Catfunc

  return tdbp;
} // end of GetTable

/* -------------------------- Class TDBODBC -------------------------- */

/***********************************************************************/
/*  Implementation of the TDBODBC class.                               */
/***********************************************************************/
TDBODBC::TDBODBC(PODEF tdp) : TDBEXT(tdp)
{
  Ocp = NULL;
  Cnp = NULL;

  if (tdp) {
    Connect = tdp->Connect;
    Ops.User = tdp->Username;
    Ops.Pwd = tdp->Password;
    Ops.Cto = tdp->Cto;
    Ops.Qto = tdp->Qto;
    Catver = tdp->Catver;
    Ops.UseCnc = tdp->UseCnc;
  } else {
    Connect = NULL;
    Ops.User = NULL;
    Ops.Pwd = NULL;
    Ops.Cto = DEFAULT_LOGIN_TIMEOUT;
    Ops.Qto = DEFAULT_QUERY_TIMEOUT;
    Catver = 0;
    Ops.UseCnc = false;
  } // endif tdp

} // end of TDBODBC standard constructor

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)
{
  return new(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 = strstr(Connect, "DBQ="))) {
   char *p, *lc = strlwr(PlugDup(g, Connect));

   if ((p = strstr(lc, "database=")))
    p1 = Connect + (p - lc);

   i = 9;
  } else
   i = 4;

    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));
      return true;
    } else {
   // Column name can be encoded in UTF-8
   Decode(colp->GetName(), buf, sizeof(buf));
   len += (strlen(buf) + 6);  // comma + quotes + valist
   ((PEXTCOL)colp)->SetRank(++Nparm);
    } // endif colp

 // Below 32 is enough to contain the fixed part of the query
 if (Catalog && *Catalog)
  catp = Catalog;

 if (catp)
  len += strlen(catp) + 1;

 if (Schema && *Schema)
  schmp = Schema;

 if (schmp)
  len += strlen(schmp) + 1;

 // Table name can be encoded in UTF-8
 Decode(TableName, buf, sizeof(buf));
 len += (strlen(buf) + 32);
 Query = new(g) STRING(g, len, "INSERT INTO ");

 if (catp) {
  Query->Append(catp);

  if (schmp) {
   Query->Append('.');
   Query->Append(schmp);
  } // endif schmp

  Query->Append('.');
 } else if (schmp) {
  Query->Append(schmp);
  Query->Append('.');
 } // endif schmp

 if (Quote) {
  // Put table name between identifier quotes in case in contains blanks
  Query->Append(Quote);
  Query->Append(buf);
  Query->Append(Quote);
 } else
  Query->Append(buf);

 Query->Append('(');

 for (colp = Columns; colp; colp = colp->GetNext()) {
  if (b)
   Query->Append(", ");
  else
   b = true;

  // Column name can be in UTF-8 encoding
  Decode(colp->GetName(), buf, sizeof(buf));

  if (Quote) {
   // Put column name between identifier quotes in case in contains blanks
   Query->Append(Quote);
   Query->Append(buf);
   Query->Append(Quote);
  } else
   Query->Append(buf);

 } // endfor colp

 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(')');

  return oom;
} // end of MakeInsert

/***********************************************************************/
/*  ODBC Bind Parameter function.                                      */
/***********************************************************************/
bool TDBODBC::BindParameters(PGLOBAL g)
{
 PODBCCOL colp;

 for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
  colp->AllocateBuffers(g, 0);

  if (Ocp->BindParam(colp))
   return true;

 } // endfor colp

 return false;
} // end of BindParameters

#if 0
/***********************************************************************/
/*  MakeUpdate: make the SQL statement to send to ODBC connection.     */
/***********************************************************************/
char *TDBODBC::MakeUpdate(PGLOBAL g)
{
  char *qc, *stmt = NULL, cmd[8], tab[96], end[1024];

  stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
  memset(end, 0, sizeof(end));

  if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
      sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
    qc = Ocp->GetQuoteChar();
  else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2)
    qc = (Quoted) ? Quote : "";
  else {
    strcpy(g->Message, "Cannot use this UPDATE command");
    return NULL;
  } // endif sscanf

  assert(!stricmp(cmd, "update"));
  strcat(strcat(strcat(strcpy(stmt, "UPDATE "), qc), TableName), qc);

  for (int i = 0; end[i]; i++)
    if (end[i] == '`')
      end[i] = *qc;

  strcat(stmt, end);
  return stmt;
} // end of MakeUpdate

/***********************************************************************/
/*  MakeDelete: make the SQL statement to send to ODBC connection.     */
/***********************************************************************/
char *TDBODBC::MakeDelete(PGLOBAL g)
{
 char *qc, *stmt = NULL, cmd[8], from[8], tab[96], end[512];

 stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
 memset(end, 0, sizeof(end));

 if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
    sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
  qc = Ocp->GetQuoteChar();
 else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
  qc = (Quoted) ? Quote : "";
 else {
  strcpy(g->Message, "Cannot use this DELETE command");
  return NULL;
 } // endif sscanf

 assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
 strcat(strcat(strcat(strcpy(stmt, "DELETE FROM "), qc), TableName), qc);

 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 (trace(1))
    htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
            this, Tdb_No, Use, Mode);

  if (Use == USE_OPEN) {
    /*******************************************************************/
    /*  Table already open, just replace it at its beginning.          */
    /*******************************************************************/
    if (Memory == 1) {
      if ((Qrp = Ocp->AllocateResult(g)))
        Memory = 2;            // Must be filled
      else
        Memory = 0;            // Allocation failed, don't use it

    } else if (Memory == 2)
      Memory = 3;              // Ok to use memory result

    if (Memory < 3) {
      // Method will depend on cursor type
      if (Query && (Rbuf = Ocp->Rewind(Query->GetStr(), (PODBCCOL)Columns)) < 0) {
        if (Mode != MODE_READX) {
          Ocp->Close();
          return true;
        } else {
          Rbuf = 0;
        }
      }
    } else {
      Rbuf = Qrp->Nblin;
    }

    CurNum = 0;
    Fpos = 0;
    Curpos = 1;
    return false;
  } // 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);
  else if (Ocp->IsOpen())
    Ocp->Close();

  if (Ocp->Open(Connect, &Ops, Options) < 1)
    return true;
  else if (Quoted)
    Quote = Ocp->GetQuoteChar();

  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 ((n = Ocp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
     char* msg = PlugDup(g, g->Message);

     snprintf(g->Message, sizeof(g->Message), "Get result size: %s (rc=%d)", msg, n);
     return true;
    } else if (n) {
     Ocp->m_Rows = n;

     if ((Qrp = Ocp->AllocateResult(g)))
      Memory = 2;            // Must be filled
     else {
      strcpy(g->Message, "Result set memory allocation failed");
      return true;
     } // endif n

    } else     // Void result
     Memory = 0;

    Ocp->m_Rows = 0;
   } else
        return true;

    } // endif Memory

    if (!(rc = MakeSQL(g, false))) {
      for (PODBCCOL colp = (PODBCCOL)Columns; colp;
                    colp = (PODBCCOL)colp->GetNext())
        if (!colp->IsSpecial())
          colp->AllocateBuffers(g, Rows);

   rc = (Mode == MODE_READ)
       ? ((Rows = Ocp->ExecDirectSQL(Query->GetStr(), (PODBCCOL)Columns)) < 0)
     : false;
    } // endif rc

  } else if (Mode == MODE_INSERT) {
    if (!(rc = MakeInsert(g))) {
      if (Nparm != Ocp->PrepareSQL(Query->GetStr())) {
        strcpy(g->Message, MSG(PARM_CNT_MISS));
        rc = true;
      } else
        rc = BindParameters(g);

    } // endif rc

  } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
    rc = false;  // wait for CheckCond before calling MakeCommand(g);
  } else
    snprintf(g->Message, sizeof(g->Message), "Invalid mode %d", Mode);

  if (rc) {
    Ocp->Close();
    return true;
  } // endif rc

  /*********************************************************************/
  /*  Reset statistics values.                                         */
  /*********************************************************************/
  num_read = num_there = num_eq[0] = num_eq[1] = 0;
  return false;
} // end of OpenDB

#if 0
/***********************************************************************/
/*  GetRecpos: return the position of last read record.                */
/***********************************************************************/
int 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;
  } else if (Memory == 3) {
    Fpos = recpos;
    CurNum = -1;
  } else if (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");
    return true;
  } // endif's

  // Indicate the table position was externally set
  Placed = true;
  return false;
} // 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

  return false;
 } else {
  if (hc->MakeKeyWhere(g, Query, op, c, kr))
   return true;

  if (To_CondFil) {
   if (To_CondFil->Idx != hc->active_index) {
    To_CondFil->Idx = hc->active_index;
    To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
    *To_CondFil->Body= 0;

    if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond)))
     PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);

   } // endif active_index

   if (To_CondFil)
    if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
     strcpy(g->Message, "Readkey: Out of memory");
     return true;
    } // endif Append

  } // endif To_Condfil

  Mode = MODE_READ;
 } // endif's op

 if (trace(33))
  htrc("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));

    rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
    Placed = false;
  } else {
    if (Memory != 3) {
      if (++CurNum >= Rbuf) {
        Rbuf = Ocp->Fetch();
        Curpos = Fpos + 1;
        CurNum = 0;
        } // endif CurNum

      rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
    } else                 // Getting result from memory
      rc = (Fpos < Qrp->Nblin) ? RC_OK : RC_EF;

    if (rc == RC_OK) {
      if (Memory == 2)
        Qrp->Nblin++;

      Fpos++;                // Used for memory and pos
    } // endif rc

  } // endif Placed

  if (trace(2))
    htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);

  return rc;
} // end of ReadDB

/***********************************************************************/
/*  Data Base Insert write routine for ODBC access method.             */
/***********************************************************************/
int TDBODBC::WriteDB(PGLOBAL g)
{
  int n = Ocp->ExecuteSQL();

  if (n < 0) {
    AftRows = n;
    return RC_FX;
  } else
    AftRows += n;

  return RC_OK;
} // end of WriteDB

/***********************************************************************/
/*  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);

} // end of CloseDB

/* --------------------------- ODBCCOL ------------------------------- */

/***********************************************************************/
/*  ODBCCOL public constructor.                                        */
/***********************************************************************/
ODBCCOL::ODBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
       : EXTCOL(cdp, tdbp, cprec, i, am)
{
  // Set additional ODBC access method information for column.
  Slen = 0;
  StrLen = &Slen;
  Sqlbuf = NULL;
} // end of ODBCCOL constructor

/***********************************************************************/
/*  ODBCCOL private constructor.                                       */
/***********************************************************************/
ODBCCOL::ODBCCOL(void) : EXTCOL()
{
  Slen = 0;
  StrLen = &Slen;
  Sqlbuf = NULL;
} // end of ODBCCOL constructor

/***********************************************************************/
/*  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);

    Value->Reset();
    goto put;
  } else
    Value->SetNull(false);

  if (Bufp && tdbp->Rows) {
    if (Buf_Type == TYPE_DATE)
      *Sqlbuf = ((TIMESTAMP_STRUCT*)Bufp)[n];
    else
      Value->SetValue_pvblk(Blkp, n);

  } // endif Bufp

  if (Buf_Type == TYPE_DATE) {
    struct tm dbtime;

    memset(&dbtime, 0, sizeof(tm));
    dbtime.tm_sec = (int)Sqlbuf->second;
    dbtime.tm_min = (int)Sqlbuf->minute;
    dbtime.tm_hour = (int)Sqlbuf->hour;
    dbtime.tm_mday = (int)Sqlbuf->day;
    dbtime.tm_mon = (int)Sqlbuf->month - 1;
    dbtime.tm_year = (int)Sqlbuf->year - 1900;
    ((DTVAL*)Value)->MakeTime(&dbtime);
  } else if (Buf_Type == TYPE_DECIM && tdbp->Sep) {
    // Be sure to use decimal point
    char *p = strchr(Value->GetCharValue(), tdbp->Sep);

    if (p)
      *p = '.';

  } // endif Buf_Type

  if (trace(2)) {
    char buf[64];

    htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n",
      Name, tdbp->Rows, Bufp, Buf_Type, Value->GetCharString(buf));
  } // endif trace

 put:
  if (tdbp->Memory != 2)
    return;

  /*********************************************************************/
  /*  Fill the allocated result structure.                             */
  /*********************************************************************/
  if (Value->IsNull()) {
    if (Crp->Nulls)
      Crp->Nulls[i] = '*';           // Null value

    Crp->Kdata->Reset(i);
  } else
    Crp->Kdata->SetValue(Value, i);

} // end of ReadColumn

/***********************************************************************/
/*  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));

  if (!rows)
    return;

  if (Buf_Type == TYPE_DATE)
    Bufp = PlugSubAlloc(g, NULL, rows * sizeof(TIMESTAMP_STRUCT));
  else {
    Blkp = AllocValBlock(g, NULL, Buf_Type, rows, GetBuflen(), 
                                  GetScale(), true, false, false);
    Bufp = Blkp->GetValPointer();
  } // endelse

  if (rows > 1)
    StrLen = (SQLLEN *)PlugSubAlloc(g, NULL, rows * sizeof(SQLLEN));

} // end of AllocateBuffers

/***********************************************************************/
/*  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

  if (Buf_Type == TYPE_DATE) {
    struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm);

    Sqlbuf->second = dbtime->tm_sec;
    Sqlbuf->minute = dbtime->tm_min;
    Sqlbuf->hour   = dbtime->tm_hour;
    Sqlbuf->day    = dbtime->tm_mday;
    Sqlbuf->month  = dbtime->tm_mon + 1;
    Sqlbuf->year   = dbtime->tm_year + 1900;
    Sqlbuf->fraction = 0;
  } else if (Buf_Type == TYPE_DECIM) {
    // Some data sources require local decimal separator
    char *p, sep = ((PTDBODBC)To_Tdb)->Sep;

    if (sep && (p = strchr(Value->GetCharValue(), '.')))
      *p = sep;

  } // endif Buf_Type

  if (Nullable)
    *StrLen = (Value->IsNull()) ? SQL_NULL_DATA :
         (IsTypeChar(Buf_Type)) ? SQL_NTS : 0;

} // end of WriteColumn

/* -------------------------- Class TDBXDBC -------------------------- */

/***********************************************************************/
/*  Implementation of the TDBXDBC class.                               */
/***********************************************************************/
TDBXDBC::TDBXDBC(PODEF tdp) : TDBODBC(tdp)
{
  Cmdlist = NULL;
  Cmdcol = NULL;
  Mxr = tdp->Maxerr;
  Nerr = 0;
} // end of TDBXDBC constructor

TDBXDBC::TDBXDBC(PTDBXDBC tdbp) : TDBODBC(tdbp)
{
  Cmdlist = tdbp->Cmdlist;
  Cmdcol = tdbp->Cmdcol;
  Mxr = tdbp->Mxr;
  Nerr = tdbp->Nerr;
} // end of TDBXDBC copy constructor

PTDB TDBXDBC::Clone(PTABS t)
{
  PTDB     tp;
  PXSRCCOL cp1, cp2;
  PGLOBAL  g = t->G;        // Is this really useful ???

  tp = new(g) TDBXDBC(this);

  for (cp1 = (PXSRCCOL)Columns; cp1; cp1 = (PXSRCCOL)cp1->GetNext()) {
    cp2 = new(g) XSRCCOL(cp1, tp);  // Make a copy
    NewPointer(t, cp1, cp2);
  } // endfor cp1

  return tp;
} // end of CopyOne

/***********************************************************************/
/*  Allocate XSRC column description block.                            */
/***********************************************************************/
PCOL TDBXDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
  PXSRCCOL colp = new(g) XSRCCOL(cdp, this, cprec, n);

  if (!colp->Flag)
    Cmdcol = colp->GetName();

  return colp;
} // end of MakeCol

/***********************************************************************/
/*  MakeCMD: make the SQL statement to send to ODBC connection.        */
/***********************************************************************/
PCMD TDBXDBC::MakeCMD(PGLOBAL g)
{
  PCMD xcmd = NULL;

  if (To_CondFil) {
    if (Cmdcol) {
      if (!stricmp(Cmdcol, To_CondFil->Body) &&
          (To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
        xcmd = To_CondFil->Cmds;
      } else
        strcpy(g->Message, "Invalid command specification filter");

    } else
      strcpy(g->Message, "No command column in select list");

  } else if (!Srcdef)
    strcpy(g->Message, "No Srcdef default command");
  else
    xcmd = new(g) CMD(g, Srcdef);

  return xcmd;
} // end of MakeCMD

#if 0
/***********************************************************************/
/*  ODBC Bind Parameter function.                                      */
/***********************************************************************/
bool TDBXDBC::BindParameters(PGLOBAL g)
{
  PODBCCOL colp;

  for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
    colp->AllocateBuffers(g, 0);

    if (Ocp->BindParam(colp))
      return true;

    } // endfor colp

  return false;
} // 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");
    return true;
  } // 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);
  } else if (Ocp->IsOpen())
    Ocp->Close();

  if (Ocp->Open(Connect, &Ops, Options) < 1)
    return true;

  Use = USE_OPEN;       // Do it now in case we are recursively called

  if (Mode != MODE_READ && Mode != MODE_READX) {
    strcpy(g->Message, "No INSERT/DELETE/UPDATE of XDBC tables");
    return true;
  } // 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;
  return false;
} // 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 ------------------------------- */

/***********************************************************************/
/*  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;

  switch (Flag) {
    case  0: Value->SetValue_psz(tdbp->Query->GetStr()); break;
  case  1: Value->SetValue(tdbp->AftRows);             break;
  case  2: Value->SetValue_psz(g->Message);            break;
  default: Value->SetValue_psz("Invalid Flag");        break;
    } // endswitch Flag

} // end of ReadColumn

/***********************************************************************/
/*  WriteColumn: Should never be called.                               */
/***********************************************************************/
void 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 --------------------------- */

/***********************************************************************/
/*  TDBOTB class constructor.                                          */
/***********************************************************************/
TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
{
  Dsn = tdp->GetConnect();
  Schema = tdp->GetTabschema();
  Tab = tdp->GetTabname();
 Tabtyp = tdp->Tabtyp;
  Ops.User = tdp->Username;
  Ops.Pwd = tdp->Password;
  Ops.Cto = tdp->Cto;
  Ops.Qto = tdp->Qto;
  Ops.UseCnc = tdp->UseCnc;
} // end of TDBOTB constructor

/***********************************************************************/
/*  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
C=70 H=96 G=83

¤ Dauer der Verarbeitung: 0.21 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=1126864
#Domains=1897691