How to send C++ and mysql dynamic mysql queries

前端 未结 3 688
执念已碎
执念已碎 2020-12-21 22:45

Working with Visual Studio, Windows 7 and mysql.h library.

What I want to do is send a MySQL query like this:

mysql_query(conn, \"SELECT pass FROM us         


        
3条回答
  •  生来不讨喜
    2020-12-21 23:31

    Use a prepared statement, which lets you parameterize values, similar to how functions let you parameterize variables in statement blocks. If using MySQL Connector/C++:

    // use std::unique_ptr, boost::shared_ptr, or whatever is most appropriate for RAII
    // Connector/C++ requires boost, so 
    std::unique_ptr db;
    std::unique_ptr getPassword
    std::unique_ptr result;
    std::string name = "Nikolai Gogol";
    std::string password;
    
    ...
    
    getPassword = db->prepareStatement("SELECT pass FROM users WHERE name=? LIMIT 1");
    
    getPassword->setString(1, name);
    result = getPassword->execute();
    if (result->first()) {
        password = result->getString("pass");
    } else {
        // no result
        ...
    }
    
    // smart pointers will handle deleting the sql::* instances
    

    Create classes to handle database access and wrap that in a method, and the rest of the application doesn't even need to know that a database is being used.

    If you really want to use the old C API for some reason:

    MYSQL *mysql;
    ...
    
    const my_bool yes=1, no=0;
    const char* getPassStmt = "SELECT password FROM users WHERE username=? LIMIT 1";
    MYSQL_STMT *getPassword;
    MYSQL_BIND getPassParams;
    MYSQL_BIND result;
    
    std::string name = "Nikolai Gogol";
    std::string password;
    
    if (! (getPassword = mysql_stmt_init(mysql))) {
        // error: couldn't allocate space for statement
        ...
    }
    if (mysql_stmt_prepare(getPassword, getPassStmt, strlen(getPassStmt))) {
        /* error preparing statement; handle error and 
           return early or throw an exception. RAII would make
           this easier.
        */
        ...
    } else {
        unsigned long nameLength = name.size();
        memset(&getPassParams, 0, sizeof(getPassParams));
        getPassParams.buffer_type = MYSQL_TYPE_STRING;
        getPassParams.buffer = (char*) name.c_str();
        getPassParams.length = &nameLength;
    
        if (mysql_stmt_bind_param(getPassword, &getPassParams)) {
            /* error binding param */
            ...
        } else if (mysql_stmt_execute(getPassword)) {
            /* error executing query */
            ...
        } else {
            // for mysql_stmt_num_rows()
            mysql_stmt_store_result(getPassword);
            if (mysql_stmt_num_rows(getPassword)) {
                unsigned long passwordLength=0;
                memset(&result, 0, sizeof(result));
                result.length = &passwordLength;
                mysql_stmt_bind_result(getPassword, &result);
    
                mysql_stmt_fetch(getPassword);
                if (passwordLength > 0) {
                    result.buffer = new char[passwordLength+1];
                    memset(result.buffer, 0, passwordLength+1);
                    result.buffer_length = passwordLength+1;
                    if (mysql_stmt_fetch_column(getPassword, &result, 0, 0)) {
                        ...
                    } else {
                        password = static_cast(result.buffer);
                    }
                }
            } else {
                // no result
                cerr << "No user '" << name << "' found." << endl;
            }
        }
        mysql_stmt_free_result(getPassword);
    }
    mysql_stmt_close(getPassword);
    
    mysql_close(mysql);
    

    As you see, Connector/C++ is simpler. It's also less error prone; I probably made more mistakes using the C API than Connector/C++.

    See also:

    • Developing Database Applications Using MySQL Connector/C++
    • Connector C++ in the MySQL Forge wiki

提交回复
热议问题