DB diff : Compare two databases via ODBC

Download dbdiff.zip

Synopsis:

BaseInfo.h
CheckAttr.h
ColumnRS.cpp
ColumnRS.h
Common.h
Comparer.h
CSql.cpp
CSql.h
CSqlDBC.cpp
CSqlDBC.h
CSqlENV.cpp
CSqlENV.h
CSqlImpl.cpp
CSqlImpl.h
CSqlStmt.cpp
CSqlSTMT.h
dbdiff.cpp
dbgdefines.h
DSNInfo.h
Dumper.h
Header.h
SqlColumn.cpp
SqlColumn.h
SqlQuery.cpp
SqlQuery.h
SqlTable.h
SQPair.h
TableRS.cpp
TableRS.h


BaseInfo.h

Synopsis
#pragma once

#ifndef BASEINFO_H
#define BASEINFO_H

//--------------------------------------------------------------
class BaseInfo
  {
  public:
    BaseInfo()
      {}
    BaseInfo(const string& n)
        : m_name(n)
      {}
    BaseInfo(const UCHAR* const n)
        : m_name((char*)n)
      {}

    BaseInfo(const BaseInfo& d)
        : m_name(d.m_name)
      {}

    const string& name() const
      {
      return m_name;
      }

    bool operator == (const BaseInfo& rhs) const
      {
      return m_name == rhs.m_name;
      }
    bool operator != (const BaseInfo& rhs) const
      {
      return m_name != rhs.m_name;
      }
    bool operator < (const BaseInfo& rhs) const
      {
      return m_name < rhs.m_name;
      }
    bool operator > (const BaseInfo& rhs) const
      {
      return m_name > rhs.m_name;
      }

  private:
    string m_name;
  } ;

#endif

CheckAttr.h

Synopsis
#pragma once

#ifndef CHECKATTR_H
#define CHECKATTR_H

//--------------------------------------------------------------
#include "Header.h"

template < class T >
bool CheckAttr(Header& hdr, const string& colname, const string& attr, const T& lhs, const T& rhs)
  {
  if (lhs == rhs)
    return true;

  hdr.Print();
  cout << "Changed : column " << colname
  << " : '" << attr << "' changed from " << lhs
  << " to " << rhs
  << endl;

  return false;
  }

#endif

ColumnRS.cpp

Synopsis
#include "Common.h"
#include "DSNInfo.h"
#include "CSqlImpl.h"
#include "SqlColumn.h"
#include "ColumnRS.h"

#include "dbgdefines.h"

const int STR_LEN = 128 + 1;
const int REM_LEN = 254 + 1;


struct ColumnRSPrivate
  {

  UCHAR szQualifier[STR_LEN];
  UCHAR szOwner[STR_LEN];
  UCHAR szTableName[STR_LEN];
  UCHAR szColName[STR_LEN];
  UCHAR szTypeName[STR_LEN];
  UCHAR szRemarks[REM_LEN];
  SDWORD Precision;
  SDWORD Length;
  SWORD DataType;
  SWORD Scale;
  SWORD Radix;
  SWORD Nullable;

  SDWORD cbQualifier;
  SDWORD cbOwner;
  SDWORD cbTableName;
  SDWORD cbColName;
  SDWORD cbTypeName;
  SDWORD cbRemarks;
  SDWORD cbDataType;
  SDWORD cbPrecision;
  SDWORD cbLength;
  SDWORD cbScale;
  SDWORD cbRadix;
  SDWORD cbNullable;
  } ;

//--------------------------------------------------------------------------------
ColumnRS::ColumnRS()
  {
  m_priv = new ColumnRSPrivate;
  Clear();
  }

//--------------------------------------------------------------------------------
void ColumnRS::Bind(CSqlImpl& pimpl)
  {
  USHORT i = 1;
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szQualifier, STR_LEN, &m_priv->cbQualifier));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szOwner, STR_LEN, &m_priv->cbOwner));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szTableName, STR_LEN, &m_priv->cbTableName));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szColName, STR_LEN, &m_priv->cbColName));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_SSHORT, &m_priv->DataType, 0, &m_priv->cbDataType));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szTypeName, STR_LEN, &m_priv->cbTypeName));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_SLONG, &m_priv->Precision, 0, &m_priv->cbPrecision));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_SLONG, &m_priv->Length, 0, &m_priv->cbLength));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_SSHORT, &m_priv->Scale, 0, &m_priv->cbScale));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_SSHORT, &m_priv->Radix, 0, &m_priv->cbRadix));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_SSHORT, &m_priv->Nullable, 0, &m_priv->cbNullable));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szRemarks, REM_LEN, &m_priv->cbRemarks));
  }

//--------------------------------------------------------------------------------
void ColumnRS::Clear()
  {
  m_priv->szQualifier[0] = 0;
  m_priv->szQualifier[0] = 0;
  m_priv->szOwner[0] = 0;
  m_priv->szTableName[0] = 0;
  m_priv->szColName[0] = 0;
  m_priv->szTypeName[0] = 0;
  m_priv->szRemarks[0] = 0;
  m_priv->Precision = 0;
  m_priv->Length = 0;
  m_priv->DataType = 0;
  m_priv->Scale = 0;
  m_priv->Radix = 0;
  m_priv->Nullable = 0;
  }

//--------------------------------------------------------------------------------
SqlColumn ColumnRS::GetData()
  {
  return SqlColumn(m_priv->szColName,
      m_priv->DataType,
      m_priv->szTypeName,
      m_priv->Precision,
      m_priv->Length,
      m_priv->Scale,
      m_priv->Radix,
      m_priv->Nullable);
  }

ColumnRS.h

Synopsis
#pragma once

#ifndef COLUMNRS_H
#define COLUMNRS_H

