Función SQLBulkOperations

Conformidad
Versión introducida: Cumplimiento de estándares ODBC 3.0: ODBC

Resumen
SQLBulkOperations realiza inserciones masivas y operaciones masivas de marcadores, incluidas las operaciones de actualización, eliminación y captura por marcador.

Sintaxis

  
SQLRETURN SQLBulkOperations(  
     SQLHSTMT       StatementHandle,  
     SQLUSMALLINT   Operation);  

Argumentos

StatementHandle
[Entrada] Identificador de instrucción.

operación
[Entrada] Operación que se va a realizar:

SQL_ADD SQL_UPDATE_BY_BOOKMARK SQL_DELETE_BY_BOOKMARK SQL_FETCH_BY_BOOKMARK

Para obtener más información, vea "Comentarios".

Devoluciones

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_STILL_EXECUTING, SQL_ERROR o SQL_INVALID_HANDLE.

Diagnóstico

Cuando SQLBulkOperations devuelve SQL_ERROR o SQL_SUCCESS_WITH_INFO, se puede obtener un valor SQLSTATE asociado mediante una llamada a SQLGetDiagRec con un HandleType de SQL_HANDLE_STMT y un identificador de StatementHandle. En la tabla siguiente se enumeran los valores SQLSTATE devueltos normalmente por SQLBulkOperations y se explica cada uno en el contexto de esta función; la notación "(DM)" precede a las descripciones de SQLSTATEs devueltas por el Administrador de controladores. El código de retorno asociado a cada valor SQLSTATE es SQL_ERROR, a menos que se indique lo contrario.

Para todos esos SQLSTATEs que pueden devolver SQL_SUCCESS_WITH_INFO o SQL_ERROR (excepto 01xxx SQLSTATEs), se devuelve SQL_SUCCESS_WITH_INFO si se produce un error en una o varias filas de una operación de varias filas, pero no todas, y SQL_ERROR se devuelve si se produce un error en una operación de fila única.

SQLSTATE Error Descripción
01000 Advertencia general Mensaje informativo específico del controlador. (Function devuelve SQL_SUCCESS_WITH_INFO).
01004 Truncamiento derecho de datos de cadena El argumento Operation se SQL_FETCH_BY_BOOKMARK, y los datos binarios o de cadena devueltos para una columna o columnas con un tipo de datos de SQL_C_CHAR o SQL_C_BINARY provocaron el truncamiento de datos binarios no de caracteres no vacíos o no NULL.
01S01 Error en la fila El argumento Operation se SQL_ADD y se produjo un error en una o varias filas al realizar la operación, pero al menos una fila se agregó correctamente. (Function devuelve SQL_SUCCESS_WITH_INFO).

(Este error solo se produce cuando una aplicación está trabajando con ODBC 2. controlador x ).
01S07 Truncamiento fraccionado El argumento Operation se SQL_FETCH_BY_BOOKMARK, el tipo de datos del búfer de aplicación no se SQL_C_CHAR o SQL_C_BINARY, y los datos devueltos a los búferes de aplicación para una o varias columnas se truncaron. (Para los tipos de datos numéricos de C, la parte fraccionarcional del número se ha truncado. Para los tipos de datos time, timestamp e interval C que contienen un componente de hora, se trunca la parte fraccionarcional de la hora).

(Function devuelve SQL_SUCCESS_WITH_INFO).
07006 Infracción de atributo de tipo de datos restringido El argumento Operation se SQL_FETCH_BY_BOOKMARK y el valor de datos de una columna del conjunto de resultados no se pudo convertir en el tipo de datos especificado por el argumento TargetType en la llamada a SQLBindCol.

El argumento Operation se SQL_UPDATE_BY_BOOKMARK o SQL_ADD, y el valor de datos de los búferes de la aplicación no se pudo convertir en el tipo de datos de una columna del conjunto de resultados.
07009 Índice de descriptor no válido El argumento Operation se SQL_ADD y una columna estaba enlazada con un número de columna mayor que el número de columnas del conjunto de resultados.
21S02 El grado de tabla derivada no coincide con la lista de columnas El argumento Operation se SQL_UPDATE_BY_BOOKMARK; y no se puede actualizar ninguna columna porque todas las columnas no estaban enlazadas o de solo lectura, o bien el valor del búfer de longitud o indicador enlazado se SQL_COLUMN_IGNORE.
22001 Truncamiento derecho de datos de cadena La asignación de un carácter o valor binario a una columna del conjunto de resultados dio como resultado el truncamiento de caracteres no vacíos (para caracteres) o caracteres o bytes no NULL (para binarios).
22003 Valor numérico fuera del intervalo El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK, y la asignación de un valor numérico a una columna del conjunto de resultados provocó que toda la parte (en lugar de fraccionar) del número se truncase.

