db.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,858 行 · 第 1/5 页

CPP
1,858
字号
///////////////////////////////////////////////////////////////////////////////
// Name:        db.cpp
// Purpose:     Implementation of the wxDb class.  The wxDb class represents a connection
//              to an ODBC data source.  The wxDb class allows operations on the data
//              source such as opening and closing the data source.
// Author:      Doug Card
// Modified by: George Tasker
//              Bart Jourquin
//              Mark Johnson, wxWindows@mj10777.de
// Mods:        Dec, 1998:
//                -Added support for SQL statement logging and database cataloging
// Mods:        April, 1999
//                -Added QUERY_ONLY mode support to reduce default number of cursors
//                -Added additional SQL logging code
//                -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections
//                -Set ODBC option to only read committed writes to the DB so all
//                   databases operate the same in that respect
// Created:     9.96
// RCS-ID:      $Id: db.cpp,v 1.125.2.2 2006/01/17 16:51:03 JS Exp $
// Copyright:   (c) 1996 Remstar International, Inc.
// Licence:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

/*
// SYNOPSIS START
// SYNOPSIS STOP
*/
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
    #pragma implementation "db.h"
#endif

#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifdef DBDEBUG_CONSOLE
    #include "wx/ioswrap.h"
#endif

#ifndef WX_PRECOMP
    #include "wx/string.h"
    #include "wx/object.h"
    #include "wx/list.h"
    #include "wx/utils.h"
    #include "wx/log.h"
#endif
#include "wx/filefn.h"
#include "wx/wxchar.h"

#if wxUSE_ODBC

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>

#include "wx/db.h"

// DLL options compatibility check:
#include "wx/app.h"
WX_CHECK_BUILD_OPTIONS("wxODBC")

WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0;

wxChar const *SQL_LOG_FILENAME         = wxT("sqllog.txt");
wxChar const *SQL_CATALOG_FILENAME     = wxT("catalog.txt");

#ifdef __WXDEBUG__
    extern wxList TablesInUse;
#endif

// SQL Log defaults to be used by GetDbConnection
wxDbSqlLogState SQLLOGstate = sqlLogOFF;

static wxString SQLLOGfn = SQL_LOG_FILENAME;

// The wxDb::errorList is copied to this variable when the wxDb object
// is closed.  This way, the error list is still available after the
// database object is closed.  This is necessary if the database
// connection fails so the calling application can show the operator
// why the connection failed.  Note: as each wxDb object is closed, it
// will overwrite the errors of the previously destroyed wxDb object in
// this variable.  NOTE: This occurs during a CLOSE, not a FREEing of the
// connection
wxChar DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN+1];


// This type defines the return row-struct form
// SQLTablePrivileges, and is used by wxDB::TablePrivileges.
typedef struct
{
   wxChar        tableQual[128+1];
   wxChar        tableOwner[128+1];
   wxChar        tableName[128+1];
   wxChar        grantor[128+1];
   wxChar        grantee[128+1];
   wxChar        privilege[128+1];
   wxChar        grantable[3+1];
} wxDbTablePrivilegeInfo;


/********** wxDbConnectInf Constructor - form 1 **********/
wxDbConnectInf::wxDbConnectInf()
{
    Henv = 0;
    freeHenvOnDestroy = false;

    Initialize();
}  // Constructor


/********** wxDbConnectInf Constructor - form 2 **********/
wxDbConnectInf::wxDbConnectInf(HENV henv, const wxString &dsn, const wxString &userID,
                       const wxString &password, const wxString &defaultDir,
                       const wxString &fileType, const wxString &description)
{
    Henv = 0;
    freeHenvOnDestroy = false;

    Initialize();

    if (henv)
        SetHenv(henv);
    else
        AllocHenv();

    SetDsn(dsn);
    SetUserID(userID);
    SetPassword(password);
    SetDescription(description);
    SetFileType(fileType);
    SetDefaultDir(defaultDir);
}  // wxDbConnectInf Constructor


