C++ - Access field in recordset - c++

I am trying to access the field values of recordset. Currently there is a loop to count the recordsets but I don't know how to access specific fields.
rc = SQLDriverConnect(hDbc, NULL, (SQLWCHAR*)L"Driver={Microsoft Access Driver (*.mdb, *.accdb)};DSN='';DBQ=C:\\Temp\\Data.accdb;", SQL_NTS,szConnStrOut, 255, &iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
if (SQL_SUCCEEDED(rc))
{
rc2 = SQLAllocStmt(hDbc, &hStmt);
rc2 = SQLPrepare(hStmt, (SQLWCHAR*)L"SELECT UniqueID FROM ObjectCheck", SQL_NTS);
/* Execute the query and create a record set */
rc2 = SQLExecute(hStmt);
/* Loop through the rows in the result set */
rc2 = SQLFetch(hStmt);
while (SQL_SUCCEEDED(rc2))
{
rc2 = SQLFetch(hStmt);
rowCount++;
//cout << UniqueID;
//rc3 = SQLAllocStmt(hDbc, &hStmt);
//rc3 = SQLPrepare(hStmt, (SQLWCHAR*)L"SELECT * FROM DependsOn WHERE UniqueID = " , SQL_NTS);
};
cout << rowCount;
}
Best regards
Steve

Related

SCOPE_IDENTITY() always return NULL if used with SQLBindParameter

I try to insert a data to database via ODBC sql server.
And I want to get the Id of this row back, so I use SELECT SCOPE_IDENTITY();
Since this table has id as primary key and auto increment.
Insert function works fine, the data get inserted into database.
But when I use SELECT SCOPE_IDENTITY(); They return NULL.
so I try to use pure statement without SQLBindParameter. SELECT SCOPE_IDENTITY(); works perfectly. Do you have any advice why I got the problem when use SQLBindParameter?
Here is my table in dB :
[primary key] (long) Id
(nvarchar(255)) Name
(short) Position
Here is insert function with SQLBindParameter :
std::string name = "testname";
std::wstring ws = L"INSERT INTO [dbo].[Test] ([Name], [Position]) VALUES (?,1);";
RETCODE RetCode = SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_CHAR, name.length(), 0, (SQLPOINTER)name.c_str(), name.length(), NULL);
if(RetCode != SQL_SUCCESS)
{
HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode);
}
RetCode = SQLExecDirect(hStmt, (SQLWCHAR*)ws.c_str(), SQL_NTS);
switch(RetCode)
{
case SQL_SUCCESS:
break;
//other cases
}
SQLFreeStmt(hStmt, SQL_CLOSE);
Here is SELECT SCOPE_IDENTITY() code :
std::wstring ws = L"SELECT SCOPE_IDENTITY();";
RETCODE RetCode = SQLExecDirect(hStmt, (SQLWCHAR*)ws.c_str(), SQL_NTS);
switch (RetCode)
{
case SQL_SUCCESS:
{
long id= -1;
SQLLEN indPtr;
SQLBindCol(hStmt, 1, SQL_C_LONG, &id, 0, &indPtr);
if (SQLFetch(hStmt) == SQL_SUCCESS)
{
if (indPtr != SQL_NULL_DATA)
{
std::cout << "Result id: " << characterId << std::endl;
}
else
{
std::cout << "Result id: NULL " << std::endl;
}
}
break;
}
//other cases
}
SQLFreeStmt(hStmt, SQL_CLOSE);
Here is insert function with out SQLBindParameter :
std::wstring ws = L"INSERT INTO [dbo].[Test] ([Name], [Position]) VALUES ('testname', 1);";
RetCode = SQLExecDirect(hStmt, (SQLWCHAR*)ws.c_str(), SQL_NTS);
switch(RetCode)
{
case SQL_SUCCESS:
break;
//other cases
}
SQLFreeStmt(hStmt, SQL_CLOSE);
The solution for this problem is to use "OUTPUT" clause in order to return member of inserted item instead of calling SELECT SCOPE_IDENTITY();
so the completely sql command is INSERT INTO [dbo].[Test] ([Name], [Position]) OUTPUT INSERTED.[Id] VALUES (?,1);

Is there a way to query .accdb/.mdb files with C++?