//--------------------------------------------------------------
class ColumnRS
  {
  public:
    ColumnRS();
    void Bind(CSqlImpl& pimpl);
    void Clear();
    SqlColumn GetData();

  private:
    struct ColumnRSPrivate* m_priv;
  } ;

#endif

Common.h

Synopsis
#pragma once

#ifndef COMMON_H
#define COMMON_H

#include <windows.h>
#include <sqlext.h>
#include <iostream>
#include <string>
using namespace std;

#endif

Comparer.h

Synopsis
#pragma once

#ifndef COMPARER_H
#define COMPARER_H 
//--------------------------------------------------------------

class Comparer
  {
  public:
    template < class T >
    void Lists(const string& str, const T& l1, const T& l2, T& result)
      {
      Header header(str);
      typename T::const_iterator it1 = l1.begin();
      typename T::const_iterator it2 = l2.begin();
      while (it1 != l1.end() || it2 != l2.end())
        {
        if (it1 == l1.end())
          {
          header.Print();
          cout << "Added  : " << (*it2).name() << endl;
          it2++;
          continue;
          }
        if (it2 == l2.end())
          {
          header.Print();
          cout << "Deleted: " << (*it1).name() << endl;
          it1++;
          continue;
          }
        if (*it1 > *it2)
          {
          header.Print();
          cout << "Added  : " << (*it2).name() << endl;
          it2++;
          continue;
          }

        if (*it1 < *it2)
          {
          header.Print();
          cout << "Deleted: " << (*it1).name() << endl;
          it1++;
          continue;
          }

        if (verbosity > 0)
          {
          header.Print();
          cout << "Common : " << (*it1).name() << endl;
          }

        if ((*it1).matches(header, *it2))
          result.push_back(*it1);

        it1++;
        it2++;
        }
      }

    //--------------------------------------------------------------
    void Content(const string& str, CSql& s1, CSql& s2, const string& table, SqlColumnsList& cols1)
      {
      SqlColumnsList cols2 = cols1;
      // _ASSERTE(cols1.size() == cols2.size());

      SqlColumnsList::iterator it2;
      SqlColumnsList::iterator it1;

      //creaet SQL statement:
      //     select col1,col2,col3 from table
      string query = "select ";
      for (it1 = cols1.begin(); it1 != cols1.end(); ++it1)
        {
        if (it1 != cols1.begin())
          query += ", ";
        query += (*it1).name();
        }

      query += " from ";
      query += table;

      SqlQuery sq1 = s1.Query();
      SqlQuery sq2 = s2.Query();
      SQPair sqpair(sq1, sq2);

      sqpair.BindColumns(cols1, cols2);
      sqpair.Exec(query);
      sqpair.Fetch();
      while (!sqpair.isEOF())
        {
        if (sqpair.CheckOneEOF("new entry in sq2: ", "new entry in sq1: "))
          continue;

        for (it1 = cols1.begin(), it2 = cols2.begin(); it1 != cols1.end() && it2 != cols1.end(); ++it1, ++it2)
          {
          if ((*it1) != (*it2))
            {
            cout << "column '" << (*it1).name() << "' : " << endl;
            sqpair.Print(it1, it2);
            }
          }

        sqpair.Fetch();
        }

      sqpair.CloseCursor();
      }

  } ;
#endif

CSql.cpp

Synopsis
#include "Common.h"

#include "SqlTable.h"
#include "SqlColumn.h"
#include "CSqlENV.h"
#include "CSqlImpl.h"
#include "TableRS.h"
#include "ColumnRS.h"
#include "DSNInfo.h"
#include "CSql.h"

#include "dbgdefines.h"

//--------------------------------------------------------------
CSql::CSql()
    : m_private(*(new CSqlImpl))
  { }

//--------------------------------------------------------------
CSql::~CSql()
  {
  delete &m_private;
  }

//--------------------------------------------------------------
const DSNInfoList& CSql::GetAllDSNs()
  {
  DSNInfo di;
  for (m_private.GetFirstDSN(di); m_private.IsSuccess(); m_private.GetNextDSN(di))
    m_dsns.push_back(di);

  m_dsns.sort();
  return m_dsns;
  }

//--------------------------------------------------------------
SqlQuery CSql::Query()
  {
  return SqlQuery(m_private);
  }

//--------------------------------------------------------------
void CSql::Connect(const string& dsn)
  {
  m_private.Connect(dsn, "sa", "");
  }

//--------------------------------------------------------------
const SqlTablesList& CSql::GetTables()
  {
  m_tables.clear();
  m_private.FetchTables();

  TableRS row;
  row.Bind(m_private);

  for (; ; )
    {
    row.Clear();
    if (m_private.Fetch())
      break;

    if (row.Skip())
      continue;

    m_tables.push_back(row.GetData());
    }

  m_private.CloseCursor();
  m_tables.sort();
  return m_tables;
  }

//--------------------------------------------------------------
const SqlColumnsList& CSql::GetColumns(const string& table)
  {
  m_columns.clear();
  m_private.FetchColumns(table);

  ColumnRS row;
  row.Bind(m_private);
  for (; ; )
    {
    row.Clear();
    if (m_private.Fetch())
      break;

    m_columns.push_back(row.GetData());
    }

  m_private.CloseCursor();
  m_columns.sort();
  return m_columns;
  }


CSql.h

Synopsis
#pragma once

#ifndef CSQL_H
#define CSQL_H

//--------------------------------------------------------------
#include "SqlQuery.h"

class CSql
  {
  public:
    CSql();
    ~CSql();
    const DSNInfoList& GetAllDSNs();
    void Connect(const string& dsn);
    const SqlTablesList& GetTables();
    const SqlColumnsList& GetColumns(const string& table);
    SqlQuery Query();

  private:
    const CSql& operator= (const CSql&);
    CSqlImpl& m_private;
    DSNInfoList m_dsns;
    SqlTablesList m_tables;
    SqlColumnsList m_columns;
  } ;

#endif