wxDbConnectInf::~wxDbConnectInf()
{
    if (freeHenvOnDestroy)
    {
        FreeHenv();
    }
}  // wxDbConnectInf Destructor



/********** wxDbConnectInf::Initialize() **********/
bool wxDbConnectInf::Initialize()
{
    freeHenvOnDestroy = false;

    if (freeHenvOnDestroy && Henv)
        FreeHenv();

    Henv = 0;
    Dsn[0] = 0;
    Uid[0] = 0;
    AuthStr[0] = 0;
    ConnectionStr[0] = 0;
    Description.Empty();
    FileType.Empty();
    DefaultDir.Empty();

    useConnectionStr = false;

    return true;
}  // wxDbConnectInf::Initialize()


/********** wxDbConnectInf::AllocHenv() **********/
bool wxDbConnectInf::AllocHenv()
{
    // This is here to help trap if you are getting a new henv
    // without releasing an existing henv
    wxASSERT(!Henv);

    // Initialize the ODBC Environment for Database Operations
    if (SQLAllocEnv(&Henv) != SQL_SUCCESS)
    {
        wxLogDebug(wxT("A problem occurred while trying to get a connection to the data source"));
        return false;
    }

    freeHenvOnDestroy = true;

    return true;
}  // wxDbConnectInf::AllocHenv()


void wxDbConnectInf::FreeHenv()
{
    wxASSERT(Henv);

    if (Henv)
        SQLFreeEnv(Henv);

    Henv = 0;
    freeHenvOnDestroy = false;

}  // wxDbConnectInf::FreeHenv()


void wxDbConnectInf::SetDsn(const wxString &dsn)
{
    wxASSERT(dsn.Length() < WXSIZEOF(Dsn));

    wxStrncpy(Dsn, dsn, WXSIZEOF(Dsn)-1);
    Dsn[WXSIZEOF(Dsn)-1] = 0;  // Prevent buffer overrun
}  // wxDbConnectInf::SetDsn()


void wxDbConnectInf::SetUserID(const wxString &uid)
{
    wxASSERT(uid.Length() < WXSIZEOF(Uid));
    wxStrncpy(Uid, uid, WXSIZEOF(Uid)-1);
    Uid[WXSIZEOF(Uid)-1] = 0;  // Prevent buffer overrun
}  // wxDbConnectInf::SetUserID()


void wxDbConnectInf::SetPassword(const wxString &password)
{
    wxASSERT(password.Length() < WXSIZEOF(AuthStr));

    wxStrncpy(AuthStr, password, WXSIZEOF(AuthStr)-1);
    AuthStr[WXSIZEOF(AuthStr)-1] = 0;  // Prevent buffer overrun
}  // wxDbConnectInf::SetPassword()

void wxDbConnectInf::SetConnectionStr(const wxString &connectStr)
{
    wxASSERT(connectStr.Length() < WXSIZEOF(ConnectionStr));

    useConnectionStr = wxStrlen(connectStr) > 0;

    wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1);
    ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0;  // Prevent buffer overrun
}  // wxDbConnectInf::SetConnectionStr()


/********** wxDbColFor Constructor **********/
wxDbColFor::wxDbColFor()
{
    Initialize();
}  // wxDbColFor::wxDbColFor()


/********** wxDbColFor::Initialize() **********/
void wxDbColFor::Initialize()
{
    s_Field.Empty();
    int i;
    for (i=0; i<7; i++)
    {
        s_Format[i].Empty();
        s_Amount[i].Empty();
        i_Amount[i] = 0;
    }
    i_Nation      = 0;                     // 0=EU, 1=UK, 2=International, 3=US
    i_dbDataType  = 0;
    i_sqlDataType = 0;
    Format(1,DB_DATA_TYPE_VARCHAR,0,0,0);  // the Function that does the work
}  // wxDbColFor::Initialize()