I have a school project where I need to develop an application that queries and writes into Access database files, but using C++.
After some research I found about ODBC, and that it could help me, but I had no luck. I've tried differents connection strings, but nothing seems to work.
What I've done so far:
#include "pch.h"
#include <windows.h>
#include <sqlext.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
char szDSN[256] = "Driver={Microsoft Access Driver (*.mdb,
*.accdb)};DBQ=C:\\EntrySystem.mdb";
/* Data Access Method used in this sample */
const char* DAM = "Direct ODBC";
HENV hEnv;
HDBC hDbc;
/* ODBC API return status */
RETCODE rc;
int iConnStrLength2Ptr;
char szConnStrOut[256];
unsigned char query[] = "SELECT * from Condomino;";
SQLCHAR chval1[128], chval2[128], colName[128];
int ret1;
int ret2;
/* Number of rows and columns in result set */
SQLINTEGER rowCount = 0;
SQLSMALLINT fieldCount = 0, currentField = 0;
HSTMT hStmt;
/* Allocate an environment handle */
rc = SQLAllocEnv(&hEnv);
/* Allocate a connection handle */
rc = SQLAllocConnect(hEnv, &hDbc);
/* Connect to the 'Northwind 2007.accdb' database */
rc = SQLDriverConnect(hDbc, NULL, (SQLWCHAR*)szDSN,
SQL_NTS, (SQLWCHAR*)szConnStrOut,
255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
if (SQL_SUCCEEDED(rc))
{
printf("%s: Successfully connected to database. Data source name: \n %s\n",
DAM, szConnStrOut);
/* Prepare SQL query */
printf("%s: SQL query:\n %s\n", DAM, query);
rc = SQLAllocStmt(hDbc, &hStmt);
rc = SQLPrepare(hStmt, (SQLWCHAR*)query, SQL_NTS);
/* Bind result set columns to the local buffers */
rc = SQLBindCol(hStmt, 1, SQL_C_CHAR, chval1, 128, (SQLINTEGER*)&ret1);
rc = SQLBindCol(hStmt, 2, SQL_C_CHAR, chval2, 128, (SQLINTEGER*)&ret2);
/* Excecute the query and create a record set */
rc = SQLExecute(hStmt);
if (SQL_SUCCEEDED(rc))
{
printf("%s: Retrieve schema info for the given result set:\n", DAM);
SQLNumResultCols(hStmt, &fieldCount);
if (fieldCount > 0)
{
for (currentField = 1; currentField <= fieldCount; currentField++)
{
SQLDescribeCol(hStmt, currentField,
(SQLWCHAR*)colName, sizeof(colName), 0, 0, 0, 0, 0);
printf(" | %s", colName);
}
printf("\n");
}
else
{
printf("%s: Error: Number of fields in the result set is 0.\n", DAM);
}
printf("%s: Fetch the actual data:\n", DAM);
/* Loop through the rows in the result set */
rc = SQLFetch(hStmt);
while (SQL_SUCCEEDED(rc))
{
printf(" | %s | %s\n", chval1, chval2);
rc = SQLFetch(hStmt);
rowCount++;
};
printf("%s: Total Row Count: %d\n", DAM, rowCount);
rc = SQLFreeStmt(hStmt, SQL_DROP);
}
}
else
{
printf("%s: Couldn't connect to %s.\nLastError: %d\n", DAM, szDSN, GetLastError());
}
/* Disconnect and free up allocated handles */
SQLDisconnect(hDbc);
SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
printf("%s: Cleanup. Done.\n", DAM);
return 0;
}
I expect it to query all rows from my table "condomino", but the library (sqlext) keep giving me the error "0". Any help would be welcome, if you any other solutions, let me know.
Yes.
Seems like you are having issue with Access connection strings. An alternative is to create User DNS ; go to control panel / administrative tools / ODBC Data Source / choose Microsoft Access Database - configure and set your path to your *.mdb ( use of *.accdb recommended)
Now your connection string will be simplified as ( driver name is case sensitive ):
SQLWCHAR outstr[1024];
SQLSMALLINT outstrlen;
SQLReturnCode = SQLDriverConnect(hDatabase, NULL, L"DSN=Microsoft Access Driver;", SQL_NTS,
outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);

C++ ODBC SQL - Insert into table not working

