Condividi tramite


Eseguire una copia bulk di dati da variabili di programma (ODBC)

In questo esempio viene illustrato come utilizzare le funzioni che consentono di eseguire la copia bulk di dati dalle variabili di programma a SQL Server utilizzando bcp_bind e bcp_sendrow. Per semplificare questo esempio, è stato rimosso il codice per il controllo degli errori.

L'esempio è stato sviluppato per ODBC versione 3.0 o successiva.

Nota sulla sicurezza   Se possibile, utilizzare l'autenticazione di Windows. Se l'autenticazione di Windows non è disponibile, agli utenti verrà richiesto di immettere le credenziali in fase di esecuzione. Evitare di archiviare le credenziali in un file. Se è necessario rendere persistenti le credenziali, è consigliabile crittografarle utilizzando CryptoAPI Win32.

Per utilizzare le funzioni di copia bulk direttamente sulle variabili di programma

  1. Allocare un handle di ambiente e un handle di connessione.

  2. Impostare SQL_COPT_SS_BCP e SQL_BCP_ON in modo da abilitare le operazioni di copia bulk.

  3. Connettersi a SQL Server.

  4. Chiamare bcp_init per impostare le informazioni seguenti:

    • Nome della tabella o della vista dalla quale o nella quale si desidera eseguire la copia bulk.

    • Specificare NULL come nome del file di dati.

    • Nome di un file di dati per la ricezione di eventuali messaggi di errore della copia bulk (specificare NULL se non si desidera che venga creato un file dei messaggi).

    • Direzione della copia, ovvero DB_IN per indicare la copia dall'applicazione alla vista o alla tabella oppure DB_OUT per indicare la copia dalla tabella o dalla vista all'applicazione.

  5. Chiamare il metodo bcp_bind per ogni colonna della copia bulk da associare alla colonna di una variabile di programma.

  6. Inserire dati nelle variabili di programma e chiamare bcp_sendrow per inviare una riga di dati.

  7. Dopo che sono state inviate diverse righe, chiamare bcp_batch per eseguire il checkpoint delle righe già inviate. È consigliabile chiamare bcp_batch almeno una volta ogni 1000 righe.

  8. Dopo che tutte le righe sono state inviate, chiamare bcp_done per completare l'operazione.

È possibile variare il percorso e la lunghezza delle variabili di programma durante un'operazione di copia bulk chiamando i metodi bcp_colptr e bcp_collen. Utilizzare bcp_control per impostare le varie opzioni di copia bulk. Utilizzare bcp_moretext per inviare i dati text, ntext e image in segmenti al server.

Esempio

Questo esempio non è supportato in IA64.

È necessaria un'origine dati ODBC denominata AdventureWorks, il cui database predefinito è il database di esempio AdventureWorks. È possibile scaricare il database di esempio AdventureWorks dalla home page del sito relativo a progetti della community ed esempi per Microsoft SQL Server. Questa origine dati deve essere basata sul driver ODBC fornito dal sistema operativo (il nome del driver è "SQL Server"). Se questo esempio viene compilato ed eseguito come applicazione a 32 bit in un sistema operativo a 64 bit, è necessario creare l'origine dati ODBC con Amministratore ODBC in %windir%\SysWOW64\odbcad32.exe.

In questo esempio viene eseguita la connessione all'istanza predefinita di SQL Server nel computer in uso. Per connettersi a un'istanza denominata, modificare la definizione dell'origine dati ODBC per specificare l'istanza in base al formato: server\istanzadenominata. Per impostazione predefinita, SQL Server Express viene installato in un'istanza denominata.

Eseguire il primo listato di codice (Transact-SQL) per creare le tabelle che verranno utilizzate dall'esempio.

Compilare il secondo listato di codice (C++) con odbc32.lib e odbcbcp.lib. Se è stata eseguita la compilazione con MSBuild.exe, copiare Bcpfmt.fmt e Bcpodbc.bcp dalla directory del progetto in quella contenente il file con estensione exe e quindi richiamare tale file.

