home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 32 / IOPROG_32.ISO / SOFT / SqlEval7 / devtools / samples / ODBC / loaddata / lddlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-30  |  41.5 KB  |  1,381 lines

  1. // LoadDataDlg.cpp : implementation file
  2. //
  3. // This file is part of Microsoft SQL Server online documentation.
  4. // Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
  5. //
  6. // This source code is an intended supplement to the Microsoft SQL
  7. // Server online references and related electronic documentation.
  8. #include "stdafx.h"
  9. #include "LoadData.h"
  10. #include "LDDlg.h"
  11.  
  12. #include "GetFile.h"
  13. #include "ColAttr.h"
  14. #include "Script.h"
  15. #include "ODBCErr.h"
  16.  
  17. #include "odbcinst.h"
  18.  
  19. #define ENDTRAN(sRet)         (SQL_SUCCEEDED(sRet)  ?    \
  20.         SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_COMMIT) : \
  21.         SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK))
  22.  
  23. #ifdef _DEBUG
  24. #define new DEBUG_NEW
  25. #undef THIS_FILE
  26. static char THIS_FILE[] = __FILE__;
  27. #endif
  28.  
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CLoadDataDlg dialog
  31. CLoadDataDlg::CLoadDataDlg(CWnd* pParent /*=NULL*/)
  32.     : CDialog(CLoadDataDlg::IDD, pParent)
  33.     {
  34.     //{{AFX_DATA_INIT(CLoadDataDlg)
  35.     //}}AFX_DATA_INIT
  36.     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  37.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  38.     }
  39.  
  40. void CLoadDataDlg::DoDataExchange(CDataExchange* pDX)
  41.     {
  42.     CDialog::DoDataExchange(pDX);
  43.     //{{AFX_DATA_MAP(CLoadDataDlg)
  44.     DDX_Control(pDX, IDC_STATIC_CONNECTION, m_grpConnect);
  45.     DDX_Control(pDX, IDC_STATIC_PATH, m_staticPath);
  46.     DDX_Control(pDX, IDC_STATIC_FILES, m_grpFiles);
  47.     DDX_Control(pDX, IDC_EDIT_PATH, m_editPath);
  48.     DDX_Control(pDX, IDB_CLOSE, m_btnClose);
  49.     DDX_Control(pDX, IDB_BROWSE_PATH, m_btnBrowse);
  50.     DDX_Control(pDX, IDB_GO, m_btnGo);
  51.     DDX_Control(pDX, IDB_DISCONNECT, m_btnDisconnect);
  52.     DDX_Control(pDX, IDB_CONNECT, m_btnConnect);
  53.     DDX_Control(pDX, IDC_STATIC_DSN, m_staticDSN);
  54.     DDX_Control(pDX, IDC_STATIC_PROGRESS, m_staticProgress);
  55.     DDX_Control(pDX, IDC_PROGRESS, m_progress);
  56.     DDX_Control(pDX, IDC_COMBO_DSN, m_comboDSN);
  57.     //}}AFX_DATA_MAP
  58.     }
  59.  
  60. BEGIN_MESSAGE_MAP(CLoadDataDlg, CDialog)
  61.     //{{AFX_MSG_MAP(CLoadDataDlg)
  62.     ON_WM_SYSCOMMAND()
  63.     ON_BN_CLICKED(IDB_CLOSE, OnClose)
  64.     ON_BN_CLICKED(IDB_CONNECT, OnConnect)
  65.     ON_BN_CLICKED(IDB_DISCONNECT, OnDisconnect)
  66.     ON_BN_CLICKED(IDB_GO, OnGo)
  67.     ON_BN_CLICKED(IDB_BROWSE_PATH, OnBrowsePath)
  68.     ON_EN_CHANGE(IDC_EDIT_PATH, OnChangeEditPath)
  69.     //}}AFX_MSG_MAP
  70. END_MESSAGE_MAP()
  71.  
  72. /////////////////////////////////////////////////////////////////////////////
  73. // CLoadDataDlg message handler -- WM_INITDIALOG
  74. //
  75. // Set initial state of flags for connection and .cmd file. Get the list
  76. //  of available SQL Server data sources and fill the combo box.
  77. BOOL CLoadDataDlg::OnInitDialog()
  78.     {
  79.     CDialog::OnInitDialog();
  80.  
  81.     // Set the icon for this dialog.  The framework does this automatically
  82.     //  when the application's main window is not a dialog
  83.     SetIcon(m_hIcon, TRUE);            // Set big icon
  84.     SetIcon(m_hIcon, FALSE);        // Set small icon
  85.  
  86.     // Set our connected and file exists flags
  87.     m_bConnected = FALSE;
  88.     m_bCmdFileExists = FALSE;
  89.  
  90.     // Load the data source combo with available SQL Server datasources
  91.     SQLTCHAR    acDSN[SQL_MAX_DSN_LENGTH + 1];
  92.     SQLSMALLINT cbDSN;
  93.     SQLTCHAR    acDesc[SQL_MAX_OPTION_STRING_LENGTH + 1];
  94.     SQLSMALLINT cbDesc;
  95.  
  96.     if (SQL_SUCCEEDED(SQLDataSources(m_henv, SQL_FETCH_FIRST_USER, 
  97.         acDSN, SQL_MAX_DSN_LENGTH + 1, &cbDSN, 
  98.         acDesc, SQL_MAX_OPTION_STRING_LENGTH + 1, &cbDesc)))
  99.         {
  100.         do
  101.             {
  102.             if (_tcsstr((TCHAR*) acDesc, _T("SQL Server")) != NULL)
  103.                 {
  104.                 m_comboDSN.AddString((TCHAR*) acDSN);
  105.                 }
  106.             }
  107.         while (SQL_SUCCEEDED(SQLDataSources(m_henv, SQL_FETCH_NEXT,
  108.             acDSN, SQL_MAX_DSN_LENGTH + 1, &cbDSN,
  109.             acDesc, SQL_MAX_OPTION_STRING_LENGTH + 1, &cbDesc)));
  110.         }
  111.  
  112.     // Set the selection for the data source combo.
  113.     m_comboDSN.SetCurSel(0);
  114.     return TRUE;
  115.     }
  116.  
  117. /////////////////////////////////////////////////////////////////////////////
  118. // CLoadDataDlg message handler -- SYSCOMMAND (messages from the system
  119. //  menu)
  120. //
  121. // If the message is SC_CLOSE (user pressed the X, chose close from
  122. //  the system menu, or pressed [Alt-F4]) and we're connected, then
  123. //  disconnect. Let the dialog's handler see all messages.
  124. void CLoadDataDlg::OnSysCommand(UINT nID, LPARAM lParam)
  125.     {
  126.     if (nID == SC_CLOSE && m_bConnected)
  127.         {
  128.         OnDisconnect();
  129.         }
  130.  
  131.     CDialog::OnSysCommand(nID, lParam);
  132.     }
  133.  
  134. /////////////////////////////////////////////////////////////////////////////
  135. // CLoadDataDlg message handler -- Go button generated BN_CLICK
  136. //
  137. // Get the command file and load it. Process commands in order.
  138. void CLoadDataDlg::OnGo() 
  139.     {
  140.     int     cmdToke;
  141.     CString strCmdFile;
  142.     int     idxBackSlash;
  143.     PSTR    szAllCommands = NULL;
  144.     PSTR    szCurCommand;
  145.     BOOL    bFatalError = FALSE;
  146.  
  147.     m_szArgs = NULL;
  148.     m_szPath = NULL;
  149.  
  150.     m_editPath.GetWindowText(strCmdFile);
  151.     idxBackSlash = strCmdFile.ReverseFind(_T('\\'));
  152.     if (idxBackSlash)
  153.         {
  154.         // Add one for the slash...
  155.         idxBackSlash++;
  156.         // ...one for the terminator
  157.         m_szPath = new TCHAR[idxBackSlash + 1];
  158.  
  159.         _tcsncpy(m_szPath, (LPCTSTR) strCmdFile, idxBackSlash);
  160.         m_szPath[idxBackSlash] = (TCHAR) NULL;
  161.         }
  162.     else
  163.         {
  164.         m_szPath = new TCHAR[1];
  165.         m_szPath[0] = (TCHAR) NULL;
  166.         }
  167.     
  168.     SetGoButtons(TRUE);
  169.  
  170.     // Get the command string...
  171.     if (GetOSFile((LPCTSTR) strCmdFile, (PBYTE*) &szAllCommands) == TRUE)
  172.         {
  173.         m_progress.SetStep(11);
  174.  
  175.         szCurCommand = szAllCommands;
  176.         while (bFatalError == FALSE && 
  177.             (cmdToke = GetNextCmd(&szCurCommand, &m_szArgs)) != EOF)
  178.             {
  179.             switch (cmdToke)
  180.                 {
  181.                 case PROGRESSTEXT:
  182.                     {
  183.                     m_staticProgress.SetWindowText(m_szArgs);
  184.                     break;
  185.                     }
  186.             
  187.                 case SCRIPTRUN:
  188.                     {
  189.                     if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmt) ==
  190.                             SQL_SUCCESS)
  191.                         {
  192.                         switch (ScriptRun())
  193.                             {
  194.                             case SQL_SUCCESS_WITH_INFO:
  195.                                 {
  196.                                 DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  197.                                 break;
  198.                                 }
  199.  
  200.                             case SQL_ERROR:
  201.                                 {
  202.                                 DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  203.                                 bFatalError = TRUE;
  204.                                 }
  205.                             }
  206.  
  207.                         SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
  208.                         }
  209.  
  210.                     m_progress.StepIt();
  211.                     break;
  212.                     }
  213.  
  214.                 case LOADDATA:
  215.                     {
  216.                     if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmt) ==
  217.                             SQL_SUCCESS)
  218.                         {
  219.                         if (LoadData() == SQL_ERROR)
  220.                             {
  221.                             bFatalError = TRUE;
  222.                             }
  223.                         SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt);
  224.                         }
  225.  
  226.                     m_progress.StepIt();
  227.                     break;
  228.                     }
  229.  
  230.                 case BADCOMMAND:
  231.                     {
  232.                     CString     strError;
  233.                     strError.Format(IDS_ERR_UNKNOWNCMD, m_szArgs);
  234.                     
  235.                     AfxMessageBox(strError);
  236.  
  237.                     bFatalError = TRUE;
  238.                     }
  239.                 }
  240.             
  241.             delete [] m_szArgs;
  242.             m_szArgs = NULL;
  243.             }
  244.         }
  245.  
  246.     if (szAllCommands)
  247.         delete [] szAllCommands;
  248.  
  249.     if (m_szPath)
  250.         {
  251.         delete [] m_szPath;
  252.         m_szPath = NULL;
  253.         }
  254.  
  255.     m_progress.SetPos(0);
  256.     SetGoButtons(FALSE);
  257.     }
  258.  
  259. /////////////////////////////////////////////////////////////////////////////
  260. // CLoadDataDlg message handler -- Close button generated BN_CLICK
  261. //
  262. // If connected, disconnect, then act like Cancel pressed on normal dialog.
  263. void CLoadDataDlg::OnClose() 
  264.     {
  265.     // If connected, disconnect, then CDialog::OnCancel processing
  266.     if (m_bConnected)
  267.         {
  268.         OnDisconnect();
  269.         }
  270.  
  271.     CDialog::OnCancel();
  272.     }
  273.  
  274. /////////////////////////////////////////////////////////////////////////////
  275. // CLoadDataDlg message handler -- Connect button generated BN_CLICK
  276. //
  277. // Use SQLDriverConnect with the user selected datasource to attempt a
  278. //  connection to the SQL Server.
  279. void CLoadDataDlg::OnConnect() 
  280.     {
  281.     CString     strDatasource;
  282.     CString     strConnect = _T("DSN=");
  283.  
  284.     // Get the datasource selected by the user.
  285.     m_comboDSN.GetLBText(m_comboDSN.GetCurSel(), strDatasource);
  286.     strConnect += strDatasource;
  287.     strConnect += _T(";");
  288.  
  289.     // If this fails, there's not a lot we can do.
  290.     if (SQLAllocHandle(SQL_HANDLE_DBC, m_henv, &m_hdbc) != SQL_SUCCESS)
  291.         {
  292.         AfxMessageBox(IDS_ERR_ALLOCHDBC);
  293.         return;
  294.         }
  295.  
  296.     CWaitCursor     wait;
  297.     switch (SQLDriverConnect(m_hdbc, AfxGetMainWnd()->m_hWnd,
  298.         (SQLTCHAR*) ((LPCTSTR) strConnect), SQL_NTS, NULL, 0, NULL,
  299.         SQL_DRIVER_COMPLETE))
  300.         {
  301.         case SQL_SUCCESS:
  302.         case SQL_SUCCESS_WITH_INFO:
  303.             {
  304.             m_bConnected = TRUE;
  305.  
  306.             SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
  307.                 (SQLPOINTER) SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER);
  308.  
  309.             // Set buttons.
  310.             SetConnectedButtons();
  311.             break;
  312.             }
  313.  
  314.         case SQL_NO_DATA:
  315.             {
  316.             // User canceled or other event for which we have no
  317.             //  information.
  318.             break;
  319.             }
  320.  
  321.         default:
  322.             {
  323.             DisplayErrors(SQL_HANDLE_DBC, m_hdbc);
  324.  
  325.             SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc);
  326.             m_hdbc = NULL;
  327.             }
  328.         }
  329.     }
  330.  
  331. /////////////////////////////////////////////////////////////////////////////
  332. // CLoadDataDlg message handler -- Disconnect button generated BN_CLICK
  333. //
  334. // Disconnect, free the handle, reset the buttons as needed.
  335. void CLoadDataDlg::OnDisconnect() 
  336.     {
  337.     SQLDisconnect(m_hdbc);
  338.     SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc);
  339.     m_hdbc = NULL;
  340.     m_bConnected = FALSE;
  341.  
  342.     // Set buttons
  343.     SetConnectedButtons();
  344.     }
  345.  
  346. /////////////////////////////////////////////////////////////////////////////
  347. // CLoadDataDlg message handler -- Browse button generated BN_CLICK
  348. //
  349. // Use the OpenFile common dialog box to browse for a .cmd file.
  350. void CLoadDataDlg::OnBrowsePath() 
  351.     {
  352.     static TCHAR BASED_CODE szFilter[] = 
  353.         _T("Command Files (*.cmd) | *.cmd ||");
  354.     
  355.     CString     strFileName;
  356.     m_editPath.GetWindowText(strFileName);
  357.  
  358.     if (!strFileName.GetLength())
  359.         {
  360.         strFileName = _T("*.cmd");
  361.         }
  362.  
  363.     CFileDialog fd(TRUE, _T("cmd"), (LPCTSTR) strFileName,
  364.                     OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
  365.                     szFilter);
  366.  
  367.     if (fd.DoModal() == IDOK)
  368.         {
  369.         m_editPath.SetWindowText(fd.GetPathName());
  370.         }
  371.     }
  372.  
  373. /////////////////////////////////////////////////////////////////////////////
  374. // CLoadDataDlg message handler -- EN_CHANGE sent from .cmd file edit.
  375. //
  376. // Test to see if the Go button should be enabled.
  377. void CLoadDataDlg::OnChangeEditPath() 
  378.     {
  379.     SetReadyButtons();
  380.     }
  381.  
  382. /////////////////////////////////////////////////////////////////////////////
  383. // DisplayErrors -- Build a message box string from the error list and
  384. //  display it.
  385. void CLoadDataDlg::DisplayErrors
  386.     (
  387.     SQLSMALLINT eHandleType,
  388.     SQLHANDLE hodbc
  389.     )
  390.     {
  391.     CODBCErrList*   plistErrors;
  392.     CString         strAllErrors;
  393.     CString         strError;
  394.     UINT            nErr;
  395.     UINT            nErrs = 4;          // Number of errors limit.
  396.  
  397.     plistErrors = new CODBCErrList(eHandleType, hodbc);
  398.     if (plistErrors->GetReturnCode() == INVALID_OBJECT)
  399.         {
  400.         AfxMessageBox(IDS_INVALID_HANDLE_AT_ERROR);
  401.         delete plistErrors;
  402.         return;
  403.         }
  404.  
  405.     plistErrors->FormatHeader(strAllErrors);
  406.     nErrs = min(nErrs, plistErrors->GetCount());
  407.     for (nErr = 0; nErr < nErrs; nErr++)
  408.         {
  409.         plistErrors->FormatErr(strError, nErr + 1);
  410.         strAllErrors += _T("\n\n");
  411.         strAllErrors += strError;
  412.         }
  413.  
  414.     if (nErrs < plistErrors->GetCount())
  415.         {
  416.         strError.LoadString(IDS_ERR_TOOMANYERRORS);
  417.         strAllErrors += _T("\n\n");
  418.         strAllErrors += strError;
  419.         }
  420.     
  421.     AfxMessageBox(strAllErrors);
  422.  
  423.     delete plistErrors;
  424.     }
  425.  
  426. /////////////////////////////////////////////////////////////////////////////
  427. // SetConnectedButtons -- When disconnected, the Connect, Browse and Close
  428. //  buttons are enabled. Go and Disconnect are disabled. Connecting
  429. //  reverses the enabled state of the Disconnect and Connect buttons.
  430. void CLoadDataDlg::SetConnectedButtons()
  431.     {
  432.     m_btnDisconnect.EnableWindow(m_bConnected);
  433.  
  434.     m_btnConnect.EnableWindow(!m_bConnected);
  435.     m_staticDSN.EnableWindow(!m_bConnected);
  436.     m_comboDSN.EnableWindow(!m_bConnected);
  437.  
  438.     SetReadyButtons();
  439.     }
  440.  
  441. /////////////////////////////////////////////////////////////////////////////
  442. // SetReadyButtons -- If connected and there's text in the edit, then
  443. //  enable the Go button.
  444. void CLoadDataDlg::SetReadyButtons()
  445.     {
  446.     if (m_editPath.GetWindowTextLength())
  447.         {
  448.         if (m_bCmdFileExists == FALSE)
  449.             {
  450.             m_bCmdFileExists = TRUE;
  451.             }
  452.         }
  453.     else
  454.         {
  455.         if (m_bCmdFileExists == TRUE)
  456.             {
  457.             m_bCmdFileExists = FALSE;
  458.             }
  459.         }
  460.  
  461.     m_btnGo.EnableWindow(m_bConnected && m_bCmdFileExists);
  462.     }
  463.  
  464. /////////////////////////////////////////////////////////////////////////////
  465. // SetGoButtons -- When Go is pressed, any changes are disallowed until
  466. //  completion of command processing.
  467. void CLoadDataDlg::SetGoButtons(BOOL bEnabled)
  468.     {
  469.     m_grpConnect.EnableWindow(!bEnabled);
  470.     m_btnDisconnect.EnableWindow(!bEnabled);
  471.     m_grpFiles.EnableWindow(!bEnabled);
  472.     m_staticPath.EnableWindow(!bEnabled);
  473.     m_editPath.EnableWindow(!bEnabled);
  474.     m_btnBrowse.EnableWindow(!bEnabled);
  475.  
  476.     m_btnGo.EnableWindow(!bEnabled);
  477.     }
  478.  
  479. /////////////////////////////////////////////////////////////////////////////
  480. // LoadData -- Process a text file, loading the text data to the server
  481. //  as directed.
  482. //
  483. // Return SQL_SUCCESS if attributes retrieved, other ODBC-generated
  484. //  error on failure.
  485. SQLRETURN CLoadDataDlg::LoadData()
  486.     {
  487.     BOOL            bIdentityInsert = FALSE;
  488.     BOOL            bHasLongData    = FALSE;
  489.  
  490.     SQLRETURN       sRet;
  491.     CObList         Columns;
  492.     CColAttr*       pColAttr;
  493.     
  494.     UINT            nCols = 0;
  495.     UINT            nCol;
  496.     
  497.     PSTR            pData = NULL;
  498.     PSTR            pCurLine = NULL;
  499.     PTSTR*          ppColNames = NULL;
  500.     PSTR            pNextLine = NULL;
  501.     
  502.     CString         strColNames(_T(""));
  503.     CString         strParamMarkers(_T(""));
  504.  
  505.     CString         strCommand;
  506.     
  507.     UINT*           aBindOffsets = NULL;
  508.     UINT*           aIndOffsets = NULL;
  509.     UINT            cbArrayRow = 0;
  510.     UINT            nParamRows = 1;
  511.     BYTE*           pValues = NULL;
  512.     
  513.     UINT            nParamsInSet;
  514.     SQLUSMALLINT*   acParamStatus = NULL;
  515.     SQLINTEGER      nParamsProcessed;
  516.  
  517.     PSTR            lpLast;
  518.  
  519.     PDATA_AT_EXEC*  aDataAtExecs = NULL;
  520.     PDATA_AT_EXEC   pDataAtExec;
  521.     PDATA_AT_EXEC*  pParamData;
  522.     CString         strPathAndFile = m_szPath;
  523.  
  524.     PTSTR           szTableName;
  525.     PTSTR           szDataFile;
  526.     UINT            cbTableName;
  527.     UINT            cbDataFile;
  528.         
  529.     szTableName = _tcstok(m_szArgs, _T(","));
  530.     szDataFile  = _tcstok(NULL, _T(","));
  531.     
  532.     cbTableName = TrimQuotes(szTableName, szTableName);
  533.     cbDataFile  = TrimQuotes(szDataFile, szDataFile);
  534.  
  535.     // Check for the basics...
  536.     if (!cbTableName || !cbDataFile)
  537.         {
  538.         return (SQL_ERROR);
  539.         }
  540.  
  541.     strPathAndFile += szDataFile;
  542.     if (GetOSFile((LPCTSTR) (strPathAndFile), (PBYTE*) &pData) == FALSE)
  543.         {
  544.         return (SQL_ERROR);
  545.         }
  546.  
  547.     // The first line of the data file should be a list of column names. The
  548.     //  format of the data is "colname 1","colname 2", ... ,"colname n".
  549.     pCurLine = pData;
  550.     if (GetNextLine(&pCurLine, &pNextLine) == EOF)
  551.         {
  552.         sRet = SQL_ERROR;
  553.         goto CLEAN_EXIT;
  554.         }
  555.  
  556.     if (GetColNamesFromData(pNextLine, &nCols, &ppColNames) == FALSE)
  557.         {
  558.         sRet = SQL_ERROR;
  559.         goto CLEAN_EXIT;
  560.         }
  561.  
  562.     // Get the column attributes from the table on the server. The column
  563.     //  attributes provide a check on data column presence and provide 
  564.     //  data types and bind parameter buffer widths.
  565.     if (!SQL_SUCCEEDED(GetColAttributes(szTableName, nCols, ppColNames,
  566.         Columns)))
  567.         {
  568.         goto CLEAN_EXIT;
  569.         }
  570.  
  571.     // Check for an identity column in the table and turn it off if
  572.     //  our column list includes the identity column.
  573.     bIdentityInsert = bTableHasIdentity(Columns, nCols);
  574.     if ((bIdentityInsert = bTableHasIdentity(Columns, nCols)) == TRUE)
  575.         {
  576.         strCommand.Format(IDS_IDENTITY_ON, szTableName);
  577.         if (!SQL_SUCCEEDED(ExecDirectCommand(strCommand)))
  578.             {
  579.             goto CLEAN_EXIT;
  580.             }
  581.         }
  582.  
  583.     // Check for long data types (LONG_VARCHAR or LONG_VARBINARY). If
  584.     //  long data types exist, then all INSERT statements will occur as 
  585.     //  language events and not RPCs.  In that case, we simply submit
  586.     //  character data from the data files. If RPCs will be used,
  587.     //  convert data to base type and use parameter arrays for fast
  588.     //  insert.
  589.     if ((bHasLongData = bTableHasLongData(Columns, nCols)) == TRUE)
  590.         {
  591.         aDataAtExecs = new PDATA_AT_EXEC[nCols];
  592.         }
  593.  
  594.     // Build the structures needed to extract data. The loop creates the
  595.     //  data at execution structure array if it encounters text or image
  596.     //  data types in the structure of the table and the data in the file.
  597.     //  Text and image data types force the SQL Server driver to use
  598.     //  language events for stored procedure execution, though our app
  599.     //  wants to convert char data to binary types for space and other
  600.     //  reasons.
  601.     aBindOffsets = new UINT[nCols];
  602.     aIndOffsets  = new UINT[nCols];
  603.     CalcArraySize(Columns, nCols, bHasLongData, aBindOffsets, aIndOffsets,
  604.         aDataAtExecs, &cbArrayRow);
  605.  
  606.     // Get memory for bound values and indicators.
  607.     if (bHasLongData == FALSE)
  608.         {
  609.         nParamRows = (UINT) (0x10000 / cbArrayRow);
  610.         acParamStatus = new SQLUSMALLINT[nParamRows];
  611.         }
  612.     pValues = new BYTE[cbArrayRow * nParamRows];
  613.     
  614.     // Bind parameters.
  615.     sRet = BindParameters(nCols, Columns, aBindOffsets, pValues,
  616.         aIndOffsets, bHasLongData);
  617.     if (sRet == SQL_ERROR)
  618.         {
  619.         goto CLEAN_EXIT;
  620.         }
  621.     
  622.     // Build the insert statement and prepare it. Preparation after binding
  623.     //  is prefered.
  624.     for (nCol = 0; nCol < nCols; nCol++)
  625.         {
  626.         if (strColNames.GetLength())
  627.             {
  628.             strColNames += _T(",");
  629.             strParamMarkers += _T(",");
  630.             }
  631.  
  632.         strColNames += ppColNames[nCol];
  633.         strParamMarkers += _T("?");
  634.         }
  635.     strCommand.Format(IDS_INSERT_STMT, (LPCTSTR) szTableName,
  636.         (LPCTSTR) strColNames, (LPCTSTR) strParamMarkers);
  637.  
  638.     if (FAILED(SQLPrepare(m_hstmt, (SQLTCHAR*) ((LPCTSTR) strCommand),
  639.         SQL_NTS)))
  640.         {
  641.         DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  642.         ENDTRAN(SQL_ERROR);
  643.  
  644.         goto CLEAN_EXIT;
  645.         }
  646.  
  647.     // If appropriate, set for parameter array processing.
  648.     if (bHasLongData == FALSE)
  649.         {
  650.         SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAM_BIND_TYPE,
  651.             (SQLPOINTER) cbArrayRow, SQL_IS_UINTEGER);
  652.         SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAM_STATUS_PTR,
  653.             (SQLPOINTER) acParamStatus, SQL_IS_POINTER);
  654.         SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR,
  655.             (SQLPOINTER) &nParamsProcessed, SQL_IS_POINTER);
  656.         }
  657.  
  658.     // Consume the data file, executing the INSERT statement as we go.
  659.     lpLast = pCurLine + strlen(pCurLine);
  660.     while (pCurLine < lpLast && sRet != SQL_ERROR)
  661.         {
  662.         if (bHasLongData)
  663.             {
  664.             if ((pCurLine = GetDataRow(Columns, nCols, pCurLine, pValues,
  665.                 aDataAtExecs, aBindOffsets, aIndOffsets)) == NULL)
  666.                 {
  667.                 sRet = SQL_ERROR;
  668.                 goto CLEAN_EXIT;
  669.                 }
  670.             }
  671.         else
  672.             {
  673.             if ((pCurLine = FillDataArray(Columns, nCols, nParamRows, 
  674.                 cbArrayRow, pCurLine, pValues, aBindOffsets, aIndOffsets,
  675.                 &nParamsInSet)) == NULL)
  676.                 {
  677.                 sRet = SQL_ERROR;
  678.                 goto CLEAN_EXIT;
  679.                 }
  680.  
  681.             SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMSET_SIZE,
  682.                 (SQLPOINTER) nParamsInSet, SQL_IS_UINTEGER);
  683.             }
  684.  
  685.         sRet = SQLExecute(m_hstmt);
  686.  
  687.         if (sRet == SQL_NEED_DATA)
  688.             {
  689.             while ((sRet = SQLParamData(m_hstmt, (SQLPOINTER*) &pParamData))
  690.                 == SQL_NEED_DATA)
  691.                 {
  692.                 pDataAtExec = *pParamData;
  693.                 if (!SQL_SUCCEEDED(sRet = SQLPutData(m_hstmt,
  694.                     (SQLPOINTER) pDataAtExec->pData, pDataAtExec->cbData)))
  695.                     break;
  696.                 }
  697.             }
  698.  
  699.         if (sRet != SQL_SUCCESS)
  700.             {
  701.             DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  702.             }
  703.  
  704.         // Commit or rollback on each batch.
  705.         ENDTRAN(sRet);
  706.         }
  707.  
  708.  
  709. CLEAN_EXIT:
  710.     if (bHasLongData == FALSE)
  711.         {
  712.         SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAM_STATUS_PTR,
  713.             (SQLPOINTER) NULL, SQL_IS_POINTER);
  714.         SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR,
  715.             (SQLPOINTER) NULL, SQL_IS_POINTER);
  716.         SQLSetStmtAttr(m_hstmt, SQL_ATTR_PARAMSET_SIZE,
  717.             (SQLPOINTER) 1, SQL_IS_UINTEGER);
  718.         }
  719.  
  720.     SQLFreeStmt(m_hstmt, SQL_RESET_PARAMS);
  721.  
  722.     if (acParamStatus != NULL)
  723.         delete [] acParamStatus;
  724.  
  725.     if (pData != NULL)
  726.         delete [] pData;
  727.  
  728.     if (pNextLine != NULL)
  729.         delete [] pNextLine;
  730.  
  731.     if (nCols != 0)
  732.         {
  733.         for (nCol = 0; nCol < nCols; nCol++)
  734.             {
  735.             delete [] ppColNames[nCol];
  736.             }
  737.         delete [] ppColNames;
  738.  
  739.         if (aDataAtExecs != NULL)
  740.             {
  741.             for (nCol = 0; nCol < nCols; nCol++)
  742.                 {
  743.                 if (aDataAtExecs[nCol] != NULL)
  744.                     {
  745.                     pDataAtExec = aDataAtExecs[nCol];
  746.                     if (pDataAtExec->pData)
  747.                         {
  748.                         delete [] pDataAtExec->pData;
  749.                         }
  750.                     delete pDataAtExec;
  751.                     }
  752.                 }
  753.             delete [] aDataAtExecs;
  754.             }
  755.         }
  756.  
  757.     if (aIndOffsets != NULL)
  758.         delete [] aIndOffsets;
  759.  
  760.     if (pValues != NULL)
  761.         delete [] pValues;
  762.  
  763.     if (aBindOffsets != NULL)
  764.         delete [] aBindOffsets;
  765.  
  766.     if (bIdentityInsert)
  767.         {
  768.         strCommand.Format(IDS_IDENTITY_OFF, szTableName);
  769.         ExecDirectCommand(strCommand);
  770.         }
  771.  
  772.     if (!Columns.IsEmpty())
  773.         {
  774.         for (POSITION pos = Columns.GetHeadPosition(); pos != NULL; )
  775.             {
  776.             pColAttr = (CColAttr*) Columns.GetNext(pos);
  777.             delete pColAttr;
  778.             }
  779.         }
  780.  
  781.     return (sRet);
  782.     }
  783.  
  784. /////////////////////////////////////////////////////////////////////////////
  785. // GetColAttributes -- Get the attributes of the server's columns.
  786. //
  787. // Return SQL_SUCCESS if attributes retrieved, other ODBC generated
  788. //  error on failure.
  789. SQLRETURN CLoadDataDlg::GetColAttributes
  790.     (
  791.     LPCTSTR szTableName,
  792.     UINT nCols,
  793.     PTSTR* ppColNames,
  794.     CObList& ColList
  795.     )
  796.     {
  797.     SQLRETURN   sRet;
  798.     UINT        nCol;
  799.     
  800.     CString     strColumns(_T(""));
  801.     CString     strCommand;
  802.     CColAttr*   pColAttr;
  803.  
  804.     for (nCol = 0; nCol < nCols; nCol++)
  805.         {
  806.         if (strColumns.GetLength())
  807.             {
  808.             strColumns += _T(", ");
  809.             }
  810.         strColumns += ppColNames[nCol];
  811.         }
  812.  
  813.     strCommand.Format(IDS_SELECT_ALL, (LPCTSTR) strColumns, szTableName);
  814.     if (!SQL_SUCCEEDED(sRet = SQLPrepare(m_hstmt,
  815.         (SQLTCHAR*) ((LPCTSTR) strCommand), SQL_NTS)))
  816.         {
  817.         DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  818.         }
  819.  
  820.     for (nCol = 0; nCol < nCols && sRet == SQL_SUCCESS; nCol++)
  821.         {
  822.         pColAttr = new CColAttr(m_hstmt, nCol + 1);
  823.         if (pColAttr != NULL)
  824.             {
  825.             if (pColAttr->GetAttr() == SQL_SUCCESS)
  826.                 {
  827.                 ColList.AddTail((CObject*) pColAttr);
  828.                 }
  829.             else
  830.                 {
  831.                 DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  832.                 sRet = SQL_ERROR;
  833.                 }
  834.             }
  835.         else
  836.             {
  837.             AfxMessageBox(_T("Memory allocation error."));
  838.             sRet = SQL_ERROR;
  839.             }
  840.         }
  841.  
  842.     SQLCloseCursor(m_hstmt);
  843.     ENDTRAN(SQL_ERROR);
  844.  
  845.     return (sRet);
  846.     }
  847.  
  848. /////////////////////////////////////////////////////////////////////////////
  849. // BindParameters -- Determine data type on the server, type of data in data
  850. //  file. Use SQLBindParameter to bind for SQLExecute.
  851. //
  852. // Returns SQL_SUCCESS if all parameters bound successfully, ODBC error
  853. //  code otherwise.
  854. SQLRETURN CLoadDataDlg::BindParameters
  855.     (
  856.     UINT nCols,
  857.     CObList& Columns,
  858.     UINT* aBindOffsets,
  859.     BYTE* pValues,
  860.     UINT* aIndOffsets,
  861.     BOOL bBindToChar
  862.     )
  863.     {
  864.     UINT        nCol;
  865.     SQLSMALLINT eSQLType;
  866.     SQLSMALLINT eCType;
  867.     SQLUINTEGER cbColumn;
  868.     SQLSMALLINT nDecimals;
  869.     SQLUINTEGER cbBuffer;
  870.     CColAttr*   pColAttr;
  871.  
  872.     for (nCol = 0; nCol < nCols; nCol++)
  873.         {
  874.         pColAttr = (CColAttr*) Columns.GetAt(Columns.FindIndex(nCol));
  875.         eSQLType = pColAttr->GetODBCType();
  876.         cbColumn = pColAttr->GetDisplaySize();
  877.  
  878.         if (bBindToChar)
  879.             {
  880.             eCType = SQL_C_CHAR;
  881.             cbBuffer = pColAttr->GetCharBufferWidth();
  882.             }
  883.         else
  884.             {
  885.             eCType = pColAttr->GetDefaultBindType();
  886.             cbBuffer = (SQLUINTEGER) pColAttr->GetBoundBufferWidth();
  887.             }
  888.  
  889.         nDecimals = 0;
  890.         switch (eSQLType)
  891.             {
  892.             case SQL_CHAR:
  893.             case SQL_WCHAR:
  894.             case SQL_VARCHAR:
  895.             case SQL_WVARCHAR:
  896.             case SQL_BINARY:
  897.             case SQL_VARBINARY:
  898.                 break;
  899.  
  900.             case SQL_NUMERIC:
  901.             case SQL_DECIMAL:
  902.                 {
  903.                 nDecimals = pColAttr->GetDecimalDigits();
  904.                 break;
  905.                 }
  906.  
  907.             case SQL_LONGVARBINARY:
  908.             case SQL_LONGVARCHAR:
  909.             case SQL_WLONGVARCHAR:
  910.                 {
  911.                 // cbBuffer = sizeof(PDATA_AT_EXEC);
  912.                 cbBuffer = sizeof(PDATA_AT_EXEC);
  913.                 break;
  914.                 }
  915.  
  916.             case SQL_BIT:
  917.             case SQL_TINYINT:
  918.             case SQL_SMALLINT:
  919.             case SQL_INTEGER:
  920.             case SQL_DOUBLE:
  921.             case SQL_FLOAT:
  922.             case SQL_REAL:
  923.                 {
  924.                 cbColumn = 0;
  925.                 break;
  926.                 }
  927.  
  928.             case SQL_TYPE_TIMESTAMP:
  929.                 {
  930.                 cbColumn = 23;
  931.                 nDecimals = 3;
  932.                 break;
  933.                 }
  934.  
  935.             default:
  936.                 {
  937.                 // Raise unsupported data type error and return
  938.                 AfxMessageBox(IDS_UNSUPPORTED_DATATYPE);
  939.                 return (FALSE);
  940.                 }
  941.             }
  942.  
  943.         if (SQLBindParameter(m_hstmt, nCol + 1, SQL_PARAM_INPUT, eCType,
  944.             eSQLType, cbColumn, nDecimals,  pValues + aBindOffsets[nCol],
  945.             cbBuffer, (SQLINTEGER*) (pValues + aIndOffsets[nCol]))
  946.             == SQL_ERROR)
  947.             {
  948.             DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  949.             return (SQL_ERROR);
  950.             }
  951.         }
  952.  
  953.     return (SQL_SUCCESS);
  954.     }
  955.  
  956. /////////////////////////////////////////////////////////////////////////////
  957. // bTableHasIdentity -- Check the listed columns for an identity property.
  958. // 
  959. // Returns TRUE if an identity column is found, FALSE otherwise.
  960. BOOL CLoadDataDlg::bTableHasIdentity
  961.     (
  962.     CObList& ColList,
  963.     UINT nCols
  964.     )
  965.     {
  966.     BOOL        bIdentity = FALSE;
  967.     UINT        nCol;
  968.  
  969.     for (nCol = 0; nCol < nCols && bIdentity == FALSE; nCol++)
  970.         {
  971.         bIdentity = ((CColAttr*) 
  972.             ColList.GetAt(ColList.FindIndex(nCol)))->GetIsIdentity();
  973.         }
  974.  
  975.     return (bIdentity);
  976.     }
  977.  
  978. /////////////////////////////////////////////////////////////////////////////
  979. // bTableHasLongData -- Check the listed columns for any that are text or
  980. //  image.
  981. // 
  982. // Returns TRUE if any column is LONG_VARCHAR or LONG_VARBINARY, FALSE 
  983. //  otherwise.
  984. BOOL CLoadDataDlg::bTableHasLongData
  985.     (
  986.     CObList& ColList,
  987.     UINT nCols
  988.     )
  989.     {
  990.     BOOL        bLongData = FALSE;
  991.     UINT        nCol;
  992.  
  993.     for (nCol = 0; nCol < nCols && bLongData == FALSE; nCol++)
  994.         {
  995.         bLongData = ((CColAttr*) 
  996.             ColList.GetAt(ColList.FindIndex(nCol)))->GetIsLongData();
  997.         }
  998.  
  999.     return (bLongData);
  1000.     }
  1001.  
  1002. /////////////////////////////////////////////////////////////////////////////
  1003. // ExecDirectCommand -- Execute the command passed, process results,
  1004. //  commit transaction and return. 
  1005. SQLRETURN CLoadDataDlg::ExecDirectCommand
  1006.     (
  1007.     CString& strCommand
  1008.     )
  1009.     {
  1010.     SQLRETURN   sRet = SQLExecDirect(m_hstmt,
  1011.         (SQLTCHAR*) ((LPCTSTR) strCommand), SQL_NTS);
  1012.  
  1013.     if (SQL_SUCCEEDED(sRet))
  1014.         {
  1015.         while (SQL_SUCCEEDED(sRet = SQLMoreResults(m_hstmt)))
  1016.             {
  1017.             if (sRet == SQL_SUCCESS_WITH_INFO)
  1018.                 {
  1019.                 DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  1020.                 }
  1021.             }
  1022.  
  1023.         if (sRet == SQL_NO_DATA)
  1024.             {
  1025.             sRet = SQL_SUCCESS;
  1026.             }
  1027.         else if (!SQL_SUCCEEDED(sRet))
  1028.             {
  1029.             DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  1030.             }
  1031.         }
  1032.     else
  1033.         {
  1034.         DisplayErrors(SQL_HANDLE_STMT, m_hstmt);
  1035.         }
  1036.  
  1037.     ENDTRAN(sRet);
  1038.     return (sRet);
  1039.     }
  1040.  
  1041. /////////////////////////////////////////////////////////////////////////////
  1042. // CalcArraySize -- Calculate the size of a single row of the parameter data
  1043. //  array. The function fills the array of binding offsets, an array of
  1044. //  structures that control data-at-execution processing, and sets a pointer
  1045. //  to UINT with the width of a single parameter row.
  1046. void CLoadDataDlg::CalcArraySize
  1047.     (
  1048.     CObList& Columns,
  1049.     UINT nCols,
  1050.     BOOL bHasLongData,
  1051.     UINT* aBindOffsets,
  1052.     UINT* aIndOffsets,
  1053.     PDATA_AT_EXEC* aDataAtExecs,
  1054.     UINT* pcbParamRow
  1055.     )
  1056.     {
  1057.     UINT        nCol;
  1058.     UINT        cbParamRow = 0;
  1059.  
  1060.     CColAttr*   pColAttr;
  1061.     PDATA_AT_EXEC pDataAtExec;
  1062.  
  1063.     for (nCol = 0; nCol < nCols; nCol++)
  1064.         {
  1065.         aBindOffsets[nCol] = cbParamRow;
  1066.  
  1067.         pColAttr = 
  1068.             (CColAttr*) Columns.GetAt(Columns.FindIndex(nCol));
  1069.         switch (pColAttr->GetODBCType())
  1070.             {
  1071.             case SQL_LONGVARBINARY:
  1072.             case SQL_LONGVARCHAR:
  1073.             case SQL_WLONGVARCHAR:
  1074.                 {
  1075.                 cbParamRow += sizeof(PDATA_AT_EXEC);
  1076.                 
  1077.                 pDataAtExec = new DATA_AT_EXEC;
  1078.                 pDataAtExec->pData    = NULL;
  1079.                 pDataAtExec->cbData   = 0;
  1080.                 pDataAtExec->cbBuffer = 0;
  1081.                 aDataAtExecs[nCol] = pDataAtExec;
  1082.  
  1083.                 break;
  1084.                 }
  1085.  
  1086.             case SQL_FLOAT:
  1087.             case SQL_REAL:
  1088.             case SQL_DOUBLE:
  1089.                 {
  1090.                 // We let the server convert approximate numerics, use
  1091.                 //  the display width for binding;
  1092.                 cbParamRow += pColAttr->GetCharBufferWidth();
  1093.                 if (aDataAtExecs != NULL)
  1094.                     aDataAtExecs[nCol] = NULL;
  1095.                 break;
  1096.                 }
  1097.  
  1098.             default:
  1099.                 {
  1100.                 if (bHasLongData)
  1101.                     {
  1102.                     cbParamRow += pColAttr->GetCharBufferWidth();
  1103.                     }
  1104.                 else
  1105.                     {
  1106.                     cbParamRow += pColAttr->GetBoundBufferWidth();
  1107.                     }
  1108.                 if (aDataAtExecs != NULL)
  1109.                     aDataAtExecs[nCol] = NULL;
  1110.                 break;
  1111.                 }
  1112.             }
  1113.         aIndOffsets[nCol] = cbParamRow;
  1114.         cbParamRow += sizeof(SQLINTEGER);
  1115.         }
  1116.  
  1117.     *pcbParamRow = cbParamRow;
  1118.     }
  1119.  
  1120. /////////////////////////////////////////////////////////////////////////////
  1121. // FillDataArray -- If we can use an array of bound parameters (no long
  1122. //   data), then fill the array with data from our file.
  1123. PSTR CLoadDataDlg::FillDataArray
  1124.     (
  1125.     CObList& Columns,
  1126.     UINT nCols,
  1127.     UINT nParamRows,
  1128.     UINT cbParamRow,
  1129.     PSTR pdata,
  1130.     PBYTE pValues,
  1131.     UINT* aBindOffsets,
  1132.     UINT* aIndOffsets,
  1133.     UINT* pnParamsInSet
  1134.     )
  1135.     {
  1136.     UINT        nCol;
  1137.     UINT        nParamRow = 0;
  1138.     PBYTE       pParamRow;
  1139.     UINT        cbDataMax;
  1140.     UINT        cbData;
  1141.     CColAttr*   pColAttr;
  1142.     
  1143.     while (*pdata != (TCHAR) NULL && nParamRow < nParamRows)
  1144.         {
  1145.         pParamRow = &pValues[nParamRow * cbParamRow];
  1146.  
  1147.         for (nCol = 0; nCol < nCols; nCol++)
  1148.             {
  1149.             pColAttr = (CColAttr*) Columns.GetAt(Columns.FindIndex(nCol));
  1150.             cbDataMax = pColAttr->GetBoundBufferWidth();
  1151.             switch (pColAttr->GetODBCType())
  1152.                 {
  1153.                 case SQL_CHAR:
  1154.                 case SQL_VARCHAR:
  1155.                     {
  1156.                     pdata = GetCharData(pdata,
  1157.                         (char*) pParamRow + aBindOffsets[nCol], cbDataMax,
  1158.                         &cbData);
  1159.                     break;
  1160.                     }
  1161.  
  1162.                 case SQL_WCHAR:
  1163.                 case SQL_WVARCHAR:
  1164.                     {
  1165.                     pdata = GetWCharData(pdata,
  1166.                         (WCHAR*) (pParamRow + aBindOffsets[nCol]), cbDataMax,
  1167.                         &cbData);
  1168.                     break;
  1169.                     }
  1170.  
  1171.                 case SQL_NUMERIC:
  1172.                 case SQL_DECIMAL:
  1173.                 case SQL_FLOAT:         // Let the server convert char strs to
  1174.                 case SQL_DOUBLE:        //  approximate numerics
  1175.                 case SQL_REAL:
  1176.                     {
  1177.                     pdata = GetNumericData(pdata,
  1178.                         (char*) pParamRow + aBindOffsets[nCol], cbDataMax,
  1179.                         &cbData);
  1180.                     break;
  1181.                     }
  1182.  
  1183.                 case SQL_BIT:
  1184.                 case SQL_TINYINT:
  1185.                 case SQL_SMALLINT:
  1186.                 case SQL_INTEGER:
  1187.                     {
  1188.                     pdata = GetIntegerData(pdata,
  1189.                         (int*) (pParamRow + aBindOffsets[nCol]), &cbData);
  1190.                     break;
  1191.                     }
  1192.  
  1193.                 case SQL_TYPE_TIMESTAMP:
  1194.                     {
  1195.                     pdata = GetDateData(pdata, 
  1196.                         (SQL_TIMESTAMP_STRUCT*) (pParamRow + aBindOffsets[nCol]),
  1197.                         &cbData);
  1198.                     break;
  1199.                     }
  1200.  
  1201.                 case SQL_BINARY:
  1202.                 case SQL_VARBINARY:
  1203.                     {
  1204.                     pdata = GetBinaryData(pdata, pParamRow + aBindOffsets[nCol],
  1205.                         cbDataMax, &cbData);
  1206.                     break;
  1207.                     }
  1208.  
  1209.                 default:
  1210.                     {
  1211.                     // Shouldn't ever be here, display an error and return
  1212.                     //  NULL.
  1213.                     AfxMessageBox(IDS_UNSUPPORTED_DATATYPE);
  1214.                     return (NULL);
  1215.                     }
  1216.                 }
  1217.  
  1218.             if (cbData)
  1219.                 {
  1220.                 *((SQLINTEGER*) (pParamRow + aIndOffsets[nCol]))
  1221.                     = cbData;
  1222.                 }
  1223.             else
  1224.                 {
  1225.                 *((SQLINTEGER*) (pParamRow + aIndOffsets[nCol]))
  1226.                     = SQL_NULL_DATA;
  1227.                 }
  1228.             }
  1229.  
  1230.         nParamRow++;
  1231.         }
  1232.  
  1233.     *pnParamsInSet = nParamRow;
  1234.     return (pdata);
  1235.     }
  1236.  
  1237. /////////////////////////////////////////////////////////////////////////////
  1238. // GetDataRow -- Our table contains a binding to long data (text or image).
  1239. //  The SQL Server driver will submit our prepared statement to the server
  1240. //  as a language event. Converting data for RPC execution is a waste of
  1241. //  our time and the driver's, so get all data as character with no 
  1242. //  conversion.
  1243. PSTR CLoadDataDlg::GetDataRow
  1244.     (
  1245.     CObList& Columns,
  1246.     UINT nCols, 
  1247.     PSTR pdata,
  1248.     PBYTE pValues,
  1249.     PDATA_AT_EXEC* aDataAtExecs,
  1250.     UINT* aBindOffsets,
  1251.     UINT* aIndOffsets
  1252.     )
  1253.     {
  1254.     UINT        nCol;
  1255.     UINT        cbData;
  1256.     PDATA_AT_EXEC pDataAtExec;
  1257.     SQLSMALLINT eSQLType;
  1258.     
  1259.     for (nCol = 0; nCol < nCols && *pdata != (TCHAR) NULL; nCol++)
  1260.         {
  1261.         switch (eSQLType =
  1262.             ((CColAttr*) Columns.GetAt(Columns.FindIndex(nCol)))->GetODBCType())
  1263.             {
  1264.             case SQL_LONGVARCHAR:
  1265.             case SQL_LONGVARBINARY:
  1266.             case SQL_WLONGVARCHAR:
  1267.                 {
  1268.                 pDataAtExec = aDataAtExecs[nCol];
  1269.  
  1270.                 if (eSQLType == SQL_LONGVARCHAR || 
  1271.                     eSQLType == SQL_WLONGVARCHAR)
  1272.                     {
  1273.                     pdata = GetLongCharData(pdata, pDataAtExec);
  1274.                     }
  1275.                 else
  1276.                     {
  1277.                     pdata = GetLongBinaryData(pdata, pDataAtExec);
  1278.                     }
  1279.  
  1280.                 if (pDataAtExec->cbData == 0)
  1281.                     {
  1282.                     *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
  1283.                         = SQL_NULL_DATA;
  1284.                     }
  1285.                 else
  1286.                     {
  1287.                     *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
  1288.                         = SQL_LEN_DATA_AT_EXEC(pDataAtExec->cbData);
  1289.                     *((PDATA_AT_EXEC*) (pValues + aBindOffsets[nCol]))
  1290.                         = pDataAtExec;
  1291.                     }
  1292.  
  1293.                 break;
  1294.                 }
  1295.  
  1296.             default:
  1297.                 {
  1298.                 pdata = FieldData(pdata, (char*) pValues + aBindOffsets[nCol],
  1299.                     ((CColAttr*) Columns.GetAt(
  1300.                         Columns.FindIndex(nCol)))->GetDisplaySize() + 1,
  1301.                     &cbData);
  1302.                 if (cbData == 0)
  1303.                     {
  1304.                     *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
  1305.                         = SQL_NULL_DATA;
  1306.                     }
  1307.                 else
  1308.                     {
  1309.                     *((SQLINTEGER*) (pValues + aIndOffsets[nCol]))
  1310.                         = cbData;
  1311.                     }
  1312.  
  1313.                 break;
  1314.                 }
  1315.             }
  1316.         }
  1317.  
  1318.     return (pdata);
  1319.     }
  1320.  
  1321. /////////////////////////////////////////////////////////////////////////////
  1322. // ScriptRun -- Executes a batch of Transact SQL statements one at a time.
  1323. //  ScriptRun assumes that the statements are DDL or other statements that 
  1324. //  do not return results and the function does not include any data 
  1325. //  retrieval mechanism.
  1326. //
  1327. // Returns SQL_SUCCESS if all statements execute correctly,  
  1328. //  SQL_SUCCESS_WITH_INFO if some (possibly none) of the statements executed
  1329. //  correctly, SQL_ERROR on failure to find or read the command batch file.
  1330. SQLRETURN CLoadDataDlg::ScriptRun()
  1331.     {
  1332.     PSTR        szScript;
  1333.     PSTR        szAllLines;
  1334.     PSTR        szLine;
  1335.     BOOL        bFatalError = FALSE;
  1336.     CString     strPathAndFile = m_szPath;
  1337.     CString     strCmd = _T("");
  1338.     
  1339.     if (TrimQuotes(m_szArgs, m_szArgs) == 0)
  1340.         {
  1341.         return (SQL_ERROR);
  1342.         }
  1343.  
  1344.     strPathAndFile += m_szArgs;
  1345.     if (GetOSFile((LPCTSTR) strPathAndFile, (PBYTE*) &szScript) == FALSE)
  1346.         {
  1347.         return (SQL_ERROR);
  1348.         }
  1349.  
  1350.     szAllLines = szScript;
  1351.     while (bFatalError == FALSE && 
  1352.         GetNextLine(&szAllLines,  &szLine) != EOF)
  1353.         {
  1354.         if (stricmp(szLine, "GO") == 0)
  1355.             {
  1356.             if (strCmd.GetLength())
  1357.                 {
  1358.                 bFatalError = 
  1359.                     !(SQL_SUCCEEDED(ExecDirectCommand(strCmd)));
  1360.                 
  1361.                 strCmd = _T("");
  1362.                 }
  1363.             }
  1364.         else
  1365.             {
  1366.             if (strCmd.GetLength())
  1367.                 {
  1368.                 strCmd += _T(" ");
  1369.                 }
  1370.             strCmd += szLine;
  1371.             }
  1372.  
  1373.         delete [] szLine;
  1374.         }
  1375.  
  1376.     delete [] szScript;
  1377.  
  1378.     return (bFatalError ? SQL_ERROR : SQL_SUCCESS);
  1379.     }
  1380.  
  1381.