MXS-1512 Add mock Backend class that can generate resultsets

This commit is contained in:
Johan Wikman 2017-11-28 13:35:00 +02:00
parent 6d66ffe9f7
commit 02cf284b61
2 changed files with 145 additions and 8 deletions

View File

@ -14,6 +14,7 @@
#include <maxscale/cppdefs.hh>
#include <map>
#include <maxscale/resultset.h>
#include "routersession.hh"
namespace maxscale
@ -33,6 +34,13 @@ class Backend
public:
virtual ~Backend();
/**
* Create an OK response.
*
* @return A GWBUF containing an OK response packet.
*/
static GWBUF* create_ok_response();
/**
* Called to handle a statement from a "client".
*
@ -135,6 +143,31 @@ public:
void handle_statement(RouterSession* pSession, GWBUF* pStatement);
};
/**
* The ResultsetBackend
*/
class ResultSetBackend : public BufferBackend
{
ResultSetBackend(const ResultSetBackend&);
ResultSetBackend& operator = (const ResultSetBackend&);
public:
ResultSetBackend();
void reset()
{
m_created = false;
}
void handle_statement(RouterSession* pSession, GWBUF* pStatement);
virtual RESULT_ROW* create_row(RESULTSET* pResult_set);
static RESULT_ROW* create_row(RESULTSET* pResult_set, void* pThis);
int m_counter;
bool m_created;
};
}
}

View File

@ -13,6 +13,7 @@
#include "maxscale/mock/backend.hh"
#include <algorithm>
#include <maxscale/query_classifier.h>
#include <maxscale/protocol/mysql.h>
#include <iostream>
@ -36,6 +37,19 @@ Backend::~Backend()
{
}
//static
GWBUF* Backend::create_ok_response()
{
/* Note: sequence id is always 01 (4th byte) */
const static uint8_t ok[MYSQL_OK_PACKET_MIN_LEN] =
{ 07, 00, 00, 01, 00, 00, 00, 02, 00, 00, 00 };
GWBUF* pResponse = gwbuf_alloc_and_load(sizeof(ok), &ok);
ss_dassert(pResponse);
return pResponse;
}
//
// BufferBackend
//
@ -138,18 +152,108 @@ OkBackend::OkBackend()
void OkBackend::handle_statement(RouterSession* pSession, GWBUF* pStatement)
{
/* Note: sequence id is always 01 (4th byte) */
const static uint8_t ok[MYSQL_OK_PACKET_MIN_LEN] =
{ 07, 00, 00, 01, 00, 00, 00, 02, 00, 00, 00 };
GWBUF* pResponse = gwbuf_alloc_and_load(sizeof(ok), &ok);
ss_dassert(pResponse);
enqueue_response(pSession, pResponse);
enqueue_response(pSession, create_ok_response());
gwbuf_free(pStatement);
}
//
// ResultSetBackend
//
ResultSetBackend::ResultSetBackend()
: m_counter(0)
, m_created(false)
{
}
namespace
{
class ResultSetDCB : public DCB
{
public:
ResultSetDCB()
{
DCB* pDcb = this;
memset(pDcb, 0, sizeof(*pDcb));
pDcb->func.write = &ResultSetDCB::write;
}
GWBUF* create_response() const
{
return gwbuf_alloc_and_load(m_response.size(), &m_response.front());
}
private:
int32_t write(GWBUF* pBuffer)
{
pBuffer = gwbuf_make_contiguous(pBuffer);
ss_dassert(pBuffer);
unsigned char* begin = GWBUF_DATA(pBuffer);
unsigned char* end = begin + GWBUF_LENGTH(pBuffer);
m_response.insert(m_response.end(), begin, end);
gwbuf_free(pBuffer);
return 1;
}
static int32_t write(DCB* pDcb, GWBUF* pBuffer)
{
return static_cast<ResultSetDCB*>(pDcb)->write(pBuffer);
}
std::vector<char> m_response;
};
}
void ResultSetBackend::handle_statement(RouterSession* pSession, GWBUF* pStatement)
{
qc_query_op_t op = qc_get_operation(pStatement);
if (op == QUERY_OP_SELECT)
{
RESULTSET* pResult_set = resultset_create(ResultSetBackend::create_row, this);
resultset_add_column(pResult_set, "a", 4, COL_TYPE_VARCHAR);
ResultSetDCB dcb;
resultset_stream_mysql(pResult_set, &dcb);
enqueue_response(pSession, dcb.create_response());
}
else
{
enqueue_response(pSession, create_ok_response());
}
}
RESULT_ROW* ResultSetBackend::create_row(RESULTSET* pResult_set)
{
RESULT_ROW* pRow = NULL;
if (!m_created)
{
pRow = resultset_make_row(pResult_set);
char buffer[32];
sprintf(buffer, "%d", ++m_counter);
resultset_row_set(pRow, 0, buffer);
m_created = true;
}
return pRow;
}
//static
RESULT_ROW* ResultSetBackend::create_row(RESULTSET* pResult_set, void* pThis)
{
return static_cast<ResultSetBackend*>(pThis)->create_row(pResult_set);
}
} // mock
} // maxscale