1// Copyright 2011 The Kyua Authors. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above copyright 11// notice, this list of conditions and the following disclaimer in the 12// documentation and/or other materials provided with the distribution. 13// * Neither the name of Google Inc. nor the names of its contributors 14// may be used to endorse or promote products derived from this software 15// without specific prior written permission. 16// 17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29#include "store/dbtypes.hpp" 30 31#include "model/test_program.hpp" 32#include "model/test_result.hpp" 33#include "store/exceptions.hpp" 34#include "utils/datetime.hpp" 35#include "utils/format/macros.hpp" 36#include "utils/sanity.hpp" 37#include "utils/sqlite/statement.ipp" 38 39namespace datetime = utils::datetime; 40namespace sqlite = utils::sqlite; 41 42 43/// Binds a boolean value to a statement parameter. 44/// 45/// \param stmt The statement to which to bind the parameter. 46/// \param field The name of the parameter; must exist. 47/// \param value The value to bind. 48void 49store::bind_bool(sqlite::statement& stmt, const char* field, const bool value) 50{ 51 stmt.bind(field, value ? "true" : "false"); 52} 53 54 55/// Binds a time delta to a statement parameter. 56/// 57/// \param stmt The statement to which to bind the parameter. 58/// \param field The name of the parameter; must exist. 59/// \param delta The value to bind. 60void 61store::bind_delta(sqlite::statement& stmt, const char* field, 62 const datetime::delta& delta) 63{ 64 stmt.bind(field, static_cast< int64_t >(delta.to_microseconds())); 65} 66 67 68/// Binds a string to a statement parameter. 69/// 70/// If the string is not empty, this binds the string itself. Otherwise, it 71/// binds a NULL value. 72/// 73/// \param stmt The statement to which to bind the parameter. 74/// \param field The name of the parameter; must exist. 75/// \param str The string to bind. 76void 77store::bind_optional_string(sqlite::statement& stmt, const char* field, 78 const std::string& str) 79{ 80 if (str.empty()) 81 stmt.bind(field, sqlite::null()); 82 else 83 stmt.bind(field, str); 84} 85 86 87/// Binds a test result type to a statement parameter. 88/// 89/// \param stmt The statement to which to bind the parameter. 90/// \param field The name of the parameter; must exist. 91/// \param type The result type to bind. 92void 93store::bind_test_result_type(sqlite::statement& stmt, const char* field, 94 const model::test_result_type& type) 95{ 96 switch (type) { 97 case model::test_result_broken: 98 stmt.bind(field, "broken"); 99 break; 100 101 case model::test_result_expected_failure: 102 stmt.bind(field, "expected_failure"); 103 break; 104 105 case model::test_result_failed: 106 stmt.bind(field, "failed"); 107 break; 108 109 case model::test_result_passed: 110 stmt.bind(field, "passed"); 111 break; 112 113 case model::test_result_skipped: 114 stmt.bind(field, "skipped"); 115 break; 116 117 default: 118 UNREACHABLE; 119 } 120} 121 122 123/// Binds a timestamp to a statement parameter. 124/// 125/// \param stmt The statement to which to bind the parameter. 126/// \param field The name of the parameter; must exist. 127/// \param timestamp The value to bind. 128void 129store::bind_timestamp(sqlite::statement& stmt, const char* field, 130 const datetime::timestamp& timestamp) 131{ 132 stmt.bind(field, timestamp.to_microseconds()); 133} 134 135 136/// Queries a boolean value from a statement. 137/// 138/// \param stmt The statement from which to get the column. 139/// \param column The name of the column holding the value. 140/// 141/// \return The parsed value if all goes well. 142/// 143/// \throw integrity_error If the value in the specified column is invalid. 144bool 145store::column_bool(sqlite::statement& stmt, const char* column) 146{ 147 const int id = stmt.column_id(column); 148 if (stmt.column_type(id) != sqlite::type_text) 149 throw store::integrity_error(F("Boolean value in column %s is not a " 150 "string") % column); 151 const std::string value = stmt.column_text(id); 152 if (value == "true") 153 return true; 154 else if (value == "false") 155 return false; 156 else 157 throw store::integrity_error(F("Unknown boolean value '%s'") % value); 158} 159 160 161/// Queries a time delta from a statement. 162/// 163/// \param stmt The statement from which to get the column. 164/// \param column The name of the column holding the value. 165/// 166/// \return The parsed value if all goes well. 167/// 168/// \throw integrity_error If the value in the specified column is invalid. 169datetime::delta 170store::column_delta(sqlite::statement& stmt, const char* column) 171{ 172 const int id = stmt.column_id(column); 173 if (stmt.column_type(id) != sqlite::type_integer) 174 throw store::integrity_error(F("Time delta in column %s is not an " 175 "integer") % column); 176 return datetime::delta::from_microseconds(stmt.column_int64(id)); 177} 178 179 180/// Queries an optional string from a statement. 181/// 182/// \param stmt The statement from which to get the column. 183/// \param column The name of the column holding the value. 184/// 185/// \return The parsed value if all goes well. 186/// 187/// \throw integrity_error If the value in the specified column is invalid. 188std::string 189store::column_optional_string(sqlite::statement& stmt, const char* column) 190{ 191 const int id = stmt.column_id(column); 192 switch (stmt.column_type(id)) { 193 case sqlite::type_text: 194 return stmt.column_text(id); 195 case sqlite::type_null: 196 return ""; 197 default: 198 throw integrity_error(F("Invalid string type in column %s") % column); 199 } 200} 201 202 203/// Queries a test result type from a statement. 204/// 205/// \param stmt The statement from which to get the column. 206/// \param column The name of the column holding the value. 207/// 208/// \return The parsed value if all goes well. 209/// 210/// \throw integrity_error If the value in the specified column is invalid. 211model::test_result_type 212store::column_test_result_type(sqlite::statement& stmt, const char* column) 213{ 214 const int id = stmt.column_id(column); 215 if (stmt.column_type(id) != sqlite::type_text) 216 throw store::integrity_error(F("Result type in column %s is not a " 217 "string") % column); 218 const std::string type = stmt.column_text(id); 219 if (type == "passed") { 220 return model::test_result_passed; 221 } else if (type == "broken") { 222 return model::test_result_broken; 223 } else if (type == "expected_failure") { 224 return model::test_result_expected_failure; 225 } else if (type == "failed") { 226 return model::test_result_failed; 227 } else if (type == "skipped") { 228 return model::test_result_skipped; 229 } else { 230 throw store::integrity_error(F("Unknown test result type %s") % type); 231 } 232} 233 234 235/// Queries a timestamp from a statement. 236/// 237/// \param stmt The statement from which to get the column. 238/// \param column The name of the column holding the value. 239/// 240/// \return The parsed value if all goes well. 241/// 242/// \throw integrity_error If the value in the specified column is invalid. 243datetime::timestamp 244store::column_timestamp(sqlite::statement& stmt, const char* column) 245{ 246 const int id = stmt.column_id(column); 247 if (stmt.column_type(id) != sqlite::type_integer) 248 throw store::integrity_error(F("Timestamp in column %s is not an " 249 "integer") % column); 250 const int64_t value = stmt.column_int64(id); 251 if (value < 0) 252 throw store::integrity_error(F("Timestamp in column %s must be " 253 "positive") % column); 254 return datetime::timestamp::from_microseconds(value); 255} 256