使用Visual Studio Express 2013在c++中解决SQL Server连接问题

Troubleshooting SQL Server connection in C++ using Visual Studio Express 2013

本文关键字:SQL 解决 Server 连接 问题 c++ Studio Visual Express 2013 使用      更新时间:2023-10-16

我一直在尝试得到一个简单的程序,可以在SQL Server数据库上执行一些简单的操作,但不能得到任何教程实际运行。我试图弄清楚问题是与代码还是与我的ODBC设置。任何帮助/见解都是非常感谢的。

EDIT/UPDATE: ADDITIONAL DETAIL &下列代码

现在的主程序是基于本教程。我不得不做一些改变,使VS Express 2013能够编译代码:

  • SQLCHAR *的所有实例必须更改为SQLWCHAR *。
  • 必须使用wcout来输出错误信息
  • 教程中使用的'GOTO: FINISHED'会产生对象可能未初始化的错误。我在'FINISHED'之后添加了一个'UNFIN'块,并将那些生成的错误更改为GOTO UNFIN,以使编译器高兴
  • 添加了一些调试标记,以确保我正确地遵循程序
  • 更改了连接字符串以匹配服务器,用户名和数据库的密码,我试图连接到。注意:目标数据库使用SQLServer2008
在运行程序时,我得到以下错误消息(由show_error()函数生成):
Messsage: [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified 
nSQLSTATE: IM002

它可能是像我需要在我的机器上切换的ODBC设置或我在项目设置中错过的依赖项一样简单的东西吗?

下面是代码。(请注意,对于正在测试的其他功能,还有额外的头文件。说其他功能在我目前的测试程序中被注释掉,并从下面的复制粘贴中删除,以减少混淆)

#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <sstream>//Used to int to string, and string to int operations
#include <stdlib.h>
#include <fstream>//Used for file opening, appending and writing operations
#include <iostream>
#include <Windows.h>//Used for sleep command, and window "clearwindow" function
#include <sqlext.h>     // Used for writing to SQL database
#include <sqltypes.h> 
#include <sql.h>    
using namespace std;

void show_error(unsigned int handletype, const SQLHANDLE& handle){
    SQLWCHAR sqlstate[1024];
    SQLWCHAR message[1024];
    cout << "In show_error" << endl;
    if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL)){
        cout << "Message: ";
        wcout << message;    
        cout << endl << "nSQLSTATE: ";
        wcout << sqlstate;
        cout << endl;
    }
}
bool write_to_database(/*string dbconnection, string fields, string values*/){
    SQLHANDLE sqlenvhandle;
    SQLHANDLE sqlconnectionhandle;
    SQLHANDLE sqlstatementhandle;
    SQLRETURN retcode;
    if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlenvhandle))
        goto UNFIN;
    if (SQL_SUCCESS != SQLSetEnvAttr(sqlenvhandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))
        goto UNFIN;
    if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC, sqlenvhandle, &sqlconnectionhandle))
        goto UNFIN;
    SQLWCHAR retconstring[1024];
    cout << "Made it this far at least" << endl;
    switch (SQLDriverConnect(sqlconnectionhandle,
        NULL,
        (SQLWCHAR*)"DRIVER={SQL Server};SERVER=sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx",
        SQL_NTS,
        retconstring,
        1024,
        NULL,
        SQL_DRIVER_NOPROMPT)){
    case SQL_SUCCESS_WITH_INFO:
        show_error(SQL_HANDLE_DBC, sqlconnectionhandle);
        break;
    case SQL_INVALID_HANDLE:
    case SQL_ERROR:
        cout << "Now we're in SQL_ERROR" << endl;
        show_error(SQL_HANDLE_DBC, sqlconnectionhandle);
        goto FINISHED;
    default:
        break;
    }
    if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, sqlconnectionhandle, &sqlstatementhandle))
        goto FINISHED;
    if (SQL_SUCCESS != SQLExecDirect(sqlstatementhandle, (SQLWCHAR*)"select * from testtable", SQL_NTS)){
        show_error(SQL_HANDLE_STMT, sqlstatementhandle);
        goto FINISHED;
    }
    else{
        char name[64];
        char address[64];
        int id;
        while (SQLFetch(sqlstatementhandle) == SQL_SUCCESS){
            SQLGetData(sqlstatementhandle, 1, SQL_C_ULONG, &id, 0, NULL);
            SQLGetData(sqlstatementhandle, 2, SQL_C_CHAR, name, 64, NULL);
            SQLGetData(sqlstatementhandle, 3, SQL_C_CHAR, address, 64, NULL);
            cout << id << " " << name << " " << address << endl;
        }
    }