Eseguire il terzo listato di codice (Transact-SQL) per eliminare le tabelle utilizzate dall'esempio.

// compile with: odbc32.lib odbcbcp.lib
use AdventureWorks
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'BCPSource')
     DROP TABLE BCPSource
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'BCPTarget')
     DROP TABLE BCPTarget
GO

CREATE TABLE BCPSource (cola int PRIMARY KEY, colb CHAR(10) NULL)
INSERT INTO BCPSource (cola, colb) VALUES (1, 'aaa')
INSERT INTO BCPSource (cola, colb) VALUES (2, 'bbb')
CREATE TABLE BCPTarget (cola int PRIMARY KEY, colb CHAR(10) NULL)

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>

SQLHENV henv = SQL_NULL_HENV;
HDBC hdbc1 = SQL_NULL_HDBC, hdbc2 = SQL_NULL_HDBC;
SQLHSTMT hstmt2 = SQL_NULL_HSTMT;

void Cleanup() {
   if (hstmt2 != SQL_NULL_HSTMT)
      SQLFreeHandle(SQL_HANDLE_STMT, hstmt2);

   if (hdbc1 != SQL_NULL_HDBC) {
      SQLDisconnect(hdbc1);
      SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   }
 
   if (hdbc2 != SQL_NULL_HDBC) {
      SQLDisconnect(hdbc2);
      SQLFreeHandle(SQL_HANDLE_DBC, hdbc2);
   }

   if (henv != SQL_NULL_HENV)
      SQLFreeHandle(SQL_HANDLE_ENV, henv);
}

int main() {
   RETCODE retcode;

   // BCP variables.
   char *terminator = "\0";

   // bcp_done takes a different format return code because it returns number of rows bulk copied
   // after the last bcp_batch call.
   DBINT cRowsDone = 0;

   // Set up separate return code for bcp_sendrow so it is not using the same retcode as SQLFetch.
   RETCODE SendRet;

   // Column variables.  cbCola and cbColb must be defined right before Cola and szColb because 
   // they are used as bulk copy indicator variables.
   struct ColaData {
      int cbCola;
      SQLINTEGER Cola;
   } ColaInst;

   struct ColbData {
      int cbColb;
      SQLCHAR szColb[11];
   } ColbInst;

   // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLAllocHandle(Env) Failed\n\n");
      Cleanup();
      return(9);
   }

   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
      Cleanup();
      return(9);    
   }

   // Allocate ODBC connection handle, set bulk copy mode, and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLAllocHandle(hdbc1) Failed\n\n");
      Cleanup();
      return(9);
   }

   retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP, (void *)SQL_BCP_ON, SQL_IS_INTEGER);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLSetConnectAttr(hdbc1) Failed\n\n");
      Cleanup();
      return(9);
   }

   // sample uses Integrated Security, create the SQL Server DSN using Windows NT authentication
   retcode = SQLConnect(hdbc1, (UCHAR*)"AdventureWorks", SQL_NTS, (UCHAR*)"", SQL_NTS, (UCHAR*)"", SQL_NTS);
   if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
      printf("SQLConnect() Failed\n\n");
      Cleanup();
      return(9);
   }

   // Initialize the bulk copy.
   retcode = bcp_init(hdbc1, "AdventureWorks..BCPTarget", NULL, NULL, DB_IN);
   if ( (retcode != SUCCEED) ) {
      printf("bcp_init(hdbc1) Failed\n\n");
      Cleanup();
      return(9);
   }

   // Bind the program variables for the bulk copy.
   retcode = bcp_bind(hdbc1, (BYTE *)&ColaInst.cbCola, 4, SQL_VARLEN_DATA, NULL, (INT)NULL, SQLINT4, 1);
   if ( (retcode != SUCCEED) ) {
      printf("bcp_bind(hdbc1) Failed\n\n");
      Cleanup();
      return(9);
   }

   // Could normally use strlen to calculate the bcp_bind cbTerm parameter, but this terminator 
   // is a null byte (\0), which gives strlen a value of 0. Explicitly give cbTerm a value of 1.
   retcode = bcp_bind(hdbc1, (BYTE *)&ColbInst.cbColb, 4, 11, (UCHAR*)terminator, 1, SQLCHARACTER, 2);
   if ( (retcode != SUCCEED) ) {
      printf("bcp_bind(hdbc1) Failed\n\n");
      Cleanup();
      return(9);
   }

   // Allocate second ODBC connection handle so bulk copy and cursor operations do not conflict.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc2);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLAllocHandle(hdbc2) Failed\n\n");
      Cleanup();
      return(9);
   }

   // Sample uses Integrated Security, create SQL Server DSN using Windows NT authentication. 
   retcode = SQLConnect(hdbc2, (UCHAR*)"AdventureWorks", SQL_NTS, (UCHAR*)"", SQL_NTS, (UCHAR*)"", SQL_NTS);
   if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
      printf("SQLConnect() Failed\n\n");
      Cleanup();
      return(9);
   }

   // Allocate ODBC statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt2);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLAllocHandle(hstmt2) Failed\n\n");
      Cleanup();
      return(9);
   }