CSqlDBC.cpp

Synopsis
#include "Common.h"
#include "CSqlDBC.h"
#include "CSqlENV.h"
#include "CSqlImpl.h"

#include "dbgdefines.h"

//--------------------------------------------------------------
CSqlDBC::CSqlDBC(CSqlImpl& pimpl)
    : m_private(pimpl), m_hdbc(0), m_connected(false)
  {}

//--------------------------------------------------------------
void CSqlDBC::Alloc()
  {
  m_private.CheckRC(SQLAllocConnect(m_private.henv(), &m_hdbc));
  }

//--------------------------------------------------------------
void CSqlDBC::Connect(const string& dsn, const string& userid, const string& password)
  {
  m_private.CheckRC(SQLConnect(m_hdbc,
      (UCHAR*)dsn.c_str(), SQL_NTS,
      (UCHAR*)userid.c_str(), SQL_NTS,
      (UCHAR*)password.c_str(), SQL_NTS));
  m_connected = true;
  }

//--------------------------------------------------------------
void CSqlDBC::GetTableLimits(SWORD& MaxQualLen, SWORD& MaxOwnerLen, SWORD& MaxNameLen)
  {
  SWORD s;
  m_private.CheckRC(SQLGetInfo(m_hdbc, SQL_MAX_QUALIFIER_NAME_LEN, &MaxQualLen, sizeof(SWORD), &s));
  m_private.CheckRC(SQLGetInfo(m_hdbc, SQL_MAX_OWNER_NAME_LEN, &MaxOwnerLen, sizeof(SWORD), &s));
  m_private.CheckRC(SQLGetInfo(m_hdbc, SQL_MAX_TABLE_NAME_LEN, &MaxNameLen, sizeof(SWORD), &s));
  }

//--------------------------------------------------------------
CSqlDBC::~CSqlDBC()
  {
  if (m_connected && m_hdbc)
    {
    m_private.CheckRC(SQLDisconnect(m_hdbc));
    m_connected = false;
    }

  if (m_hdbc)
    {
    m_private.CheckRC(SQLFreeConnect(m_hdbc));
    }
  }

//--------------------------------------------------------------
HDBC CSqlDBC::h()
  {
  return m_hdbc;
  }


CSqlDBC.h

Synopsis
#pragma once

#ifndef CSQLDBC_H
#define CSQLDBC_H


//--------------------------------------------------------------
class CSqlImpl;
class CSqlDBC
  {
  public:
    explicit CSqlDBC(CSqlImpl& pimpl);
    ~CSqlDBC();
    HDBC h();
    void Alloc();
    void Connect(const string& dsn, const string& userid, const string& password);
    void GetTableLimits(SWORD& MaxQualLen, SWORD& MaxOwnerLen, SWORD& MaxNameLen);

  private:
    CSqlDBC(); //unused
    const CSqlDBC& operator= (const CSqlDBC&);
    CSqlImpl& m_private;
    HDBC m_hdbc;
    bool m_connected;
  } ;

#endif

CSqlENV.cpp

Synopsis
#include "Common.h"
#include "CSqlENV.h"
#include "CSqlImpl.h"
#include "DSNInfo.h"

#include "dbgdefines.h"

//--------------------------------------------------------------
CSqlENV::CSqlENV(CSqlImpl& pimpl)
    : m_private(pimpl), m_henv(0)
  {
  m_private.CheckRC(SQLAllocEnv(&m_henv));
  }

//--------------------------------------------------------------
CSqlENV::~CSqlENV()
  {
  m_private.CheckRC(SQLFreeEnv(m_henv));
  }

//--------------------------------------------------------------
HENV CSqlENV::h()
  {
  return m_henv;
  }

//--------------------------------------------------------------
void CSqlENV::GetFirstDSN(DSNInfo& di)
  {
  SWORD dsnlen;
  SWORD desclen;
  const SWORD descmax = 1024;
  UCHAR dsn[SQL_MAX_DSN_LENGTH];
  UCHAR desc[descmax];

  m_private.SetRC(SQLDataSources(
        m_henv,
        SQL_FETCH_FIRST,
        dsn, SQL_MAX_DSN_LENGTH, &dsnlen,
        desc, descmax, &desclen));
  di = DSNInfo(dsn, desc);
  }

//--------------------------------------------------------------
void CSqlENV::GetNextDSN(DSNInfo& di)
  {
  SWORD dsnlen;
  SWORD desclen;
  const SWORD descmax = 1024;
  UCHAR dsn[SQL_MAX_DSN_LENGTH];
  UCHAR desc[descmax];

  m_private.SetRC(SQLDataSources(
        m_henv,
        SQL_FETCH_NEXT,
        dsn, SQL_MAX_DSN_LENGTH, &dsnlen,
        desc, descmax, &desclen));
  di = DSNInfo(dsn, desc);
  }

CSqlENV.h

Synopsis
#pragma once

#ifndef CSQLENV_H
#define CSQLENV_H

//--------------------------------------------------------------
class CSqlImpl;
class DSNInfo;
class CSqlENV
  {
  public:
    explicit CSqlENV(CSqlImpl& pimpl);
    ~CSqlENV();
    HENV h();
    void GetFirstDSN(DSNInfo& di);
    void GetNextDSN(DSNInfo& di);

  private:
    CSqlENV(); //unused
    const CSqlENV& operator= (const CSqlENV&);
    CSqlImpl& m_private;
    HENV m_henv;
  } ;

#endif

CSqlImpl.cpp

Synopsis
#include "Common.h"
#include "CSqlDBC.h"
#include "CSqlSTMT.h"
#include "CSqlENV.h"
#include "CSqlImpl.h"
#include "DSNInfo.h"

#include "dbgdefines.h"

//--------------------------------------------------------------
CSqlImpl::CSqlImpl()
    : m_rc(SQL_SUCCESS)
  {
  m_env = new CSqlENV(*this);
  m_dbc = new CSqlDBC(*this);
  m_stmt = new CSqlSTMT(*this);
  }

