Вызов хранимой процедуры MS SQL в C ++ - PullRequest
0 голосов
/ 16 октября 2018

Я пишу приложение, которое подключается к хранимой процедуре на сервере MS SQL (2012).Процедура для вставки данных в базу данных.У меня возникают реальные проблемы с пониманием того, как определить соединение с хранимой процедурой, связать переменные с параметрами и связать эти параметры с переменными в хранимой процедуре.Я провел несколько дней, разбираясь в MSDN, читая API-интерфейсы и пытаясь следовать приведенным здесь примерам, но, похоже, способов сделать это так много, что я не вижу «дрова для деревьев».Я думаю, что у меня есть базовая структура на месте, но я падаю на детали.

Ниже приведен код, который у меня есть.Я опустил код подключения к базе данных для простоты.Функция является частью класса rigDatabase, который имеет закрытые члены для различных дескрипторов SQL.

Основная проблема, с которой я сталкиваюсь, связана с вызовами SQLSetDescField.На основании документации и примеров, предоставленных Microsoft, эти вызовы должны работать, но вместо этого возвращать HY092 - «Неверный идентификатор атрибута / опции».Это то, что мне нужно помочь.Недавно я попытался зарегистрировать вывод из диспетчера драйверов ODBC, чтобы увидеть, пролил ли он на это какой-то свет.Вывод одного из вызовов SQLSetDescField можно увидеть под определением хранимой процедуры.

Примечание: я еще не пробовал более простой метод встраивания SQL в C. Я пытаюсь взаимодействовать ссуществующая инфраструктура (сохраненный процесс).

SQLRETURN rigDatabase::send_SQL(const char* filename, 
                                const char* extn, 
                                const char* path, 
                                DWORD& fSize, 
                                const char* rigName, 
                                FILETIME& created,
                                const char* notes) {
    SQLHDESC hIpd = NULL;
    SQLINTEGER    PartIDInd = 0;

SQL_TIMESTAMP_STRUCT datetime2;
    datetime2.year = fileDate.wYear;
    datetime2.month = fileDate.wMonth;
    datetime2.day = fileDate.wDay;
    datetime2.hour = fileDate.wHour;
    datetime2.minute = fileDate.wMinute;
    datetime2.second = fileDate.wSecond;
    datetime2.fraction = fileDate.wMilliseconds;

    retcode = SQLPrepareA(sqlStmtHandle, (SQLCHAR*)"{call insertTestRigDataTest(?, ?, ?, ?, ?, ?, ?)}", SQL_NTS);

    retcode = SQLBindParameter(sqlStmtHandle, 1, SQL_PARAM_INPUT, SQL_C_CHAR,           SQL_CHAR,           FILENAME_MAX,   0, (SQLPOINTER)filename,    0, NULL);
    retcode = SQLBindParameter(sqlStmtHandle, 2, SQL_PARAM_INPUT, SQL_C_CHAR,           SQL_CHAR,           MAX_PATH,       0, (SQLPOINTER)path,        0, NULL);
    retcode = SQLBindParameter(sqlStmtHandle, 3, SQL_PARAM_INPUT, SQL_C_CHAR,           SQL_CHAR,           BUF_SIZE,       0, (SQLPOINTER)rigName,     0, NULL);
    retcode = SQLBindParameter(sqlStmtHandle, 4, SQL_PARAM_INPUT, SQL_C_ULONG,          SQL_INTEGER,        0,              0, (SQLPOINTER)fSize,       0, &PartIDInd);
    retcode = SQLBindParameter(sqlStmtHandle, 5, SQL_PARAM_INPUT, SQL_C_CHAR,           SQL_CHAR,           4,              0, (SQLPOINTER)extn,        0, NULL);

    retcode = SQLBindParameter(sqlStmtHandle, 6, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, sizeof(SQL_TIMESTAMP_STRUCT), 0, &datetime2, 0, NULL);
    retcode = SQLBindParameter(sqlStmtHandle, 7, SQL_PARAM_INPUT, SQL_C_CHAR,           SQL_CHAR,           4000,       0, (SQLPOINTER)notes,       0, NULL);

    retcode = SQLGetStmtAttrA(sqlStmtHandle, SQL_ATTR_IMP_PARAM_DESC, &hIpd, 0, 0);

    // All calls to SQLSetDescField below return -1
            //  SQLGetDiagRecA returns "Invalid attribute/option identifier"
    retcode = SQLSetDescField(hIpd, 1, SQL_DESC_NAME, "@Filename", SQL_NTS);
    retcode = SQLSetDescField(hIpd, 2, SQL_DESC_NAME, "@Path", SQL_NTS);
    retcode = SQLSetDescField(hIpd, 3, SQL_DESC_NAME, "@Rigname", SQL_NTS);
    retcode = SQLSetDescField(hIpd, 4, SQL_DESC_NAME, "@Size", SQL_NTS);
    retcode = SQLSetDescField(hIpd, 5, SQL_DESC_NAME, "@Extn", SQL_NTS);
    retcode = SQLSetDescField(hIpd, 6, SQL_DESC_NAME, "@Created", SQL_NTS);
    retcode = SQLSetDescField(hIpd, 7, SQL_DESC_NAME, "@Notes", SQL_NTS);

    retcode = SQLExecute(sqlStmtHandle);    

    return EXIT_FAILURE;
}

