In ODBC, SQLExecute() returns SQL_NEED_DATA - c++

SQLExecute() can be successfully executed without parameters, but with parameters it returns SQL_NEED_DATA. SQLPrepare() and SQLBindParameter() execute successfully.
ret = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);
SQLSetStmtAttr(hStmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)3, 0);
SQLCHAR* SQLToExe3 = (SQLCHAR*) "INSERT INTO student VALUES(?,?,?)" ;
ret = SQLPrepare(hStmt, SQLToExe3, SQL_NTS);
Test(ret);
SQLCHAR SNOInput[SNO_Len]="2030211892", SNameInput[SName_Len]="zhangxun", SDepartInput[SDepart_Len]="CS";
SQLLEN SNOLen,SNameLen2,SDepartLen2;
ret = SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 20, 0, SNOInput, SNO_Len, &SNOLen);
ret = SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 20, 0, SNameInput, SName_Len, &SNameLen2);
ret = SQLBindParameter(hStmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 20, 0, SDepartInput, SNO_Len, &SDepartLen2);
ret = SQLExecute(hStmt);// SQLExecute return SQL_INVALID_HANDLE

SOLVED: Set the value of parameter StrLen_or_IndPtr of SQLBindParameter() to SQL_NTS

Related

Calling an MS SQL Stored Procedure in C++

I'm writing an application that connects to a stored procedure on an MS SQL (2012) Server. The procedure is for inserting data to the database. I'm having real trouble understanding how to define the connection to the stored procedure, bind variables to the parameters and associating those parameters with the variables in the stored procedure. I've spent a few days wading through MSDN reading the APIs and trying to follow examples on here, but there seem to be so many ways of doing this that I can't see the 'wood for the trees'. I think I have the basic structure in place, but I'm falling down on the detail.
Below is the code I have so far. I've omitted the database connection code for simplicity. The function is part of a class 'rigDatabase' which has private members for the various SQL handles.
The main issue I'm having is with the calls to SQLSetDescField. Based on the documentation and examples provided by Microsoft, these calls should work, but instead return HY092 - "Invalid attribute/option identifier". This is what I need help with. Recently I tried logging the output from the ODBC Driver manager to see if that shed any light on the matter. The output to one of the calls to SQLSetDescField can be seen below the Stored Procedure definition.
NB: I haven't yet tried the simpler method of embedding the SQL in the C. I'm trying to interface with existing infrastructure (the Stored Proc).
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 Stored Procedure
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 Partial Trace Log:
NB: SQLSetDescField is #defined to 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)
The issue was the use of wide strings. SQLSetDescField #defines to SQLSetDescFieldW, but the string literal was not marked as being a wide string. I was missing the 'L' before the string definietion. A sample of the correct code is below.
retcode = SQLSetDescField(hIpd, 1, SQL_DESC_NAME, L"#filename", SQL_NTS);
Interesting to note that I tried using demo code from MSDN, which is based on wide strings, but their own code featured this error. Very frustrating when you're trying to learn, but perhaps they're being like the old meccano kits - putting in deliberate errors. I certainly won't be forgetting this lesson!

SQLBindParam: setting Null value fails (ODBC)

I am trying to bind an NULL-Value to a parameter in a sql query but I always get an error HY009 Invalid argument value when I execute the statement. That strange behavior only appears when I build in release mode. In debug mode it's working fine. Any ideas?
My Code:
SQLRETURN nRet = SQLPrepare(m_hStmt, (SQLTCHAR *)strSQL, SQL_NTS); // returns SQL_SUCCESS
SQLINTEGER cbNumeric = SQL_NULL_DATA;
nRet = SQLBindParameter(m_hStmt,
parameterIndex,
SQL_PARAM_INPUT,
SQL_C_CHAR,
SQL_LONGVARCHAR,
0,
NULL,
NULL,
0,
&cbNumeric); // returns SQL_SUCCESS
nRet = SQLExecute(m_hStmt); // returns SQL_NEED_DATA
nRet = _SQLParamDataPutData(nRet); // returns Debug: SQL_SUCCESS, Release: SQL_ERROR
If I understand the documentation at https://msdn.microsoft.com/en-us/library/ms710963%28v=vs.85%29.aspx correctly, you are not allowed to pass a NULL-pointer as ParameterValuePtr argument - even if the value is a NULL-Value.
From the comments section in the doc, about the error HY009:
(DM) The argument ParameterValuePtr was a null pointer, the argument
StrLen_or_IndPtr was a null pointer, and the argument InputOutputType
was not SQL_PARAM_OUTPUT.
Does it work if you change your code to something like this:
SQLRETURN nRet = SQLPrepare(m_hStmt, (SQLTCHAR *)strSQL, SQL_NTS);
SQLCHAR dummy[1];
dummy[0] = '\0';
SQLINTEGER cbNumeric = SQL_NULL_DATA;
nRet = SQLBindParameter(m_hStmt,
parameterIndex,
SQL_PARAM_INPUT,
SQL_C_CHAR,
SQL_LONGVARCHAR,
0,
NULL,
dummy,
SQL_NTS,
&cbNumeric); // returns SQL_SUCCESS
nRet = SQLExecute(m_hStmt); // returns SQL_NEED_DATA
nRet = _SQLParamDataPutData(nRet);