FINISHED:
    SQLFreeHandle(SQL_HANDLE_STMT, sqlstatementhandle);
    SQLDisconnect(sqlconnectionhandle);
    SQLFreeHandle(SQL_HANDLE_DBC, sqlconnectionhandle);
    SQLFreeHandle(SQL_HANDLE_ENV, sqlenvhandle);
    goto ALLOVER;
UNFIN:
    cout << "Everything is unfinished" << endl;
ALLOVER:
    return true;
}

int _tmain(int argc, _TCHAR* argv[])
{
    write_to_database();
    return 0;
}

编辑/更新:

继续尝试找出错误在哪里。使用基于EasySoft教程的代码来获得可用的DSN列表感觉有点像进步。下面是更新后的程序和结果:

// SQLTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <iostream>
#include <Windows.h>//Used for sleep command, and window "clearwindow" function
#include <sql.h>    
#include <sqltypes.h> 
#include <sqlext.h>     // Used for writing to SQL database
using namespace std;

static void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT handletype){
    SQLWCHAR sqlstate[1024];
    SQLWCHAR message[1024];
    if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message,     1024, NULL)){
        cout << "Message: ";
        wcout << message;
        cout << " nSQLSTATE: ";
        wcout << sqlstate;
        cout << endl;
    }
}

static void do_sql(){
    SQLHENV env;
    SQLWCHAR dsn[256];
    SQLWCHAR desc[256];
    SQLSMALLINT dsn_ret;
    SQLSMALLINT desc_ret;
    SQLUSMALLINT direction;
    SQLRETURN ret;
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
    direction = SQL_FETCH_FIRST;
    cout << "SQL DATA SOURCES:" << endl;
    while (SQL_SUCCEEDED(ret = SQLDataSources(env, direction,
        dsn, sizeof(dsn), &dsn_ret,
        desc, sizeof(desc), &desc_ret))) {
        direction = SQL_FETCH_NEXT;
        wcout << dsn << " | " << desc << endl;
        if (ret == SQL_SUCCESS_WITH_INFO) printf("tdata truncationn");
    }

    SQLHDBC dbc;
    SQLHSTMT stmt;
    SQLWCHAR outstr[1024];
    SQLSMALLINT outstrlen;
    /* Allocate an environment handle */
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
        /* We want ODBC 3 support */
        SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
        /* Allocate a connection handle */
        SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);

        /* Connect to the DSN mydsn */
        string connstr = "DSN=EnglobalConn";
    cout << endl << endl << "ATTEMPTING TO CONNECT TO DATA SOURCE USING:" << endl         <<connstr << endl << endl;

    ret = SQLDriverConnect(dbc, NULL, (SQLWCHAR*)connstr.c_str(), SQL_NTS,
        outstr, sizeof(outstr), &outstrlen,
        SQL_DRIVER_NOPROMPT);
    if (SQL_SUCCEEDED(ret)) {
        printf("Connectedn");
        printf("Returned connection string was:nt%sn", outstr);
        if (ret == SQL_SUCCESS_WITH_INFO) {
            printf("Driver reported the following diagnosticsn");
            extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC);
        }
        SQLDisconnect(dbc);     /* disconnect from driver */
    }
    else {
        fprintf(stderr, "Failed to connectn");
        extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC);
    }
    /* free up allocated handles */
    SQLFreeHandle(SQL_HANDLE_DBC, dbc);
    SQLFreeHandle(SQL_HANDLE_ENV, env);
}

int _tmain(int argc, _TCHAR* argv[])
{
    do_sql();
    return 0;
}

程序给出如下输出。' englobaln '和'Englobal2'的错误相同

<>之前SQL数据源:dBASE文件| Microsoft Access dBASE驱动程序(*dbf, *. dbf)ndx, *中)Excel文件| Microsoft Excel Driver (*.xls, *.xlsx, *.xlsx)xlsm * .xlsb)MS Access Database | Microsoft Access Driver (*.)mdb, * .accdb)Englobal2 | SQL Serverenglobalcony | SQL Server试图使用以下命令连接到数据源:DSN = EnglobalConn连接失败消息:[microsoft][ODBC Driver Manager]数据源名称未找到,未指定默认驱动程序nSQLSTATE: IM002之前

我在谷歌上找到的一条建议是,64位Windows安装有2个ODBC集,一个在System32中,一个在SysWOW64中。我已经运行了两个并将dsn设置为相同:在C:WindowsSysWOW64 odbcad32.exe:用户数据源:Englobal2 - SQL ServerSystem DSN: englobalcony - SQL Server

C:WindowsSystem32 odbcad32.exe:用户数据源:Englobal2 - SQL ServerSystem DSN: englobalcony - SQL Server