//--------------------------------------------------------------
CSqlImpl::~CSqlImpl()
  {

  delete m_stmt;
  delete m_dbc;
  delete m_env;
  }

//--------------------------------------------------------------
void CSqlImpl::SetRC(RETCODE rc)
  {
  m_rc = rc;
  }

//--------------------------------------------------------------
void CSqlImpl::CheckRC(RETCODE rc)
  {
  m_rc = rc;
  CheckRC();
  }

//--------------------------------------------------------------
bool CSqlImpl::IsSuccess()
  {
  return m_rc == SQL_SUCCESS;
  }

//--------------------------------------------------------------
bool CSqlImpl::IsEndOfData()
  {
  return m_rc == SQL_NO_DATA_FOUND;
  }

//--------------------------------------------------------------
void CSqlImpl::Connect(const string& dsn, const string& userid, const string& password)
  {
  m_dbc->Alloc();
  m_dbc->Connect(dsn, userid, password);
  m_stmt->Alloc();
  }

//--------------------------------------------------------------
void CSqlImpl::GetTableLimits(SWORD& MaxQualLen, SWORD& MaxOwnerLen, SWORD& MaxNameLen)
  {
  m_dbc->GetTableLimits(MaxQualLen, MaxOwnerLen, MaxNameLen);
  }

//--------------------------------------------------------------
void CSqlImpl::GetFirstDSN(DSNInfo& di)
  {
  m_env->GetFirstDSN(di);
  }

//--------------------------------------------------------------
void CSqlImpl::GetNextDSN(DSNInfo& di)
  {
  m_env->GetNextDSN(di);
  }

//--------------------------------------------------------------
void CSqlImpl::CloseCursor()
  {
  m_stmt->CloseCursor();
  }

//--------------------------------------------------------------
void CSqlImpl::FetchTables()
  {
  m_stmt->FetchTables();
  }

//--------------------------------------------------------------
void CSqlImpl::FetchColumns(const string& table)
  {
  m_stmt->FetchColumns(table);
  }

//--------------------------------------------------------------
void CSqlImpl::ExecQuery(const string& sql)
  {
  m_stmt->ExecQuery(sql);
  }

//--------------------------------------------------------------
bool CSqlImpl::Fetch()
  {
  return m_stmt->Fetch();
  }

//--------------------------------------------------------------
HSTMT CSqlImpl::hstmt()
  {
  return m_stmt->h();
  }

//--------------------------------------------------------------
HENV CSqlImpl::henv()
  {
  return m_env->h();
  }

//--------------------------------------------------------------
HDBC CSqlImpl::hdbc()
  {
  return m_dbc->h();
  }

//--------------------------------------------------------------
void CSqlImpl::CheckRC()
  {
  if (IsSuccess())
    return ;

  SWORD pcbErrorMsg;
  SDWORD NativeErr;
  UCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH];
  UCHAR szSqlState[SQL_MAX_MESSAGE_LENGTH];
  m_rc = SQLError(m_env->h(), m_dbc->h(), m_stmt->h(),
      szSqlState, &NativeErr,
      szErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &pcbErrorMsg);

  if (m_rc == SQL_SUCCESS_WITH_INFO)
    cout << "Info : rc=" << m_rc;
  else
    cout << "Error: rc=" << m_rc;
  cout << " nativederr=" << NativeErr
  << " sqlstate=" << szSqlState << endl
  << " msg=" << szErrorMsg
  << endl;
  if (m_rc != SQL_SUCCESS && m_rc != SQL_SUCCESS_WITH_INFO)
    throw m_rc;
  }


CSqlImpl.h

Synopsis
#pragma once

#ifndef CSQLIMPL_H
#define CSQLIMPL_H

//--------------------------------------------------------------
class CSqlSTMT;
class CSqlENV;
class CSqlDBC;

class CSqlImpl
  {
  public:
    CSqlImpl();
    ~CSqlImpl();
    void SetRC(RETCODE rc);
    void CheckRC(RETCODE rc);
    bool IsSuccess();
    bool IsEndOfData();
    void Connect(const string& dsn, const string& userid, const string& password);
    void GetTableLimits(SWORD& MaxQualLen, SWORD& MaxOwnerLen, SWORD& MaxNameLen);
    void GetFirstDSN(DSNInfo& di);
    void GetNextDSN(DSNInfo& di);
    void CloseCursor();
    void FetchTables();
    void FetchColumns(const string& table);
    void ExecQuery(const string& sql);
    bool Fetch();
    HSTMT hstmt();
    HENV henv();
    HDBC hdbc();
    void CheckRC();

  private:
    RETCODE m_rc;
    CSqlSTMT* m_stmt;
    CSqlENV* m_env;
    CSqlDBC* m_dbc;
  } ;

#endif

CSqlStmt.cpp

Synopsis
#include "Common.h"
#include "CSqlSTMT.h"
#include "CSqlENV.h"
#include "CSqlImpl.h"

#include "dbgdefines.h"

//--------------------------------------------------------------
CSqlSTMT::CSqlSTMT(CSqlImpl& pimpl)
: m_private(pimpl), m_hstmt(0)
  {}

//--------------------------------------------------------------
CSqlSTMT::~CSqlSTMT()
  {
  if (m_hstmt)
    {
    m_private.CheckRC(SQLFreeStmt(m_hstmt, SQL_DROP));
    m_hstmt = 0;
    }
  }

//--------------------------------------------------------------
HSTMT CSqlSTMT::h()
  {
  return m_hstmt;
  }

//--------------------------------------------------------------
void CSqlSTMT::Alloc()
  {
  m_private.CheckRC(SQLAllocStmt(m_private.hdbc(), &m_hstmt));
  }