SQL Server - Calling Stored Procedures using C++ ODBC

I'm trying to call a stored procedure to insert data into a table and return a value. I'm getting a return code 99 which says SQL_NEED_DATA. I'm using Visual Studio 2008 and SQL Server Native Client 11 driver.
Code extract:
rc=SQL_SUCCESS;
SQLINTEGER exID;
SQLINTEGER cdexFolderName = SQL_NTS;
SQLINTEGER cbexRootPath = SQL_NTS;
SQL_DATE_STRUCT dsOrderDate ;
SQLINTEGER cbOrderDate = 0;
rc=SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
if(rc==SQL_SUCCESS)
rc=SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3, 0);
if(rc==SQL_SUCCESS)
rc=SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hConn);
rc = SQLDriverConnect (hConn, NULL, (SQLCHAR*) "DSN=TWPDEV;Trusted_Connection=yes;",
SQL_NTS, retconstring, 1024, NULL,SQL_DRIVER_NOPROMPT);
rc = SQLAllocHandle(SQL_HANDLE_STMT, hConn, &hStmt);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_DBC, hConn);
rc = SQLBindParameter(hStmt, 1, SQL_PARAM_OUTPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, &exID, 0, &cbexID);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_LONGVARCHAR, sizeof(dsOrderDate), 0, &dsOrderDate, 0, &cbOrderDate);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_LONGVARCHAR, 50, 0, (SQLPOINTER) ExtractionFolderName.c_str(), ExtractionFolderName.length(), &cdexFolderName);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_LONGVARCHAR, 50, 0, (SQLPOINTER) ExtractionRootPath.c_str(), ExtractionRootPath.length(), &cbexRootPath);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 5, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, (SQLPOINTER) &NoOfItemsExtracted, 0, &cbnumItemsExtracted);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 6, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, (SQLPOINTER) &Status, 0, &cbstatus);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 7, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, (SQLPOINTER) &instanceID, 0, NULL);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 8, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, (SQLPOINTER) &sourceID, 0,NULL);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLBindParameter(hStmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, (SQLPOINTER) &migrationSts, 0, &cbmigStatus);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLPrepare (hStmt, (SQLCHAR*) "{? = call dbo.procInsertExtraction(?,?,?,?,?,?,?,?)}", SQL_NTS);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
rc = SQLExecute(hStmt);
if (!(rc==0 || rc==1))
show_error(SQL_HANDLE_STMT, hStmt);
All the statements until SQL Execute are returning rc=0. I'm tried connecting to db and executed a simple SQL statement to insert data, it was successful. But failing in case of running a procedure.
Please help me in resolving this.
I believe that this could be happening because of your second parameter binding:
rc = SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_LONGVARCHAR, sizeof(dsOrderDate), 0, &dsOrderDate, 0, &cbOrderDate);
To understand this better, I suggest looking at the ODBC Help guide from the Microsoft Data Access SDK, but basically, this particular line of code appears to be meeting the conditions required for specifying that you plan on sending the data for this parameter via SQLPutData() calls.
The key components in this instance are that the parameterType argument is SQL_LONGVARCHAR and the code is specifying a pointer to a value of (0).
If you are not intending to send the parameter data via SQLPutData() calls, try setting cbOrderDate=SQL_NTS; at the top of your code instead of setting it to a value of (0).
Tony Hall

MSSQL server Stored procedure not returning output parameters when called from c++