嗨,我一直在努力解决完全相同的问题,完全相同的失败:)

(SQLWCHAR *)"DRIVER={SQL Server}; Server =sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx",

应该是

(SQLWCHAR*)_T("DRIVER={SQL Server}; Server =sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx"),

(SQLWCHAR*)TEXT("DRIVER={SQL Server}; Server =sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx"),

万岁!找到一个有效的解决方案:

使用库http://otl.sourceforge.net/(设计用于Oracle,但也可以连接到SQL Server):

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define OTL_ODBC // Compile OTL 4.0/ODBC
// The following #define is required with MyODBC 3.51.11 and higher
#define OTL_ODBC_SELECT_STM_EXECUTE_BEFORE_DESCRIBE
// #define OTL_ODBC_UNIX // uncomment this line if UnixODBC is used
#include "otlv4.h" // include the OTL 4.0 header file
otl_connect db; // connect object
void insert()
// insert rows into table
{
    otl_stream o(1, // buffer size should be == 1 always on INSERT
        "insert into test_tab values "
        "(:f1<int>, : f2<char[31]>), "
        "(:f12<int>, : f22<char[31]>), "
        "(:f13<int>, : f23<char[31]>), "
        "(:f14<int>, : f24<char[31]>), "
        "(:f15<int>, : f25<char[31]>) ",
        // INSERT statement. Multiple sets of values can be used
        // to work around the lack of the bulk interface
        db // connect object
        );
    // If the number of rows to be inserted is not known in advance,
    // another stream with the same INSERT can be opened
    otl_stream o2(1, // buffer size should be == 1 always on INSERT
        "insert into test_tab values "
        "(:f1<int>, : f2<char[31]>)",
        db // connect object
        );
    char tmp[32];
    int i;
    for (i = 1; i <= 100; ++i){
        sprintf_s(tmp, "Name%d", i);
        o << i << tmp;
    }
    for (i = 101; i <= 103; ++i){
        sprintf_s(tmp, "Name%d", i);
        o2 << i << tmp;
    }
}
void update(const int af1)
// insert rows into table
{
    otl_stream o(1, // buffer size should be == 1 always on UPDATE
        "UPDATE test_tab "
        "   SET f2 = :f2<char[31]> "
        " WHERE f1 = : f1<int>",
        // UPDATE statement
        db // connect object
        );
    o << "Name changed" << af1;
    o << otl_null() << af1 + 1; // set f2 to NULL
}
void select(const int af1)
{
    otl_stream i(50, // buffer size may be > 1
        "select :f1<int>, :f2<char[31]> from test_tab "
        /*"where f1 >= :f11<int> "*/,
            // SELECT statement
        db // connect object
        );
    // create select stream
    cout << "Here" <<endl;
        int f1;
        char f2[31];
        i << af1 << af1; // :f11 = af1, :f12 = af1
        while (!i.eof()){ // while not end-of-data
            i >> f1;
            cout << "f1 = " << f1 << ", f2 = ";
            i >> f2;
            if (i.is_null())
                cout << "NULL";
            else
                cout << f2;
        cout << endl;
    }
}
int main()
{
    otl_connect::otl_initialize(); // initialize ODBC environment
        try{
            //db.rlogon("root / XX @mysql3532");
        db.rlogon("driver={SQL Server};UID=XXXXX;PWD=XXXXXX;        server=sqlserver.myserver.com"); // connect to ODBC
        //  db.rlogon("scott/tiger@mysql35"); // connect to ODBC, alternative format
        // of connect string
        otl_cursor::direct_exec
            (
            db,
            "drop table test_table",
            otl_exception::disabled // disable OTL exceptions
            ); // drop table

        otl_cursor::direct_exec
            (
            db,
            "create table test_table(f1 int, f2 varchar(30))"
            //"create table test_tab(f1 int, f2 varchar(30)) type=innoDB" (causes MYSQL     error)
            );  // create table
        //insert(); // insert records into the table
        //update(10); // update records in the table
        //select(8); // select records from the table
        otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (600,'Test')");
        otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (-3,'Lest')");
        otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (4,'Rest')");
        otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (10,'Best')");
        otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (19,'Quest')");
        //select(20);
    }
    catch (otl_exception& p){ // intercept OTL exceptions
        cerr << "MSG: " << p.msg << endl; // print out error message
        cerr << "STM_TEXT: " << p.stm_text << endl; // print out SQL that caused the error
        cerr << "SQLSTATE: " << p.sqlstate << endl; // print out SQLSTATE message
        cerr << "VAR_INFO: " << p.var_info << endl; // print out the variable that caused     the error
    }
    db.logoff(); // disconnect from ODBC
    return 0;
}