I have been trying to insert a row into my SQL table, i get no syntax error but unfortunately when i check my table in the SQL Server Management Studio, no new entry is added. When debugging, the retCode becomes less than zero starting from the SQLConnect() function.
int main()
{
SQLHANDLE SQLEnvHandle = NULL;
SQLHANDLE SQLConnectionHandle = NULL;
SQLHANDLE SQLStatementHandle = NULL;
SQLRETURN retCode = 0;
// Insert Query
char SQLQuery[] = "insert into crm.dbo.company_name values (22,'01 electronics','#01electronics.net');";
// SQL Server Identifier
char SQLServer[] = "DRIVER={SQL Server}; SERVER=localhost, 8000; DATABASE=xxxx; UID=xxxx_xxxx; PWD=xxxx;";
do
{
// Allocate environment
retCode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &SQLEnvHandle);
// Set ODBC Version
retCode = SQLSetEnvAttr(SQLEnvHandle, SQL_ATTR_ODBC_VERSION,(SQLPOINTER*)SQL_OV_ODBC3, 0);
// Allocate Connection
retCode = SQLAllocHandle(SQL_HANDLE_DBC, SQLEnvHandle, &SQLConnectionHandle);
// Set Login Timeout
retCode = SQLSetConnectAttr(SQLConnectionHandle, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
// Set Auto Commit
retCode = SQLSetConnectAttr(SQLConnectionHandle, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)TRUE, 0);
// Connect to DSN
retCode = SQLConnect(SQLConnectionHandle, (SQLCHAR*) SQLServer, SQL_NTS, (SQLCHAR*)NULL, 0, NULL, 0);
// Allocate Statement Handle
retCode = SQLAllocHandle(SQL_HANDLE_STMT, SQLConnectionHandle, &SQLStatementHandle);
// Prepare Statement
retCode = SQLPrepare(SQLStatementHandle, (SQLCHAR*)SQLQuery, SQL_NTS);
// Execute Statement
if (SQLExecute(SQLStatementHandle) == SQL_SUCCESS || SQLExecute(SQLStatementHandle) == SQL_SUCCESS_WITH_INFO)
cout << "SUCCESS";
else
cout << "FAILURE";
} while (FALSE);
// Frees the resources and disconnects
SQLFreeHandle(SQL_HANDLE_STMT, SQLStatementHandle);
SQLDisconnect(SQLConnectionHandle);
SQLFreeHandle(SQL_HANDLE_DBC, SQLConnectionHandle);
SQLFreeHandle(SQL_HANDLE_ENV, SQLEnvHandle);
getchar();
}
When debugging, the retCode becomes less than zero starting from the SQLConnect() function.
From the docs:
When SQLConnect returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an
associated SQLSTATE value can be obtained by calling SQLGetDiagRec
with a HandleType of SQL_HANDLE_DBC and a Handle of ConnectionHandle

invalid cursor state while using table valued parameter and ODBC

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?

why doesn't my code work with older access drivers?

