1//
2// StatementExecutor.cpp
3//
4// Library: SQL/MySQL
5// Package: MySQL
6// Module: StatementExecutor
7//
8// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include <mysql.h>
16#include "Poco/SQL/MySQL/StatementExecutor.h"
17#include "Poco/Format.h"
18
19
20namespace Poco {
21namespace SQL {
22namespace MySQL {
23
24
25StatementExecutor::StatementExecutor(MYSQL* mysql)
26 : _pSessionHandle(mysql)
27 , _affectedRowCount(0)
28{
29 if ((_pHandle = mysql_stmt_init(mysql)) == 0)
30 throw StatementException("mysql_stmt_init error");
31
32 _state = STMT_INITED;
33}
34
35
36StatementExecutor::~StatementExecutor()
37{
38 mysql_stmt_close(_pHandle);
39}
40
41
42int StatementExecutor::state() const
43{
44 return _state;
45}
46
47
48void StatementExecutor::prepare(const std::string& query)
49{
50 if (_state >= STMT_COMPILED)
51 {
52 _state = STMT_COMPILED;
53 return;
54 }
55
56 int rc = mysql_stmt_prepare(_pHandle, query.c_str(), static_cast<unsigned int>(query.length()));
57 if (rc != 0)
58 {
59 // retry if connection lost
60 int err = mysql_errno(_pSessionHandle);
61 if (err == 2006 /* CR_SERVER_GONE_ERROR */ || err == 2013 /* CR_SERVER_LOST */)
62 {
63 rc = mysql_stmt_prepare(_pHandle, query.c_str(), static_cast<unsigned int>(query.length()));
64 }
65 }
66 if (rc != 0) throw StatementException("mysql_stmt_prepare error", _pHandle, query);
67
68 _query = query;
69 _state = STMT_COMPILED;
70}
71
72
73void StatementExecutor::bindParams(MYSQL_BIND* params, std::size_t count)
74{
75 if (_state < STMT_COMPILED)
76 throw StatementException("Statement is not compiled yet");
77
78 if (count != mysql_stmt_param_count(_pHandle))
79 throw StatementException("wrong bind parameters count", 0, _query);
80
81 if (count == 0) return;
82
83 if (mysql_stmt_bind_param(_pHandle, params) != 0)
84 throw StatementException("mysql_stmt_bind_param() error ", _pHandle, _query);
85}
86
87
88void StatementExecutor::bindResult(MYSQL_BIND* result)
89{
90 if (_state < STMT_COMPILED)
91 throw StatementException("Statement is not compiled yet");
92
93 if (mysql_stmt_bind_result(_pHandle, result) != 0)
94 throw StatementException("mysql_stmt_bind_result error ", _pHandle, _query);
95}
96
97
98void StatementExecutor::execute()
99{
100 if (_state < STMT_COMPILED)
101 throw StatementException("Statement is not compiled yet");
102
103 if (mysql_stmt_execute(_pHandle) != 0)
104 throw StatementException("mysql_stmt_execute error", _pHandle, _query);
105
106 _state = STMT_EXECUTED;
107
108 my_ulonglong affectedRows = mysql_affected_rows(_pSessionHandle);
109 if (affectedRows != ((my_ulonglong) - 1))
110 _affectedRowCount = static_cast<int>(affectedRows); //Was really a DELETE, UPDATE or INSERT statement
111}
112
113
114bool StatementExecutor::fetch()
115{
116 if (_state < STMT_EXECUTED)
117 throw StatementException("Statement is not executed yet");
118
119 int res = mysql_stmt_fetch(_pHandle);
120
121 // we have specified zero buffers for BLOBs, so DATA_TRUNCATED is normal in this case
122 if ((res != 0) && (res != MYSQL_NO_DATA) && (res != MYSQL_DATA_TRUNCATED))
123 throw StatementException("mysql_stmt_fetch error", _pHandle, _query);
124
125 return (res == 0) || (res == MYSQL_DATA_TRUNCATED);
126}
127
128
129bool StatementExecutor::fetchColumn(std::size_t n, MYSQL_BIND *bind)
130{
131 if (_state < STMT_EXECUTED)
132 throw StatementException("Statement is not executed yet");
133
134 int res = mysql_stmt_fetch_column(_pHandle, bind, static_cast<unsigned int>(n), 0);
135
136 if ((res != 0) && (res != MYSQL_NO_DATA))
137 throw StatementException(Poco::format("mysql_stmt_fetch_column(%z) error", n), _pHandle, _query);
138
139 return (res == 0);
140}
141
142int StatementExecutor::getAffectedRowCount() const
143{
144 return _affectedRowCount;
145}
146
147
148}}}
149