Line data Source code
1 : /*
2 : * Text:
3 : * libsnapwebsites/src/libdbprox/order_result.cpp
4 : *
5 : * Description:
6 : * Handle receiving results from a CQL order sent to snapdbproxy.
7 : *
8 : * Documentation:
9 : * See each function below.
10 : *
11 : * License:
12 : * Copyright (c) 2011-2019 Made to Order Software Corp. All Rights Reserved
13 : *
14 : * https://snapwebsites.org/
15 : * contact@m2osw.com
16 : *
17 : * Permission is hereby granted, free of charge, to any person obtaining a
18 : * copy of this software and associated documentation files (the
19 : * "Software"), to deal in the Software without restriction, including
20 : * without limitation the rights to use, copy, modify, merge, publish,
21 : * distribute, sublicense, and/or sell copies of the Software, and to
22 : * permit persons to whom the Software is furnished to do so, subject to
23 : * the following conditions:
24 : *
25 : * The above copyright notice and this permission notice shall be included
26 : * in all copies or substantial portions of the Software.
27 : *
28 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
31 : * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
32 : * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
33 : * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
34 : * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 : */
36 :
37 : //#pragma GCC push
38 : //#pragma GCC diagnostic ignored "-Wundef"
39 : //#include <sys/time.h>
40 : //#pragma GCC pop
41 :
42 : #include "libdbproxy/exception.h"
43 : #include "libdbproxy/proxy.h"
44 : #include "libdbproxy/value.h"
45 :
46 : #include <QtCore>
47 :
48 : #include <iostream>
49 : #include <sstream>
50 :
51 : #include <unistd.h>
52 :
53 :
54 : namespace libdbproxy
55 : {
56 :
57 :
58 : /** \brief Check whether the result represents a success or not.
59 : *
60 : * When you send an order to the snapdbproxy, the result may be a
61 : * failure. If this flag is false, then the result represents an
62 : * error and not the otherwise expected results from the order
63 : * sent.
64 : *
65 : * \return true if the order was successful.
66 : */
67 0 : bool order_result::succeeded() const
68 : {
69 0 : return f_succeeded;
70 : }
71 :
72 :
73 : /** \brief Set whether the result was a success or not.
74 : *
75 : * This function can beused to set the succeeded flag to true
76 : * (i.e. the CQL order succeeded) or false (the CQL order
77 : * or something in between failed.)
78 : *
79 : * \param[in] success The new value of the succeeded flag.
80 : */
81 0 : void order_result::setSucceeded(bool success)
82 : {
83 0 : f_succeeded = success;
84 0 : }
85 :
86 :
87 : /** \brief Retrieve the number of results present in this object.
88 : *
89 : * In general you want to use this function to know how far your index
90 : * can go while calling the result() function.
91 : *
92 : * \return The number of results available in this object. It may be zero.
93 : *
94 : * \sa result()
95 : */
96 0 : size_t order_result::resultCount() const
97 : {
98 0 : return f_result.size();
99 : }
100 :
101 :
102 : /** \brief Retrieve a result blob.
103 : *
104 : * This function is used to read back a resulting blob.
105 : *
106 : * \exception overflow_exception
107 : * The index must be between 0 and resultCount() - 1 or the
108 : * function raises this exception.
109 : *
110 : * \return A reference to a QByteArray representing this result data.
111 : *
112 : * \sa resultCount()
113 : */
114 0 : QByteArray const & order_result::result(int index) const
115 : {
116 0 : if(static_cast<size_t>(index) >= f_result.size())
117 : {
118 0 : throw overflow_exception("order_result::result() called with an index too large.");
119 : }
120 0 : return f_result[index];
121 : }
122 :
123 :
124 : /** \brief Add one result.
125 : *
126 : * This function adds one block of data representing a result.
127 : *
128 : * \param[in] data A blob representing a result (i.e. maybe a cell).
129 : */
130 0 : void order_result::addResult(QByteArray const & data)
131 : {
132 0 : f_result.push_back(data);
133 0 : }
134 :
135 :
136 : /** \brief Encode a set of results to be sent back to the client.
137 : *
138 : * This function is used by the snapdbproxy daemon to encode the results
139 : * and sent them to the client.
140 : *
141 : * \return A blob that the snapdbproxy can send to the client.
142 : */
143 0 : QByteArray order_result::encodeResult() const
144 : {
145 0 : if(f_result.size() > 65535)
146 : {
147 0 : throw exception("result has too make values, limit is 64Kb - 1 value (a maximum of about 20,000 rows in one go)");
148 : }
149 :
150 : // the expected size of the final buffer, to avoid realloc() calls,
151 : // possibly many such calls, we use the final size in a reserve()
152 : // before adding the data
153 : //
154 0 : uint32_t expected_size(4 + 4 + 2);
155 0 : for(auto r : f_result)
156 : {
157 0 : expected_size += 4 + r.size();
158 : }
159 0 : QCassandraEncoder encoder(expected_size);
160 :
161 : // success or failure is encoded in the 4 letter we first send
162 : // when replying to the client
163 : //
164 0 : if(f_succeeded)
165 : {
166 0 : encoder.appendSignedCharValue('S');
167 0 : encoder.appendSignedCharValue('U');
168 0 : encoder.appendSignedCharValue('C');
169 0 : encoder.appendSignedCharValue('S');
170 : }
171 : else
172 : {
173 0 : encoder.appendSignedCharValue('E');
174 0 : encoder.appendSignedCharValue('R');
175 0 : encoder.appendSignedCharValue('O');
176 0 : encoder.appendSignedCharValue('R');
177 : }
178 :
179 : // we already have the size, contrary to the order, this size does
180 : // not vary depending on certain flags, so we can directly save the
181 : // correct value at once
182 : //
183 0 : encoder.appendUInt32Value(expected_size - 8);
184 :
185 : // save the number of result buffers
186 : //
187 : // then save each result with its size followed by its data
188 : //
189 0 : encoder.appendUInt16Value(f_result.size());
190 0 : for(auto r : f_result)
191 : {
192 0 : encoder.appendBinaryValue(r);
193 : }
194 :
195 : #ifdef _DEBUG
196 0 : if(encoder.size() != expected_size)
197 : {
198 0 : throw logic_exception( "order_result::encodeResult(): the expected and encoded sizes do not match..." );
199 : }
200 : #endif
201 :
202 0 : return encoder.result();
203 : }
204 :
205 :
206 : /** \brief Decode a set of result buffers.
207 : *
208 : * This function is the opposite of the encodeResult() function. It is
209 : * used by the client to decode results sent to it by the snapdbproxy
210 : * daemon.
211 : *
212 : * \exception exception
213 : * If the buffer is of the wrong size, the reading of the data will
214 : * fail raising this exception. We may later add a try/catch within
215 : * this function to return false instead. Yet, if the order is wrong
216 : * we are going to have a hard time reading the next buffer. Plus,
217 : * if things work as expected, synchronizing the input should never
218 : * be required.
219 : *
220 : * \param[in] encoded_result A pointer to the raw data just read from
221 : * the socket.
222 : * \param[in] size The number of bytes in encoded_result.
223 : *
224 : * \return true if the function worked successfully.
225 : */
226 0 : bool order_result::decodeResult(unsigned char const * encoded_result, size_t size)
227 : {
228 : // WARNING: Here I use the horrible fromRawData() function which does
229 : // NOT copy the data to be checked here. However, that gives
230 : // me full access to the value functions against
231 : // QByteArray which is practical.
232 : //
233 : // Just make sure to only use that 'decoder' buffer in this
234 : // function. Do not pass it anywhere, or worst, return it!
235 : //
236 0 : QCassandraDecoder const decoder(QByteArray::fromRawData(reinterpret_cast<char const *>(encoded_result), size));
237 :
238 : // read the number of parameters that were included
239 : // this may be zero
240 : //
241 0 : size_t const result_count(decoder.uint16Value());
242 0 : for(size_t idx(0); idx < result_count; ++idx)
243 : {
244 : // read this parameter data and immediately push it in the
245 : // list of parameters
246 : //
247 0 : f_result.push_back(decoder.binaryValue());
248 : }
249 :
250 0 : return true;
251 : }
252 :
253 :
254 0 : void order_result::swap(order_result& rhs)
255 : {
256 0 : std::swap(f_succeeded, rhs.f_succeeded);
257 0 : f_result.swap(rhs.f_result);
258 0 : }
259 :
260 :
261 :
262 6 : } // namespace libdbproxy
263 : // vim: ts=4 sw=4 et
|