// SQLTables.cpp
// compile with: user32.lib odbc32.lib
#include <windows.h>
#include <sqlext.h>
#include <stdio.h>
// simple helper functions
int MySQLSuccess(SQLRETURN rc) {
return (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO);
}
struct DataBinding {
SQLSMALLINT TargetType;
SQLPOINTER TargetValuePtr;
SQLINTEGER BufferLength;
SQLLEN StrLen_or_Ind;
};
void printCatalog(const struct DataBinding* catalogResult, int numCols) {
for(int i = 0; i < numCols; i++)
if (catalogResult[i].StrLen_or_Ind != SQL_NULL_DATA)
printf("Catalog Name(%d) = %s \t", i + 1, (char *)catalogResult[i].TargetValuePtr);
printf("\n");
}
// remember to disconnect and free memory, and free statements and handles
int main() {
int bufferSize = 1024, i, numCols = 18;
struct DataBinding* catalogResult = (struct DataBinding*) malloc( numCols * sizeof(struct DataBinding) );
wchar_t* dbName = (wchar_t *)malloc( sizeof(wchar_t)*bufferSize );
wchar_t* userName = (wchar_t *)malloc( sizeof(wchar_t)*bufferSize );
// declare and initialize the environment, connection, statement handles
SQLHENV henv = NULL; // Environment
SQLHDBC hdbc = NULL; // Connection handle
SQLHSTMT hstmt = NULL; // Statement handle
SQLRETURN retCode;
HWND desktopHandle = GetDesktopWindow(); // desktop's window handle
SQLWCHAR connStrbuffer[1024];
SQLSMALLINT connStrBufferLen;
retCode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retCode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, -6);
retCode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
//retCode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)10, 0);
//retCode = SQLSetConnectAttr(hdbc,fOption,(SQLPOINTER)(size_t)param,0);
//retCode = SQLDriverConnect(hdbc, desktopHandle, (SQLCHAR*)"DSN=footballDB1;UID=\"\";PWD=\"\"", SQL_NTS, (SQLCHAR*)connStrbuffer, 1024 + 1, &connStrBufferLen, SQL_DRIVER_NOPROMPT);
retCode = SQLDriverConnect(hdbc, desktopHandle, (SQLCHAR*)"DSN=footballDB;UID=\"\";PWD=\"\"", SQL_NTS, (SQLCHAR*)connStrbuffer, 1024 + 1, &connStrBufferLen, SQL_DRIVER_NOPROMPT);
retCode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retCode = SQLGetInfo(hdbc, SQL_DBMS_NAME , dbName, (SQLSMALLINT)bufferSize, (SQLSMALLINT *)&bufferSize);
printf("%s\n", dbName);
retCode = SQLGetInfo(hdbc, SQL_USER_NAME, userName, (SQLSMALLINT)bufferSize, (SQLSMALLINT *)&bufferSize);
bufferSize = 1024;
// allocate memory for the binding
// free this memory when done
for ( i = 0 ; i < numCols ; i++ ) {
catalogResult[i].TargetType = SQL_C_CHAR;
catalogResult[i].BufferLength = (bufferSize + 1);
catalogResult[i].TargetValuePtr = malloc( sizeof(unsigned char)*catalogResult[i].BufferLength );
}
// setup the binding (can be used even if the statement is closed by closeStatementHandle)
for ( i = 0 ; i < numCols ; i++ )
retCode = SQLBindCol(hstmt, (SQLUSMALLINT)i + 1, catalogResult[i].TargetType, catalogResult[i].TargetValuePtr, catalogResult[i].BufferLength, &(catalogResult[i].StrLen_or_Ind));
// all catalogs query
printf( "A list of names of all catalogs\n" );
//retCode = SQLTables( hstmt, (SQLCHAR*)"%", SQL_NTS, (SQLCHAR*)NULL, SQL_NTS, (SQLCHAR*)NULL, SQL_NTS, (SQLCHAR*)NULL, SQL_NTS );
retCode = SQLTables( hstmt, (unsigned char*)NULL, SQL_NTS, (unsigned char*)NULL, SQL_NTS, (unsigned char*)NULL, SQL_NTS, (unsigned char*)"'VIEW','TABLE'", SQL_NTS );
//retCode = SQLTables( hstmt, (SQLCHAR*)NULL, 0, (SQLCHAR*)"schema1", SQL_NTS, (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"'VIEW','TABLE'", SQL_NTS );
//retCode = SQLTables( hstmt, (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"%", SQL_NTS, (SQLCHAR*)"test", SQL_NTS);
//retCode = SQLColumns(hstmt, (SQLCHAR*)NULL, 0, (SQLCHAR*)NULL, SQL_NTS, (SQLCHAR*)"test", SQL_NTS, (SQLCHAR*)NULL, 0);
//retCode = SQLColumns(hstmt, (SQLCHAR*)NULL, 0, (SQLCHAR*)NULL, SQL_NTS, (SQLCHAR*)"CLAIMS_HISTORY_1", SQL_NTS, (SQLCHAR*)NULL, 0);
printf( "retCode = %d:%d\n", retCode, SQL_SUCCESS);
for ( retCode = SQLFetch(hstmt) ; MySQLSuccess(retCode) ; retCode = SQLFetch(hstmt) )
printCatalog( catalogResult, numCols );
getchar();
}
This piece of code is supposed to return the table names in a database and works for access databases saved with *.accdb (ie. the Microsoft Driver) extensions, which i am guessing is one of the latest drivers but i am not able to figure out why it does not work with the Driver do Microsoft Access ( *.mdb). can anyone tell me as to why this is happening?
this is a sample output when a DSN is created with the latest driver.
ACCESS
A list of names of all catalogs
retCode = 0:0
Catalog Name(1) = C:\Users\akisho02\Desktop\New folder (4)\football club db2.acc
db Catalog Name(3) = db_clubs Catalog Name(4) = TABLE Catalog
≡¡║ε½½½½½½½½■ε■ε■ε■ Catalog Name(18) =
Catalog Name(1) = C:\Users\akisho02\Desktop\New folder (4)\football club db2.acc
db Catalog Name(3) = db_items Catalog Name(4) = TABLE Catalog
≡¡║ε½½½½½½½½■ε■ε■ε■ Catalog Name(18) =
Catalog Name(1) = C:\Users\akisho02\Desktop\New folder (4)\football club db2.acc
db Catalog Name(3) = db_REGION Catalog Name(4) = TABLE Catalog
and this is a sample output when i create a DSN with the earlier drivers
ACCESS
A list of names of all catalogs
retCode = 0:0
Catalog Name(1) = C:\Users\akisho02\Desktop\football club db Catalog Name(3)
≡¡║ε½½½½½½½½■ε■ε■ε■ Catalog Name(18) = Catalog Name(6) =
Catalog Name(1) = C:\Users\akisho02\Desktop\football club db Catalog Name(3)
≡¡║ε½½½½½½½½■ε■ε■ε■ Catalog Name(18) = Catalog Name(6) =
Catalog Name(1) = C:\Users\akisho02\Desktop\football club db Catalog Name(3)
≡¡║ε½½½½½½½½■ε■ε■ε■ Catalog Name(18) = Catalog Name(6) =
This is a bug I saw with microsoft access driviers. I would suggest you use the latest version that the system offers in while setting up your database connection.