El argumento Operation se SQL_FETCH_BY_BOOKMARK y devolver el valor numérico de una o varias columnas enlazadas habría provocado una pérdida de dígitos significativos.
22007 Formato datetime no válido El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK, y la asignación de un valor de fecha o marca de tiempo a una columna del conjunto de resultados hizo que el campo year, month o day estuviera fuera del intervalo.

El argumento Operation se SQL_FETCH_BY_BOOKMARK y devolver el valor de fecha o marca de tiempo de una o varias columnas enlazadas habría provocado que el campo year, month o day estuviera fuera del intervalo.
22008 Desbordamiento de campo de fecha y hora El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK, y el rendimiento de la aritmética datetime en los datos que se envían a una columna del conjunto de resultados dio como resultado un campo datetime (el año, mes, día, hora, minuto o segundo) del resultado que se encuentra fuera del intervalo permitido de valores para el campo o que no es válido en función de las reglas naturales del calendario gregoriano para datetimes.

El argumento Operation se SQL_FETCH_BY_BOOKMARK y el rendimiento de la aritmética datetime en los datos que se recuperan del conjunto de resultados dio lugar a un campo datetime (el campo year, month, day, hour, minute o second) del resultado que se encuentra fuera del intervalo permitido de valores para el campo o que no es válido en función de las reglas naturales del calendario gregoriano para datetimes.
22015 Desbordamiento de campo de intervalo El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK, y la asignación de un tipo numérico o interval C exacto a un tipo de datos SQL interval causó una pérdida de dígitos significativos.

El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK; al asignar a un tipo SQL de intervalo, no había ninguna representación del valor del tipo C en el tipo SQL interval.

El argumento Operation se SQL_FETCH_BY_BOOKMARK y la asignación de un tipo SQL numérico o de intervalo exacto a un tipo C de intervalo causó una pérdida de dígitos significativos en el campo inicial.

El argumento Operation fue SQL_FETCH_BY_BOOKMARK; al asignar a un tipo de intervalo C, no había ninguna representación del valor del tipo SQL en el tipo C del intervalo C.
22018 Valor de carácter no válido para la especificación de conversión El argumento Operation fue SQL_FETCH_BY_BOOKMARK; el tipo C era un numérico exacto o aproximado, una fecha y hora o un tipo de datos interval; el tipo SQL de la columna era un tipo de datos de caracteres; y el valor de la columna no era un literal válido del tipo C enlazado.

El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK; el tipo SQL era un numérico exacto o aproximado, una fecha y hora o un tipo de datos interval; el tipo C se SQL_C_CHAR; y el valor de la columna no era un literal válido del tipo SQL enlazado.
23000 Infracción de restricción de integridad El argumento Operation se SQL_ADD, SQL_DELETE_BY_BOOKMARK o SQL_UPDATE_BY_BOOKMARK, y se infringió una restricción de integridad.

El argumento Operation se SQL_ADD y una columna que no estaba enlazada se define como NOT NULL y no tiene ningún valor predeterminado.

El argumento Operation se SQL_ADD, la longitud especificada en el búfer de StrLen_or_IndPtr enlazado se SQL_COLUMN_IGNORE y la columna no tenía un valor predeterminado.
24000 Estado de cursor no válido StatementHandle estaba en un estado ejecutado, pero ningún conjunto de resultados estaba asociado a StatementHandle.
40001 Error de serialización La transacción se revierte debido a un interbloqueo de recursos con otra transacción.
40003 Finalización de instrucciones desconocida Error en la conexión asociada durante la ejecución de esta función y no se puede determinar el estado de la transacción.
42000 Error de sintaxis o infracción de acceso El controlador no pudo bloquear la fila según sea necesario para realizar la operación solicitada en el argumento Operation .
44000 Infracción de WITH CHECK OPTION El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK, y la inserción o actualización se realizó en una tabla vista (o una tabla derivada de la tabla vista) que se creó especificando WITH CHECK OPTION, de forma que una o varias filas afectadas por la inserción o actualización ya no estarán presentes en la tabla vista.
HY000 Error general Se produjo un error para el que no había ningún SQLSTATE específico y para el que no se definió SQLSTATE específico de la implementación. El mensaje de error devuelto por SQLGetDiagRec en el búfer *MessageText describe el error y su causa.
HY001 Error de asignación de memoria El controlador no pudo asignar memoria necesaria para admitir la ejecución o finalización de la función.
HY008 Operación cancelada El procesamiento asincrónico se ha habilitado para StatementHandle. Se llamó a la función y antes de completar la ejecución, se llamó a SQLCancel o SQLCancelHandle en statementHandle. A continuación, se llamó a la función de nuevo en StatementHandle.

Se llamó a la función y antes de completar la ejecución, se llamó a SQLCancel o SQLCancelHandle en statementHandle desde un subproceso diferente en una aplicación multiproceso.
HY010 Error de secuencia de función (DM) Se llamó a una función de ejecución asincrónica para el identificador de conexión asociado a StatementHandle. Esta función asincrónica todavía se estaba ejecutando cuando se llamó a la función SQLBulkOperations .