//--------------------------------------------------------------
void CSqlSTMT::CloseCursor()
  {
  m_private.CheckRC(SQLFreeStmt(m_private.hstmt(), SQL_CLOSE));
  }

//--------------------------------------------------------------
void CSqlSTMT::FetchTables()
  {
  m_private.CheckRC(SQLTables(m_hstmt,
    0, SQL_NTS,
    0, SQL_NTS,
    0, SQL_NTS,
    0, SQL_NTS));
  }

//--------------------------------------------------------------
void CSqlSTMT::FetchColumns(const string& table)
  {
  m_private.CheckRC(SQLColumns(m_hstmt,
    NULL, 0,
    NULL, 0,
    (UCHAR*) table.c_str(), SQL_NTS,
    NULL, 0));
  }

//--------------------------------------------------------------
bool CSqlSTMT::Fetch()
  {
  m_private.SetRC(SQLFetch(m_hstmt));
  if (m_private.IsEndOfData())
    return true;
  m_private.CheckRC();
  return false;
  }

//--------------------------------------------------------------
void CSqlSTMT::ExecQuery(const string& sql)
  {
  m_private.CheckRC(SQLPrepare(m_hstmt, (UCHAR*)sql.c_str(), sql.length()+1));
  m_private.CheckRC(SQLExecute(m_hstmt));
  }

CSqlSTMT.h

Synopsis
#pragma once

#ifndef CSQLSTMT_H
#define CSQLSTMT_H

//--------------------------------------------------------------
class CSqlImpl;
class CSqlSTMT
  {
  public:
    explicit CSqlSTMT(CSqlImpl& pimpl);
    ~CSqlSTMT();
    HSTMT h();
    void Alloc();
    void CloseCursor();
    void ExecQuery(const string& sql);
    bool Fetch(); //returns true when done
    void FetchTables();
    void FetchColumns(const string& table);

  private:
    CSqlSTMT(); //unused
    const CSqlSTMT& operator= (const CSqlSTMT&);
    CSqlImpl& m_private;
    HSTMT m_hstmt;
  } ;

#endif

dbdiff.cpp

Synopsis
#include "Common.h"
#include <list>
#include <iomanip>
#include <time.h>

#include "dbgdefines.h"

int verbosity = 0;

#include "DSNInfo.h"
#include "SqlTable.h"
#include "CheckAttr.h"
#include "SqlColumn.h"
#include "SqlQuery.h"
#include "CSql.h"
#include "SQPair.h"
#include "Dumper.h"
#include "Comparer.h"

//--------------------------------------------------------------
int main()
  {
  //int dbgf = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
  //_CrtSetDbgFlag(dbgf | _CRTDBG_LEAK_CHECK_DF);

  clock_t start = clock();
  try
    {
    Dumper d;
    Comparer c;
    CSql s1;
#if 1
    //mdb
    const string dsn1 = "DBDIFFA";
    const string dsn2 = "DBDIFFB";
#endif
#if 0
    //globalstore mine vs jeff's
    const string dsn1 = "DBDIFF1";
    const string dsn2 = "DBDIFF2";
#endif
#if 0
    //gstr v42 vs v43
    const string dsn1 = "DBDIFFX";
    const string dsn2 = "DBDIFFY";
#endif

    d.Dsns(s1.GetAllDSNs());

    s1.Connect(dsn1);

    SqlTablesList t1 = s1.GetTables();
    d.Tables(t1, string("Tables for " + dsn1));

    CSql s2;
    s2.Connect(dsn2);

    SqlTablesList t2 = s2.GetTables();
    d.Tables(t2, string("Tables for " + dsn2));

    SqlTablesList commontables;
    c.Lists("Comparing table lists", t1, t2, commontables);
    d.Tables(commontables, "Common Tables");

    SqlColumnsList commoncolumns;
    for (SqlTablesIterator it = commontables.begin(); it != commontables.end(); ++it)
      {
      string name = (*it).name();
      SqlColumnsList c1 = s1.GetColumns(name);
      SqlColumnsList c2 = s2.GetColumns(name);
      c.Lists(string("Comparing column lists for table: " + name), c1, c2, commoncolumns);
      d.Columns(commoncolumns, string("Common columns for table " + name));

      if (commoncolumns.size() > 0)
        c.Content(string("Comparing content for table: " + name), s1, s2, name, commoncolumns);

      commoncolumns.clear();
      }
    }
  catch (RETCODE rc)
    {
    cout << "An SQL operation failed: rc=" << rc << endl;
    }
  catch (...)
    {
    cout << "An exception occurred" << endl;
    }

  cout << "That took: " << (clock() - start) / CLOCKS_PER_SEC << " seconds" << endl;
  cout << "Done. Press enter to continue..." << endl;
  cin.get();
  return 0;
  }

dbgdefines.h

Synopsis
#pragma once

#ifndef DBGDEFINES_H
#define DBGDEFINES_H

//#include <crtdbg.h>
//_CRTIMP void * __cdecl operator new( unsigned int, int, const char *, int);
//#define new CRT_NEW
//#define CRT_NEW  new(_NORMAL_BLOCK, __FILE__, __LINE__)

#endif

DSNInfo.h

Synopsis
#pragma once

#ifndef DSNINFO_H
#define DSNINFO_H

#include "BaseInfo.h"
#include <list>

//--------------------------------------------------------------
class DSNInfo : public BaseInfo
  {
  public:
    DSNInfo()
      {}
    DSNInfo(const string& n, const string& d)
        : BaseInfo(n), m_desc(d)
      {}
    DSNInfo(const UCHAR* const n, const UCHAR* const d)
        : BaseInfo(n), m_desc((char*)d)
      {}

    DSNInfo(const DSNInfo& d)
        : BaseInfo(d.name()), m_desc(d.m_desc)
      {}

    const string& desc() const
      {
      return m_desc;
      }

  private:
    string m_desc;
  } ;

