I am trying to use SQLConnect() to connect sqlserver with C++:
retcode = SQLConnect(hdbc, (UCHAR*)"My server name",
strlen((const char*)"My server name"),(UCHAR*)"My ID",
strlen((const char*)"My ID"),(UCHAR*)"My PW",
strlen((const char*)"My PW"));
but it always return -1 to "retcode". Is there anything wrong with the format of my server name? And how could I set the initial catalog of it?
Syntax of SQLConnect is as below
SQLRETURN SQLConnect(
SQLHDBC ConnectionHandle,
SQLCHAR * ServerName,
SQLSMALLINT NameLength1,
SQLCHAR * UserName,
SQLSMALLINT NameLength2,
SQLCHAR * Authentication,
SQLSMALLINT NameLength3);
eg:
retcode= SQLConnect(hdbc, (SQLCHAR*) "servername", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);
change the example according to your requirement and check
More information msdn
Related
I am trying to read a large object from a PostgreSQL database using ODBC from Visual Studio C++. I can't get it to work.
The driver is PostgresSQL ANSI(x64) 9.50.04.00.
The data type of the column is lo, created with:
CREATE DOMAIN lo AS oid;
The column contains the object ids of the large objects.
My understanding is that when the driver sees a lo type, it will handle it as SQL_LONGVARBINARY.
However, the query fails. The diagnostics message is:
HY003 [Microsoft][OBDC Driver Manager] Program type out of range
Here is the code with the noise removed:
wchar_t* connect0 = L"DSN=picdb;";
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT stmt;
SQLLEN sqllen = -1;
PBYTE image = new BYTE[0];
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
SQLDriverConnect(dbc, NULL, connect0, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
SQLExecDirect(stmt, L"select lo from image_list where id=964945", SQL_NTS);
SQLFetch(stmt);
SQLGetData(stmt, 1, SQL_LONGVARBINARY, image, 0, &sqllen); //<----- It fails here
image = new BYTE[sqllen];
SQLGetData(stmt, 1, SQL_LONGVARBINARY, image, sqllen, &sqllen);
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
I can read regular data from the database just fine. And I can read the BLOB data from the database with Java/JDBC, but I need it to work in C++.
Why do I get the error, and what can I do to fix it?
This seems to work:
wchar_t* connect0 = L"DSN=picdb;";
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT stmt;
SQLLEN sqllen = -1;
PBYTE image = new BYTE[0];
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
SQLDriverConnect(dbc, NULL, connect0, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
SQLExecDirect(stmt, L"select lo from image_list where id=964945", SQL_NTS);
SQLFetch(stmt);
SQLGetData(stmt, 1, SQL_C_BINARY, image, 0, &sqllen);
image = new BYTE[sqllen];
SQLBindParameter(stmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, image, sqllen, NULL );
SQLGetData(stmt, 1, SQL_C_BINARY, image, sqllen, &sqllen);
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
I would like to create Table Valued Parameter in MSSQL Server using ODBC and c++. Such a SQL Code works fine in SQL Server:
DECLARE #T1 as TABLE
(
PK INT IDENTITY NOT NULL,
Wert CHAR(20),
Name CHAR(20)
)
INSERT INTO #T1(Wert,Name) VALUES ('123','Babio')
INSERT INTO #T1(Wert,Name) VALUES ('214','Martin')
INSERT INTO #T1(Wert,Name) VALUES ('236','Karo')
select * FROM #T1 where Wert=123
I have written this block of code in c++ to send this SQL Code to SQL Server using ODBC:
int main()
{
SQLHENV henv=SQL_NULL_HENV;
SQLHDBC hdbc=SQL_NULL_HDBC;
SQLHSTMT hstmt=SQL_NULL_HSTMT;
SQLRETURN rc;
SQLCHAR Statement[] = "DECLARE #T1 as TABLE (PK INT IDENTITY NOT NULL, Wert CHAR(20), Name CHAR(20)) INSERT INTO #T1(Wert,Name) VALUES ('123','Babak') INSERT INTO #T1(Wert,Name) VALUES ('214','Martin') INSERT INTO #T1(Wert,Name) VALUES ('236','Karo') select Name FROM #T1 Where Wert=123" ;
SQLWCHAR dsn[30] = L"mssqltest"; //Name DNS
SQLWCHAR user[10] = L"di_test";
SQLWCHAR pass[10] = L"di_test";
SQLCHAR retValFName[256];
SQLCHAR retValLName[256];
SQLINTEGER cbLName,cbFName;
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
rc= SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(void *) SQL_OV_ODBC3,0);
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
rc = SQLConnectW(hdbc, (SQLWCHAR *)dsn, SQL_NTS, (SQLWCHAR *) user, SQL_NTS, (SQLWCHAR *) pass, SQL_NTS);
rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);
rc = SQLPrepareA(hstmt, (SQLCHAR *)Statement, SQL_NTS);
rc = SQLExecute(hstmt);
if(rc==SQL_SUCCESS)
{
while(true)
{
rc=SQLFetch(hstmt); // In this line rc=-1
if(rc==SQL_SUCCESS || rc==SQL_SUCCESS_WITH_INFO)
{
SQLGetData(hstmt,1,SQL_C_CHAR,retValFName,256, &cbLName);
std::cout << retValFName <<" "<< std::endl;
system("pause");
}
else
{
break;
}
}
}
return 0;
}
If I check the error, I see this error which says:
Invalid Cursor state
How could be my code changes to run this code to create and make a query on Table Valued Parameter in SQL?
I am trying to run following stored procedure using ODBC:
CREATE PROCEDURE [dbo].[Add]
--WITH ENCRYPTION
AS
DECLARE #LoopVar BIGINT = 0
, #MaxVar BIGINT = 0
, #rows BIGINT = 0
SET #LoopVar = 1
set #rows = 125000
insert into debug values(987654321)
insert into debug values(#LoopVar)
insert into debug values(#rows)
WHILE(#LoopVar <= #rows)
BEGIN
SET #LoopVar = #LoopVar + 1
WAITFOR DELAY '00:00:01'
insert into debug values(#LoopVar)
END
insert into debug values(123456789)
GO
The C++ code for running the stored procedure is:
RETCODE rc = SQL_SUCCESS;
HENV henv = SQL_NULL_HENV;
HDBC hdbc = SQL_NULL_HDBC;
SQLHSTMT hstmt = SQL_NULL_HSTMT;
SQLTCHAR * pszConnection = _T("DRIVER={SQL Server Native Client 10.0};Server=myserver;Trusted_Connection=Yes;Initial Catalog=testdb;");
SQLTCHAR * pszInsertStmt = _T("{call [testdb].[dbo].Add}");
SQLLEN cbParamLength;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HENV, &henv);
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
SQLSetConnectAttr( hdbc, SQL_ATTR_LOGIN_TIMEOUT, reinterpret_cast<SQLPOINTER>(600), SQL_IS_UINTEGER);
SQLDriverConnect( hdbc, NULL, pszConnection, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
SQLSetStmtAttr(hstmt, SQL_QUERY_TIMEOUT, (SQLPOINTER)12000, SQL_IS_UINTEGER);
SQLSetStmtAttr(hstmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)12000, SQL_IS_UINTEGER);
SQLINTEGER attr;
rc = SQLGetStmtAttr( hstmt, SQL_ATTR_QUERY_TIMEOUT, &attr, 0, NULL ) ;
rc = SQLGetStmtAttr( hstmt, SQL_QUERY_TIMEOUT, &attr, 0, NULL ) ;
rc = SQLGetConnectAttr(hdbc, SQL_ATTR_CONNECTION_TIMEOUT, &attr, 0, NULL);
rc = SQLExecDirect(hstmt, pszInsertStmt, SQL_NTS);
if (!SUCCESS(rc)) {
if (hstmt)
PrintError(SQL_HANDLE_STMT, hstmt);
if (hdbc)
PrintError(SQL_HANDLE_DBC, hdbc);
if(henv)
PrintError(SQL_HANDLE_ENV, henv);
}
if (hstmt)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if (hdbc) {
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
if (henv)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
I have set query time in the code above. The connection time out is 0 (which I believe means no timeout). But no matter what I do, the stored procedure times out in 78 seconds. Does any one have any idea as to what I should do so that stored procedure can run indefinitely?
Please note if I run the stored procedure from SQL Server Management Studio directly, it works just fine..
Thanks in advance,
-Neel.
If anyone interested, the solution was to put "SET NOCOUNT ON" as the first line in stored procedure.
The rc return -1 but i can't get any error message and status after calling SQLGetDiagRec
SQLRETURN rc;
SQLHENV henv1 = NULL;
SQLHDBC hdbc1= NULL;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv1);
SQLSetEnvAttr(henv1,SQL_ATTR_ODBC_VERSION,(void*)SQL_OV_ODBC3,0);
rc =SQLAllocHandle(SQL_HANDLE_DBC, henv1, &hdbc1);
char szDSN[256] = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};DSN=data;DBQ=D:\\data\\data.accdb;";
char out[256];
int iConnStrLength2Ptr;
rc = SQLDriverConnect(hdbc1, NULL, (SQLWCHAR*)&szDSN, SQL_NTS, (SQLWCHAR*)&out,255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
SQLWCHAR SQLState[256];
SQLINTEGER NativeErrorPtr;
SQLWCHAR MessageText[256];
SQLSMALLINT TextLengthPtr = 255;
SQLGetDiagRec(SQL_HANDLE_ENV,henv1,1,(SQLWCHAR*)SQLState,&NativeErrorPtr,(SQLWCHAR*)MessageText,255,&TextLengthPtr);
You are not really showing the error testing part of the code. After SQLDriverConnect you should check !SQL_SUCCEEDED(rc). The call to SQLGetDiagRec is on the environment handle but the error occurred on a connection handle so you probably want to change your call to SQLGetDiagRec.
We create and cache ODBC connections created using SQLDriverConnect; we've found circumstances where the connection becomes lost... prepared statements stop working, etc.
I didn't see an obvious function to test a connection/statement is valid, or to reset/re-create a connection, which seems like it would be a fairly common pattern. Can anyone suggest how this is best implemented?
This answer is along the same lines, is that the correct solution here too? If so is there any neat way to 're-boot' an existing statement to use the new connection? And if a connection is discovered to be dead does it still need to be freed?
In my mind there has always been some confusion over whether SQL_ATTR_CONNECTION_DEAD works to test if a connection is still alive before you make a call which requires it to be alive. This is based on the usage of many ODBC drivers, including the ones I wrote and I suspect they may all implement it differently.
In the post you refer to Nick's answer (SQL_ATTR_CONNECTION_DEAD) does not work with many drivers I have access to:
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
#include <stdlib.h>
static void extract_error(
char *fn,
SQLHANDLE handle,
SQLSMALLINT type);
main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLCHAR outstr[1024];
SQLSMALLINT outstr_len;
SQLRETURN ret;
SQLINTEGER dead;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
ret = SQLDriverConnect(hdbc, (void *)0, "DSN=xx;UID=xx;PWD=xx", SQL_NTS,
outstr, sizeof(outstr), &outstr_len,
SQL_DRIVER_COMPLETE);
if (!SQL_SUCCEEDED(ret)) {
extract_error("SQLDriverConnect", hdbc, SQL_HANDLE_DBC);
exit(1);
}
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
ret = SQLPrepare(hstmt, "select 123", SQL_NTS);
if (!SQL_SUCCEEDED(ret)) {
extract_error("SQLPrepare", hstmt, SQL_HANDLE_STMT);
exit(1);
}
ret = SQLExecute(hstmt);
if (!SQL_SUCCEEDED(ret)) {
extract_error("SQLExecute", hstmt, SQL_HANDLE_STMT);
exit(1);
}
sleep(120);
SQLGetConnectAttr(hdbc, SQL_ATTR_CONNECTION_DEAD, &dead, 0, NULL);
printf ("dead=%ld\n", dead);
ret = SQLExecute(hstmt);
if (!SQL_SUCCEEDED(ret)) {
extract_error("SQLExecute", hstmt, SQL_HANDLE_STMT);
}
SQLGetConnectAttr(hdbc, SQL_ATTR_CONNECTION_DEAD, &dead, 0, NULL);
printf ("dead=%ld\n", dead);
}
static void extract_error(
char *fn,
SQLHANDLE handle,
SQLSMALLINT type)
{
SQLINTEGER i = 0, native;
SQLCHAR state[ 7 ];
SQLCHAR text[256];
SQLSMALLINT len;
int ret;
fprintf(stderr,
"\n"
"The driver reported the following diagnostics whilst running "
"%s\n\n",
fn);
do
{
ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
sizeof(text), &len );
if (SQL_SUCCEEDED(ret))
printf( "%s:%ld:%ld:%s\n", state, i, native, text );
}
while( ret == SQL_SUCCESS );
}
which outputs with a number of drivers:
dead=0
# At this point I took the server down
The driver reported the following diagnostics whilst running SQLExecute
08S01:1:0:[SQL Server Driver 10.0][SQL Server]Communication link failure: short write
dead=0
The other option specified in the post you refer to is SQL_COPT_SS_CONNECTION_DEAD but that is specific to MS SQL Server.
Since I presume you don't intend for any statement handles to fail ordinarily can't you just run the stmt and if it fails assume the connection is dead and reconnect and reprepare?
If a connection does die you do still need to call SQLFreeHandle for the various handles.