(DM) SE llamó a SQLExecute, SQLExecDirect o SQLMoreResults para la instrucciónHandle y devolvió SQL_PARAM_DATA_AVAILABLE. Se llamó a esta función antes de recuperar los datos para todos los parámetros transmitidos.

(DM) La InstrucciónHandle especificada no estaba en estado ejecutado. Se llamó a la función sin llamar primero a SQLExecDirect, SQLExecute o una función de catálogo.

(DM) Se llamó a una función de ejecución asincrónica (no esta) para statementHandle y todavía se estaba ejecutando cuando se llamó a esta función.

(DM) SE llamó a SQLExecute, SQLExecDirect o SQLSetPos para la instrucciónHandle y devolvió SQL_NEED_DATA. Se llamó a esta función antes de enviar datos para todos los parámetros o columnas de datos en ejecución.

(DM) El controlador era un ODBC 2. Se llamó al controlador x y SQLBulkOperations para un StatementHandle antes de llamar a SQLFetchScroll o SQLFetch .

(DM) SE llamó a SQLBulkOperations después de llamar a SQLExtendedFetch en statementHandle.
HY011 El atributo no se puede establecer ahora (DM) El controlador era un ODBC 2. x driver y el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR se estableció entre llamadas a SQLFetch o SQLFetchScroll y SQLBulkOperations.
HY013 Error de administración de memoria No se pudo procesar la llamada de función porque no se pudo acceder a los objetos de memoria subyacentes, posiblemente debido a condiciones de memoria baja.
HY090 Longitud de búfer o cadena no válida El argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK; un valor de datos no era un puntero nulo; el tipo de datos C se SQL_C_BINARY o SQL_C_CHAR; y el valor de longitud de columna era menor que 0, pero no igual a SQL_DATA_AT_EXEC, SQL_COLUMN_IGNORE, SQL_NTS o SQL_NULL_DATA, o menor o igual que SQL_LEN_DATA_AT_EXEC_OFFSET.

El valor de un búfer de longitud/indicador se SQL_DATA_AT_EXEC; el tipo SQL era SQL_LONGVARCHAR, SQL_LONGVARBINARY o un tipo de datos largo específico del origen de datos; y el tipo de información SQL_NEED_LONG_DATA_LEN en SQLGetInfo era "Y".

El argumento Operation se SQL_ADD, el atributo de instrucción SQL_ATTR_USE_BOOKMARK se estableció en SQL_UB_VARIABLE y la columna 0 estaba enlazada a un búfer cuya longitud no era igual a la longitud máxima del marcador para este conjunto de resultados. (Esta longitud está disponible en el campo SQL_DESC_OCTET_LENGTH del IRD y se puede obtener llamando a SQLDescribeCol, SQLColAttribute o SQLGetDescField).
HY092 Identificador de atributo no válido (DM) El valor especificado para el argumento Operation no era válido.

El argumento Operation se SQL_ADD, SQL_UPDATE_BY_BOOKMARK o SQL_DELETE_BY_BOOKMARK, y el atributo de instrucción SQL_ATTR_CONCURRENCY se estableció en SQL_CONCUR_READ_ONLY.

El argumento Operation se SQL_DELETE_BY_BOOKMARK, SQL_FETCH_BY_BOOKMARK o SQL_UPDATE_BY_BOOKMARK, y la columna bookmark no estaba enlazada o el atributo de instrucción SQL_ATTR_USE_BOOKMARKS se estableció en SQL_UB_OFF.
HY117 La conexión se suspende debido a un estado de transacción desconocido. Solo se permiten funciones de desconexión y de solo lectura. (DM) Para obtener más información sobre el estado suspendido, vea Función SQLEndTran.
HYC00 Característica opcional no implementada El controlador o el origen de datos no admiten la operación solicitada en el argumento Operation .
HYT00 Tiempo de espera agotado El período de tiempo de espera de la consulta expiró antes de que el origen de datos devolva el conjunto de resultados. El período de tiempo de espera se establece a través de SQLSetStmtAttr con un argumento Attribute de SQL_ATTR_QUERY_TIMEOUT.
HYT01 Se ha agotado el tiempo de espera de la conexión. El período de tiempo de espera de conexión expiró antes de que el origen de datos respondiera a la solicitud. El período de tiempo de espera de conexión se establece a través de SQLSetConnectAttr, SQL_ATTR_CONNECTION_TIMEOUT.
IM001 El controlador no admite esta función (DM) El controlador asociado a StatementHandle no admite la función .
IM017 El sondeo está deshabilitado en modo de notificación asincrónica Cada vez que se usa el modelo de notificación, el sondeo está deshabilitado.
IM018 No se ha llamado a SQLCompleteAsync para completar la operación asincrónica anterior en este identificador. Si la llamada de función anterior en el identificador devuelve SQL_STILL_EXECUTING y si el modo de notificación está habilitado, se debe llamar a SQLCompleteAsync en el identificador para realizar el procesamiento posterior y completar la operación.

