Я пишу приложение, которое подключается к хранимой процедуре на сервере 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)