mySQL return NO_DATA, but record exists

66 views Asked by At

Trying to run the following

std::wstring query1 = L"SELECT st.table_id FROM information_schema.INNODB_TABLES st  WHERE st.name = ?;";

or

std::wstring query1 = L"SELECT st.table_id FROM information_schema.INNODB_TABLES st  WHERE st.name = CONCAT(?, '/', ?);";

returns SQL_NO_DATA, but if the parameter is spelled out the record is returned.

Code is as follows:

auto res1 = mysql_stmt_init( m_db );
if( !res1 )
{
    std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
    errors.push_back( err );
    result = 1;
}
else
{
    if( mysql_stmt_prepare( res1, m_pimpl->m_myconv.to_bytes( query1.c_str() ).c_str(), query1.length() ) )
    {
        std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
        errors.push_back( err );
        result = 1;
    }
    else
    {
        MYSQL_BIND params[2];
        unsigned long str_length1, str_length2;
        str_length1 = strlen( m_pimpl->m_myconv.to_bytes( schema.c_str() ) .c_str() ) * 2;
        str_length2 = strlen( m_pimpl->m_myconv.to_bytes( table.c_str() ).c_str() ) * 2;
        char *str_data1 = new char[str_length1], *str_data2 = new char[str_length2];
        memset( str_data1, '\0', str_length1 );
        memset( str_data2, '\0', str_length2 );
        memset( params, 0, sizeof( params ) );
        strncpy( str_data1, m_pimpl->m_myconv.to_bytes( schema.c_str() ) .c_str(), str_length1 );
        strncpy( str_data2, m_pimpl->m_myconv.to_bytes( table.c_str() ).c_str(), str_length2 );
        params[0].buffer_type = MYSQL_TYPE_STRING;
        params[0].buffer = (char *) str_data1;
        params[0].buffer_length = strlen( str_data1 );
        params[0].is_null = 0;
        params[0].length = &str_length1;
        params[1].buffer_type = MYSQL_TYPE_STRING;
        params[1].buffer = (char *) str_data2;
        params[1].buffer_length = strlen( str_data2 );
        params[1].is_null = 0;
        params[1].length = &str_length2;
        if( mysql_stmt_bind_param( res1, params ) )
        {
            std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
            errors.push_back( err );
            result = 1;
        }
        else
        {
            auto prepare_meta_result = mysql_stmt_result_metadata( res1 );
            if( !prepare_meta_result )
            {
                std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
                errors.push_back( err );
                result = 1;
            }
            else
            {
                if( mysql_stmt_execute( res1 ) )
                {
                    std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
                    errors.push_back( err );
                    result = 1;
                }
                else
                {
                    MYSQL_BIND results1[1];
                    bool is_null[1], error[1];
                    unsigned long length[1];
                    memset( results1, 0, sizeof( results1 ) );
                    results1[0].buffer_type = MYSQL_TYPE_LONG;
                    
                    results1[0].buffer = (char *) &tableId;
                    results1[0].is_null = &is_null[1];
                    results1[0].error = &error[1];
                    results1[0].length = &length[1];
                    
                    if( mysql_stmt_bind_result( res1, results1 ) )
                    {
                        std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
                        errors.push_back( err );
                        result = 1;
                    }
                    else
                    {
                        while( true )
                        {
                            auto dataset = mysql_stmt_fetch( res1 );
                            if( dataset == 1 || dataset == MYSQL_NO_DATA )
                                break;
                            else
                                id = tableId;
                        }
                        mysql_free_result( prepare_meta_result );
                    }
                }
            }
        }
    }
}
if( mysql_stmt_close( res1 ) )
{
    std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
    errors.push_back( err );
    result = 1;
}

What am I missing?

1

There are 1 answers

2
Tim Roberts On

I suspect you have a lifetime issue. Consider the following code:

{
    if( mysql_stmt_prepare( res1, m_pimpl->m_myconv.to_bytes( query1.c_str() ).c_str(), query1.length() ) )
    {

You take your wstring query1 (and WHY is it a wstring if you need it to be a std::string???), and pass it to m_pimpl->m_myconv.to_bytes. I assume that function does the Unicode-to-ANSI translation and returns a std::string. You then call c_str() on that to get a buffer, and pass that to mysql_stmt_prepare.

HOWEVER, what to_bytes returns is a temporary. As soon as the if statement exits, that string goes out of scope and will be destroyed, leaving the statement holding a pointer into nothing. I suggest you try:

    std::string query1s = m_pimpl->m_myconv.to_bytes( query1.c_str() );
    if( mysql_stmt_prepare( res1, query1s.c_str(), query1s.length() ) )
    {

This has the additional benefit of letting you print the value of query1s to make sure it matches your expectation.

Now, IF mysql_stmt_prepare actually copies the input string, instead of just grabbing a pointer, then this won't fix anything.