Comentarios

Precaución

Para obtener información acerca de qué instrucción se puede llamar a SQLBulkOperations en y lo que debe hacer para la compatibilidad con ODBC 2. X aplicaciones, consulte la sección Cursores de bloque, Cursores desplazables y Compatibilidad con versiones anteriores del Apéndice G: Directrices para controladores para la compatibilidad con versiones anteriores.

Una aplicación usa SQLBulkOperations para realizar las siguientes operaciones en la tabla base o vista que corresponde a la consulta actual:

  • Agregue nuevas filas.

  • Actualice un conjunto de filas donde un marcador identifica cada fila.

  • Elimine un conjunto de filas donde un marcador identifica cada fila.

  • Capturar un conjunto de filas donde un marcador identifica cada fila.

Después de una llamada a SQLBulkOperations, la posición del cursor de bloque no está definida. La aplicación tiene que llamar a SQLFetchScroll para establecer la posición del cursor. Una aplicación solo debe llamar a SQLFetchScroll con un argumento FetchOrientation de SQL_FETCH_FIRST, SQL_FETCH_LAST, SQL_FETCH_ABSOLUTE o SQL_FETCH_BOOKMARK. La posición del cursor no está definida si la aplicación llama a SQLFetch o SQLFetchScroll con un argumento FetchOrientation de SQL_FETCH_PRIOR, SQL_FETCH_NEXT o SQL_FETCH_RELATIVE.

Una columna se puede omitir en operaciones masivas realizadas por una llamada a SQLBulkOperations estableciendo el búfer de longitud o indicador de columna especificado en la llamada a SQLBindCol, en SQL_COLUMN_IGNORE.

No es necesario que la aplicación establezca el atributo de instrucción SQL_ATTR_ROW_OPERATION_PTR cuando llama a SQLBulkOperations porque las filas no se pueden omitir al realizar operaciones masivas con esta función.

El búfer al que apunta el atributo de instrucción SQL_ATTR_ROWS_FETCHED_PTR contiene el número de filas afectadas por una llamada a SQLBulkOperations.

Cuando el argumento Operation se SQL_ADD o SQL_UPDATE_BY_BOOKMARK y la lista de selección de la especificación de consulta asociada al cursor contiene más de una referencia a la misma columna, se define si se genera un error o el controlador o el controlador omite las referencias duplicadas y realiza las operaciones solicitadas.

Para obtener más información sobre cómo usar SQLBulkOperations, vea Actualizar datos con SQLBulkOperations.

Realización de inserciones masivas

Para insertar datos con SQLBulkOperations, una aplicación realiza la siguiente secuencia de pasos:

  1. Ejecuta una consulta que devuelve un conjunto de resultados.

  2. Establece el atributo de instrucción SQL_ATTR_ROW_ARRAY_SIZE en el número de filas que desea insertar.

  3. Llama a SQLBindCol para enlazar los datos que desea insertar. Los datos se enlazan a una matriz con un tamaño igual al valor de SQL_ATTR_ROW_ARRAY_SIZE.

    Nota

    El tamaño de la matriz a la que apunta el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR debe ser igual a SQL_ATTR_ROW_ARRAY_SIZE o SQL_ATTR_ROW_STATUS_PTR debe ser un puntero nulo.

  4. Llama a SQLBulkOperations(StatementHandle, SQL_ADD) para realizar la inserción.

  5. Si la aplicación ha establecido el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR, puede inspeccionar esta matriz para ver el resultado de la operación.

Si una aplicación enlaza la columna 0 antes de llamar a SQLBulkOperations con un argumento Operation de SQL_ADD, el controlador actualizará los búferes de la columna enlazada 0 con los valores de marcador para la fila recién insertada. Para que esto ocurra, la aplicación debe haber establecido el atributo de instrucción SQL_ATTR_USE_BOOKMARKS en SQL_UB_VARIABLE antes de ejecutar la instrucción. (Esto no funciona con ODBC 2. controlador x ).

SqlBulkOperations puede agregar datos largos en partes mediante llamadas a SQLParamData y SQLPutData. Para obtener más información, vea "Proporcionar datos largos para inserciones masivas y Novedades" más adelante en esta referencia de función.

No es necesario que la aplicación llame a SQLFetch o SQLFetchScroll antes de llamar a SQLBulkOperations (excepto cuando se contrae a ODBC 2. x driver; consulte Compatibilidad con versiones anteriores y cumplimiento de estándares).

El comportamiento se define por el controlador si SQLBulkOperations, con un argumento Operation de SQL_ADD, se llama a en un cursor que contiene columnas duplicadas. El controlador puede devolver un SQLSTATE definido por el controlador, agregar los datos a la primera columna que aparece en el conjunto de resultados o realizar otro comportamiento definido por el controlador.

Realizar Novedades masiva mediante marcadores

