home *** CD-ROM | disk | FTP | other *** search
- // LoadDataDlg.cpp : implementation file
- //
- // This file is part of Microsoft SQL Server online documentation.
- // Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
- //
- // This source code is an intended supplement to the Microsoft SQL
- // Server online references and related electronic documentation.
- #include "stdafx.h"
- #include "LoadData.h"
- #include "LDDlg.h"
-
- #include "GetFile.h"
- #include "ColAttr.h"
- #include "Script.h"
- #include "ODBCErr.h"
-
- #include "odbcinst.h"
-
- #define ENDTRAN(sRet) (SQL_SUCCEEDED(sRet) ? \
- SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_COMMIT) : \
- SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK))
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg dialog
- CLoadDataDlg::CLoadDataDlg(CWnd* pParent /*=NULL*/)
- : CDialog(CLoadDataDlg::IDD, pParent)
- {
- //{{AFX_DATA_INIT(CLoadDataDlg)
- //}}AFX_DATA_INIT
- // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
-
- void CLoadDataDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CLoadDataDlg)
- DDX_Control(pDX, IDC_STATIC_CONNECTION, m_grpConnect);
- DDX_Control(pDX, IDC_STATIC_PATH, m_staticPath);
- DDX_Control(pDX, IDC_STATIC_FILES, m_grpFiles);
- DDX_Control(pDX, IDC_EDIT_PATH, m_editPath);
- DDX_Control(pDX, IDB_CLOSE, m_btnClose);
- DDX_Control(pDX, IDB_BROWSE_PATH, m_btnBrowse);
- DDX_Control(pDX, IDB_GO, m_btnGo);
- DDX_Control(pDX, IDB_DISCONNECT, m_btnDisconnect);
- DDX_Control(pDX, IDB_CONNECT, m_btnConnect);
- DDX_Control(pDX, IDC_STATIC_DSN, m_staticDSN);
- DDX_Control(pDX, IDC_STATIC_PROGRESS, m_staticProgress);
- DDX_Control(pDX, IDC_PROGRESS, m_progress);
- DDX_Control(pDX, IDC_COMBO_DSN, m_comboDSN);
- //}}AFX_DATA_MAP
- }
-
- BEGIN_MESSAGE_MAP(CLoadDataDlg, CDialog)
- //{{AFX_MSG_MAP(CLoadDataDlg)
- ON_WM_SYSCOMMAND()
- ON_BN_CLICKED(IDB_CLOSE, OnClose)
- ON_BN_CLICKED(IDB_CONNECT, OnConnect)
- ON_BN_CLICKED(IDB_DISCONNECT, OnDisconnect)
- ON_BN_CLICKED(IDB_GO, OnGo)
- ON_BN_CLICKED(IDB_BROWSE_PATH, OnBrowsePath)
- ON_EN_CHANGE(IDC_EDIT_PATH, OnChangeEditPath)
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- WM_INITDIALOG
- //
- // Set initial state of flags for connection and .cmd file. Get the list
- // of available SQL Server data sources and fill the combo box.
- BOOL CLoadDataDlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
-
- // Set the icon for this dialog. The framework does this automatically
- // when the application's main window is not a dialog
- SetIcon(m_hIcon, TRUE); // Set big icon
- SetIcon(m_hIcon, FALSE); // Set small icon
-
- // Set our connected and file exists flags
- m_bConnected = FALSE;
- m_bCmdFileExists = FALSE;
-
- // Load the data source combo with available SQL Server datasources
- SQLTCHAR acDSN[SQL_MAX_DSN_LENGTH + 1];
- SQLSMALLINT cbDSN;
- SQLTCHAR acDesc[SQL_MAX_OPTION_STRING_LENGTH + 1];
- SQLSMALLINT cbDesc;
-
- if (SQL_SUCCEEDED(SQLDataSources(m_henv, SQL_FETCH_FIRST_USER,
- acDSN, SQL_MAX_DSN_LENGTH + 1, &cbDSN,
- acDesc, SQL_MAX_OPTION_STRING_LENGTH + 1, &cbDesc)))
- {
- do
- {
- if (_tcsstr((TCHAR*) acDesc, _T("SQL Server")) != NULL)
- {
- m_comboDSN.AddString((TCHAR*) acDSN);
- }
- }
- while (SQL_SUCCEEDED(SQLDataSources(m_henv, SQL_FETCH_NEXT,
- acDSN, SQL_MAX_DSN_LENGTH + 1, &cbDSN,
- acDesc, SQL_MAX_OPTION_STRING_LENGTH + 1, &cbDesc)));
- }
-
- // Set the selection for the data source combo.
- m_comboDSN.SetCurSel(0);
- return TRUE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- SYSCOMMAND (messages from the system
- // menu)
- //
- // If the message is SC_CLOSE (user pressed the X, chose close from
- // the system menu, or pressed [Alt-F4]) and we're connected, then
- // disconnect. Let the dialog's handler see all messages.
- void CLoadDataDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if (nID == SC_CLOSE && m_bConnected)
- {
- OnDisconnect();
- }
-
- CDialog::OnSysCommand(nID, lParam);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- Go button generated BN_CLICK
- //
- // Get the command file and load it. Process commands in order.
- void CLoadDataDlg::OnGo()
- {
- int cmdToke;
- CString strCmdFile;
- int idxBackSlash;
- PSTR szAllCommands = NULL;
- PSTR szCurCommand;
- BOOL bFatalError = FALSE;
-
- m_szArgs = NULL;
- m_szPath = NULL;
-
- m_editPath.GetWindowText(strCmdFile);
- idxBackSlash = strCmdFile.ReverseFind(_T('\\'));
- if (idxBackSlash)
- {
- // Add one for the slash...
- idxBackSlash++;
- // ...one for the terminator
- m_szPath = new TCHAR[idxBackSlash + 1];
-
- _tcsncpy(m_szPath, (LPCTSTR) strCmdFile, idxBackSlash);
- m_szPath[idxBackSlash] = (TCHAR) NULL;
- }
- else
- {
- m_szPath = new TCHAR[1];
- m_szPath[0] = (TCHAR) NULL;
- }
-
- SetGoButtons(TRUE);
-
- // Get the command string...
- if (GetOSFile((LPCTSTR) strCmdFile, (PBYTE*) &szAllCommands) == TRUE)
- {
- m_progress.SetStep(11);
-
- szCurCommand = szAllCommands;
- while (bFatalError == FALSE &&
- (cmdToke = GetNextCmd(&szCurCommand, &m_szArgs)) != EOF)
- {
- switch (cmdToke)
- {
- case PROGRESSTEXT:
- {
- m_staticProgress.SetWindowText(m_szArgs);
- break;
- }
-
- case SCRIPTRUN:
- {
- if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmt) ==
- SQL_SUCCESS)
- {
- switch (ScriptRun())
- {
- case SQL_SUCCESS_WITH_INFO:
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- break;
- }
-
- case SQL_ERROR:
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- bFatalError = TRUE;
- }
- }
-
- SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
- }
-
- m_progress.StepIt();
- break;
- }
-
- case LOADDATA:
- {
- if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmt) ==
- SQL_SUCCESS)
- {
- if (LoadData() == SQL_ERROR)
- {
- bFatalError = TRUE;
- }
- SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
- }
-
- m_progress.StepIt();
- break;
- }
-
- case BADCOMMAND:
- {
- CString strError;
- strError.Format(IDS_ERR_UNKNOWNCMD, m_szArgs);
-
- AfxMessageBox(strError);
-
- bFatalError = TRUE;
- }
- }
-
- delete [] m_szArgs;
- m_szArgs = NULL;
- }
- }
-
- if (szAllCommands)
- delete [] szAllCommands;
-
- if (m_szPath)
- {
- delete [] m_szPath;
- m_szPath = NULL;
- }
-
- m_progress.SetPos(0);
- SetGoButtons(FALSE);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- Close button generated BN_CLICK
- //
- // If connected, disconnect, then act like Cancel pressed on normal dialog.
- void CLoadDataDlg::OnClose()
- {
- // If connected, disconnect, then CDialog::OnCancel processing
- if (m_bConnected)
- {
- OnDisconnect();
- }
-
- CDialog::OnCancel();
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- Connect button generated BN_CLICK
- //
- // Use SQLDriverConnect with the user selected datasource to attempt a
- // connection to the SQL Server.
- void CLoadDataDlg::OnConnect()
- {
- CString strDatasource;
- CString strConnect = _T("DSN=");
-
- // Get the datasource selected by the user.
- m_comboDSN.GetLBText(m_comboDSN.GetCurSel(), strDatasource);
- strConnect += strDatasource;
- strConnect += _T(";");
-
- // If this fails, there's not a lot we can do.
- if (SQLAllocHandle(SQL_HANDLE_DBC, m_henv, &m_hdbc) != SQL_SUCCESS)
- {
- AfxMessageBox(IDS_ERR_ALLOCHDBC);
- return;
- }
-
- CWaitCursor wait;
- switch (SQLDriverConnect(m_hdbc, AfxGetMainWnd()->m_hWnd,
- (SQLTCHAR*) ((LPCTSTR) strConnect), SQL_NTS, NULL, 0, NULL,
- SQL_DRIVER_COMPLETE))
- {
- case SQL_SUCCESS:
- case SQL_SUCCESS_WITH_INFO:
- {
- m_bConnected = TRUE;
-
- SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
- (SQLPOINTER) SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER);
-
- // Set buttons.
- SetConnectedButtons();
- break;
- }
-
- case SQL_NO_DATA:
- {
- // User canceled or other event for which we have no
- // information.
- break;
- }
-
- default:
- {
- DisplayErrors(SQL_HANDLE_DBC, m_hdbc);
-
- SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc);
- m_hdbc = NULL;
- }
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- Disconnect button generated BN_CLICK
- //
- // Disconnect, free the handle, reset the buttons as needed.
- void CLoadDataDlg::OnDisconnect()
- {
- SQLDisconnect(m_hdbc);
- SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc);
- m_hdbc = NULL;
- m_bConnected = FALSE;
-
- // Set buttons
- SetConnectedButtons();
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- Browse button generated BN_CLICK
- //
- // Use the OpenFile common dialog box to browse for a .cmd file.
- void CLoadDataDlg::OnBrowsePath()
- {
- static TCHAR BASED_CODE szFilter[] =
- _T("Command Files (*.cmd) | *.cmd ||");
-
- CString strFileName;
- m_editPath.GetWindowText(strFileName);
-
- if (!strFileName.GetLength())
- {
- strFileName = _T("*.cmd");
- }
-
- CFileDialog fd(TRUE, _T("cmd"), (LPCTSTR) strFileName,
- OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
- szFilter);
-
- if (fd.DoModal() == IDOK)
- {
- m_editPath.SetWindowText(fd.GetPathName());
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CLoadDataDlg message handler -- EN_CHANGE sent from .cmd file edit.
- //
- // Test to see if the Go button should be enabled.
- void CLoadDataDlg::OnChangeEditPath()
- {
- SetReadyButtons();
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // DisplayErrors -- Build a message box string from the error list and
- // display it.
- void CLoadDataDlg::DisplayErrors
- (
- SQLSMALLINT eHandleType,
- SQLHANDLE hodbc
- )
- {
- CODBCErrList* plistErrors;
- CString strAllErrors;
- CString strError;
- UINT nErr;
- UINT nErrs = 4; // Number of errors limit.
-
- plistErrors = new CODBCErrList(eHandleType, hodbc);
- if (plistErrors->GetReturnCode() == INVALID_OBJECT)
- {
- AfxMessageBox(IDS_INVALID_HANDLE_AT_ERROR);
- delete plistErrors;
- return;
- }
-
- plistErrors->FormatHeader(strAllErrors);
- nErrs = min(nErrs, plistErrors->GetCount());
- for (nErr = 0; nErr < nErrs; nErr++)
- {
- plistErrors->FormatErr(strError, nErr + 1);
- strAllErrors += _T("\n\n");
- strAllErrors += strError;
- }
-
- if (nErrs < plistErrors->GetCount())
- {
- strError.LoadString(IDS_ERR_TOOMANYERRORS);
- strAllErrors += _T("\n\n");
- strAllErrors += strError;
- }
-
- AfxMessageBox(strAllErrors);
-
- delete plistErrors;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // SetConnectedButtons -- When disconnected, the Connect, Browse and Close
- // buttons are enabled. Go and Disconnect are disabled. Connecting
- // reverses the enabled state of the Disconnect and Connect buttons.
- void CLoadDataDlg::SetConnectedButtons()
- {
- m_btnDisconnect.EnableWindow(m_bConnected);
-
- m_btnConnect.EnableWindow(!m_bConnected);
- m_staticDSN.EnableWindow(!m_bConnected);
- m_comboDSN.EnableWindow(!m_bConnected);
-
- SetReadyButtons();
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // SetReadyButtons -- If connected and there's text in the edit, then
- // enable the Go button.
- void CLoadDataDlg::SetReadyButtons()
- {
- if (m_editPath.GetWindowTextLength())
- {
- if (m_bCmdFileExists == FALSE)
- {
- m_bCmdFileExists = TRUE;
- }
- }
- else
- {
- if (m_bCmdFileExists == TRUE)
- {
- m_bCmdFileExists = FALSE;
- }
- }
-
- m_btnGo.EnableWindow(m_bConnected && m_bCmdFileExists);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // SetGoButtons -- When Go is pressed, any changes are disallowed until
- // completion of command processing.
- void CLoadDataDlg::SetGoButtons(BOOL bEnabled)
- {
- m_grpConnect.EnableWindow(!bEnabled);
- m_btnDisconnect.EnableWindow(!bEnabled);
- m_grpFiles.EnableWindow(!bEnabled);
- m_staticPath.EnableWindow(!bEnabled);
- m_editPath.EnableWindow(!bEnabled);
- m_btnBrowse.EnableWindow(!bEnabled);
-
- m_btnGo.EnableWindow(!bEnabled);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // LoadData -- Process a text file, loading the text data to the server
- // as directed.
- //
- // Return SQL_SUCCESS if attributes retrieved, other ODBC-generated
- // error on failure.
- SQLRETURN CLoadDataDlg::LoadData()
- {
- BOOL bIdentityInsert = FALSE;
- BOOL bHasLongData = FALSE;
-
- SQLRETURN sRet;
- CObList Columns;
- CColAttr* pColAttr;
-
- UINT nCols = 0;
- UINT nCol;
-
- PSTR pData = NULL;
- PSTR pCurLine = NULL;
- PTSTR* ppColNames = NULL;
- PSTR pNextLine = NULL;
-
- CString strColNames(_T(""));
- CString strParamMarkers(_T(""));
-
- CString strCommand;
-
- UINT* aBindOffsets = NULL;
- UINT* aIndOffsets = NULL;
- UINT cbArrayRow = 0;
- UINT nParamRows = 1;
- BYTE* pValues = NULL;
-
- UINT nParamsInSet;
- SQLUSMALLINT* acParamStatus = NULL;
- SQLINTEGER nParamsProcessed;
-
- PSTR lpLast;
-
- PDATA_AT_EXEC* aDataAtExecs = NULL;
- PDATA_AT_EXEC pDataAtExec;
- PDATA_AT_EXEC* pParamData;
- CString strPathAndFile = m_szPath;
-
- PTSTR szTableName;
- PTSTR szDataFile;
- UINT cbTableName;
- UINT cbDataFile;
-
- szTableName = _tcstok(m_szArgs, _T(","));
- szDataFile = _tcstok(NULL, _T(","));
-
- cbTableName = TrimQuotes(szTableName, szTableName);
- cbDataFile = TrimQuotes(szDataFile, szDataFile);
-
- // Check for the basics...
- if (!cbTableName || !cbDataFile)
- {
- return (SQL_ERROR);
- }
-
- strPathAndFile += szDataFile;
- if (GetOSFile((LPCTSTR) (strPathAndFile), (PBYTE*) &pData) == FALSE)
- {
- return (SQL_ERROR);
- }
-
- // The first line of the data file should be a list of column names. The
- // format of the data is "colname 1","colname 2", ... ,"colname n".
- pCurLine = pData;
- if (GetNextLine(&pCurLine, &pNextLine) == EOF)
- {
- sRet = SQL_ERROR;
- goto CLEAN_EXIT;
- }
-
- if (GetColNamesFromData(pNextLine, &nCols, &ppColNames) == FALSE)
- {
- sRet = SQL_ERROR;
- goto CLEAN_EXIT;
- }
-
- // Get the column attributes from the table on the server. The column
- // attributes provide a check on data column presence and provide
- // data types and bind parameter buffer widths.
- if (!SQL_SUCCEEDED(GetColAttributes(szTableName, nCols, ppColNames,
- Columns)))
- {
- goto CLEAN_EXIT;
- }
-
- // Check for an identity column in the table and turn it off if
- // our column list includes the identity column.
- bIdentityInsert = bTableHasIdentity(Columns, nCols);
- if ((bIdentityInsert = bTableHasIdentity(Columns, nCols)) == TRUE)
- {
- strCommand.Format(IDS_IDENTITY_ON, szTableName);
- if (!SQL_SUCCEEDED(ExecDirectCommand(strCommand)))
- {
- goto CLEAN_EXIT;
- }
- }
-
- // Check for long data types (LONG_VARCHAR or LONG_VARBINARY). If
- // long data types exist, then all INSERT statements will occur as
- // language events and not RPCs. In that case, we simply submit
- // character data from the data files. If RPCs will be used,
- // convert data to base type and use parameter arrays for fast
- // insert.
- if ((bHasLongData = bTableHasLongData(Columns, nCols)) == TRUE)
- {
- aDataAtExecs = new PDATA_AT_EXEC[nCols];
- }
-
- // Build the structures needed to extract data. The loop creates the
- // data at execution structure array if it encounters text or image
- // data types in the structure of the table and the data in the file.
- // Text and image data types force the SQL Server driver to use
- // language events for stored procedure execution, though our app
- // wants to convert char data to binary types for space and other
- // reasons.
- aBindOffsets = new UINT[nCols];
- aIndOffsets = new UINT[nCols];
- CalcArraySize(Columns, nCols, bHasLongData, aBindOffsets, aIndOffsets,
- aDataAtExecs, &cbArrayRow);
-
- // Get memory for bound values and indicators.
- if (bHasLongData == FALSE)
- {
- nParamRows = (UINT) (0x10000 / cbArrayRow);
- acParamStatus = new SQLUSMALLINT[nParamRows];
- }
- pValues = new BYTE[cbArrayRow * nParamRows];
-
- // Bind parameters.
- sRet = BindParameters(nCols, Columns, aBindOffsets, pValues,
- aIndOffsets, bHasLongData);
- if (sRet == SQL_ERROR)
- {
- goto CLEAN_EXIT;
- }
-
- // Build the insert statement and prepare it. Preparation after binding
- // is prefered.
- for (nCol = 0; nCol < nCols; nCol++)
- {
- if (strColNames.GetLength())
- {
- strColNames += _T(",");
- strParamMarkers += _T(",");
- }
-
- strColNames += ppColNames[nCol];
- strParamMarkers += _T("?");
- }
- strCommand.Format(IDS_INSERT_STMT, (LPCTSTR) szTableName,
- (LPCTSTR) strColNames, (LPCTSTR) strParamMarkers);
-
- if (FAILED(SQLPrepare(m_hstmt, (SQLTCHAR*) ((LPCTSTR) strCommand),
- SQL_NTS)))
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- ENDTRAN(SQL_ERROR);
-
- goto CLEAN_EXIT;
- }
-
- // If appropriate, set for parameter array processing.
- if (bHasLongData == FALSE)
- {
- SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAM_BIND_TYPE,
- (SQLPOINTER) cbArrayRow, SQL_IS_UINTEGER);
- SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAM_STATUS_PTR,
- (SQLPOINTER) acParamStatus, SQL_IS_POINTER);
- SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR,
- (SQLPOINTER) &nParamsProcessed, SQL_IS_POINTER);
- }
-
- // Consume the data file, executing the INSERT statement as we go.
- lpLast = pCurLine + strlen(pCurLine);
- while (pCurLine < lpLast && sRet != SQL_ERROR)
- {
- if (bHasLongData)
- {
- if ((pCurLine = GetDataRow(Columns, nCols, pCurLine, pValues,
- aDataAtExecs, aBindOffsets, aIndOffsets)) == NULL)
- {
- sRet = SQL_ERROR;
- goto CLEAN_EXIT;
- }
- }
- else
- {
- if ((pCurLine = FillDataArray(Columns, nCols, nParamRows,
- cbArrayRow, pCurLine, pValues, aBindOffsets, aIndOffsets,
- &nParamsInSet)) == NULL)
- {
- sRet = SQL_ERROR;
- goto CLEAN_EXIT;
- }
-
- SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMSET_SIZE,
- (SQLPOINTER) nParamsInSet, SQL_IS_UINTEGER);
- }
-
- sRet = SQLExecute(m_hstmt);
-
- if (sRet == SQL_NEED_DATA)
- {
- while ((sRet = SQLParamData(m_hstmt, (SQLPOINTER*) &pParamData))
- == SQL_NEED_DATA)
- {
- pDataAtExec = *pParamData;
- if (!SQL_SUCCEEDED(sRet = SQLPutData(m_hstmt,
- (SQLPOINTER) pDataAtExec->pData, pDataAtExec->cbData)))
- break;
- }
- }
-
- if (sRet != SQL_SUCCESS)
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- }
-
- // Commit or rollback on each batch.
- ENDTRAN(sRet);
- }
-
-
- CLEAN_EXIT:
- if (bHasLongData == FALSE)
- {
- SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAM_STATUS_PTR,
- (SQLPOINTER) NULL, SQL_IS_POINTER);
- SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR,
- (SQLPOINTER) NULL, SQL_IS_POINTER);
- SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMSET_SIZE,
- (SQLPOINTER) 1, SQL_IS_UINTEGER);
- }
-
- SQLFreeStmt(m_hstmt, SQL_RESET_PARAMS);
-
- if (acParamStatus != NULL)
- delete [] acParamStatus;
-
- if (pData != NULL)
- delete [] pData;
-
- if (pNextLine != NULL)
- delete [] pNextLine;
-
- if (nCols != 0)
- {
- for (nCol = 0; nCol < nCols; nCol++)
- {
- delete [] ppColNames[nCol];
- }
- delete [] ppColNames;
-
- if (aDataAtExecs != NULL)
- {
- for (nCol = 0; nCol < nCols; nCol++)
- {
- if (aDataAtExecs[nCol] != NULL)
- {
- pDataAtExec = aDataAtExecs[nCol];
- if (pDataAtExec->pData)
- {
- delete [] pDataAtExec->pData;
- }
- delete pDataAtExec;
- }
- }
- delete [] aDataAtExecs;
- }
- }
-
- if (aIndOffsets != NULL)
- delete [] aIndOffsets;
-
- if (pValues != NULL)
- delete [] pValues;
-
- if (aBindOffsets != NULL)
- delete [] aBindOffsets;
-
- if (bIdentityInsert)
- {
- strCommand.Format(IDS_IDENTITY_OFF, szTableName);
- ExecDirectCommand(strCommand);
- }
-
- if (!Columns.IsEmpty())
- {
- for (POSITION pos = Columns.GetHeadPosition(); pos != NULL; )
- {
- pColAttr = (CColAttr*) Columns.GetNext(pos);
- delete pColAttr;
- }
- }
-
- return (sRet);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // GetColAttributes -- Get the attributes of the server's columns.
- //
- // Return SQL_SUCCESS if attributes retrieved, other ODBC generated
- // error on failure.
- SQLRETURN CLoadDataDlg::GetColAttributes
- (
- LPCTSTR szTableName,
- UINT nCols,
- PTSTR* ppColNames,
- CObList& ColList
- )
- {
- SQLRETURN sRet;
- UINT nCol;
-
- CString strColumns(_T(""));
- CString strCommand;
- CColAttr* pColAttr;
-
- for (nCol = 0; nCol < nCols; nCol++)
- {
- if (strColumns.GetLength())
- {
- strColumns += _T(", ");
- }
- strColumns += ppColNames[nCol];
- }
-
- strCommand.Format(IDS_SELECT_ALL, (LPCTSTR) strColumns, szTableName);
- if (!SQL_SUCCEEDED(sRet = SQLPrepare(m_hstmt,
- (SQLTCHAR*) ((LPCTSTR) strCommand), SQL_NTS)))
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- }
-
- for (nCol = 0; nCol < nCols && sRet == SQL_SUCCESS; nCol++)
- {
- pColAttr = new CColAttr(m_hstmt, nCol + 1);
- if (pColAttr != NULL)
- {
- if (pColAttr->GetAttr() == SQL_SUCCESS)
- {
- ColList.AddTail((CObject*) pColAttr);
- }
- else
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- sRet = SQL_ERROR;
- }
- }
- else
- {
- AfxMessageBox(_T("Memory allocation error."));
- sRet = SQL_ERROR;
- }
- }
-
- SQLCloseCursor(m_hstmt);
- ENDTRAN(SQL_ERROR);
-
- return (sRet);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // BindParameters -- Determine data type on the server, type of data in data
- // file. Use SQLBindParameter to bind for SQLExecute.
- //
- // Returns SQL_SUCCESS if all parameters bound successfully, ODBC error
- // code otherwise.
- SQLRETURN CLoadDataDlg::BindParameters
- (
- UINT nCols,
- CObList& Columns,
- UINT* aBindOffsets,
- BYTE* pValues,
- UINT* aIndOffsets,
- BOOL bBindToChar
- )
- {
- UINT nCol;
- SQLSMALLINT eSQLType;
- SQLSMALLINT eCType;
- SQLUINTEGER cbColumn;
- SQLSMALLINT nDecimals;
- SQLUINTEGER cbBuffer;
- CColAttr* pColAttr;
-
- for (nCol = 0; nCol < nCols; nCol++)
- {
- pColAttr = (CColAttr*) Columns.GetAt(Columns.FindIndex(nCol));
- eSQLType = pColAttr->GetODBCType();
- cbColumn = pColAttr->GetDisplaySize();
-
- if (bBindToChar)
- {
- eCType = SQL_C_CHAR;
- cbBuffer = pColAttr->GetCharBufferWidth();
- }
- else
- {
- eCType = pColAttr->GetDefaultBindType();
- cbBuffer = (SQLUINTEGER) pColAttr->GetBoundBufferWidth();
- }
-
- nDecimals = 0;
- switch (eSQLType)
- {
- case SQL_CHAR:
- case SQL_WCHAR:
- case SQL_VARCHAR:
- case SQL_WVARCHAR:
- case SQL_BINARY:
- case SQL_VARBINARY:
- break;
-
- case SQL_NUMERIC:
- case SQL_DECIMAL:
- {
- nDecimals = pColAttr->GetDecimalDigits();
- break;
- }
-
- case SQL_LONGVARBINARY:
- case SQL_LONGVARCHAR:
- case SQL_WLONGVARCHAR:
- {
- // cbBuffer = sizeof(PDATA_AT_EXEC);
- cbBuffer = sizeof(PDATA_AT_EXEC);
- break;
- }
-
- case SQL_BIT:
- case SQL_TINYINT:
- case SQL_SMALLINT:
- case SQL_INTEGER:
- case SQL_DOUBLE:
- case SQL_FLOAT:
- case SQL_REAL:
- {
- cbColumn = 0;
- break;
- }
-
- case SQL_TYPE_TIMESTAMP:
- {
- cbColumn = 23;
- nDecimals = 3;
- break;
- }
-
- default:
- {
- // Raise unsupported data type error and return
- AfxMessageBox(IDS_UNSUPPORTED_DATATYPE);
- return (FALSE);
- }
- }
-
- if (SQLBindParameter(m_hstmt, nCol + 1, SQL_PARAM_INPUT, eCType,
- eSQLType, cbColumn, nDecimals, pValues + aBindOffsets[nCol],
- cbBuffer, (SQLINTEGER*) (pValues + aIndOffsets[nCol]))
- == SQL_ERROR)
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- return (SQL_ERROR);
- }
- }
-
- return (SQL_SUCCESS);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // bTableHasIdentity -- Check the listed columns for an identity property.
- //
- // Returns TRUE if an identity column is found, FALSE otherwise.
- BOOL CLoadDataDlg::bTableHasIdentity
- (
- CObList& ColList,
- UINT nCols
- )
- {
- BOOL bIdentity = FALSE;
- UINT nCol;
-
- for (nCol = 0; nCol < nCols && bIdentity == FALSE; nCol++)
- {
- bIdentity = ((CColAttr*)
- ColList.GetAt(ColList.FindIndex(nCol)))->GetIsIdentity();
- }
-
- return (bIdentity);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // bTableHasLongData -- Check the listed columns for any that are text or
- // image.
- //
- // Returns TRUE if any column is LONG_VARCHAR or LONG_VARBINARY, FALSE
- // otherwise.
- BOOL CLoadDataDlg::bTableHasLongData
- (
- CObList& ColList,
- UINT nCols
- )
- {
- BOOL bLongData = FALSE;
- UINT nCol;
-
- for (nCol = 0; nCol < nCols && bLongData == FALSE; nCol++)
- {
- bLongData = ((CColAttr*)
- ColList.GetAt(ColList.FindIndex(nCol)))->GetIsLongData();
- }
-
- return (bLongData);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // ExecDirectCommand -- Execute the command passed, process results,
- // commit transaction and return.
- SQLRETURN CLoadDataDlg::ExecDirectCommand
- (
- CString& strCommand
- )
- {
- SQLRETURN sRet = SQLExecDirect(m_hstmt,
- (SQLTCHAR*) ((LPCTSTR) strCommand), SQL_NTS);
-
- if (SQL_SUCCEEDED(sRet))
- {
- while (SQL_SUCCEEDED(sRet = SQLMoreResults(m_hstmt)))
- {
- if (sRet == SQL_SUCCESS_WITH_INFO)
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- }
- }
-
- if (sRet == SQL_NO_DATA)
- {
- sRet = SQL_SUCCESS;
- }
- else if (!SQL_SUCCEEDED(sRet))
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- }
- }
- else
- {
- DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
- }
-
- ENDTRAN(sRet);
- return (sRet);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CalcArraySize -- Calculate the size of a single row of the parameter data
- // array. The function fills the array of binding offsets, an array of
- // structures that control data-at-execution processing, and sets a pointer
- // to UINT with the width of a single parameter row.
- void CLoadDataDlg::CalcArraySize
- (
- CObList& Columns,
- UINT nCols,
- BOOL bHasLongData,
- UINT* aBindOffsets,
- UINT* aIndOffsets,
- PDATA_AT_EXEC* aDataAtExecs,
- UINT* pcbParamRow
- )
- {
- UINT nCol;
- UINT cbParamRow = 0;
-
- CColAttr* pColAttr;
- PDATA_AT_EXEC pDataAtExec;
-
- for (nCol = 0; nCol < nCols; nCol++)
- {
- aBindOffsets[nCol] = cbParamRow;
-
- pColAttr =
- (CColAttr*) Columns.GetAt(Columns.FindIndex(nCol));
- switch (pColAttr->GetODBCType())
- {
- case SQL_LONGVARBINARY:
- case SQL_LONGVARCHAR:
- case SQL_WLONGVARCHAR:
- {
- cbParamRow += sizeof(PDATA_AT_EXEC);
-
- pDataAtExec = new DATA_AT_EXEC;
- pDataAtExec->pData = NULL;
- pDataAtExec->cbData = 0;
- pDataAtExec->cbBuffer = 0;
- aDataAtExecs[nCol] = pDataAtExec;
-
- break;
- }
-
- case SQL_FLOAT:
- case SQL_REAL:
- case SQL_DOUBLE:
- {
- // We let the server convert approximate numerics, use
- // the display width for binding;
- cbParamRow += pColAttr->GetCharBufferWidth();
- if (aDataAtExecs != NULL)
- aDataAtExecs[nCol] = NULL;
- break;
- }
-
- default:
- {
- if (bHasLongData)
- {
- cbParamRow += pColAttr->GetCharBufferWidth();
- }
- else
- {
- cbParamRow += pColAttr->GetBoundBufferWidth();
- }
- if (aDataAtExecs != NULL)
- aDataAtExecs[nCol] = NULL;
- break;
- }
- }
- aIndOffsets[nCol] = cbParamRow;
- cbParamRow += sizeof(SQLINTEGER);
- }
-
- *pcbParamRow = cbParamRow;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // FillDataArray -- If we can use an array of bound parameters (no long
- // data), then fill the array with data from our file.
- PSTR CLoadDataDlg::FillDataArray
- (
- CObList& Columns,
- UINT nCols,
- UINT nParamRows,
- UINT cbParamRow,
- PSTR pdata,
- PBYTE pValues,
- UINT* aBindOffsets,
- UINT* aIndOffsets,
- UINT* pnParamsInSet
- )
- {
- UINT nCol;
- UINT nParamRow = 0;
- PBYTE pParamRow;
- UINT cbDataMax;
- UINT cbData;
- CColAttr* pColAttr;
-
- while (*pdata != (TCHAR) NULL && nParamRow < nParamRows)
- {
- pParamRow = &pValues[nParamRow * cbParamRow];
-
- for (nCol = 0; nCol < nCols; nCol++)
- {
- pColAttr = (CColAttr*) Columns.GetAt(Columns.FindIndex(nCol));
- cbDataMax = pColAttr->GetBoundBufferWidth();
- switch (pColAttr->GetODBCType())
- {
- case SQL_CHAR:
- case SQL_VARCHAR:
- {
- pdata = GetCharData(pdata,
- (char*) pParamRow + aBindOffsets[nCol], cbDataMax,
- &cbData);
- break;
- }
-
- case SQL_WCHAR:
- case SQL_WVARCHAR:
- {
- pdata = GetWCharData(pdata,
- (WCHAR*) (pParamRow + aBindOffsets[nCol]), cbDataMax,
- &cbData);
- break;
- }
-
- case SQL_NUMERIC:
- case SQL_DECIMAL:
- case SQL_FLOAT: // Let the server convert char strs to
- case SQL_DOUBLE: // approximate numerics
- case SQL_REAL:
- {
- pdata = GetNumericData(pdata,
- (char*) pParamRow + aBindOffsets[nCol], cbDataMax,
- &cbData);
- break;
- }
-
- case SQL_BIT:
- case SQL_TINYINT:
- case SQL_SMALLINT:
- case SQL_INTEGER:
- {
- pdata = GetIntegerData(pdata,
- (int*) (pParamRow + aBindOffsets[nCol]), &cbData);
- break;
- }
-
- case SQL_TYPE_TIMESTAMP:
- {
- pdata = GetDateData(pdata,
- (SQL_TIMESTAMP_STRUCT*) (pParamRow + aBindOffsets[nCol]),
- &cbData);
- break;
- }
-
- case SQL_BINARY:
- case SQL_VARBINARY:
- {
- pdata = GetBinaryData(pdata, pParamRow + aBindOffsets[nCol],
- cbDataMax, &cbData);
- break;
- }
-
- default:
- {
- // Shouldn't ever be here, display an error and return
- // NULL.
- AfxMessageBox(IDS_UNSUPPORTED_DATATYPE);
- return (NULL);
- }
- }
-
- if (cbData)
- {
- *((SQLINTEGER*) (pParamRow + aIndOffsets[nCol]))
- = cbData;
- }
- else
- {
- *((SQLINTEGER*) (pParamRow + aIndOffsets[nCol]))
- = SQL_NULL_DATA;
- }
- }
-
- nParamRow++;
- }
-
- *pnParamsInSet = nParamRow;
- return (pdata);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // GetDataRow -- Our table contains a binding to long data (text or image).
- // The SQL Server driver will submit our prepared statement to the server
- // as a language event. Converting data for RPC execution is a waste of
- // our time and the driver's, so get all data as character with no
- // conversion.
- PSTR CLoadDataDlg::GetDataRow
- (
- CObList& Columns,
- UINT nCols,
- PSTR pdata,
- PBYTE pValues,
- PDATA_AT_EXEC* aDataAtExecs,
- UINT* aBindOffsets,
- UINT* aIndOffsets
- )
- {
- UINT nCol;
- UINT cbData;
- PDATA_AT_EXEC pDataAtExec;
- SQLSMALLINT eSQLType;
-
- for (nCol = 0; nCol < nCols && *pdata != (TCHAR) NULL; nCol++)
- {
- switch (eSQLType =
- ((CColAttr*) Columns.GetAt(Columns.FindIndex(nCol)))->GetODBCType())
- {
- case SQL_LONGVARCHAR:
- case SQL_LONGVARBINARY:
- case SQL_WLONGVARCHAR:
- {
- pDataAtExec = aDataAtExecs[nCol];
-
- if (eSQLType == SQL_LONGVARCHAR ||
- eSQLType == SQL_WLONGVARCHAR)
- {
- pdata = GetLongCharData(pdata, pDataAtExec);
- }
- else
- {
- pdata = GetLongBinaryData(pdata, pDataAtExec);
- }
-
- if (pDataAtExec->cbData == 0)
- {
- *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
- = SQL_NULL_DATA;
- }
- else
- {
- *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
- = SQL_LEN_DATA_AT_EXEC(pDataAtExec->cbData);
- *((PDATA_AT_EXEC*) (pValues + aBindOffsets[nCol]))
- = pDataAtExec;
- }
-
- break;
- }
-
- default:
- {
- pdata = FieldData(pdata, (char*) pValues + aBindOffsets[nCol],
- ((CColAttr*) Columns.GetAt(
- Columns.FindIndex(nCol)))->GetDisplaySize() + 1,
- &cbData);
- if (cbData == 0)
- {
- *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
- = SQL_NULL_DATA;
- }
- else
- {
- *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
- = cbData;
- }
-
- break;
- }
- }
- }
-
- return (pdata);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // ScriptRun -- Executes a batch of Transact SQL statements one at a time.
- // ScriptRun assumes that the statements are DDL or other statements that
- // do not return results and the function does not include any data
- // retrieval mechanism.
- //
- // Returns SQL_SUCCESS if all statements execute correctly,
- // SQL_SUCCESS_WITH_INFO if some (possibly none) of the statements executed
- // correctly, SQL_ERROR on failure to find or read the command batch file.
- SQLRETURN CLoadDataDlg::ScriptRun()
- {
- PSTR szScript;
- PSTR szAllLines;
- PSTR szLine;
- BOOL bFatalError = FALSE;
- CString strPathAndFile = m_szPath;
- CString strCmd = _T("");
-
- if (TrimQuotes(m_szArgs, m_szArgs) == 0)
- {
- return (SQL_ERROR);
- }
-
- strPathAndFile += m_szArgs;
- if (GetOSFile((LPCTSTR) strPathAndFile, (PBYTE*) &szScript) == FALSE)
- {
- return (SQL_ERROR);
- }
-
- szAllLines = szScript;
- while (bFatalError == FALSE &&
- GetNextLine(&szAllLines, &szLine) != EOF)
- {
- if (stricmp(szLine, "GO") == 0)
- {
- if (strCmd.GetLength())
- {
- bFatalError =
- !(SQL_SUCCEEDED(ExecDirectCommand(strCmd)));
-
- strCmd = _T("");
- }
- }
- else
- {
- if (strCmd.GetLength())
- {
- strCmd += _T(" ");
- }
- strCmd += szLine;
- }
-
- delete [] szLine;
- }
-
- delete [] szScript;
-
- return (bFatalError ? SQL_ERROR : SQL_SUCCESS);
- }
-
-