Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract JSON type as string #3491

Merged
merged 4 commits into from
May 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Data/MySQL/include/Poco/Data/MySQL/Extractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ class MySQL_API Extractor: public Poco::Data::AbstractExtractor

bool extractLongLOB(std::size_t pos);

bool extractJSON(std::size_t pos);

// Prevent VC8 warning "operator= could not be generated"
Extractor& operator=(const Extractor&);

Expand Down
22 changes: 20 additions & 2 deletions Data/MySQL/src/Extractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,12 @@ bool Extractor::extract(std::size_t pos, std::string& val)

//mysql reports TEXT types as FDT_BLOB when being extracted
MetaColumn::ColumnDataType columnType = _metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type();
if (columnType != Poco::Data::MetaColumn::FDT_STRING && columnType != Poco::Data::MetaColumn::FDT_BLOB)
if (columnType != Poco::Data::MetaColumn::FDT_STRING && columnType != Poco::Data::MetaColumn::FDT_BLOB && columnType != Poco::Data::MetaColumn::FDT_JSON)
throw MySQLException("Extractor: not a string");

if (columnType == Poco::Data::MetaColumn::FDT_JSON && !extractJSON(pos))
return false;

val.assign(reinterpret_cast<const char*>(_metadata.rawData(pos)), _metadata.length(pos));
return true;
}
Expand All @@ -142,7 +145,7 @@ bool Extractor::extract(std::size_t pos, Poco::Data::BLOB& val)
throw MySQLException("Extractor: attempt to extract more parameters, than query result contain");

if (_metadata.isNull(static_cast<Poco::UInt32>(pos)))
return false;
return false;

if (_metadata.metaColumn(static_cast<Poco::UInt32>(pos)).type() != Poco::Data::MetaColumn::FDT_BLOB)
throw MySQLException("Extractor: not a blob");
Expand Down Expand Up @@ -285,6 +288,21 @@ bool Extractor::extractLongLOB(std::size_t pos)
return true;
}

bool Extractor::extractJSON(std::size_t pos)
{
// JSON columns are fetched with a zero-length
// buffer to avoid allocating huge amounts of memory.
// Therefore, when extracting the buffers need to be adjusted.

_metadata.adjustColumnSizeToFit(pos);

MYSQL_BIND* row = _metadata.row();
row->buffer_type = MYSQL_TYPE_JSON;
if (!_stmt.fetchColumn(pos, &row[pos]))
return false;

return true;
}

//////////////
// Not implemented
Expand Down
3 changes: 3 additions & 0 deletions Data/MySQL/src/ResultMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ namespace
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_JSON:
return field.length;

default:
Expand Down Expand Up @@ -128,6 +129,8 @@ namespace
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
return Poco::Data::MetaColumn::FDT_BLOB;
case MYSQL_TYPE_JSON:
return Poco::Data::MetaColumn::FDT_JSON;
default:
return Poco::Data::MetaColumn::FDT_UNKNOWN;
}
Expand Down
18 changes: 18 additions & 0 deletions Data/MySQL/testsuite/src/MySQLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,14 @@ void MySQLTest::testLongBLOB()
_pExecutor->longBlob();
}

void MySQLTest::testJSON()
{
if (!_pSession) fail("Test not available.");

recreatePersonJSONTable();
_pExecutor->json();
}


void MySQLTest::testUnsignedInts()
{
Expand Down Expand Up @@ -770,6 +778,15 @@ void MySQLTest::recreatePersonLongBLOBTable()
}


void MySQLTest::recreatePersonJSONTable()
{
dropTable("Person");
try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Biography JSON)", now; }
catch (ConnectionException& ce) { std::cout << ce.displayText() << std::endl; fail("recreatePersonLongBLOBTable()"); }
catch (StatementException& se) { std::cout << se.displayText() << std::endl; fail("recreatePersonLongBLOBTable()"); }
}