Para realizar actualizaciones masivas mediante marcadores con SQLBulkOperations, una aplicación realiza los pasos siguientes en secuencia:

  1. Establece el atributo de instrucción SQL_ATTR_USE_BOOKMARKS en SQL_UB_VARIABLE.

  2. Ejecuta una consulta que devuelve un conjunto de resultados.

  3. Establece el atributo de instrucción SQL_ATTR_ROW_ARRAY_SIZE en el número de filas que desea actualizar.

  4. Llama a SQLBindCol para enlazar los datos que desea actualizar. Los datos se enlazan a una matriz con un tamaño igual al valor de SQL_ATTR_ROW_ARRAY_SIZE. También llama a SQLBindCol para enlazar la columna 0 (la columna de marcador).

  5. Copia los marcadores de las filas que le interesan actualizar a la matriz enlazada a la columna 0.

  6. Novedades los datos de los búferes enlazados.

    Nota

    El tamaño de la matriz a la que apunta el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR debe ser igual a SQL_ATTR_ROW_ARRAY_SIZE o SQL_ATTR_ROW_STATUS_PTR debe ser un puntero nulo.

  7. Llama a SQLBulkOperations(StatementHandle, SQL_UPDATE_BY_BOOKMARK).

    Nota

    Si la aplicación ha establecido el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR, puede inspeccionar esta matriz para ver el resultado de la operación.

  8. Opcionalmente, llama a SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK) para capturar datos en los búferes de aplicación enlazados para comprobar que se ha producido la actualización.

  9. Si se han actualizado los datos, el controlador cambia el valor de la matriz de estado de fila para las filas adecuadas a SQL_ROW_UPDATED.

Las actualizaciones masivas realizadas por SQLBulkOperations pueden incluir datos largos mediante llamadas a SQLParamData y SQLPutData. Para obtener más información, vea "Proporcionar datos largos para inserciones masivas y Novedades" más adelante en esta referencia de función.

Si los marcadores se conservan entre cursores, la aplicación no necesita llamar a SQLFetch o SQLFetchScroll antes de actualizar por marcadores. Puede usar marcadores almacenados desde un cursor anterior. Si los marcadores no se conservan entre cursores, la aplicación debe llamar a SQLFetch o SQLFetchScroll para recuperar los marcadores.

El comportamiento es definido por el controlador si SQLBulkOperations, con un argumento Operation de SQL_UPDATE_BY_BOOKMARK, se llama a en un cursor que contiene columnas duplicadas. El controlador puede devolver un SQLSTATE definido por el controlador, actualizar la primera columna que aparece en el conjunto de resultados o realizar otro comportamiento definido por el controlador.

Realización de capturas masivas mediante marcadores

Para realizar capturas masivas mediante marcadores con SQLBulkOperations, una aplicación realiza los pasos siguientes en secuencia:

  1. Establece el atributo de instrucción SQL_ATTR_USE_BOOKMARKS en SQL_UB_VARIABLE.

  2. Ejecuta una consulta que devuelve un conjunto de resultados.

  3. Establece el atributo de instrucción SQL_ATTR_ROW_ARRAY_SIZE en el número de filas que desea capturar.

  4. Llama a SQLBindCol para enlazar los datos que desea capturar. Los datos se enlazan a una matriz con un tamaño igual al valor de SQL_ATTR_ROW_ARRAY_SIZE. También llama a SQLBindCol para enlazar la columna 0 (la columna de marcador).

  5. Copia los marcadores de las filas que está interesado en capturar en la matriz enlazada a la columna 0. (Se supone que la aplicación ya ha obtenido los marcadores por separado).

    Nota

    El tamaño de la matriz a la que apunta el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR debe ser igual a SQL_ATTR_ROW_ARRAY_SIZE o SQL_ATTR_ROW_STATUS_PTR debe ser un puntero nulo.

  6. Llama a SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK).

  7. Si la aplicación ha establecido el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR, puede inspeccionar esta matriz para ver el resultado de la operación.

Si los marcadores se conservan entre cursores, la aplicación no necesita llamar a SQLFetch o SQLFetchScroll antes de capturar por marcadores. Puede usar marcadores almacenados desde un cursor anterior. Si los marcadores no se conservan entre cursores, la aplicación debe llamar a SQLFetch o SQLFetchScroll una vez para recuperar los marcadores.

Realización de eliminaciones masivas mediante marcadores