SQLLEN lDataLengthA;
SQLLEN lDataLengthB;

   // Bind the SELECT statement to the same program variables bound to the bulk copy operation.
   retcode = SQLBindCol(hstmt2, 1, SQL_C_SLONG, &ColaInst.Cola, 0, &lDataLengthA);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLBindCol(hstmt2) Failed\n\n");
      Cleanup();
      return(9);
   }

   retcode = SQLBindCol(hstmt2, 2, SQL_C_CHAR, &ColbInst.szColb, 11, &lDataLengthB);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
      printf("SQLBindCol(hstmt2) Failed\n\n");
      Cleanup();
      return(9);
   }

   // Execute SELECT statement to build a cursor containing data to be bulk copied to new table.
   retcode = SQLExecDirect(hstmt2, (UCHAR*)"SELECT * FROM BCPSource", SQL_NTS);
   if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
      printf("SQLExecDirect Failed\n\n");
      Cleanup();
      return(9);
   }
   // Go into a loop fetching rows from the cursor until each row is fetched. Because the 
   // bcp_bind calls and SQLBindCol calls each reference the same variables, each fetch fills 
   // the variables used by bcp_sendrow, so all you have to do to send the data to SQL Server is 
   // to call bcp_sendrow.
   while ( (retcode = SQLFetch(hstmt2) ) != SQL_NO_DATA) {
      if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
         printf("SQLFetch Failed\n\n");
         Cleanup();
         return(9);
      }

      ColaInst.cbCola = (int)lDataLengthA;
      ColbInst.cbColb = (int)lDataLengthB;

     if ( (SendRet = bcp_sendrow(hdbc1) ) != SUCCEED ) {
         printf("bcp_sendrow(hdbc1) Failed\n\n");
         Cleanup();
         return(9);
      }
   }

   // Signal the end of the bulk copy operation.
   cRowsDone = bcp_done(hdbc1);
   if ( (cRowsDone == -1) ) {
      printf("bcp_done(hdbc1) Failed\n\n");
      Cleanup();
      return(9);
   }

   printf("Number of rows bulk copied after last bcp_batch call = %d.\n", cRowsDone);

   // Cleanup.
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt2);
   SQLDisconnect(hdbc1);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
   SQLDisconnect(hdbc2);
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc2);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);

use AdventureWorks
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'BCPSource')
     DROP TABLE BCPSource
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'BCPTarget')
     DROP TABLE BCPTarget
GO

Vedere anche

Concetti

Copia bulk da variabili di programma

Altre risorse

Procedure per l'esecuzione di una copia bulk con il driver ODBC di SQL Server (ODBC)