예제 #1
0
PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
m_rowCount(rowCount),
m_rowPosition(0),
m_fieldCount(fieldCount),
m_rBind(NULL),
m_stmt(stmt),
m_res(result),
m_isNull(NULL),
m_length(NULL)
{
    if (!m_res)
        return;

    if (m_stmt->bind_result_done)
    {
        delete[] m_stmt->bind->length;
        delete[] m_stmt->bind->is_null;
    }

    m_rBind = new MYSQL_BIND[m_fieldCount];
    m_isNull = new my_bool[m_fieldCount];
    m_length = new unsigned long[m_fieldCount];

    memset(m_isNull, 0, sizeof(my_bool) * m_fieldCount);
    memset(m_rBind, 0, sizeof(MYSQL_BIND) * m_fieldCount);
    memset(m_length, 0, sizeof(unsigned long) * m_fieldCount);

    //- This is where we store the (entire) resultset
    if (mysql_stmt_store_result(m_stmt))
    {
        TC_LOG_WARN("sql.sql", "%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
        delete[] m_rBind;
        delete[] m_isNull;
        delete[] m_length;
        return;
    }

    //- This is where we prepare the buffer based on metadata
    uint32 i = 0;
    MYSQL_FIELD* field = mysql_fetch_field(m_res);
    while (field)
    {
        size_t size = Field::SizeForType(field);

        m_rBind[i].buffer_type = field->type;
        m_rBind[i].buffer = malloc(size);
        memset(m_rBind[i].buffer, 0, size);
        m_rBind[i].buffer_length = size;
        m_rBind[i].length = &m_length[i];
        m_rBind[i].is_null = &m_isNull[i];
        m_rBind[i].error = NULL;
        m_rBind[i].is_unsigned = field->flags & UNSIGNED_FLAG;

        ++i;
        field = mysql_fetch_field(m_res);
    }

    //- This is where we bind the bind the buffer to the statement
    if (mysql_stmt_bind_result(m_stmt, m_rBind))
    {
        TC_LOG_WARN("sql.sql", "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
        delete[] m_rBind;
        delete[] m_isNull;
        delete[] m_length;
        return;
    }

    m_rowCount = mysql_stmt_num_rows(m_stmt);

    m_rows.resize(uint32(m_rowCount));
    while (_NextRow())
    {
        m_rows[uint32(m_rowPosition)] = new Field[m_fieldCount];
        for (uint64 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
        {
            if (!*m_rBind[fIndex].is_null)
                m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(m_rBind[fIndex].buffer,
                                                            m_rBind[fIndex].buffer_length,
                                                            m_rBind[fIndex].buffer_type,
                                                           *m_rBind[fIndex].length);
            else
                switch (m_rBind[fIndex].buffer_type)
                {
                    case MYSQL_TYPE_TINY_BLOB:
                    case MYSQL_TYPE_MEDIUM_BLOB:
                    case MYSQL_TYPE_LONG_BLOB:
                    case MYSQL_TYPE_BLOB:
                    case MYSQL_TYPE_STRING:
                    case MYSQL_TYPE_VAR_STRING:
                    m_rows[uint32(m_rowPosition)][fIndex].SetByteValue("",
                                                            m_rBind[fIndex].buffer_length,
                                                            m_rBind[fIndex].buffer_type,
                                                           *m_rBind[fIndex].length);
                    break;
                    default:
                    m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(nullptr,
                                                            m_rBind[fIndex].buffer_length,
                                                            m_rBind[fIndex].buffer_type,
                                                           *m_rBind[fIndex].length);
                }
        }
        m_rowPosition++;
    }
    m_rowPosition = 0;

    /// All data is buffered, let go of mysql c api structures
    CleanUp();
}
예제 #2
0
VALUE db_mysql_result_from_statement(VALUE self, VALUE statement) {
    int n, row, cols;
    MYSQL_STMT *s;
    MYSQL_FIELD *fields;
    MYSQL_RES *result;
    Result *r = db_mysql_result_handle(self);

    if (!rb_obj_is_kind_of(statement, cDMS))
        rb_raise(eSwiftArgumentError, "invalid Mysql::Statement");

    r->statement = statement;
    s = db_mysql_statement_handle_safe(statement)->statement;

    mysql_stmt_store_result(s);
    result = mysql_stmt_result_metadata(s);
    db_mysql_result_load(self, result, mysql_stmt_insert_id(s), mysql_stmt_affected_rows(s));

    if (result) {
        cols       = mysql_num_fields(result);
        fields     = mysql_fetch_fields(result);
        r->bind    = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND) * cols);
        r->lengths = (unsigned long *)malloc(sizeof(unsigned long) * cols);
        r->is_null = (my_bool *)malloc(sizeof(my_bool) * cols);
        memset(r->bind, 0, sizeof(MYSQL_BIND) * cols);

        for (n = 0; n < cols; n++) {
            r->bind[n].length      = &r->lengths[n];
            r->bind[n].is_null     = &r->is_null[n];
            r->bind[n].buffer_type = fields[n].type;

            switch(fields[n].type) {
                case MYSQL_TYPE_NULL:
                    r->bind[n].buffer        = malloc(1);
                    r->bind[n].buffer_length = 1;
                    break;
                case MYSQL_TYPE_TINY:
                case MYSQL_TYPE_SHORT:
                case MYSQL_TYPE_YEAR:
                case MYSQL_TYPE_INT24:
                case MYSQL_TYPE_LONG:
                case MYSQL_TYPE_LONGLONG:
                case MYSQL_TYPE_FLOAT:
                case MYSQL_TYPE_DOUBLE:
                    r->bind[n].buffer        = malloc(8);
                    r->bind[n].buffer_length = 8;
                    memset(r->bind[n].buffer, 0, 8);
                    break;
                case MYSQL_TYPE_DECIMAL:
                case MYSQL_TYPE_STRING:
                case MYSQL_TYPE_VAR_STRING:
                case MYSQL_TYPE_TINY_BLOB:
                case MYSQL_TYPE_BLOB:
                case MYSQL_TYPE_MEDIUM_BLOB:
                case MYSQL_TYPE_LONG_BLOB:
                case MYSQL_TYPE_NEWDECIMAL:
                case MYSQL_TYPE_BIT:
                    r->bind[n].buffer        = malloc(fields[n].length);
                    r->bind[n].buffer_length = fields[n].length;
                    memset(r->bind[n].buffer, 0, fields[n].length);
                    if (!(fields[n].flags & BINARY_FLAG))
                         r->bind[n].buffer_type = MYSQL_TYPE_STRING;
                    break;
                case MYSQL_TYPE_TIME:
                case MYSQL_TYPE_DATE:
                case MYSQL_TYPE_DATETIME:
                case MYSQL_TYPE_TIMESTAMP:
                    r->bind[n].buffer        = malloc(sizeof(MYSQL_TIME));
                    r->bind[n].buffer_length = sizeof(MYSQL_TIME);
                    memset(r->bind[n].buffer, 0, sizeof(MYSQL_TIME));
                    break;
                default:
                    rb_raise(rb_eTypeError, "unknown buffer_type: %d", fields[n].type);
            }
        }

        if (mysql_stmt_bind_result(s, r->bind) != 0)
            rb_raise(eSwiftRuntimeError, "%s", mysql_stmt_error(s));
    }

    r->start    = mysql_stmt_row_tell(s);
    r->selected = mysql_stmt_num_rows(s);
    r->affected = mysql_stmt_affected_rows(s);
    return self;
}
예제 #3
0
unsigned int wxMySQLRecordset::GetRowCount()
{
	return mysql_stmt_num_rows(m_Stmt);
}
예제 #4
0
PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
m_rowCount(rowCount),
m_rowPosition(0),
m_fieldCount(fieldCount),
m_rBind(nullptr),
m_stmt(stmt),
m_metadataResult(result)
{
    if (!m_metadataResult)
        return;

    if (m_stmt->bind_result_done)
    {
        delete[] m_stmt->bind->length;
        delete[] m_stmt->bind->is_null;
    }

    m_rBind = new MYSQL_BIND[m_fieldCount];

    //- for future readers wondering where the f**k this is freed - mysql_stmt_bind_result moves pointers to these
    // from m_rBind to m_stmt->bind and it is later freed by the `if (m_stmt->bind_result_done)` block just above here
    // MYSQL_STMT lifetime is equal to connection lifetime
    my_bool* m_isNull = new my_bool[m_fieldCount];
    unsigned long* m_length = new unsigned long[m_fieldCount];

    memset(m_isNull, 0, sizeof(my_bool) * m_fieldCount);
    memset(m_rBind, 0, sizeof(MYSQL_BIND) * m_fieldCount);
    memset(m_length, 0, sizeof(unsigned long) * m_fieldCount);

    //- This is where we store the (entire) resultset
    if (mysql_stmt_store_result(m_stmt))
    {
        TC_LOG_WARN("sql.sql", "%s:mysql_stmt_store_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
        delete[] m_rBind;
        delete[] m_isNull;
        delete[] m_length;
        return;
    }

    m_rowCount = mysql_stmt_num_rows(m_stmt);

    //- This is where we prepare the buffer based on metadata
    MYSQL_FIELD* field = mysql_fetch_fields(m_metadataResult);
    std::size_t rowSize = 0;
    for (uint32 i = 0; i < m_fieldCount; ++i)
    {
        uint32 size = SizeForType(&field[i]);
        rowSize += size;

        m_rBind[i].buffer_type = field[i].type;
        m_rBind[i].buffer_length = size;
        m_rBind[i].length = &m_length[i];
        m_rBind[i].is_null = &m_isNull[i];
        m_rBind[i].error = nullptr;
        m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
    }

    char* dataBuffer = new char[rowSize * m_rowCount];
    for (uint32 i = 0, offset = 0; i < m_fieldCount; ++i)
    {
        m_rBind[i].buffer = dataBuffer + offset;
        offset += m_rBind[i].buffer_length;
    }

    //- This is where we bind the bind the buffer to the statement
    if (mysql_stmt_bind_result(m_stmt, m_rBind))
    {
        TC_LOG_WARN("sql.sql", "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
        mysql_stmt_free_result(m_stmt);
        CleanUp();
        delete[] m_isNull;
        delete[] m_length;
        return;
    }

    m_rows.resize(uint32(m_rowCount) * m_fieldCount);
    while (_NextRow())
    {
        for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
        {
            unsigned long buffer_length = m_rBind[fIndex].buffer_length;
            unsigned long fetched_length = *m_rBind[fIndex].length;
            if (!*m_rBind[fIndex].is_null)
            {
                void* buffer = m_stmt->bind[fIndex].buffer;
                switch (m_rBind[fIndex].buffer_type)
                {
                    case MYSQL_TYPE_TINY_BLOB:
                    case MYSQL_TYPE_MEDIUM_BLOB:
                    case MYSQL_TYPE_LONG_BLOB:
                    case MYSQL_TYPE_BLOB:
                    case MYSQL_TYPE_STRING:
                    case MYSQL_TYPE_VAR_STRING:
                        // warning - the string will not be null-terminated if there is no space for it in the buffer
                        // when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED
                        // we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string
                        // in this case using Field::GetCString will result in garbage
                        // TODO: remove Field::GetCString and use boost::string_ref (currently proposed for TS as string_view, maybe in C++17)
                        if (fetched_length < buffer_length)
                            *((char*)buffer + fetched_length) = '\0';
                        break;
                    default:
                        break;
                }

                m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
                    buffer,
                    MysqlTypeToFieldType(m_rBind[fIndex].buffer_type),
                    fetched_length);

                // move buffer pointer to next part
                m_stmt->bind[fIndex].buffer = (char*)buffer + rowSize;
            }
            else
            {
                m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
                    nullptr,
                    MysqlTypeToFieldType(m_rBind[fIndex].buffer_type),
                    *m_rBind[fIndex].length);
            }

#ifdef TRINITY_STRICT_DATABASE_TYPE_CHECKS
            m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&field[fIndex], fIndex);
#endif
        }
        m_rowPosition++;
    }
    m_rowPosition = 0;

    /// All data is buffered, let go of mysql c api structures
    mysql_stmt_free_result(m_stmt);
}
예제 #5
0
bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult,
		uint64* pRowCount, uint32* pFieldCount) {
	if (!m_Mysql)
		return false;

	uint32 index = stmt->m_index;
	{
		MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index);
		ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
		m_mStmt->m_stmt = stmt; // Cross reference them for debug output
		stmt->m_stmt = m_mStmt; // TODO: Cleaner way

		stmt->BindParameters();

		MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
		MYSQL_BIND* msql_BIND = m_mStmt->GetBind();

		uint32 _s = 0;
		if (sLog->GetSQLDriverQueryLogging())
			_s = getMSTime();

		if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) {
			uint32 lErrno = mysql_errno(m_Mysql);
			sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s",
					m_mStmt->getQueryString(m_queries[index].first).c_str(),
					lErrno, mysql_stmt_error(msql_STMT));

			if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
				return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again

			m_mStmt->ClearParameters();
			return false;
		}

		if (mysql_stmt_execute(msql_STMT)) {
			uint32 lErrno = mysql_errno(m_Mysql);
			sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s",
					m_mStmt->getQueryString(m_queries[index].first).c_str(),
					lErrno, mysql_stmt_error(msql_STMT));

			if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
				return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again

			m_mStmt->ClearParameters();
			return false;
		}

		if (sLog->GetSQLDriverQueryLogging())
			sLog->outSQLDriver("[%u ms] SQL(p): %s",
					getMSTimeDiff(_s, getMSTime()),
					m_mStmt->getQueryString(m_queries[index].first).c_str());

		m_mStmt->ClearParameters();

		*pResult = mysql_stmt_result_metadata(msql_STMT);
		*pRowCount = mysql_stmt_num_rows(msql_STMT);
		*pFieldCount = mysql_stmt_field_count(msql_STMT);

		return true;
	}
}
예제 #6
0
int mysql_drv_store_results(db_result_set_t *rs)
{
  MYSQL        *con = rs->connection->ptr;
  MYSQL_RES    *res;
  MYSQL_ROW    row;
  int rc;

#ifdef HAVE_PS
  /* Is this result set from prepared statement? */
  if (rs->statement != NULL && rs->statement->emulated == 0)
  {
    if (rs->statement->ptr == NULL)
      return 1;

    rc = mysql_stmt_store_result(rs->statement->ptr);
    DEBUG("mysql_stmt_store_result(%p) = %d", rs->statement->ptr, rc);
    if (rc)
    {
      rc = mysql_errno(con);
      DEBUG("mysql_errno(%p) = %d", con, rc);
      if (rc == ER_LOCK_DEADLOCK || rc == ER_LOCK_WAIT_TIMEOUT)
      {
        log_text(LOG_WARNING,
                 "mysql_stmt_store_result() failed with error: (%d) %s", rc,
                 mysql_error(con));
        return SB_DB_ERROR_DEADLOCK;
      }

      log_text(LOG_ALERT, "MySQL error: %s\n", mysql_error(con));
      return SB_DB_ERROR_FAILED;
    }
    rs->nrows = mysql_stmt_num_rows(rs->statement->ptr);
    DEBUG("mysql_stmt_num_rows(%p) = %d", rs->statement->ptr, rs->nrows);
    do {
      rc = mysql_stmt_fetch(rs->statement->ptr);
      DEBUG("mysql_stmt_fetch(%p) = %d", rs->statement->ptr, rc);
    } while(rc == 0);

    return SB_DB_ERROR_NONE;
  }
#endif
  
  if (con == NULL)
    return SB_DB_ERROR_FAILED;
  
  /* using store results for speed will not work for large sets */
  res = mysql_store_result(con);
  DEBUG("mysql_store_result(%p) = %p", con, res);
  if (res == NULL)
  {
      rc = mysql_errno(con);
      DEBUG("mysql_errno(%p) = %u", con, rc);
      if (rc == ER_LOCK_DEADLOCK || rc == ER_LOCK_WAIT_TIMEOUT)
      {
        log_text(LOG_WARNING,
                 "mysql_store_result() failed with error: (%u) %s", rc,
                 mysql_error(con));
        return SB_DB_ERROR_DEADLOCK;
      }
    log_text(LOG_ALERT, "MySQL error: %s", mysql_error(con));
    return SB_DB_ERROR_FAILED; 
  }
  rs->ptr = (void *)res;

  rs->nrows = mysql_num_rows(res);
  DEBUG("mysql_num_rows(%p) = %u", res, rs->nrows);
  
  /* just fetch result */
  while((row = mysql_fetch_row(res)))
    DEBUG("mysql_fetch_row(%p) = %p", res, row);

  return SB_DB_ERROR_NONE;
}