Para realizar eliminaciones masivas mediante marcadores con SQLBulkOperations, una aplicación realiza los pasos siguientes en secuencia:

  1. Establece el atributo de instrucción SQL_ATTR_USE_BOOKMARKS en SQL_UB_VARIABLE.

  2. Ejecuta una consulta que devuelve un conjunto de resultados.

  3. Establece el atributo de instrucción SQL_ATTR_ROW_ARRAY_SIZE en el número de filas que desea eliminar.

  4. Llama a SQLBindCol para enlazar la columna 0 (la columna de marcador).

  5. Copia los marcadores de las filas que está interesado en eliminar en la matriz enlazada a la columna 0.

    Nota

    El tamaño de la matriz a la que apunta el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR debe ser igual a SQL_ATTR_ROW_ARRAY_SIZE o SQL_ATTR_ROW_STATUS_PTR debe ser un puntero nulo.

  6. Llama a SQLBulkOperations(StatementHandle, SQL_DELETE_BY_BOOKMARK).

  7. Si la aplicación ha establecido el atributo de instrucción SQL_ATTR_ROW_STATUS_PTR, puede inspeccionar esta matriz para ver el resultado de la operación.

Si los marcadores se conservan entre cursores, la aplicación no tiene que llamar a SQLFetch o SQLFetchScroll antes de eliminar por marcadores. Puede usar marcadores almacenados desde un cursor anterior. Si los marcadores no se conservan entre cursores, la aplicación debe llamar a SQLFetch o SQLFetchScroll una vez para recuperar los marcadores.

Proporcionar datos largos para inserciones masivas y Novedades

Se pueden proporcionar datos largos para inserciones masivas y actualizaciones realizadas por llamadas a SQLBulkOperations. Para insertar o actualizar datos largos, una aplicación realiza los pasos siguientes además de los pasos descritos en las secciones "Realizar inserciones masivas" y "Realizar Novedades masivas mediante marcadores" anteriormente en este tema.

  1. Cuando enlaza los datos mediante SQLBindCol, la aplicación coloca un valor definido por la aplicación, como el número de columna, en el búfer *TargetValuePtr para las columnas de datos en ejecución. El valor se puede usar más adelante para identificar la columna.

    La aplicación coloca el resultado de la macro SQL_LEN_DATA_AT_EXEC(length) en el búfer *StrLen_or_IndPtr . Si el tipo de datos SQL de la columna es SQL_LONGVARBINARY, SQL_LONGVARCHAR o un tipo de datos específico del origen de datos largo y el controlador devuelve "Y" para el tipo de información de SQL_NEED_LONG_DATA_LEN en SQLGetInfo, la longitud es el número de bytes de datos que se enviarán para el parámetro; de lo contrario, debe ser un valor no negativo y se omite.

  2. Cuando se llama a SQLBulkOperations , si hay columnas de datos en ejecución, la función devuelve SQL_NEED_DATA y continúa con el paso 3, que sigue. (Si no hay columnas de datos en ejecución, el proceso se ha completado).

  3. La aplicación llama a SQLParamData para recuperar la dirección del búfer *TargetValuePtr para que se procese la primera columna de datos en ejecución. SQLParamData devuelve SQL_NEED_DATA. La aplicación recupera el valor definido por la aplicación del búfer *TargetValuePtr .

    Nota

    Aunque los parámetros de datos en ejecución son similares a las columnas de datos en ejecución, el valor devuelto por SQLParamData es diferente para cada una.

    Las columnas de datos en ejecución son columnas de un conjunto de filas para el que se enviarán datos con SQLPutData cuando se actualice o inserte una fila con SQLBulkOperations. Se enlazan con SQLBindCol. El valor devuelto por SQLParamData es la dirección de la fila en el búfer *TargetValuePtr que se está procesando.

  4. La aplicación llama a SQLPutData una o varias veces para enviar datos para la columna. Se necesita más de una llamada si no se puede devolver todo el valor de datos en el búfer *TargetValuePtr especificado en SQLPutData; solo se permiten varias llamadas a SQLPutData para la misma columna cuando se envían datos de caracteres C a una columna con un tipo de datos específico del origen de datos, binario o de caracteres, o al enviar datos binarios de C a una columna con un tipo de datos específico de origen de datos, binarios o caracteres.

  5. La aplicación llama a SQLParamData de nuevo para indicar que todos los datos se han enviado para la columna.

    • Si hay más columnas de datos en ejecución, SQLParamData devuelve SQL_NEED_DATA y la dirección del búfer TargetValuePtr para la siguiente columna de datos en ejecución que se va a procesar. La aplicación repite los pasos 4 y 5.

    • Si no hay más columnas de datos en ejecución, el proceso se completa. Si la instrucción se ejecutó correctamente, SQLParamData devuelve SQL_SUCCESS o SQL_SUCCESS_WITH_INFO; si se produjo un error en la ejecución, devuelve SQL_ERROR. En este momento, SQLParamData puede devolver cualquier SQLSTATE que SQLBulkOperations pueda devolver.

Si se cancela la operación o se produce un error en SQLParamData o SQLPutData después de que SQLBulkOperations devuelva SQL_NEED_DATA y antes de que se envíen datos para todas las columnas de datos en ejecución, la aplicación solo puede llamar a SQLCancel, SQLGetDiagField, SQLGetDiagRec, SQLGetFunctions, SQLParamData o SQLPutData para la instrucción o la conexión asociada a la instrucción . Si llama a cualquier otra función para la instrucción o la conexión asociada a la instrucción , la función devuelve SQL_ERROR y SQLSTATE HY010 (error de secuencia de función).