I have a stored procedure which when i call from MSSQL Server GUI.It returns the results correctly.But when i call the same procedure from my C++ code it Executes correctly but doesn't give the output parameter results.
I tried the stored procedure simply returning the output without it doing anything else it succeeded but the stored procedure given below fails.I think there is something wrong happening while the execution of stored procedure.
Heres my stored procedure:
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'putFileinFTandJT' AND type = 'P')
DROP PROCEDURE putFileinFTandJT
GO
CREATE PROCEDURE putFileinFTandJT
/* Put incoming file in File Table & Job Table */
/* IN */ #input varchar(max),
/* IN */ #flName varchar(max),
/* IN */ #uid INT,
/* IN */ #jbid INT,
/* OUT */#t INT OUTPUT,
/* OUT */#t1 INT OUTPUT
AS
DECLARE #orgFileID INT = -1;
DECLARE #temp1 INT;
DECLARE #newFileID INT;
DECLARE #versionCnt INT = 0;
/* SET autocommit = 0; */
EXEC getDirId #input,#temp1 OUTPUT ;
if #temp1 = -1
EXEC putDir #uid,#input,#temp1 OUTPUT;
select #orgFileID = FileID from FileTable where DirID=#temp1 and FileName=#flName and VersionNumber = 0;
IF #orgFileID = -1
BEGIN
set #orgFileID = 0;
insert into FileTable(FileName,DirID,IsDirectory,UserID,VersionNumber,isduplicate) values(#flName,#temp1,0,#uid,0,0);
END
ELSE
BEGIN
select #versionCnt = count(*) from VersionTable where FileID = #orgFileID;
insert into FileTable(FileName,DirID,IsDirectory,UserID,VersionNumber,isduplicate) values(#flName,#temp1,0,#uid,#versionCnt + 1,0);
SET #versionCnt = #versionCnt + 1;
END
select #newFileID = FileID from FileTable where FileName = #flName and DirID = #temp1 and VersionNumber = #versionCnt;
insert into JobTable values(#jbid,#newFileID);
commit;
set #t = #newFileID;
set #t1 = #orgFileID;
GO
//Editing
Here is the cpp code
HWND desktopHandle = GetDesktopWindow();
SQLCHAR buff[255]={0};
int intval1=0,intval2=0,intval3 = 0,intval4,intval5;
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 = SQLDriverConnect(hdbc, desktopHandle, (SQLWCHAR*) L"Driver={SQL Server};Server=WIN-E9EO4VT0V8I;Database=connector;UID=sa;PWD=spsoft_123;Trusted_Connection=False;", SQL_NTS, NULL, 0, NULL, 0);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLPrepare(hstmt, (SQLWCHAR*)L"{call putFileinFTandJT(?,?,?,?,?,?,?)}" , SQL_NTS);
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 100, 0, szQuote, 0, &cbValue2);
retcode = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 50, 0, szQuote2, 0, &cbValue2);
retcode = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &iuser , 0, &cbValue5);
retcode = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG , SQL_INTEGER, 0, 0, &ibackup , 0, &cbValue5);
retcode = SQLBindParameter(hstmt, 5, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &intval1, 0, &cbValue6);
retcode = SQLBindParameter(hstmt, 6, SQL_PARAM_OUTPUT, SQL_C_SLONG , SQL_INTEGER, 0, 0, &intval2, 0, &cbValue7);
retcode = SQLBindParameter(hstmt, 7, SQL_PARAM_OUTPUT, SQL_C_SLONG , SQL_INTEGER, 0, 0, &intval3, 0, &cbValue8);
retcode = SQLExecute(hstmt);
if(retcode==SQL_ERROR)
{
SQLWCHAR sqlstate[1024];
SQLWCHAR message[1024];
if(SQL_SUCCESS == SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sqlstate, NULL, message, 1024, NULL))
std::cout<<"Message: "<<(wchar_t*)message<<"\nSQLSTATE: "<<sqlstate<<std::endl;
}
Please help as i am not getting any ideas.
Thanks
Are there additional result counts being returned in your results? I'm not sure exactly which API you're using, but to get output parameters from SP calls in my experience has often meant walking through the results returned skipping over result counts for the final RPC result. (You might also try putting set nocount on in the SP).

Can ColumnSize argument of ODBC SQLBindParameter be strlen(param) + 1 for SQLCHAR type parameter?

The example for SQLBindParameter function at http://msdn.microsoft.com/en-us/library/ms710963(v=vs.85).aspx passes the size of the character array as the ColumnSize argument (6th argument) when the C type is SQL_C_CHAR.
Quoting parts of the examples from that page:
SQLCHAR szEmployeeID[EMPLOYEE_ID_LEN];
SQL_DATE_STRUCT dsOrderDate;
SQLINTEGER cbCustID = 0, cbOrderDate = 0, cbEmployeeID = SQL_NTS;
...
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, EMPLOYEE_ID_LEN,
0, szEmployeeID, 0, &cbEmployeeID);
I want to know if it is okay to pass the length of the string parameter plus 1 as the ColumnSize argument. In other words, I want to know if the following call is okay if we assume that szEmployeeID contains a null-terminated string.
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, strlen(szEmployeeID) + 1,
0, szEmployeeID, 0, &cbEmployeeID);
I believe this can be very useful in calls like these:
SQLLEN nts = SQL_NTS;
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, 6,
0, "hello", 0, &nts);
char *domain = "stackoverflow.com";
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, strlen(domain) + 1,
0, domain, 0, &nts);
The answer to this question is "Yes".