// Function to convert from FILETIME to int64
unsigned __int64 FILETIME_to_int64( const FILETIME& ac_FileTime ) {
    ULARGE_INTEGER    lv_Large;

    lv_Large.LowPart = ac_FileTime.dwLowDateTime;
    lv_Large.HighPart = ac_FileTime.dwHighDateTime;

    return lv_Large.QuadPart;
}

хранимая процедура MS SQL

USE [TestRigDataTest]
GO
/****** Object:  StoredProcedure [dbo].[insertTestRigDataTest]    Script Date: 16/10/2018 10:14:34 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[insertTestRigDataTest] 
(
    @fileName   nvarchar(255),
    @path       nvarchar(255),
    @rigName    nvarchar(255),
    @size       [numeric](18, 0),
    @extn       nvarchar(255),
    @created    [datetime],
    @notes      nvarchar(4000) = NULL
)
AS
BEGIN

    SET NOCOUNT ON;

    declare @id int
    declare @tmpNotes nvarchar(4000)

    set @tmpNotes=''

    select @id=id,@tmpNotes=notes from [TestRigDataTest].[dbo].[RigData]
        where
            [Filename]=@filename and
            [Path]=@Path and
            [Size]=@Size and
            [Extension]=@Extn and
            [created]=@created

    if @@rowcount=0
        begin
            INSERT INTO [TestRigDataTest].[dbo].[RigData] (
                   [Filename], [Path], [Rigname] ,[UploadDate] ,[Size] ,[Extension]  ,[created]  ,[notes]
                   )
                VALUES (
                   @fileName, @path, @rigName, getdate(), @size, @extn, @created, @notes
                   )
        end
    else
        begin
            if @notes != ''
                begin
                    update [TestRigDataTest].[dbo].[RigData] set [notes]=@tmpNotes  + CHAR(13)+CHAR(10) + @notes
                    where id=@id
            end
        end
END

ODBC Driver Manager Журнал частичной трассировки: NB: SQLSetDescField #определен для SQLSetDescFieldW

AirCatFeeder    26f0-1e50   ENTER SQLSetDescFieldW 
    SQLHDESC            0x00000000004CB9E8
    SQLSMALLINT                  2 
    SQLSMALLINT               1011 <SQL_DESC_NAME>
    SQLPOINTER          0x000000013FBA15EC [      -3] "??h\ 0"
    SQLINTEGER                  -3 

AirCatFeeder    26f0-1e50   ENTER SQLSetDescField 
    SQLHDESC            0x00000000004CB9E8
    SQLSMALLINT                  2 
    SQLSMALLINT               1011 <SQL_DESC_NAME>
    SQLPOINTER          0x000000013FBA15EC [      -3] "@Path\ 0"
    SQLINTEGER                  -3 

AirCatFeeder    26f0-1e50   EXIT  SQLSetDescField  with return code -1 (SQL_ERROR)
    SQLHDESC            0x00000000004CB9E8
    SQLSMALLINT                  2 
    SQLSMALLINT               1011 <SQL_DESC_NAME>
    SQLPOINTER          0x000000013FBA15EC [      -3] "@Path\ 0"
    SQLINTEGER                  -3 

    DIAG [HY092] [Microsoft][ODBC SQL Server Driver]Invalid attribute/option identifier (0) 

AirCatFeeder    26f0-1e50   EXIT  SQLSetDescFieldW  with return code -1 (SQL_ERROR)
    SQLHDESC            0x00000000004CB9E8
    SQLSMALLINT                  2 
    SQLSMALLINT               1011 <SQL_DESC_NAME>
    SQLPOINTER          0x000000013FBA15EC [      -3] "??h\ 0"
    SQLINTEGER                  -3 

    DIAG [HY092] [Microsoft][ODBC SQL Server Driver]Invalid attribute/option identifier (0) 

1 Ответ

0 голосов
/ 24 октября 2018

Проблема заключалась в использовании широких строк.SQLSetDescField # определяет SQLSetDescFieldW, но строковый литерал не был помечен как широкая строка.Я пропустил букву «L» до определения строки.Ниже приведен пример правильного кода.

retcode = SQLSetDescField(hIpd, 1, SQL_DESC_NAME, L"@filename", SQL_NTS);

Интересно отметить, что я пытался использовать демонстрационный код из MSDN, который основан на широких строках, но в их собственном коде была эта ошибка.Очень расстраивает, когда вы пытаетесь учиться, но, возможно, они похожи на старые наборы для конструктора - вносят преднамеренные ошибки.Я, конечно, не забуду этот урок!

...