Si la aplicación llama a SQLCancel mientras el controlador sigue necesitando datos para las columnas de datos en ejecución, el controlador cancela la operación. A continuación, la aplicación puede llamar a SQLBulkOperations de nuevo; la cancelación no afecta al estado del cursor ni a la posición actual del cursor.

Matriz de Estados de fila

La matriz de estado de fila contiene valores de estado para cada fila de datos del conjunto de filas después de una llamada a SQLBulkOperations. El controlador establece los valores de estado de esta matriz después de una llamada a SQLFetch, SQLFetchScroll, SQLSetPos o SQLBulkOperations. Esta matriz se rellena inicialmente mediante una llamada a SQLBulkOperations si no se ha llamado a SQLFetch o SQLFetchScroll antes de SQLBulkOperations. El atributo de instrucción SQL_ATTR_ROW_STATUS_PTR apunta a esta matriz. El número de elementos de las matrices de estado de fila debe ser igual al número de filas del conjunto de filas (según lo definido por el atributo de instrucción SQL_ATTR_ROW_ARRAY_SIZE). Para obtener información sobre esta matriz de estado de fila, vea SQLFetch.

Ejemplo de código

En el ejemplo siguiente se capturan 10 filas de datos a la vez de la tabla Customers. A continuación, solicita al usuario que realice una acción. Para reducir el tráfico de red, el búfer de ejemplo actualiza, elimina e inserta localmente en las matrices enlazadas, pero en desplazamientos pasados los datos del conjunto de filas. Cuando el usuario elige enviar actualizaciones, eliminaciones e inserciones en el origen de datos, el código establece el desplazamiento de enlace correctamente y llama a SQLBulkOperations. Para simplificar, el usuario no puede almacenar en búfer más de 10 actualizaciones, eliminaciones o inserciones.

// SQLBulkOperations_Function.cpp  
// compile with: ODBC32.lib  
#include <windows.h>  
#include <sqlext.h>  
#include "stdio.h"  
  
#define UPDATE_ROW 100  
#define DELETE_ROW 101  
#define ADD_ROW 102  
#define SEND_TO_DATA_SOURCE 103  
#define UPDATE_OFFSET 10  
#define INSERT_OFFSET 20  
#define DELETE_OFFSET 30  
  
// Define structure for customer data (assume 10 byte maximum bookmark size).  
typedef struct tagCustStruct {  
   SQLCHAR Bookmark[10];  
   SQLINTEGER BookmarkLen;  
   SQLUINTEGER CustomerID;  
   SQLINTEGER CustIDInd;  
   SQLCHAR CompanyName[51];  
   SQLINTEGER NameLenOrInd;  
   SQLCHAR Address[51];  
   SQLINTEGER AddressLenOrInd;  
   SQLCHAR Phone[11];  
   SQLINTEGER PhoneLenOrInd;  
} CustStruct;  
  
// Allocate 40 of these structures. Elements 0-9 are for the current rowset,  
// elements 10-19 are for the buffered updates, elements 20-29 are for  
// the buffered inserts, and elements 30-39 are for the buffered deletes.  
CustStruct CustArray[40];  
SQLUSMALLINT RowStatusArray[10], Action, RowNum, NumUpdates = 0, NumInserts = 0,  
NumDeletes = 0;  
SQLLEN BindOffset = 0;  
SQLRETURN retcode;  
SQLHENV henv = NULL;  
SQLHDBC hdbc = NULL;  
SQLHSTMT hstmt = NULL;  
  