typedef list < DSNInfo > DSNInfoList;
typedef DSNInfoList::const_iterator DSNInfoIterator;

#endif

Dumper.h

Synopsis
#pragma once

#ifndef DUMPER_H
#define DUMPER_H

//--------------------------------------------------------------
class Dumper
  {
  public:
    void Dsns(const DSNInfoList& l)
      {
      if (verbosity < 2)
        return ;

      cout << setw(25) << "Name" << " " << "Description" << endl;
      cout << setw(25) << setfill('-') << "-" << " " << setw(50) << "-" << setfill(' ') << endl;
      for (DSNInfoIterator it = l.begin(); it != l.end(); it++)
        {
        cout << setw(25) << (*it).name() << " " << (*it).desc() << endl;
        }
      cout << endl << endl;
      }

    //--------------------------------------------------------------
    void Tables(const SqlTablesList& t, const string& prefix)
      {
      if (verbosity < 2)
        return ;

      cout << prefix << endl;
      cout << setw(25) << "Name" << endl;
      cout << setw(25) << setfill('-') << "-" << setfill(' ') << endl;
      for (SqlTablesIterator it = t.begin(); it != t.end(); it++)
        {
        cout << (*it).name() << endl;
        }
      cout << endl << endl;
      }

    //--------------------------------------------------------------
    void Columns(const SqlColumnsList& c, const string& prefix)
      {
      if (verbosity < 2)
        return ;
      cout << prefix << endl;
      cout << setw(25) << "Name" << endl;
      cout << setw(25) << setfill('-') << "-" << setfill(' ') << endl;
      for (SqlColumnsIterator it = c.begin(); it != c.end(); it++)
        {
        cout << (*it).name() << endl;
        }
      cout << endl << endl;
      }

  } ;

#endif

Header.h

Synopsis
#pragma once

#ifndef HEADER_H
#define HEADER_H

//--------------------------------------------------------------
class Header
  {
  public:
    explicit Header(const string& h)
        : m_printed(false), m_header(h)
      { }
    void Print()
      {
      if (m_printed)
        return ;
      cout << m_header << endl;
      m_printed = true;
      }
    ~Header()
      {
      if (m_printed)
        cout << "--- done" << endl << endl;
      }
  private:
    Header();
    bool m_printed;
    const Header& operator=(const Header&);
    const string m_header;
  } ;

#endif

SqlColumn.cpp

Synopsis
#include "Common.h"
#include "SqlColumn.h"
#include "CheckAttr.h"
#include "BaseInfo.h"

#include "dbgdefines.h"

ostream& operator << (ostream& os, const SqlColumn& sc)
  {
  switch (sc.datatype())
    {
  case SQL_DECIMAL:
  case SQL_NUMERIC:
  case SQL_VARCHAR:
  case SQL_CHAR:
    os << (char*) sc.databuf();
    break;
  case SQL_SMALLINT:
    os << *((short*) sc.databuf());
    break;
  case SQL_INTEGER:
    os << *((long*) sc.databuf());
    break;
  case SQL_REAL:
    os << *((float*) sc.databuf());
    break;
  case SQL_FLOAT:
  case SQL_DOUBLE:
    os << *((double*) sc.databuf());
    break;

    }
  return os;
  }

SqlColumn::SqlColumn()
  {}
SqlColumn::SqlColumn(const string& n)
    : BaseInfo(n)
  {}
SqlColumn::SqlColumn(const UCHAR* const name,
    short datatype,
    const UCHAR* const typname,
    long precision,
    long length,
    short scale,
    short radix,
    short nullable)
    : BaseInfo(name),
    m_datatype(datatype),
    m_typename((char*)typname),
    m_precision(precision),
    m_length(length),
    m_scale(scale),
    m_radix(radix),
    m_nullable(nullable) //,
    //m_data(0)
  {}

SqlColumn::SqlColumn(const SqlColumn& t)
    : BaseInfo(t.name()),
    m_datatype(t.m_datatype),
    m_typename(t.m_typename),
    m_precision(t.m_precision),
    m_length(t.m_length),
    m_scale(t.m_scale),
    m_radix(t.m_radix),
    m_nullable(t.m_nullable) //,
    //m_data(0)
  {}

SqlColumn::~SqlColumn()
  {
  // delete [] m_data;
  }

bool SqlColumn::matches(Header& hdr, const SqlColumn& rhs) const
  {
  //these have to be a series of assignments
  //to ensure that all of the CheckAttr() get called!
  bool eq = true;
  eq = CheckAttr(hdr, name(), "TypeName", m_typename, rhs.m_typename) && eq;
  eq = CheckAttr(hdr, name(), "Precision", m_precision, rhs.m_precision) && eq;
  eq = CheckAttr(hdr, name(), "Length", m_length, rhs.m_length) && eq;
  eq = CheckAttr(hdr, name(), "Scale", m_scale, rhs.m_scale) && eq;
  eq = CheckAttr(hdr, name(), "Radix", m_radix, rhs.m_radix) && eq;
  eq = CheckAttr(hdr, name(), "Nullable", m_nullable, rhs.m_nullable) && eq;

  return eq;
  }

short SqlColumn::datatype() const
  {
  return m_datatype;
  }
long SqlColumn::datalen() const
  {
  return m_length;
  }
void* SqlColumn::databuf() const
  {
  return (void*)(char*)m_data;
  }
void SqlColumn::AllocBuffer()
  {
  // delete [] m_data;
  // m_data = new char[m_length];
  // memset(m_data, 0x00, m_length);

  }

bool SqlColumn::operator != (const SqlColumn& rhs) const
  {
  //_ASSERTE(m_data);
  //_ASSERTE(m_data != (char*)0xcdcdcdcd);
  //_ASSERTE(rhs.m_data);
  //_ASSERTE(rhs.m_data != (char*)0xcdcdcdcd);

  if (m_datatype == SQL_VARCHAR)
    return strcmp(m_data, rhs.m_data) != 0;

  return memcmp(m_data, rhs.m_data, m_length) != 0;
  }