/********** wxDbColFor::Format() **********/
int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType,
                       short columnLength, short decimalDigits)
{
    // ----------------------------------------------------------------------------------------
    // -- 19991224 : mj10777 : Create
    // There is still a lot of work to do here, but it is a start
    // It handles all the basic data-types that I have run into up to now
    // The main work will have be with Dates and float Formatting
    //    (US 1,000.00 ; EU 1.000,00)
    // There are wxWindow plans for locale support and the new wxDateTime.  If
    //    they define some constants (wxEUROPEAN) that can be gloably used,
    //    they should be used here.
    // ----------------------------------------------------------------------------------------
    // There should also be a function to scan in a string to fill the variable
    // ----------------------------------------------------------------------------------------
    wxString tempStr;
    i_Nation      = Nation;                                       // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
    i_dbDataType  = dbDataType;
    i_sqlDataType = sqlDataType;
    s_Field.Printf(wxT("%s%d"),s_Amount[1].c_str(),i_Amount[1]);  // OK for VARCHAR, INTEGER and FLOAT

    if (i_dbDataType == 0)                                        // Filter unsupported dbDataTypes
    {
        if ((i_sqlDataType == SQL_VARCHAR)
#if wxUSE_UNICODE
    #if defined(SQL_WCHAR)
            || (i_sqlDataType == SQL_WCHAR) 
    #endif
    #if defined(SQL_WVARCHAR)
            || (i_sqlDataType == SQL_WVARCHAR)
    #endif
#endif
            || (i_sqlDataType == SQL_LONGVARCHAR))
            i_dbDataType = DB_DATA_TYPE_VARCHAR;
        if ((i_sqlDataType == SQL_C_DATE) || (i_sqlDataType == SQL_C_TIMESTAMP))
            i_dbDataType = DB_DATA_TYPE_DATE;
        if (i_sqlDataType == SQL_C_BIT)
            i_dbDataType = DB_DATA_TYPE_INTEGER;
        if (i_sqlDataType == SQL_NUMERIC)
            i_dbDataType = DB_DATA_TYPE_VARCHAR;   // glt - ??? is this right?
        if (i_sqlDataType == SQL_REAL)
            i_dbDataType = DB_DATA_TYPE_FLOAT;
        if (i_sqlDataType == SQL_C_BINARY)
            i_dbDataType = DB_DATA_TYPE_BLOB;
    }

    if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE))
    {   // DBASE Numeric
        i_dbDataType = DB_DATA_TYPE_FLOAT;
    }

    switch(i_dbDataType)     // TBD: Still a lot of proper formatting to do
    {
        case DB_DATA_TYPE_VARCHAR:
            s_Field = wxT("%s");
            break;
        case DB_DATA_TYPE_INTEGER:
            s_Field = wxT("%d");
            break;
        case DB_DATA_TYPE_FLOAT:
            if (decimalDigits == 0)
                decimalDigits = 2;
            tempStr.Printf(wxT("%%%d.%d"), columnLength, decimalDigits);
            s_Field.Printf(wxT("%sf"), tempStr.c_str());
            break;
        case DB_DATA_TYPE_DATE:
            if (i_Nation == 0)      // timestamp       YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
            {
                s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
            }
            if (i_Nation == 1)      // European        DD.MM.YYYY HH:MM:SS.SSS
            {
                s_Field = wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
            }
            if (i_Nation == 2)      // UK              DD/MM/YYYY HH:MM:SS.SSS
            {
                s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
            }
            if (i_Nation == 3)      // International   YYYY-MM-DD HH:MM:SS.SSS
            {
                s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
            }
            if (i_Nation == 4)      // US              MM/DD/YYYY HH:MM:SS.SSS
            {
                s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
            }
            break;
          case DB_DATA_TYPE_BLOB:
            s_Field.Printf(wxT("Unable to format(%d)-SQL(%d)"), dbDataType,sqlDataType);        //
                break;
        default:
            s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"), dbDataType,sqlDataType);        //
            break;
    };
    return TRUE;
}  // wxDbColFor::Format()


/********** wxDbColInf Constructor **********/
wxDbColInf::wxDbColInf()
{
    Initialize();
}  // wxDbColInf::wxDbColInf()


/********** wxDbColInf Destructor ********/

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?