int main() {  
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);   
  
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);   
   retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  
   retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);  
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);  
  
   // Set the following statement attributes:  
   // SQL_ATTR_CURSOR_TYPE:           Keyset-driven  
   // SQL_ATTR_ROW_BIND_TYPE:         Row-wise  
   // SQL_ATTR_ROW_ARRAY_SIZE:        10  
   // SQL_ATTR_USE_BOOKMARKS:         Use variable-length bookmarks  
   // SQL_ATTR_ROW_STATUS_PTR:        Points to RowStatusArray  
   // SQL_ATTR_ROW_BIND_OFFSET_PTR:   Points to BindOffset  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(CustStruct), 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, (SQLPOINTER)SQL_UB_VARIABLE, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, &BindOffset, 0);  
  
   // Bind arrays to the bookmark, CustomerID, CompanyName, Address, and Phone columns.  
   retcode = SQLBindCol(hstmt, 0, SQL_C_VARBOOKMARK, CustArray[0].Bookmark, sizeof(CustArray[0].Bookmark), &CustArray[0].BookmarkLen);  
   retcode = SQLBindCol(hstmt, 1, SQL_C_ULONG, &CustArray[0].CustomerID, 0, &CustArray[0].CustIDInd);  
   retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, CustArray[0].CompanyName, sizeof(CustArray[0].CompanyName), &CustArray[0].NameLenOrInd);  
   retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, CustArray[0].Address, sizeof(CustArray[0].Address), &CustArray[0].AddressLenOrInd);  
   retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, CustArray[0].Phone, sizeof(CustArray[0].Phone), &CustArray[0].PhoneLenOrInd);  
  
   // Execute a statement to retrieve rows from the Customers table.  
   retcode = SQLExecDirect(hstmt, (SQLCHAR*)"SELECT CustomerID, CompanyName, Address, Phone FROM Customers", SQL_NTS);  
  
   // Fetch and display the first 10 rows.  
   retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);  
   // DisplayCustData(CustArray, 10);  
  
   // Call GetAction to get an action and a row number from the user.  
   // while (GetAction(&Action, &RowNum)) {  
   Action = SQL_FETCH_NEXT;  
   RowNum = 2;  
   switch (Action) {  
      case SQL_FETCH_NEXT:  
      case SQL_FETCH_PRIOR:  
      case SQL_FETCH_FIRST:  
      case SQL_FETCH_LAST:  
      case SQL_FETCH_ABSOLUTE:  
      case SQL_FETCH_RELATIVE:  
         // Fetch and display the requested data.  
         SQLFetchScroll(hstmt, Action, RowNum);  
         // DisplayCustData(CustArray, 10);  
         break;  
  
      case UPDATE_ROW:  
         // Check if we have reached the maximum number of buffered updates.  
         if (NumUpdates < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered updates section of CustArray, copy the bookmark of the row  
            // being updated to the same element, and increment the update counter.  
            // Checking to see we have not already buffered an update for this  
            // row not shown.  
            // GetNewCustData(CustArray, UPDATE_OFFSET + NumUpdates);  
            memcpy(CustArray[UPDATE_OFFSET + NumUpdates].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
            CustArray[UPDATE_OFFSET + NumUpdates].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
            NumUpdates++;  
         } else {  
            printf("Buffers full. Send buffered changes to the data source.");  
         }  
         break;  
      case DELETE_ROW:  
         // Check if we have reached the maximum number of buffered deletes.  
         if (NumDeletes < 10) {  
            // Copy the bookmark of the row being deleted to the next available element  
            // of the buffered deletes section of CustArray and increment the delete  
            // counter. Checking to see we have not already buffered an update for  
            // this row not shown.  
            memcpy(CustArray[DELETE_OFFSET + NumDeletes].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
  
            CustArray[DELETE_OFFSET + NumDeletes].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
  
            NumDeletes++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case ADD_ROW:  
         // reached maximum number of buffered inserts?  
         if (NumInserts < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered inserts section of CustArray and increment insert counter.  
            // GetNewCustData(CustArray, INSERT_OFFSET + NumInserts);  
            NumInserts++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case SEND_TO_DATA_SOURCE:  
         // If there are any buffered updates, inserts, or deletes, set the array size  
         // to that number, set the binding offset to use the data in the buffered  
         // update, insert, or delete part of CustArray, and call SQLBulkOperations to  
         // do the updates, inserts, or deletes. Because we will never have more than  
         // 10 updates, inserts, or deletes, we can use the same row status array.  
         if (NumUpdates) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumUpdates, 0);  
            BindOffset = UPDATE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_UPDATE_BY_BOOKMARK);  
            NumUpdates = 0;  
         }  
  
         if (NumInserts) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumInserts, 0);  
            BindOffset = INSERT_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_ADD);  
            NumInserts = 0;  
         }  
  
         if (NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumDeletes, 0);  
            BindOffset = DELETE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_DELETE_BY_BOOKMARK);  
            NumDeletes = 0;  
         }  
  
         // If there were any updates, inserts, or deletes, reset the binding offset  
         // and array size to their original values.  
         if (NumUpdates || NumInserts || NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
            BindOffset = 0;  
         }  
         break;  
   }  
   // }  
  
   // Close the cursor.  
   SQLFreeStmt(hstmt, SQL_CLOSE);  
}  
Para información acerca de Vea
Enlace de un búfer a una columna de un conjunto de resultados SQLBindCol (función)
Cancelación del procesamiento de instrucciones Función SQLCancel
Capturar un bloque de datos o desplazarse por un conjunto de resultados Función SQLFetchScroll
Obtención de un único campo de un descriptor Función SQLGetDescField
Obtención de varios campos de un descriptor Función SQLGetDescRec
Establecer un único campo de un descriptor Función SQLSetDescField
Establecimiento de varios campos de un descriptor Función SQLSetDescRec
Colocación del cursor, actualización de datos en el conjunto de filas o actualización o eliminación de datos en el conjunto de filas Función SQLSetPos
Establecimiento de un atributo de instrucción Función SQLSetStmtAttr

Consulte también

Referencia de API ODBC
Archivos de encabezado de ODBC