SqlColumn.h

Synopsis
#pragma once

#ifndef SQLCOLUMN_H
#define SQLCOLUMN_H

//--------------------------------------------------------------
#include "Header.h"
#include "BaseInfo.h"
#include <list>

class SqlColumn : public BaseInfo
  {
  public:
    SqlColumn();
    SqlColumn(const string& n);
    SqlColumn(const UCHAR* const name,
        short datatype,
        const UCHAR* const typname,
        long precision,
        long length,
        short scale,
        short radix,
        short nullable);
    SqlColumn(const SqlColumn& t);

    ~SqlColumn();

    bool matches(Header& hdr, const SqlColumn& rhs) const;
    short datatype() const;
    long datalen() const;
    void* databuf() const;
    void AllocBuffer();
    bool operator != (const SqlColumn& rhs) const;

  private:
    short m_datatype;
    string m_typename;
    long m_precision;
    long m_length;
    short m_scale;
    short m_radix;
    short m_nullable;
    char m_data[1024];
  } ;

ostream& operator << (ostream& os, const SqlColumn& sc);

typedef list < SqlColumn > SqlColumnsList;
typedef SqlColumnsList::const_iterator SqlColumnsIterator;

#endif

SqlQuery.cpp

Synopsis
#include "Common.h"
#include "CSqlENV.h"
#include "CSqlImpl.h"
#include "SqlQuery.h"


#include "dbgdefines.h"

//--------------------------------------------------------------
SqlQuery::SqlQuery(CSqlImpl& pimpl)
    : m_private(pimpl), m_row(0)
  {}

//--------------------------------------------------------------
SqlQuery::SqlQuery(const SqlQuery& sq)
    : m_private(sq.m_private), m_row(0)
  {}

//--------------------------------------------------------------
void SqlQuery::Exec(const string& sql) const
  {
  m_private.ExecQuery(sql);
  }

//--------------------------------------------------------------
void SqlQuery::CloseCursor() const
  {
  m_private.CloseCursor();
  }

//--------------------------------------------------------------
bool SqlQuery::isEOF() const
  {
  return m_private.IsEndOfData();
  }

//--------------------------------------------------------------
void SqlQuery::Fetch()
  {
  m_private.Fetch();
  ++m_row;
  }

//--------------------------------------------------------------
void SqlQuery::Bind()
  {
  //col.AllocBuffer();
  //#define SQL_C_CHAR    SQL_CHAR             /* CHAR, VARCHAR, DECIMAL, NUMERIC */
  //#define SQL_C_LONG    SQL_INTEGER          /* INTEGER                      */
  //#define SQL_C_SHORT   SQL_SMALLINT         /* SMALLINT                     */
  //#define SQL_C_FLOAT   SQL_REAL             /* REAL                         */
  //#define SQL_C_DOUBLE  SQL_DOUBLE           /* FLOAT, DOUBLE                */
  //#if (ODBCVER >= 0x0300)
  //#define       SQL_C_NUMERIC           SQL_NUMERIC
  //#endif  /* ODBCVER >= 0x0300 */
  //#define SQL_C_DEFAULT 99

  short datatype = SQL_C_DEFAULT;
  switch (m_col->datatype())
    {
  case SQL_VARCHAR:
  case SQL_DECIMAL:
  case SQL_NUMERIC:
  case SQL_CHAR:
    datatype = SQL_C_CHAR;
    break;

  default:
    datatype = m_col->datatype();
    }

  SDWORD s = 0;
  m_private.CheckRC(SQLBindCol(m_private.hstmt(),
      m_colno,
      datatype,
      m_col->databuf(),
      m_col->datalen(),
      &s));
  }

//--------------------------------------------------------------
void SqlQuery::Dump() const
  {
  cout << "sqlquery::dump='" << (char*)(m_col->databuf()) << "'" << endl;
  }

//--------------------------------------------------------------
void SqlQuery::BindColumns(SqlColumnsList& cols)
  {

  USHORT colno = 0;
  for (SqlColumnsList::iterator it = cols.begin(); it != cols.end(); ++it)
    {
    m_col = &(*it);
    m_colno = ++colno;
    Bind();
    }
  }

//--------------------------------------------------------------
long SqlQuery::Row() const
  {
  return m_row;
  }

SqlQuery.h

Synopsis
#pragma once

#ifndef SQLQUERY_H
#define SQLQUERY_H


//--------------------------------------------------------------
class CSqlImpl;

#include "SqlColumn.h"

class SqlQuery
  {
  public:
    explicit SqlQuery(CSqlImpl& pimpl);
    SqlQuery(const SqlQuery& sq);
    void Exec(const string& sql) const;
    void CloseCursor() const;
    void BindColumns(SqlColumnsList& cols);
    void Bind();
    long Row() const;
    bool isEOF() const;
    void Fetch();
    void Dump() const;

  private:
    SqlQuery();
    const SqlQuery& operator=(const SqlQuery&);
    SqlColumn* m_col;
    USHORT m_colno;
    CSqlImpl& m_private;
    long m_row;
  } ;

#endif

SqlTable.h

Synopsis
#pragma once

#ifndef SQLTABLE_H
#define SQLTABLE_H

#include "Header.h"
#include "BaseInfo.h"
#include <string>
#include <list>

//--------------------------------------------------------------

class SqlTable : public BaseInfo
  {

  public:
    SqlTable()
      {}

    SqlTable(const string& n)
        : BaseInfo(n)
      {}

    SqlTable(const UCHAR* const n)
        : BaseInfo(n)
      {}

    SqlTable(const SqlTable& t)
        : BaseInfo(t.name())
      {}

    bool matches(Header& /*hdr*/, const SqlTable& /*rhs*/) const
      {
      return true;
      }

  private:
    //none
  }

