How do you create new database using MFC ODBC API?
In the connection string you should mention the name of the database you want to connect to. What if I have just-installed SQL Server containing no user databases?
Which database name do you specify in the connection string?
E.g. for SQL Server:
CDatabase db;
db.OpenEx(L"Driver={ODBC Driver 11 for SQL Server};Server=myServerAddress;"
L"Database=????????;Uid=myUsername;Pwd=myPassword", CDatabase::noOdbcDialog);
db.ExecuteSQL(L"CREATE DATABASE testdb");
Should I use System Databases (e.g. master, model, etc.)?
Is there some more generic approach?
You can omit Database= in the connection string. Then you create a new database and after that you switch to that database using USE.
Something like this works fine for me:
SQLWCHAR strConnect[256] = L"Driver={SQL Server};Server=.\\MACHINE;Trusted_Connection=yes;";
SQLWCHAR strConnectOut[1024] = { 0 };
SQLSMALLINT nNumOut = 0;
SQLRETURN nResult = SQLDriverConnect(handleDBC, NULL, (SQLWCHAR*)strConnect, SQL_NTS, (SQLWCHAR*)strConnectOut, sizeof(strConnectOut), &nNumOut, SQL_DRIVER_NOPROMPT);
if (!SQL_SUCCEEDED(nResult))
// some error handling
SQLHSTMT handleStatement = SQL_NULL_HSTMT;
nResult = SQLAllocHandle(SQL_HANDLE_STMT, handleDBC, (SQLHANDLE*)&handleStatement);
if (!SQL_SUCCEEDED(nResult))
// some error handling
// Create a new database and use that
nResult = SQLExecDirect(handleStatement, L"CREATE DATABASE Foobar", SQL_NTS);
nResult = SQLExecDirect(handleStatement, L"USE Foobar", SQL_NTS);
// create table Wallet in database Foobar
nResult = SQLExecDirect(handleStatement, L"CREATE TABLE Wallet (WalletID int NOT NULL, Name nvarchar(5) NOT NULL)", SQL_NTS);
Related
So I have a table in mssql created like this:
CREATE TABLE employee(ID bigint,Age int,Salary DECIMAL(17,7), DATA varbinary($var_len), Occupation varchar(200), TimeCol DATETIME)
Now I would like to run a query and bind SALARY field to an SQL_C_NUMERIC type. I have just edited the code taken from a microsoft doc:
RETCODE retcode;
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc1 = SQL_NULL_HDBC;
SQLHSTMT hstmt1 = SQL_NULL_HSTMT;
SQLHDESC hdesc = NULL;
SQL_NUMERIC_STRUCT NumStr;
const std::string connectionString = "DSN=dsn_name;Trusted_Connection=Yes;";
char out_connection_string[1024];
short out_connection_string_length = -1;
SQLINTEGER strlen1;
SQLINTEGER strlen2;
retcode = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
retcode = SQLDriverConnect(hdbc1, NULL, (SQLCHAR*)connectionString.c_str(), connectionString.size(),
(SQLCHAR*)out_connection_string, 1024, &out_connection_string_length, SQL_DRIVER_NOPROMPT);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
retcode = SQLExecDirect(hstmt1, (UCHAR *)"select '20031201143000' as t, SALARY as SYMBOL_NAME, AGE from employee", SQL_NTS);
retcode = SQLBindCol(hstmt1, 2, SQL_C_NUMERIC, &NumStr, 19, &strlen1);
retcode = SQLGetStmtAttr(hstmt1, SQL_ATTR_APP_ROW_DESC, &hdesc, 0, NULL);
// If I comment these 3 lines out, everything works
retcode = SQLSetDescField(hdesc, 2, SQL_DESC_TYPE, (VOID*)SQL_C_NUMERIC, 0);
retcode = SQLSetDescField(hdesc, 2, SQL_DESC_PRECISION, (VOID*)17, 0);
retcode = SQLSetDescField(hdesc, 2, SQL_DESC_SCALE, (VOID*)7, 0);
// If I comment this SQLBindCol there is no crash
SQLINTEGER id;
retcode = SQLBindCol(hstmt1, 3, SQL_C_SLONG, &id, 4, &strlen2);
memset(NumStr.val, 0, 16);
// Call SQLFetch to fetch the first record.
while((retcode = SQLFetch(hstmt1)) != SQL_NO_DATA)// crash!
{
....
SQL_Fetch crashes with an access violation. If I change the order of AGE and SALARY in the select statement, it works. If I comment out the setting of descriptor fields, it works. If I do not bind the AGE field it works. If I set SQL_DESC_TYPE to another type instead of SQL_C_NUMERIC, it works.
Am I doing something illegal, are there odbc constraints of which I am unaware or is it a Microsoft bug?
UPDATE: Adding some information:
OS version: Windows 7 Professional, 6.1
ODBC driver manager version: 6.01.7601.17514
ODBC driver version:
Name: SQL Server
Version: 6.01.7601.17514
Date: 21.11.2010
MSSQL server version:
Microsoft SQL Server 2008 (SP4) - 10.0.6000.29 (X64) Sep 3 2014 04:11:34 Copyright (c) 1988-2008 Microsoft Corporation Express Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1)
My ODBC DSN and driver are 32-bit though
I made a PostgreSQL30 data source name. I tested it and I managed to connect to that dsn through ODBC data source window manager. There was a button Test and It showed message dialog, telling me that connection was success.
Now I wonder how would I connect to that DSN through c++ code and get some data.
This is my code, i saw few examplex online and come up with this code
enter code here
HENV hEnv = NULL; // for allocating memory usingSQLAllocEnv
HDBC hDBC = NULL; // connection handler
HSTMT hStmt = NULL; // statement handler
const char* szDSN = "PostgreSQL30"; // DataSourceName (config in windows
control panel)
const char* szUID = "postgres"; //username of the database
const char* szPasswd = "postgres"; //password of the database
RETCODE retcode;
int rcod = 1;
int i, j, no = 2;
int main()
{
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
std::cout << retcode << std::endl;
SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC);
std::cout << retcode << std::endl;
retcode = SQLConnectA(hDBC,(SQLCHAR*)szDSN, SQL_NTS, (SQLCHAR*)szUID, SQL_NTS,
(SQLCHAR*)szPasswd,
SQL_NTS);
std::cout << (SQLCHAR*)szUID << std::endl;
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
// connected!!
std::cout << "Hello World!\n SUCCESSS COME ON PLEASE";
}
else {
std::cout << retcode << std::endl;
}
SQLFreeHandle(SQL_HANDLE_ENV, &hEnv);
SQLFreeHandle(SQL_HANDLE_DBC, &hDBC);
}
But I cant comprehend why would this work, I mean how is this code knows to call SQLAllocHandle implemented by Postgres driver ?
My question is how would I connect to DSN thorugh C++ code and get some data
In fact ODBC Driver Manager makes these calls to ODBC driver when performing your SQLConnect call: on this stage it "knows" which driver you want to use. Look at the SQLConnect function description, "Comments" section:
"The Driver Manager does not connect to a driver until the application calls a function (SQLConnect, SQLDriverConnect, or SQLBrowseConnect) to connect to the driver. Until that point, the Driver Manager works with its own handles and manages connection information. When the application calls a connection function, the Driver Manager checks whether a driver is currently connected to for the specified ConnectionHandle:
If a driver is not connected to, the Driver Manager connects to the driver and calls SQLAllocHandle with a HandleType of SQL_HANDLE_ENV, SQLAllocHandle with a HandleType of SQL_HANDLE_DBC, SQLSetConnectAttr (if the application specified any connection attributes), and the connection function in the driver. The Driver Manager returns SQLSTATE IM006 (Driver's SQLSetConnectOption failed) and SQL_SUCCESS_WITH_INFO for the connection function if the driver returned an error for SQLSetConnectAttr. For more information, see Connecting to a Data Source or Driver.
If the specified driver is already connected to on the ConnectionHandle, the Driver Manager calls only the connection function in the driver. In this case, the driver must make sure that all connection attributes for the ConnectionHandle maintain their current settings.
If a different driver is connected to, the Driver Manager calls SQLFreeHandle with a HandleType of SQL_HANDLE_DBC, and then, if no other driver is connected to in that environment, it calls SQLFreeHandle with a HandleType of SQL_HANDLE_ENV in the connected driver and then disconnects that driver. It then performs the same operations as when a driver is not connected to.
The driver then allocates handles and initializes itself."
Full text here: SQLConnect function comments
const char* szDSN = "PostgreSQL30"; // DataSourceName (config in windows
control panel)
If you check in the ODBC Data source, This DSN (PostgreSQL30) would be created using an appropriate driver. The driver manager knows which driver to load based on the configured ODBC data source information.
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 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
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.