home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 32 / IOPROG_32.ISO / SOFT / SqlEval7 / devtools / samples / DBLIB / c / textcopy / textcopy.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-09  |  28.3 KB  |  948 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  FILE: textcopy.cpp
  4. //              
  5. //      Text and image copy application
  6. //
  7. //  FUNCTIONS:
  8. //
  9. //      main() - Main application
  10. //
  11. //  COMMENTS:
  12. //
  13. ///////////////////////////////////////////////////////////////////////////////
  14.  
  15. #include <afx.h>                // MFC 
  16. #include <iostream.h>           // iostream
  17. #include <stdlib.h>             // C run-time
  18.  
  19. #if defined (_DEBUG)
  20. #undef THIS_FILE
  21. static char BASED_CODE THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24. #define DBNTWIN32               // Win32 DB-Library for Windows NT
  25. #include <sqlfront.h>           // DB-Library
  26. #include <sqldb.h>              // DB-Library
  27.  
  28. extern "C"
  29. {
  30.     #include "getopt.h"         // GetOption
  31. }
  32.  
  33. #include "textcopy.h"           // specific to this program
  34.  
  35. // GLOBAL VARIABLES
  36. BOOL bDebug = FALSE;            // debug info
  37. BYTE* aBuf;
  38.  
  39. ///////////////////////////////////////////////////////////////////////////////
  40. //
  41. //  FUNCTION: main()
  42. //
  43. //      Main application
  44. //
  45. //  PARAMETERS:
  46. //
  47. //      argc - count of command line arguments
  48. //      argv - array of command line argument strings
  49. //      envp - array of environment strings
  50. //
  51. //  RETURNS: 0
  52. //
  53. //  COMMENTS:
  54. //
  55. ///////////////////////////////////////////////////////////////////////////////
  56.  
  57. int main (
  58.     int argc,
  59.     char** argv,
  60.     char** envp)
  61. {
  62.     char chOpt;                 // gotten option character
  63.     char* pszParam;             // gotten parameter
  64.     int nChunkSize = 4096;          // chunk size
  65.     CString strChunkSize = "4096";  // chunk size
  66.     CString strColumnType;
  67.  
  68.     CString strServer,          // SQL Server
  69.         strLogin,               // login
  70.         strPassword,            // password
  71.         strDatabase,            // database
  72.         strTable,               // table
  73.         strColumn,              // column
  74.         strWhere,               // where clause
  75.         strFile;                // file
  76.     BOOL bServer = FALSE,       // flags for tracking options
  77.         bLogin = FALSE,
  78.         bPassword = FALSE,
  79.         bDatabase = FALSE,
  80.         bTable = FALSE,
  81.         bColumn = FALSE,
  82.         bWhere = FALSE,
  83.         bFile = FALSE,
  84.         bIn = FALSE,
  85.         bOut = FALSE;
  86.  
  87.     // banner
  88.     cout << "TEXTCOPY Version 1.0" << endl;
  89.  
  90.     // initialize DB-Library, get DB-Library version number
  91.     CString strDblibVersion;
  92.     strDblibVersion = dbinit();
  93.     if (strDblibVersion.IsEmpty())
  94.     {
  95.         cout << err << "Could not initialize DB-Library" << endl;
  96.         return (1);
  97.     }
  98.     cout << strDblibVersion << endl;
  99.     
  100.     // get command-line options and parameters
  101.     while (TRUE)
  102.     {
  103.         // all the following command-line options are valid, they
  104.         // are neither case sensitive nor white-space sensitive, and
  105.         // both '/' and '-' are valid switch characters
  106.         //
  107.         //  OPTION  PARAMETER           DESCRIPTION
  108.         //
  109.         //  /S      [sqlserver]         SQL Server
  110.         //  /U      [login]             Login
  111.         //  /P      [password]          Password
  112.         //  /D      [database]          Database
  113.         //  /T      table               Table
  114.         //  /C      column              Column
  115.         //  /W      "where clause"      Where clause in double quotes
  116.         //  /F      file                File
  117.         //  /I                          Into SQL Server from file
  118.         //  /O                          Out of SQL Server into file
  119.         //  /K      chunksize           Chunk size in bytes
  120.         //  /Z                          Debug information
  121.         //  /?                          Usage information
  122.         //
  123.         // for example, all of the following are valid ways to specify
  124.         // a connection to a SQL Server named 'gizmo'
  125.         //
  126.         //  /Sgizmo     /sgizmo     -Sgizmo     -sgizmo
  127.         //  /S gizmo    /s gizmo    -S gizmo    -s gizmo
  128.  
  129.         chOpt = GetOption(argc, argv, "s:S:u:U:p:P:d:D:t:T:c:C:w:W:f:F:k:K:iIoOzZ?", &pszParam);
  130.         if (chOpt > 1)
  131.         {
  132.             // chOpt is valid argument
  133.             switch (chOpt)
  134.             {
  135.             case 's':   // SQL Server
  136.             case 'S':
  137.                 bServer = TRUE;
  138.                 strServer = pszParam;
  139.                 break;
  140.             case 'u':   // login
  141.             case 'U':
  142.                 bLogin = TRUE;
  143.                 strLogin = pszParam;
  144.                 break;
  145.             case 'p':   // password
  146.             case 'P':
  147.                 bPassword = TRUE;
  148.                 strPassword = pszParam;
  149.                 break;
  150.             case 'd':   // database
  151.             case 'D':
  152.                 bDatabase = TRUE;
  153.                 strDatabase = pszParam;
  154.                 break;
  155.             case 't':   // table
  156.             case 'T':
  157.                 bTable = TRUE;
  158.                 strTable = pszParam;
  159.                 break;
  160.             case 'c':   // column
  161.             case 'C':
  162.                 bColumn = TRUE;
  163.                 strColumn = pszParam;
  164.                 break;
  165.             case 'w':   // where clause
  166.             case 'W':
  167.                 bWhere = TRUE;
  168.                 strWhere = pszParam;
  169.                 break;
  170.             case 'f':   // file
  171.             case 'F':
  172.                 bFile = TRUE;
  173.                 strFile = pszParam;
  174.                 break;
  175.             case 'i':   // direction: into SQL Server from file
  176.             case 'I':
  177.                 bIn = TRUE;
  178.                 break;
  179.             case 'o':   // direction: out of SQL Server into file
  180.             case 'O':
  181.                 bOut = TRUE;
  182.                 break;
  183.             case 'k':   // chunk size in bytes
  184.             case 'K':
  185.                 if (pszParam != NULL)
  186.                 {
  187.                     nChunkSize = atoi (pszParam);
  188.                     _itoa (nChunkSize, strChunkSize.GetBuffer(20), 10);
  189.                     strChunkSize.ReleaseBuffer();
  190.                     if (strChunkSize != pszParam)
  191.                     {
  192.                         cout << err << "Converted chunk size '" << pszParam << "' to " << nChunkSize << endl;
  193.                         return (0);
  194.                     }
  195.                 }
  196.                 break;
  197.             case 'z':   // debug
  198.             case 'Z':
  199.                 bDebug = TRUE;
  200.                 break;
  201.             case '?':   // usage info
  202.                 DisplayUsage();
  203.                 return(0);
  204.                 break;
  205.             }
  206.         }
  207.         if (chOpt == 0)
  208.         {
  209.             // end of argument list
  210.             break;
  211.         }
  212.         if ((chOpt == 1) || (chOpt == -1))
  213.         {
  214.             // standalone param or error
  215.             cout << err << "Argument '" << pszParam << "' not recognized" << endl;
  216.             break;
  217.         }
  218.     }
  219.  
  220.     if ((chOpt == 1) || (chOpt == -1))
  221.     {
  222.         // exit on error
  223.         return (1);
  224.     }
  225.  
  226.     // prompt the user for any unspecified options
  227.     if (!bServer)
  228.     {
  229.         cout << "Type the SQL Server to connect to: ";
  230.         cinstr (strServer);
  231.     }
  232.  
  233.     if (!bLogin)
  234.     {
  235.         cout << "Type your login: ";
  236.         cinstr (strLogin);
  237.     }
  238.  
  239.     if (!bPassword)
  240.     {
  241.         cout << "Type your password: ";
  242.         cinstr (strPassword);
  243.     }
  244.  
  245.     if (!bDatabase)
  246.     {
  247.         cout << "Type the database: ";
  248.         cinstr (strDatabase);
  249.     }
  250.  
  251.     if (!bTable)
  252.     {
  253.         cout << "Type the table: ";
  254.         cinstr (strTable);
  255.     }
  256.     
  257.     if (!bColumn)
  258.     {
  259.         cout << "Type the text or image column: ";
  260.         cinstr (strColumn);
  261.     }
  262.     
  263.     if (!bWhere)
  264.     {
  265.         cout << "Type the where clause: ";
  266.         cinstr (strWhere);
  267.     }
  268.     
  269.     if (!bFile)
  270.     {
  271.         cout << "Type the file: ";
  272.         cinstr (strFile);
  273.     }
  274.  
  275.     if (!bIn && !bOut)
  276.     {
  277.         while (TRUE)
  278.         {
  279.             CString strDirection;
  280.             cout << "Type the direction ('I' for in, 'O' for out): ";
  281.             cinstr (strDirection);
  282.             if (strDirection.CompareNoCase("i") == 0)
  283.             {
  284.                 bIn = TRUE;
  285.                 break;
  286.             }
  287.             else
  288.             {
  289.                 if (strDirection.CompareNoCase("o") == 0)
  290.                 {
  291.                     bOut = TRUE;
  292.                     break;
  293.                 }
  294.                 else
  295.                 {
  296.                     cout << err << "The value '" << strDirection << "' is invalid." << endl;
  297.                 }
  298.             }
  299.         }
  300.     }
  301.  
  302.     // parameter validation
  303.     if (strTable.IsEmpty())
  304.     {
  305.         cout << err << "You did not specify a table." << endl;
  306.         return (1);
  307.     }
  308.  
  309.     if (strColumn.IsEmpty())
  310.     {
  311.         cout << err << "You did not specify a column." << endl;
  312.         return (1);
  313.     }
  314.  
  315.     if (strWhere.IsEmpty())
  316.     {
  317.         cout << err << "You did not specify a where clause." << endl;
  318.         return (1);
  319.     }
  320.  
  321.     /*
  322.     CString strLowerWhere = strWhere;
  323.     strLowerWhere.MakeLower();
  324.     if (strLowerWhere.Find ("where ") == -1)
  325.     {
  326.         cout << err << "Your where clause '" << strWhere << "' did not contain the keyword 'where'." << endl;
  327.         return (1);
  328.     }
  329.     */
  330.  
  331.     if (strFile.IsEmpty())
  332.     {
  333.         cout << err << "You did not specify a file." << endl;
  334.         return (1);
  335.     }
  336.  
  337.     if (bIn && bOut)
  338.     {
  339.         cout << err << "You cannot specify both 'in' and 'out' directions." << endl;
  340.         return (1);
  341.     }
  342.  
  343.     if (nChunkSize < 1024)
  344.     {
  345.         cout << err << "Your specified chunk size of " << nChunkSize << " bytes is too small." << endl;
  346.         return (1);
  347.     }
  348.  
  349.     if (bDebug)
  350.     {
  351.         cout << dbg << "Final parameters:" << endl;
  352.         cout << dbg << "  Server: " << strServer << endl;
  353.         cout << dbg << "  Login: " << strLogin << endl;
  354.         cout << dbg << "  Password: " << strPassword << endl;
  355.         cout << dbg << "  Database: " << strDatabase << endl;
  356.         cout << dbg << "  Table: " << strTable << endl;
  357.         cout << dbg << "  Column: " << strColumn << endl;
  358.         cout << dbg << "  Where clause: " << strWhere << endl;
  359.         cout << dbg << "  File: " << strFile << endl;
  360.         cout << dbg << "  Direction: ";
  361.         if (bIn)
  362.         {
  363.             cout << "Into SQL Server from file." << endl;
  364.         }
  365.         if (bOut)
  366.         {
  367.             cout << "Out of SQL Server into file." << endl;
  368.         }
  369.         cout << dbg << "  Chunk size: " << nChunkSize << " bytes" << endl;
  370.     }
  371.  
  372.     // install error and message handlers
  373.     dberrhandle (ErrorHandler);
  374.     dbmsghandle (MessageHandler);
  375.  
  376.     // set DB-Library options
  377.     dbsettime(30);
  378.     dbsetlogintime(10);
  379.  
  380.     // get login record
  381.     PLOGINREC pLoginRec;
  382.     pLoginRec = dblogin();
  383.     if (pLoginRec == NULL)
  384.     {
  385.         cout << err << "Could not allocate a login record" << endl;
  386.         return (1);
  387.     }
  388.  
  389.     // fill the login record 
  390.     DBSETLUSER (pLoginRec, strLogin);       // set the login
  391.     DBSETLPWD (pLoginRec, strPassword);     // set the password
  392.     DBSETLAPP (pLoginRec, "textcopy");      // set the app name
  393.     DBSETLHOST (pLoginRec, "textcopy");     // set the host name
  394.  
  395.     // attempt to connect to SQL Server
  396.     PDBPROCESS pDbproc;
  397.     pDbproc = dbopen (pLoginRec, strServer);
  398.     dbfreelogin (pLoginRec);
  399.     if (pDbproc == NULL)
  400.     {
  401.         cout << err << "Could not connect to SQL Server '" << strServer << "'" << endl;
  402.         return (1);
  403.     }
  404.  
  405.     // re-used DB-Library return code
  406.     RETCODE r;
  407.  
  408.     // set textlimit and textsize options for this connection
  409.     if (bOut)
  410.     {
  411.         dbsetopt (pDbproc, DBTEXTLIMIT, strChunkSize);
  412.         dbsetopt (pDbproc, DBTEXTSIZE, "2147483647");
  413.     }
  414.  
  415.     if (bIn)
  416.     {
  417.         dbsetopt (pDbproc, DBTEXTSIZE, "1024");
  418.     }
  419.  
  420.     // must send and execute batch to set options
  421.     r = dbsqlexec (pDbproc);
  422.     if (r == FAIL)
  423.     {
  424.         cout << err << "Query execution failed." << endl;
  425.         Cleanup (pDbproc);
  426.         return (1);
  427.     }
  428.  
  429.     // get empty result set(s) from setting options
  430.     while (TRUE)
  431.     {
  432.         r = dbresults (pDbproc);
  433.         if (r == FAIL)
  434.         {
  435.             cout << err << "Query results failed." << endl;
  436.             Cleanup (pDbproc);
  437.             return (1);
  438.         }
  439.         if (r == NO_MORE_RESULTS)
  440.             break; // while loop
  441.     }
  442.  
  443.     // use specified database
  444.     if (!strDatabase.IsEmpty())
  445.     {
  446.         r = dbuse (pDbproc, strDatabase);
  447.         if (r == FAIL)
  448.         {
  449.             cout << err << "Could not use database '" << strDatabase << "'" << endl;
  450.             Cleanup(pDbproc);
  451.             return (1);
  452.         }
  453.     }
  454.  
  455.     // build query
  456.     CString strQuery;
  457.  
  458.     strQuery = "select " + strColumn + " from " + strTable + " " + strWhere;
  459.     D(cout << "Query: " << strQuery << endl);
  460.  
  461.     r = dbcmd (pDbproc, strQuery);
  462.  
  463.     // send and execute query 
  464.     r = dbsqlexec (pDbproc);
  465.     if (r == FAIL)
  466.     {
  467.         cout << err << "Query execution failed." << endl;
  468.         Cleanup (pDbproc);
  469.         return (1);
  470.     }
  471.  
  472.     // get first result set
  473.     r = dbresults (pDbproc);
  474.     if (r != SUCCEED)
  475.     {
  476.         cout << err << "Query results failed." << endl;
  477.         Cleanup (pDbproc);
  478.         return (1);
  479.     }
  480.  
  481.     // verify that only a single column was selected    
  482.     if (dbnumcols (pDbproc) != 1)
  483.     {
  484.         cout << err << "More than one column specified." << endl;
  485.         Cleanup (pDbproc);
  486.         return (1);
  487.     }
  488.  
  489.     // verify that the single column selected is either text or image
  490.     int nColumnType;
  491.     nColumnType = dbcoltype (pDbproc, 1);
  492.     if ((nColumnType != SQLTEXT) && (nColumnType != SQLIMAGE))
  493.     {
  494.         cout << err << "Specified column is not a text or image column." << endl;
  495.         Cleanup (pDbproc);
  496.         return (1);
  497.     }
  498.     else
  499.     {
  500.         if (nColumnType == SQLTEXT)
  501.         {
  502.             strColumnType = "text";
  503.         }
  504.         if (nColumnType == SQLIMAGE)
  505.         {
  506.             strColumnType = "image";
  507.         }
  508.     }
  509.  
  510.     // buffer for data transfer between DB-Library and file
  511.     aBuf = new BYTE[nChunkSize];
  512.     if (aBuf == 0)
  513.     {
  514.         cout << err << "Unable to allocate transfer buffer of '" << nChunkSize << "' bytes." << endl;
  515.         Cleanup (pDbproc);
  516.         return (1);
  517.     }
  518.  
  519.     // if the data is coming out of SQL Server and into a file, use dbreadtext
  520.     // (instead of dbnextrow) to read the text or image data from the row
  521.     // in chunks
  522.     if (bOut)
  523.     {
  524.     try
  525.     {
  526.         // set up file 
  527.         CFile file (strFile, CFile::modeCreate | CFile::modeWrite);
  528.         D(cout << "File '" << strFile << "' opened for write" << endl);
  529.  
  530.         DBINT lWriteBytes;
  531.         while (TRUE)
  532.         {
  533.             // read chunk of text or image data from SQL Server into aBuf
  534.             lWriteBytes = dbreadtext (pDbproc, aBuf, nChunkSize);
  535.             switch (lWriteBytes)
  536.             {
  537.             case 0:
  538.                 // end of text or image row
  539.                 //D(cout << "End of row" << endl);
  540.                 break;
  541.             case -1:
  542.                 // dbreadtext failed
  543.                 cout << err << "Text or image data retrieval failed." << endl;
  544.                 Cleanup (pDbproc);
  545.                 return (1);
  546.                 break;
  547.             case NO_MORE_ROWS:
  548.                 //D(cout << "No more rows" << endl);
  549.                 break;
  550.             default:
  551.                 // dbreadtext has placed lBytes of text or image data
  552.                 // into aBuf, now write that chunk to the file
  553.                 file.Write (aBuf, lWriteBytes);
  554.                 D(cout << "Wrote " << lWriteBytes << " bytes to file" << endl);
  555.                 break;
  556.             }
  557.             if ((lWriteBytes == -1) || (lWriteBytes == NO_MORE_ROWS))
  558.                 break; // while loop
  559.         }
  560.         file.Close();
  561.         D(cout << "File closed" << endl);
  562.     }
  563.     catch (CFileException* e)
  564.     {
  565.         //if (e->m_cause == CFileException::fileNotFound)
  566.         cout << err << "Problem with file '" << strFile << "'." << endl;
  567.         e->Delete();
  568.         Cleanup (pDbproc);
  569.         return (1);
  570.     }
  571.  
  572.     }
  573.  
  574.     DBBINARY aTextPointer[DBTXPLEN], aTextTimestamp[DBTXTSLEN];
  575.     DBBINARY *pTextPointer, *pTextTimestamp;
  576.     
  577.     // if the data is going into SQL Server from a file, copy the text
  578.     // pointer and text timestamp values into private buffers
  579.     if (bIn)
  580.     {
  581.         // get the single row
  582.         STATUS s;
  583.         s = dbnextrow (pDbproc);
  584.         if (s != REG_ROW)
  585.         {
  586.             cout << err << "Row retrieval failed." << endl;
  587.             Cleanup (pDbproc);
  588.             return (1);
  589.         }
  590.  
  591.         // get the pointers to the text pointer and text timestamp values
  592.         pTextPointer = dbtxptr (pDbproc, 1);
  593.         pTextTimestamp = dbtxtimestamp (pDbproc, 1);
  594.         if ((pTextPointer == NULL) || (pTextTimestamp == NULL))
  595.         {
  596.             cout << err << "Text or image pointer and timestamp retrieval failed." << endl;
  597.             Cleanup (pDbproc);
  598.             return (1);
  599.         }
  600.  
  601.         // copy the actual text pointer and text timestamp values into
  602.         // private buffers
  603.         memcpy (aTextPointer, pTextPointer, DBTXPLEN);
  604.         memcpy (aTextTimestamp, pTextTimestamp, DBTXTSLEN);
  605.  
  606.         // we should only have received one row, so call dbnextrow
  607.         // to get NO_MORE_ROWS
  608.         s = dbnextrow (pDbproc);
  609.         switch (s)
  610.         {
  611.         case NO_MORE_ROWS:
  612.             // this is what we expect
  613.             break;
  614.         case REG_ROW:
  615.             cout << err << "Where clause returned more than one row." << endl;
  616.             Cleanup (pDbproc);
  617.             return (1);
  618.             break;
  619.         default:
  620.             cout << err << "Row retrieval failed." << endl;
  621.             Cleanup (pDbproc);
  622.             return (1);
  623.             break;
  624.         }
  625.     }
  626.     
  627.     // get NO_MORE_RESULTS to clear out all results
  628.     r = dbresults (pDbproc);
  629.     if (r != NO_MORE_RESULTS)
  630.     {
  631.         cout << err << "Query results failed." << endl;
  632.         Cleanup (pDbproc);
  633.         return (1);
  634.     }
  635.  
  636.     // if the data is going into SQL Server from a file, use dbwritetext
  637.     // (with the private copies of the text or image pointer and timestamp
  638.     // values) and dbmoretext to write the text or image data to
  639.     // SQL Server in chunks
  640.     if (bIn)
  641.     {
  642.     try
  643.     {
  644.         // set up file
  645.         CFile file (strFile, CFile::modeRead);
  646.         D(cout << "File '" << strFile << "' opened for read" << endl);
  647.         D(cout << "File is " << file.GetLength() << " bytes long" << endl);
  648.  
  649.         // call dbwritetext will NULL text value to indicate that the text
  650.         // values will be sent in chunks using dbmoretext
  651.         r = dbwritetext (pDbproc, strTable + "." + strColumn,
  652.             aTextPointer, DBTXPLEN, aTextTimestamp,
  653.             TRUE, file.GetLength(), NULL);
  654.         if (r == FAIL)
  655.         {
  656.             cout << err << "Text or image write failed." << endl;
  657.             Cleanup (pDbproc);
  658.             return (1);
  659.         }
  660.         
  661.         // call dbsqlok and dbresults to prepare for calling dbmoretext
  662.         r = dbsqlok (pDbproc);
  663.         if (r == FAIL)
  664.         {
  665.             cout << err << "Text or image write failed." << endl;
  666.             Cleanup (pDbproc);
  667.             return (1);
  668.         }
  669.         r = dbresults (pDbproc);
  670.         if (r == FAIL)
  671.         {
  672.             cout << err << "Query results failed." << endl;
  673.             Cleanup (pDbproc);
  674.             return (1);
  675.         }
  676.  
  677.         // read each chunk from the file and write it to SQL Server
  678.         UINT nReadBytes = nChunkSize;
  679.         while (nReadBytes == UINT(nChunkSize))
  680.         {
  681.             // read chunk from file into aBuf
  682.             nReadBytes = file.Read (aBuf, nChunkSize);
  683.             D(cout << "Read "<< nReadBytes << " bytes from file" << endl);
  684.             
  685.             // write chunk of text or image data from aBuf to SQL Server
  686.             r = dbmoretext (pDbproc, nReadBytes, aBuf);
  687.             if (r == FAIL)
  688.             {
  689.                 cout << err << "Text or image write failed." << endl;
  690.                 Cleanup (pDbproc);
  691.                 return (1);
  692.             }
  693.         }
  694.  
  695.         file.Close();
  696.         D(cout << "File closed" << endl);
  697.  
  698.         // call dbsqlok and dbresults to signal end of calls to
  699.         // dbmoretext and completion of text or image write
  700.         r = dbsqlok (pDbproc);
  701.         if (r == FAIL)
  702.         {
  703.             cout << err << "Text or image write failed." << endl;
  704.             Cleanup (pDbproc);
  705.             return (1);
  706.         }
  707.         r = dbresults (pDbproc);
  708.         if (r == FAIL)
  709.         {
  710.             cout << err << "Query results failed." << endl;
  711.             Cleanup (pDbproc);
  712.             return (1);
  713.         }
  714.     }
  715.     catch (CFileException* e)
  716.     {
  717.         //if (e->m_cause == CFileException::fileNotFound)
  718.         cout << err << "Problem with file '" << strFile << "'." << endl;
  719.         e->Delete();
  720.         Cleanup (pDbproc);
  721.         return (1);
  722.     }
  723.  
  724.     }
  725.  
  726.     // display success message
  727.     if (bIn)
  728.     {
  729.         cout << "Data copied into SQL Server " << strColumnType << " column from file '" << strFile << "'." << endl;
  730.     }
  731.     if (bOut)
  732.     {
  733.         cout << "Data copied out of SQL Server " << strColumnType << " column into file '" << strFile << "'." << endl;
  734.     }
  735.  
  736.     // prepare DB-Library for exit
  737.     Cleanup (pDbproc);
  738.  
  739.     return (0);
  740. }
  741.  
  742. ///////////////////////////////////////////////////////////////////////////////
  743. //
  744. //  FUNCTION: Cleanup()
  745. //
  746. //      Prepare DB-Library for exit
  747. //
  748. //  PARAMETERS:
  749. //
  750. //      pDbproc - pointer to DBPROCESS connection
  751. //
  752. //  RETURNS: 0
  753. //
  754. //  COMMENTS:
  755. //
  756. ///////////////////////////////////////////////////////////////////////////////
  757.  
  758. int Cleanup (PDBPROCESS pDbproc)
  759. {
  760.     delete [] aBuf;
  761.     dbcancel (pDbproc);
  762.     dbclose (pDbproc);
  763.     return (0);
  764. }
  765.  
  766. ///////////////////////////////////////////////////////////////////////////////
  767. //
  768. //  FUNCTION: ErrorHandler()
  769. //
  770. //      Called when a DB-Library error occurs
  771. //
  772. //  PARAMETERS:
  773. //
  774. //      pDbproc - pointer to DBPROCESS connection
  775. //      nDblibSeverity - DB-Library error severity
  776. //      nDblibErrorNo - DB-Library error number
  777. //      nOSErrorNo - operating system error number
  778. //      lpstrDblibError - DB-Library error string
  779. //      lpstrOSError - operating system error string
  780. //
  781. //  RETURNS: One of three DB-Library return continuation codes:
  782. //
  783. //      INT_CANCEL
  784. //      INT_CONTINUE
  785. //      INT_EXIT
  786. //
  787. //  COMMENTS:
  788. //
  789. ///////////////////////////////////////////////////////////////////////////////
  790.  
  791. extern "C" int ErrorHandler (
  792.     PDBPROCESS pDbproc,
  793.     INT nSeverity,
  794.     INT nDBLibError,
  795.     INT nOSError,
  796.     LPCSTR pszDBLibError,
  797.     LPCSTR pszOSError)
  798. {
  799.     // display DB-Library error information
  800.     cout << "DB-Library Error " << nDBLibError << ": " << pszDBLibError << endl;
  801.  
  802.     if ((pDbproc == NULL) || (DBDEAD(pDbproc)))
  803.     {
  804.         return(INT_EXIT);
  805.     }
  806.     else
  807.     {
  808.         if (nOSError != DBNOERR)
  809.         {
  810.             // this DB-Library error was caused by an operating system
  811.             // error, so display OS error information
  812.             cout << "Operating System Error " << nOSError << ": " << pszOSError << endl;
  813.         }
  814.  
  815.         return(INT_CANCEL);
  816.     }
  817. }
  818.  
  819. ///////////////////////////////////////////////////////////////////////////////
  820. //
  821. //  FUNCTION: MessageHandler()
  822. //
  823. //      Called when a SQL Server message is received
  824. //
  825. //  PARAMETERS:
  826. //
  827. //      pDbproc - pointer to DBPROCESS connection
  828. //      lMessage - SQL Server message number
  829. //      nState - SQL Server message state
  830. //      nSeverity - SQL Server message severity
  831. //      pszMessage - SQL Server message string
  832. //      pszServer - the SQL Server that sent this message
  833. //      pszProcedure - the stored procedure (if any) where the message
  834. //                     occurred
  835. //      usLine - the line number (if any) of the batch or stored procedure
  836. //                 where the message occurred
  837. //
  838. //  RETURNS: 0
  839. //
  840. //  COMMENTS:
  841. //
  842. ///////////////////////////////////////////////////////////////////////////////
  843.  
  844. extern "C" int MessageHandler (
  845.     PDBPROCESS pDbproc,
  846.     DBINT lMessage,
  847.     INT nState,
  848.     INT nSeverity,
  849.     LPCSTR pszMessage,
  850.     LPCSTR pszServer,
  851.     LPCSTR pszProcedure,
  852.     DBUSMALLINT usLine)
  853. {
  854.     // only display certain SQL Serve messages when debug info enabled
  855.     switch (lMessage)
  856.     {
  857.     case 5701:
  858.         if (!bDebug)
  859.         {
  860.             return (0);
  861.         }
  862.         break;
  863.     }
  864.  
  865.     // display SQL Server message information
  866.     cout << "SQL Server";
  867.  
  868.     if (pszServer != NULL)
  869.     {
  870.         if (*pszServer != '\0')
  871.         {
  872.             cout << " '" << pszServer << "'";
  873.         }
  874.     }
  875.  
  876.     cout << " Message " << lMessage << ": " << pszMessage;
  877.  
  878.     if (usLine != 0)
  879.     {
  880.         cout << " (Concerning line " << usLine;
  881.         if (pszProcedure != NULL)
  882.         {
  883.             cout << " of stored procedure '" << pszProcedure << "'";
  884.         }
  885.         cout << ")";
  886.     }
  887.  
  888.     cout << endl;
  889.  
  890.     return(0);
  891. }
  892.  
  893. ///////////////////////////////////////////////////////////////////////////////
  894. //
  895. //  FUNCTION: DisplayUsage()
  896. //
  897. //      Display usage information
  898. //
  899. //  PARAMETERS:
  900. //
  901. //  RETURNS: 0
  902. //
  903. //  COMMENTS:
  904. //
  905. ///////////////////////////////////////////////////////////////////////////////
  906.  
  907. int DisplayUsage (void)
  908. {
  909.     cout << endl;
  910.     cout << "Copies a single text or image value into or out of SQL Server. The value" << endl;
  911.     cout << "is a specified text or image 'column' of a single row (specified by the" << endl;
  912.     cout << "\"where clause\") of the specified 'table'." << endl;
  913.     cout << endl;
  914.     cout << "If the direction is IN (/I) then the data from the specified 'file' is" << endl;
  915.     cout << "copied into SQL Server, replacing the existing text or image value. If the" << endl;
  916.     cout << "direction is OUT (/O) then the text or image value is copied from" << endl;
  917.     cout << "SQL Server into the specified 'file', replacing any existing file." << endl;
  918.     cout << endl;
  919.     cout << "TEXTCOPY [/S [sqlserver]] [/U [login]] [/P [password]]" << endl;
  920.     cout << "  [/D [database]] [/T table] [/C column] [/W\"where clause\"]" << endl;
  921.     cout << "  [/F file] [{/I | /O}] [/K chunksize] [/Z] [/?]" << endl;
  922.     cout << endl;
  923.     cout << "  /S sqlserver       The SQL Server to connect to. If 'sqlserver' is not" << endl;
  924.     cout << "                     specified, the local SQL Server is used." << endl;
  925.     cout << "  /U login           The login to connect with. If 'login' is not specified," << endl;
  926.     cout << "                     a trusted connection will be used." << endl;
  927.     cout << "  /P password        The password for 'login'. If 'password' is not" << endl;
  928.     cout << "                     specified, a NULL password will be used." << endl;
  929.     cout << "  /D database        The database that contains the table with the text or" << endl;
  930.     cout << "                     image data. If 'database' is not specified, the default" << endl;
  931.     cout << "                     database of 'login' is used." << endl;
  932.     cout << "  /T table           The table that contains the text or image value." << endl;
  933.     cout << "  /C column          The text or image column of 'table'." << endl;
  934.     cout << "  /W \"where clause\"  A complete where clause (including the WHERE keyword)" << endl;
  935.     cout << "                     that specifies a single row of 'table'." << endl;
  936.     cout << "  /F file            The file name." << endl;
  937.     cout << "  /I                 Copy text or image value into SQL Server from 'file'." << endl;
  938.     cout << "  /O                 Copy text or image value out of SQL Server into 'file'." << endl;
  939.     cout << "  /K chunksize       Size of the data transfer buffer in bytes. Minimum" << endl;
  940.     cout << "                     value is 1024 bytes, default value is 4096 bytes." << endl;
  941.     cout << "  /Z                 Display debug information while running." << endl;
  942.     cout << "  /?                 Display this usage information and exit." << endl;
  943.     cout << endl;
  944.     cout << "You will be prompted for any required options you did not specify." << endl;
  945.  
  946.     return (0);
  947. }
  948.