;
typedef list < SqlTable > SqlTablesList;
typedef SqlTablesList::const_iterator SqlTablesIterator;

#endif

SQPair.h

Synopsis
#pragma once

#ifndef SQPAIR_H
#define SQPAIR_H

//--------------------------------------------------------------

class SQPair
  {

  public:
    SQPair(SqlQuery& q1, SqlQuery& q2)
        : m_sq1(q1), m_sq2(q2)
      { }

    void BindColumns(SqlColumnsList& cols1, SqlColumnsList& cols2)
      {
      m_sq1.BindColumns(cols1);
      m_sq2.BindColumns(cols2);
      }

    void Exec(const string& query) const
      {
      m_sq1.Exec(query);
      m_sq2.Exec(query);
      }

    void Fetch()
      {
      m_sq1.Fetch();
      m_sq2.Fetch();
      }

    void CloseCursor() const
      {
      m_sq1.CloseCursor();
      m_sq2.CloseCursor();
      }

    bool isEOF() const
      {
      return m_sq1.isEOF() && m_sq2.isEOF();
      }

    bool CheckOneEOF(const string& str1, const string& str2)
      {
      if (m_sq1.isEOF())
        {
        cout << str1;
        m_sq2.Dump();
        m_sq2.Fetch();
        return true;
        }

      if (m_sq2.isEOF())
        {
        cout << str2;
        m_sq1.Dump();
        m_sq1.Fetch();
        return true;
        }

      return false;
      }

    void Print(const SqlColumnsList::iterator& it1, const SqlColumnsList::iterator& it2) const
      {
      cout << "    sq1(" << m_sq1.Row() << "): " << (*it1) << endl;
      cout << "    sq2(" << m_sq2.Row() << "): " << (*it2) << endl;
      }

  private:
    SqlQuery& m_sq1;
    SqlQuery& m_sq2;
  } ;

#endif

TableRS.cpp

Synopsis
#include "Common.h"
#include "DSNInfo.h"
#include "CSqlImpl.h"
#include "SqlTable.h"
#include "TableRS.h"

#include "dbgdefines.h"
const int STR_LEN = 255;

//-------------------------------------------------------------------
struct TableRSPrivate
  {
  TableRSPrivate()
    {
    szQualifier = 0;
    szOwner = 0;
    szName = 0;
    szType = 0;
    szRemarks = 0;

    MaxQualLen = -1;
    MaxOwnerLen = -1;
    MaxNameLen = -1;
    }

  void AllocBuffers()
    {
    //_ASSERTE(MaxQualLen >= 0);
    //_ASSERTE(MaxOwnerLen >= 0);
    //_ASSERTE(MaxNameLen >= 0);

    szQualifier = new char [MaxQualLen + 1];
    szOwner = new char [MaxOwnerLen + 50];
    szName = new char [MaxNameLen + 1];
    szType = new char [STR_LEN + 1];
    szRemarks = new char [STR_LEN + 1];
    }

  ~TableRSPrivate()
    {
    delete [] szQualifier;
    delete [] szOwner;
    delete [] szName;
    delete [] szType;
    delete [] szRemarks;
    }

  void Clear()
    {
    //_ASSERTE(szQualifier);
    //_ASSERTE(szOwner);
    //_ASSERTE(szName);
    //_ASSERTE(szType);
    //_ASSERTE(szRemarks);

    szQualifier[0] = 0;
    szOwner[0] = 0;
    szName[0] = 0;
    szType[0] = 0;
    szRemarks[0] = 0;
    }

  SWORD MaxQualLen;
  SWORD MaxOwnerLen;
  SWORD MaxNameLen;

  char* szQualifier;
  char* szOwner;
  char* szName;
  char* szType;
  char* szRemarks;
  };

//-------------------------------------------------------------------
TableRS::TableRS()
  {
  m_priv = new TableRSPrivate;
  }

//-------------------------------------------------------------------
TableRS::~TableRS()
  {
  delete m_priv;
  }

//-------------------------------------------------------------------
void TableRS::Bind(CSqlImpl& pimpl)
  {
  pimpl.GetTableLimits(m_priv->MaxQualLen, m_priv->MaxOwnerLen, m_priv->MaxNameLen);

  m_priv->AllocBuffers();

  SDWORD s;
  USHORT i = 1;
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szQualifier, m_priv->MaxQualLen, &s));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szOwner, m_priv->MaxOwnerLen, &s));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szName, m_priv->MaxNameLen, &s));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szType, STR_LEN, &s));
  pimpl.CheckRC(SQLBindCol(pimpl.hstmt(), i++, SQL_C_CHAR, m_priv->szRemarks, STR_LEN, &s));
  }

//-------------------------------------------------------------------
void TableRS::Clear()
  {
  m_priv->Clear();
  }

//-------------------------------------------------------------------
SqlTable TableRS::GetData()
  {
  return SqlTable(m_priv->szName);
  }

//-------------------------------------------------------------------
bool TableRS::Skip()
  {
  if (stricmp(m_priv->szType, "SYSTEM TABLE") == 0)
    return true;
  if (stricmp(m_priv->szType, "VIEW") == 0)
    return true;
  return false;
  }


TableRS.h

Synopsis
#pragma once
#ifndef TABLERS_H
#define TABLERS_H

//#include <crtdbg.h>

//--------------------------------------------------------------
class TableRS
  {
  public:
    TableRS();
    ~TableRS();
    void Bind(CSqlImpl& pimpl);
    void Clear();
    SqlTable GetData();
    bool Skip();

  private:
    struct TableRSPrivate* m_priv;
  };

#endif






Contact me about content on this page using john_web-at-arrizza-dot-com
For Web Master or site problems contact: webadmin-at-arrizza-dot-com
Copyright John Arrizza (c) 2001-2010