Skip to content

Commit 5513b71

Browse files
committed
Execute unprepared queries.
1 parent 25d21eb commit 5513b71

File tree

14 files changed

+451
-81
lines changed

14 files changed

+451
-81
lines changed

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
add_library(${OATPP_THIS_MODULE_NAME}
3+
oatpp-postgresql/mapping/type/Uuid.cpp
4+
oatpp-postgresql/mapping/type/Uuid.hpp
35
oatpp-postgresql/mapping/Deserializer.cpp
46
oatpp-postgresql/mapping/Deserializer.hpp
57
oatpp-postgresql/mapping/Oid.hpp
@@ -21,6 +23,7 @@ add_library(${OATPP_THIS_MODULE_NAME}
2123
oatpp-postgresql/Executor.hpp
2224
oatpp-postgresql/QueryResult.cpp
2325
oatpp-postgresql/QueryResult.hpp
26+
oatpp-postgresql/Types.hpp
2427
)
2528

2629
set_target_properties(${OATPP_THIS_MODULE_NAME} PROPERTIES

src/oatpp-postgresql/Executor.cpp

Lines changed: 88 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,44 @@
3535

3636
namespace oatpp { namespace postgresql {
3737

38+
Executor::QueryParams::QueryParams(const StringTemplate& queryTemplate,
39+
const std::unordered_map<oatpp::String, oatpp::Void>& params,
40+
const mapping::TypeMapper& typeMapper,
41+
const mapping::Serializer& serializer)
42+
{
43+
44+
auto extra = std::static_pointer_cast<ql_template::Parser::TemplateExtra>(queryTemplate.getExtraData());
45+
46+
query = extra->preparedTemplate->c_str();
47+
queryName = extra->templateName->c_str();
48+
49+
count = queryTemplate.getTemplateVariables().size();
50+
51+
outData.resize(count);
52+
paramOids.resize(count);
53+
paramValues.resize(count);
54+
paramLengths.resize(count);
55+
paramFormats.resize(count);
56+
57+
for(v_uint32 i = 0; i < count; i ++) {
58+
const auto& var = queryTemplate.getTemplateVariables()[i];
59+
auto it = params.find(var.name);
60+
if(it == params.end()) {
61+
throw std::runtime_error("[oatpp::postgresql::Executor::QueryParams::QueryParams()]: "
62+
"Error. Parameter not found " + var.name->std_str());
63+
}
64+
65+
auto& data = outData[i];
66+
serializer.serialize(data, it->second);
67+
68+
paramOids[i] = typeMapper.getTypeOid(it->second.valueType);
69+
paramValues[i] = data.data;
70+
paramLengths[i] = data.dataSize;
71+
paramFormats[i] = data.dataFormat;
72+
}
73+
74+
}
75+
3876
Executor::Executor(const std::shared_ptr<provider::Provider<Connection>>& connectionProvider)
3977
: m_connectionProvider(connectionProvider)
4078
, m_resultMapper(std::make_shared<mapping::ResultMapper>())
@@ -71,69 +109,67 @@ std::shared_ptr<QueryResult> Executor::prepareQuery(const StringTemplate& queryT
71109
queryTemplate.getTemplateVariables().size(),
72110
extra->paramTypes.get());
73111

74-
return std::make_shared<QueryResult>(qres, connection, m_resultMapper);
112+
return std::make_shared<QueryResult>(qres, connection, m_connectionProvider, m_resultMapper);
75113

76114
}
77115

78-
std::shared_ptr<QueryResult> Executor::executeQuery(const StringTemplate& queryTemplate,
79-
const std::unordered_map<oatpp::String, oatpp::Void>& params,
80-
const std::shared_ptr<postgresql::Connection>& connection)
116+
std::shared_ptr<QueryResult> Executor::executeQueryPrepared(const StringTemplate& queryTemplate,
117+
const std::unordered_map<oatpp::String, oatpp::Void>& params,
118+
const std::shared_ptr<postgresql::Connection>& connection)
81119
{
82120

83-
auto extra = std::static_pointer_cast<ql_template::Parser::TemplateExtra>(queryTemplate.getExtraData());
84-
85-
v_uint32 paramsNumber = queryTemplate.getTemplateVariables().size();
121+
QueryParams queryParams(queryTemplate, params, m_typeMapper, m_serializer);
86122

87-
std::vector<mapping::Serializer::OutputData> outData(paramsNumber);
123+
PGresult *qres = PQexecPrepared(connection->getHandle(),
124+
queryParams.queryName,
125+
queryParams.count,
126+
queryParams.paramValues.data(),
127+
queryParams.paramLengths.data(),
128+
queryParams.paramFormats.data(),
129+
1);
88130

89-
std::unique_ptr<const char* []> paramValues(new const char*[paramsNumber]);
90-
std::unique_ptr<int[]> paramLengths(new int[paramsNumber]);
91-
std::unique_ptr<int[]> paramFormats(new int[paramsNumber]);
131+
return std::make_shared<QueryResult>(qres, connection, m_connectionProvider, m_resultMapper);
92132

93-
for(v_uint32 i = 0; i < paramsNumber; i ++) {
94-
const auto& var = queryTemplate.getTemplateVariables()[i];
95-
auto it = params.find(var.name);
96-
if(it == params.end()) {
97-
throw std::runtime_error("[oatpp::postgresql::Executor::executeQuery()]: "
98-
"Error. Parameter not found " + var.name->std_str());
99-
}
133+
}
100134

101-
auto& data = outData[i];
102-
m_serializer.serialize(data, it->second);
135+
std::shared_ptr<QueryResult> Executor::executeQuery(const StringTemplate& queryTemplate,
136+
const std::unordered_map<oatpp::String, oatpp::Void>& params,
137+
const std::shared_ptr<postgresql::Connection>& connection)
138+
{
103139

104-
paramValues[i] = data.data;
105-
paramLengths[i] = data.dataSize;
106-
paramFormats[i] = data.dataFormat;
107-
}
140+
QueryParams queryParams(queryTemplate, params, m_typeMapper, m_serializer);
108141

109-
PGresult *qres = PQexecPrepared(connection->getHandle(),
110-
extra->templateName->c_str(),
111-
paramsNumber,
112-
paramValues.get(),
113-
paramLengths.get(),
114-
paramFormats.get(),
115-
1);
142+
PGresult *qres = PQexecParams(connection->getHandle(),
143+
queryParams.query,
144+
queryParams.count,
145+
queryParams.paramOids.data(),
146+
queryParams.paramValues.data(),
147+
queryParams.paramLengths.data(),
148+
queryParams.paramFormats.data(),
149+
1);
116150

117-
return std::make_shared<QueryResult>(qres, connection, m_resultMapper);
151+
return std::make_shared<QueryResult>(qres, connection, m_connectionProvider, m_resultMapper);
118152

119153
}
120154

121155
data::share::StringTemplate Executor::parseQueryTemplate(const oatpp::String& name,
122156
const oatpp::String& text,
123-
const ParamsTypeMap& paramsTypeMap)
157+
const ParamsTypeMap& paramsTypeMap,
158+
bool prepare)
124159
{
125160

126161
auto&& t = ql_template::Parser::parseTemplate(text);
127162

128163
auto extra = std::make_shared<ql_template::Parser::TemplateExtra>();
129-
extra->templateName = name;
164+
t.setExtraData(extra);
130165

166+
extra->templateName = name;
131167
ql_template::TemplateValueProvider valueProvider;
132168
extra->preparedTemplate = t.format(&valueProvider);
133169

134-
extra->paramTypes = getParamTypes(t, paramsTypeMap);
135-
136-
t.setExtraData(extra);
170+
if(prepare) {
171+
extra->paramTypes = getParamTypes(t, paramsTypeMap);
172+
}
137173

138174
return t;
139175

@@ -145,7 +181,8 @@ std::shared_ptr<orm::Connection> Executor::getConnection() {
145181

146182
std::shared_ptr<orm::QueryResult> Executor::execute(const StringTemplate& queryTemplate,
147183
const std::unordered_map<oatpp::String, oatpp::Void>& params,
148-
const std::shared_ptr<orm::Connection>& connection)
184+
const std::shared_ptr<orm::Connection>& connection,
185+
bool prepare)
149186
{
150187

151188
std::shared_ptr<orm::Connection> conn = connection;
@@ -157,9 +194,19 @@ std::shared_ptr<orm::QueryResult> Executor::execute(const StringTemplate& queryT
157194

158195
auto extra = std::static_pointer_cast<ql_template::Parser::TemplateExtra>(queryTemplate.getExtraData());
159196

160-
if(!pgConnection->isPrepared(extra->templateName)) {
161-
prepareQuery(queryTemplate, pgConnection);
162-
pgConnection->setPrepared(extra->templateName);
197+
if(prepare) {
198+
199+
if (!pgConnection->isPrepared(extra->templateName)) {
200+
auto result = prepareQuery(queryTemplate, pgConnection);
201+
if(result->isSuccess()) {
202+
pgConnection->setPrepared(extra->templateName);
203+
} else {
204+
return result;
205+
}
206+
}
207+
208+
return executeQueryPrepared(queryTemplate, params, pgConnection);
209+
163210
}
164211

165212
return executeQuery(queryTemplate, params, pgConnection);

src/oatpp-postgresql/Executor.hpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,49 @@
3535
#include "oatpp/orm/Executor.hpp"
3636
#include "oatpp/core/parser/Caret.hpp"
3737

38+
#include <vector>
39+
3840
namespace oatpp { namespace postgresql {
3941

4042
class Executor : public orm::Executor {
43+
private:
44+
45+
class QueryParams {
46+
private:
47+
std::vector<mapping::Serializer::OutputData> outData;
48+
public:
49+
50+
QueryParams(const StringTemplate& queryTemplate,
51+
const std::unordered_map<oatpp::String, oatpp::Void>& params,
52+
const mapping::TypeMapper& typeMapper,
53+
const mapping::Serializer& serializer);
54+
55+
int count;
56+
57+
const char* query;
58+
const char* queryName;
59+
60+
std::vector<Oid> paramOids;
61+
std::vector<const char*> paramValues;
62+
std::vector<int> paramLengths;
63+
std::vector<int> paramFormats;
64+
65+
};
66+
4167
private:
4268
std::unique_ptr<Oid[]> getParamTypes(const StringTemplate& queryTemplate, const ParamsTypeMap& paramsTypeMap);
4369

4470
std::shared_ptr<QueryResult> prepareQuery(const StringTemplate& queryTemplate,
4571
const std::shared_ptr<postgresql::Connection>& connection);
4672

73+
std::shared_ptr<QueryResult> executeQueryPrepared(const StringTemplate& queryTemplate,
74+
const std::unordered_map<oatpp::String, oatpp::Void>& params,
75+
const std::shared_ptr<postgresql::Connection>& connection);
76+
4777
std::shared_ptr<QueryResult> executeQuery(const StringTemplate& queryTemplate,
4878
const std::unordered_map<oatpp::String, oatpp::Void>& params,
4979
const std::shared_ptr<postgresql::Connection>& connection);
80+
5081
private:
5182
std::shared_ptr<provider::Provider<Connection>> m_connectionProvider;
5283
std::shared_ptr<mapping::ResultMapper> m_resultMapper;
@@ -58,13 +89,15 @@ class Executor : public orm::Executor {
5889

5990
StringTemplate parseQueryTemplate(const oatpp::String& name,
6091
const oatpp::String& text,
61-
const ParamsTypeMap& paramsTypeMap) override;
92+
const ParamsTypeMap& paramsTypeMap,
93+
bool prepare) override;
6294

6395
std::shared_ptr<orm::Connection> getConnection() override;
6496

6597
std::shared_ptr<orm::QueryResult> execute(const StringTemplate& queryTemplate,
6698
const std::unordered_map<oatpp::String, oatpp::Void>& params,
67-
const std::shared_ptr<orm::Connection>& connection) override;
99+
const std::shared_ptr<orm::Connection>& connection,
100+
bool prepare) override;
68101

69102
};
70103

src/oatpp-postgresql/QueryResult.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,21 @@ namespace oatpp { namespace postgresql {
2828

2929
QueryResult::QueryResult(PGresult* dbResult,
3030
const std::shared_ptr<Connection>& connection,
31+
const std::shared_ptr<provider::Provider<Connection>>& connectionProvider,
3132
const std::shared_ptr<mapping::ResultMapper>& resultMapper)
3233
: m_dbResult(dbResult)
3334
, m_connection(connection)
35+
, m_connectionProvider(connectionProvider)
3436
, m_resultMapper(resultMapper)
3537
, m_resultData(dbResult)
3638
{
3739
auto status = PQresultStatus(m_dbResult);
3840
switch(status) {
41+
42+
case PGRES_SINGLE_TUPLE: {
43+
throw std::runtime_error("[oatpp::postgresql::QueryResult::QueryResult()]: Error. Single-row mode is not supported!");
44+
}
45+
3946
case PGRES_TUPLES_OK: {
4047
m_success = true;
4148
m_type = TYPE_TUPLES;
@@ -51,7 +58,11 @@ QueryResult::QueryResult(PGresult* dbResult,
5158
default: {
5259
m_success = false;
5360
m_type = TYPE_ERROR;
61+
if(status == PGRES_FATAL_ERROR) {
62+
m_connectionProvider->invalidate(m_connection);
63+
}
5464
}
65+
5566
}
5667
}
5768

@@ -63,6 +74,14 @@ bool QueryResult::isSuccess() const {
6374
return m_success;
6475
}
6576

77+
oatpp::String QueryResult::getErrorMessage() const {
78+
if(!m_success) {
79+
auto pgConnection = std::static_pointer_cast<postgresql::Connection>(m_connection);
80+
return PQerrorMessage(pgConnection->getHandle());
81+
}
82+
return nullptr;
83+
}
84+
6685
v_int64 QueryResult::position() const {
6786
return m_resultData.rowIndex;
6887
}

src/oatpp-postgresql/QueryResult.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class QueryResult : public orm::QueryResult {
4040
private:
4141
PGresult* m_dbResult;
4242
std::shared_ptr<Connection> m_connection;
43+
std::shared_ptr<provider::Provider<Connection>> m_connectionProvider;
4344
std::shared_ptr<mapping::ResultMapper> m_resultMapper;
4445
mapping::ResultMapper::ResultData m_resultData;
4546
bool m_success;
@@ -50,12 +51,15 @@ class QueryResult : public orm::QueryResult {
5051

5152
QueryResult(PGresult* dbResult,
5253
const std::shared_ptr<Connection>& connection,
54+
const std::shared_ptr<provider::Provider<Connection>>& connectionProvider,
5355
const std::shared_ptr<mapping::ResultMapper>& resultMapper);
5456

5557
~QueryResult();
5658

5759
bool isSuccess() const override;
5860

61+
oatpp::String getErrorMessage() const override;
62+
5963
v_int64 position() const override;
6064

6165
v_int64 count() const override;

src/oatpp-postgresql/Types.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/***************************************************************************
2+
*
3+
* Project _____ __ ____ _ _
4+
* ( _ ) /__\ (_ _)_| |_ _| |_
5+
* )(_)( /(__)\ )( (_ _)(_ _)
6+
* (_____)(__)(__)(__) |_| |_|
7+
*
8+
*
9+
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
10+
*
11+
* Licensed under the Apache License, Version 2.0 (the "License");
12+
* you may not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing, software
18+
* distributed under the License is distributed on an "AS IS" BASIS,
19+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20+
* See the License for the specific language governing permissions and
21+
* limitations under the License.
22+
*
23+
***************************************************************************/
24+
25+
#ifndef oatpp_postgresql_Types_hpp
26+
#define oatpp_postgresql_Types_hpp
27+
28+
#include "mapping/type/Uuid.hpp"
29+
30+
namespace oatpp { namespace postgresql {
31+
32+
/**
33+
* Uuid as oatpp primitive type.
34+
*/
35+
typedef oatpp::data::mapping::type::Primitive<mapping::type::Uuid, mapping::type::__class::Uuid> Uuid;
36+
37+
}}
38+
39+
#endif // oatpp_postgresql_Types_hpp

0 commit comments

Comments
 (0)