remove operator-> from String
[hiphop-php.git] / hphp / runtime / vm / repo-helpers.cpp
blobe1e0b7b5edebde6b0db5d110d7394a746810b841
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/repo-helpers.h"
18 #include "hphp/runtime/vm/repo.h"
19 #include "hphp/runtime/vm/blob-helper.h"
20 #include "hphp/runtime/base/builtin-functions.h"
22 namespace HPHP {
24 TRACE_SET_MOD(hhbc);
26 //==============================================================================
27 // RepoStmt.
29 RepoStmt::RepoStmt(Repo& repo)
30 : m_repo(repo), m_stmt(nullptr) {
33 RepoStmt::~RepoStmt() {
34 finalize();
37 void RepoStmt::finalize() {
38 if (m_stmt != nullptr) {
39 m_sql.clear();
40 sqlite3_finalize(m_stmt);
41 m_stmt = nullptr;
45 void RepoStmt::prepare(const std::string& sql) {
46 finalize();
47 m_sql = sql;
48 int rc = sqlite3_prepare_v2(m_repo.dbc(), sql.c_str(), sql.size(), &m_stmt,
49 nullptr);
50 if (rc != SQLITE_OK) {
51 throw RepoExc("RepoStmt::%s(repo=%p) error: '%s' --> (%d) %s\n",
52 __func__, &m_repo, sql.c_str(), rc,
53 sqlite3_errmsg(m_repo.dbc()));
57 void RepoStmt::reset() {
58 sqlite3_reset(m_stmt);
59 sqlite3_clear_bindings(m_stmt);
62 //==============================================================================
63 // RepoTxn.
65 RepoTxn::RepoTxn(Repo& repo)
66 : m_repo(repo), m_pending(true), m_error(false) {
67 try {
68 m_repo.begin();
69 } catch (RepoExc& re) {
70 rollback();
71 throw;
75 RepoTxn::~RepoTxn() {
76 if (m_pending) {
77 rollback();
81 void RepoTxn::prepare(RepoStmt& stmt, const std::string& sql) {
82 try {
83 stmt.prepare(sql);
84 } catch (const std::exception&) {
85 rollback();
86 throw;
90 void RepoTxn::exec(const std::string& sQuery) {
91 try {
92 m_repo.exec(sQuery);
93 } catch (const std::exception& e) {
94 rollback();
95 TRACE(4, "RepoTxn::%s(repo=%p) caught '%s'\n",
96 __func__, &m_repo, e.what());
97 throw;
101 void RepoTxn::commit() {
102 if (m_pending) {
103 try {
104 m_repo.commit();
105 } catch (const std::exception& e) {
106 rollback();
107 TRACE(4, "RepoTxn::%s(repo=%p) caught '%s'\n",
108 __func__, &m_repo, e.what());
109 throw;
111 m_pending = false;
115 void RepoTxn::step(RepoQuery& query) {
116 try {
117 query.step();
118 } catch (const std::exception&) {
119 rollback();
120 throw;
124 void RepoTxn::exec(RepoQuery& query) {
125 try {
126 query.exec();
127 } catch (const std::exception& e) {
128 rollback();
129 TRACE(4, "RepoTxn::%s(repo=%p) caught '%s'\n",
130 __func__, &m_repo, e.what());
131 throw;
135 void RepoTxn::rollback() {
136 assert(!m_error);
137 assert(m_pending);
138 m_error = true;
139 m_pending = false;
140 m_repo.rollback();
143 //==============================================================================
144 // RepoQuery.
146 void RepoQuery::bindBlob(const char* paramName, const void* blob,
147 size_t size, bool isStatic /* = false */) {
148 sqlite3_stmt* stmt = m_stmt.get();
149 int rc UNUSED =
150 sqlite3_bind_blob(stmt,
151 sqlite3_bind_parameter_index(stmt, paramName),
152 blob, int(size),
153 isStatic ? SQLITE_STATIC : SQLITE_TRANSIENT);
154 assert(rc == SQLITE_OK);
157 void RepoQuery::bindBlob(const char* paramName, const BlobEncoder& blob,
158 bool isStatic) {
159 return bindBlob(paramName, blob.data(), blob.size(), isStatic);
162 void RepoQuery::bindMd5(const char* paramName, const MD5& md5) {
163 char md5nbo[16];
164 md5.nbo((void*)md5nbo);
165 bindBlob(paramName, md5nbo, sizeof(md5nbo));
168 void RepoQuery::bindTypedValue(const char* paramName, const TypedValue& tv) {
169 if (tv.m_type == KindOfUninit) {
170 bindBlob(paramName, "", 0, true);
171 } else {
172 String blob = f_serialize(tvAsCVarRef(&tv));
173 bindBlob(paramName, blob.data(), blob.size());
177 void RepoQuery::bindText(const char* paramName, const char* text,
178 size_t size, bool isStatic /* = false */) {
179 sqlite3_stmt* stmt = m_stmt.get();
180 int rc UNUSED =
181 sqlite3_bind_text(stmt,
182 sqlite3_bind_parameter_index(stmt, paramName),
183 text, int(size),
184 isStatic ? SQLITE_STATIC : SQLITE_TRANSIENT);
185 assert(rc == SQLITE_OK);
188 void RepoQuery::bindStaticString(const char* paramName, const StringData* sd) {
189 if (sd == nullptr) {
190 bindNull(paramName);
191 } else {
192 bindText(paramName, sd->data(), sd->size(), true);
196 void RepoQuery::bindStdString(const char* paramName, const std::string& s) {
197 bindText(paramName, s.data(), s.size(), true);
200 void RepoQuery::bindDouble(const char* paramName, double val) {
201 sqlite3_stmt* stmt = m_stmt.get();
202 int rc UNUSED =
203 sqlite3_bind_double(stmt,
204 sqlite3_bind_parameter_index(stmt, paramName),
205 val);
206 assert(rc == SQLITE_OK);
209 void RepoQuery::bindInt(const char* paramName, int val) {
210 sqlite3_stmt* stmt = m_stmt.get();
211 int rc UNUSED =
212 sqlite3_bind_int(stmt,
213 sqlite3_bind_parameter_index(stmt, paramName),
214 val);
215 assert(rc == SQLITE_OK);
218 void RepoQuery::bindId(const char* paramName, Id id) {
219 bindInt(paramName, int(id));
222 void RepoQuery::bindOffset(const char* paramName, Offset offset) {
223 bindInt(paramName, int(offset));
226 void RepoQuery::bindAttr(const char* paramName, Attr attrs) {
227 bindInt(paramName, int(attrs));
230 void RepoQuery::bindBool(const char* paramName, bool b) {
231 bindInt(paramName, int(b));
234 void RepoQuery::bindInt64(const char* paramName, int64_t val) {
235 sqlite3_stmt* stmt = m_stmt.get();
236 int rc UNUSED =
237 sqlite3_bind_int64(stmt,
238 sqlite3_bind_parameter_index(stmt, paramName),
239 val);
240 assert(rc == SQLITE_OK);
243 void RepoQuery::bindNull(const char* paramName) {
244 sqlite3_stmt* stmt = m_stmt.get();
245 int rc UNUSED =
246 sqlite3_bind_null(stmt,
247 sqlite3_bind_parameter_index(stmt, paramName));
248 assert(rc == SQLITE_OK);
251 void RepoQuery::step() {
252 if (m_done) {
253 throw RepoExc("RepoQuery::%s(repo=%p) error: Query done",
254 __func__, &m_stmt.repo());
256 int rc = sqlite3_step(m_stmt.get());
257 switch (rc) {
258 case SQLITE_DONE:
259 m_row = false;
260 m_done = true;
261 break;
262 case SQLITE_ROW:
263 m_row = true;
264 m_done = false;
265 break;
266 default:
267 m_row = false;
268 m_done = true;
269 throw RepoExc("RepoQuery::%s(repo=%p) error: '%s' --> (%d) %s",
270 __func__, &m_stmt.repo(), m_stmt.sql().c_str(), rc,
271 sqlite3_errmsg(m_stmt.repo().dbc()));
275 void RepoQuery::reset() {
276 m_stmt.reset();
277 m_row = false;
278 m_done = false;
281 void RepoQuery::exec() {
282 step();
283 reset();
286 int64_t RepoQuery::getInsertedRowid() {
287 return sqlite3_last_insert_rowid(m_stmt.repo().dbc());
290 bool RepoQuery::isBlob(int iCol) {
291 return (iCol < sqlite3_data_count(m_stmt.get())
292 && sqlite3_column_type(m_stmt.get(), iCol) == SQLITE_BLOB);
295 bool RepoQuery::isText(int iCol) {
296 return (iCol < sqlite3_data_count(m_stmt.get())
297 && sqlite3_column_type(m_stmt.get(), iCol) == SQLITE_TEXT);
300 bool RepoQuery::isDouble(int iCol) {
301 return (iCol < sqlite3_data_count(m_stmt.get())
302 && sqlite3_column_type(m_stmt.get(), iCol) == SQLITE_FLOAT);
305 bool RepoQuery::isInt(int iCol) {
306 return (iCol < sqlite3_data_count(m_stmt.get())
307 && sqlite3_column_type(m_stmt.get(), iCol) == SQLITE_INTEGER);
310 bool RepoQuery::isNull(int iCol) {
311 return (iCol < sqlite3_data_count(m_stmt.get())
312 && sqlite3_column_type(m_stmt.get(), iCol) == SQLITE_NULL);
315 void RepoQuery::getBlob(int iCol, const void*& blob, size_t& size) {
316 if (!isBlob(iCol)) {
317 throw RepoExc(
318 "RepoQuery::%s(repo=%p) error: Column %d is not a blob in '%s'",
319 __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
321 blob = sqlite3_column_blob(m_stmt.get(), iCol);
322 size = size_t(sqlite3_column_bytes(m_stmt.get(), iCol));
325 BlobDecoder RepoQuery::getBlob(int iCol) {
326 const void* vp;
327 size_t sz;
328 getBlob(iCol, vp, sz);
329 return BlobDecoder(vp, sz);
332 void RepoQuery::getMd5(int iCol, MD5& md5) {
333 const void* blob;
334 size_t size;
335 getBlob(iCol, blob, size);
336 if (size != 16) {
337 throw RepoExc(
338 "RepoQuery::%s(repo=%p) error: Column %d is the wrong size"
339 " (expected 16, got %zu) in '%s'",
340 __func__, &m_stmt.repo(), iCol, size, m_stmt.sql().c_str());
342 new (&md5) MD5(blob);
345 void RepoQuery::getTypedValue(int iCol, TypedValue& tv) {
346 const void* blob;
347 size_t size;
348 getBlob(iCol, blob, size);
349 tvWriteUninit(&tv);
350 if (size > 0) {
351 String s = String((const char*)blob, size, CopyString);
352 Variant v = unserialize_from_string(s);
353 if (v.isString()) {
354 v = String(makeStaticString(v.asCStrRef().get()));
355 } else if (v.isArray()) {
356 v = Array(ArrayData::GetScalarArray(v.asCArrRef().get()));
357 } else {
358 // Serialized variants and objects shouldn't ever make it into the repo.
359 assert(!IS_REFCOUNTED_TYPE(v.getType()));
361 tvAsVariant(&tv) = v;
365 void RepoQuery::getText(int iCol, const char*& text) {
366 if (!isText(iCol)) {
367 throw RepoExc(
368 "RepoQuery::%s(repo=%p) error: Column %d is not text in '%s'",
369 __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
371 text = (const char*)sqlite3_column_text(m_stmt.get(), iCol);
374 void RepoQuery::getText(int iCol, const char*& text, size_t& size) {
375 getText(iCol, text);
376 size = size_t(sqlite3_column_bytes(m_stmt.get(), iCol));
379 void RepoQuery::getStdString(int iCol, std::string& s) {
380 const char* text;
381 size_t size;
382 getText(iCol, text, size);
383 s = std::string(text, size);
386 void RepoQuery::getStaticString(int iCol, StringData*& s) {
387 if (isNull(iCol)) {
388 s = nullptr;
389 } else {
390 const char* text;
391 size_t size;
392 getText(iCol, text, size);
393 s = makeStaticString(text, size);
397 void RepoQuery::getDouble(int iCol, double& val) {
398 if (!isDouble(iCol)) {
399 throw RepoExc(
400 "RepoQuery::%s(repo=%p) error: Column %d is not a double in '%s'",
401 __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
403 val = sqlite3_column_double(m_stmt.get(), iCol);
406 void RepoQuery::getInt(int iCol, int& val) {
407 if (!isInt(iCol)) {
408 throw RepoExc(
409 "RepoQuery::%s(repo=%p) error: Column %d is not an integer in '%s'",
410 __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
412 val = sqlite3_column_int(m_stmt.get(), iCol);
415 void RepoQuery::getId(int iCol, Id& id) {
416 int val;
417 getInt(iCol, val);
418 id = Id(val);
421 void RepoQuery::getOffset(int iCol, Offset& offset) {
422 int val;
423 getInt(iCol, val);
424 offset = Offset(val);
427 void RepoQuery::getAttr(int iCol, Attr& attrs) {
428 int val;
429 getInt(iCol, val);
430 attrs = Attr(val);
433 void RepoQuery::getBool(int iCol, bool& b) {
434 int val;
435 getInt(iCol, val);
436 b = bool(val);
439 void RepoQuery::getInt64(int iCol, int64_t& val) {
440 if (!isInt(iCol)) {
441 throw RepoExc(
442 "RepoQuery::%s(repo=%p) error: Column %d is not an integer in '%s'",
443 __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
445 val = sqlite3_column_int64(m_stmt.get(), iCol);
448 //==============================================================================
449 // RepoTxnQuery.
451 void RepoTxnQuery::step() {
452 assert(!m_txn.error());
453 m_txn.step(*this);
456 void RepoTxnQuery::exec() {
457 assert(!m_txn.error());
458 m_txn.exec(*this);
461 } // HPHP::VM