void MySQLTest::recreateIntsTable()
{
dropTable("Strings");
Expand Down Expand Up @@ -938,6 +955,7 @@ CppUnit::Test* MySQLTest::suite()
//CppUnit_addTest(pSuite, MySQLTest, testBLOB);
CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt);
CppUnit_addTest(pSuite, MySQLTest, testLongBLOB);
CppUnit_addTest(pSuite, MySQLTest, testJSON);
CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts);
CppUnit_addTest(pSuite, MySQLTest, testFloat);
CppUnit_addTest(pSuite, MySQLTest, testDouble);
Expand Down
2 changes: 2 additions & 0 deletions Data/MySQL/testsuite/src/MySQLTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class MySQLTest: public CppUnit::TestCase
void testBLOB();
void testBLOBStmt();
void testLongBLOB();
void testJSON();

void testUnsignedInts();
void testFloat();
Expand Down Expand Up @@ -119,6 +120,7 @@ class MySQLTest: public CppUnit::TestCase
void recreatePersonDateTable();
void recreatePersonTimeTable();
void recreatePersonLongBLOBTable();
void recreatePersonJSONTable();
void recreateStringsTable();
void recreateIntsTable();
void recreateUnsignedIntsTable();
Expand Down
25 changes: 25 additions & 0 deletions Data/MySQL/testsuite/src/SQLExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,31 @@ void SQLExecutor::longBlob()
poco_assert (res == biography);
}

void SQLExecutor::json()
{
std::string funct = "json()";
std::string lastName("lastname");
std::string firstName("firstname");
std::string address("Address");
std::string biography(R"({"biography": {"count": 42, "title": "Lorem Ipsum", "released": true}})");

int count = 0;
Statement ins = (*_pSession << "INSERT INTO Person VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(biography));
ins.execute();
try { *_pSession << "SELECT COUNT(*) FROM Person", into(count), now; }
catch (ConnectionException& ce) { std::cout << ce.displayText() << std::endl; fail(funct); }
catch (StatementException& se) { std::cout << se.displayText() << std::endl; fail(funct); }
assertTrue(count == 1);

Poco::Data::JSON res;
poco_assert(res.size() == 0);
Statement stmt = (*_pSession << "SELECT Biography FROM Person", into(res));
try { stmt.execute(); }
catch (ConnectionException& ce) { std::cout << ce.displayText() << std::endl; fail(funct); }
catch (StatementException& se) { std::cout << se.displayText() << std::endl; fail(funct); }
poco_assert(res == biography);
}


void SQLExecutor::tuples()
{
Expand Down
1 change: 1 addition & 0 deletions Data/MySQL/testsuite/src/SQLExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class SQLExecutor: public CppUnit::TestCase
void date();
void time();
void longBlob();
void json();
void unsignedInts();
void floats();
void doubles();
Expand Down
2 changes: 1 addition & 1 deletion Data/include/Poco/Data/LOB.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ class LOB

using BLOB = LOB<unsigned char>;
using CLOB = LOB<char>;

using JSON = std::string;

//
// inlines
Expand Down
1 change: 1 addition & 0 deletions Data/include/Poco/Data/MetaColumn.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class Data_API MetaColumn
FDT_TIME,
FDT_TIMESTAMP,
FDT_UUID,
FDT_JSON,
FDT_UNKNOWN
};

Expand Down
1 change: 1 addition & 0 deletions Data/src/RecordSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Poco::Dynamic::Var RecordSet::value(std::size_t col, std::size_t row, bool useFi
case MetaColumn::FDT_TIME: return value<Time>(col, row, useFilter);
case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, row);
case MetaColumn::FDT_UUID: return value<UUID>(col, row);
case MetaColumn::FDT_JSON: return value<std::string>(col, row, useFilter);
default:
throw UnknownTypeException("Data type not supported.");
}
Expand Down
2 changes: 2 additions & 0 deletions Data/src/StatementImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ void StatementImpl::makeExtractors(std::size_t count)
addInternalExtract<DateTime>(mc); break;
case MetaColumn::FDT_UUID:
addInternalExtract<UUID>(mc); break;
case MetaColumn::FDT_JSON:
addInternalExtract<std::string>(mc); break;
default:
throw Poco::InvalidArgumentException("Data type not supported.");
}
Expand Down