sqlite3_stmt * Connection::prepare( const string &query, const AttributeList ¶meters ) { if( db_ == NULL ) throw ActiveRecordException( "Database not connected", __FILE__, __LINE__ ); sqlite3_stmt *ppStmt = 0; int prepare_result = sqlite3_prepare_v2( db_, query.c_str(), query.size(), &ppStmt, 0 ); if( prepare_result != SQLITE_OK ) { stringstream error; error << "SQL error: \"" << sqlite_error( prepare_result ) << "\" "; error << "in \"" << query << "\""; bool added = false; for( AttributeList::const_iterator it = parameters.begin(); it != parameters.end(); ++it ) { error << ", "; if( ! added ) error << "["; error << *it; added = true; } if( added ) error << "]"; log( error.str() ); throw ActiveRecordException( error.str(), __FILE__, __LINE__ ); } bind_parameters( ppStmt, parameters ); return ppStmt; }
Attribute Attribute::from_field(sqlite3_stmt *pStmt, int i) { const char * type = sqlite3_column_decltype( pStmt, i ); if( type == NULL ) { // http://www.sqlite.org/capi3ref.html#sqlite3_column_decltype // expression or subquery - skip const char * value = ( const char * ) sqlite3_column_text( pStmt, i ); if( value != 0 ) // TODO - throw exception? return value; } else if( strcasecmp( type, "INTEGER" ) == 0 ) { return sqlite3_column_int( pStmt, i ); } else if( strcasecmp( type, "FLOAT" ) == 0 ) { return sqlite3_column_double( pStmt, i ); } else if( strcasecmp( type, "TEXT" ) == 0 ) { const char * value = ( const char * ) sqlite3_column_text( pStmt, i ); if( value != 0 ) // TODO - throw exception? return value; } else if( strcasecmp( type, "DATE" ) == 0 ) { const char * value = ( const char * ) sqlite3_column_text( pStmt, i ); if( value != 0 ) return Date::parse( value ); } else { stringstream error; error << "Unhandled data type: " << type; throw ActiveRecordException( error.str(), __FILE__, __LINE__ ); } }
void Connection::bind_parameters( sqlite3_stmt *ppStmt, const AttributeList ¶meters ) { int i = 0; for( AttributeList::const_iterator it = parameters.begin(); it != parameters.end(); ++it ) { switch( it->which() ) { case integer: { int value = boost::get< int >( *it ); sqlite3_bind_int( ppStmt, i + 1, value ); break; } case text: { string value = boost::get< std::string >( *it ); sqlite3_bind_text( ppStmt, i + 1, value.c_str(), value.size(), 0 ); break; } case floating_point: { double value = boost::get< double >( *it ); sqlite3_bind_double( ppStmt, i + 1, value ); break; } case date: { Date value = boost::get< Date >( *it ); string s = value.to_string(); sqlite3_bind_text( ppStmt, i + 1, s.c_str(), s.size(), 0 ); break; } default: { throw ActiveRecordException( "Type not implemented", __FILE__, __LINE__ ); } } ++i; } }
Row::Row( sqlite3_stmt *pStmt ) { int count = sqlite3_column_count( pStmt ); for( int i = 0; i < count; ++i ) { string name = sqlite3_column_name( pStmt, i ); const char * type = sqlite3_column_decltype( pStmt, i ); if( type == NULL ) { // http://www.sqlite.org/capi3ref.html#sqlite3_column_decltype // expression or subquery - skip const char * value = ( const char * ) sqlite3_column_text( pStmt, i ); if ( value != 0 ) attributes_[ name ] = value; } else if( strcasecmp( type, "INTEGER" ) == 0 ) { attributes_[ name ] = sqlite3_column_int( pStmt, i ); } else if( strcasecmp( type, "FLOAT" ) == 0 ) { attributes_[ name ] = sqlite3_column_double( pStmt, i ); } else if( strcasecmp( type, "TEXT" ) == 0 ) { const char * value = ( const char * ) sqlite3_column_text( pStmt, i ); if ( value != 0 ) attributes_[ name ] = value; } else if( strcasecmp( type, "DATE" ) == 0 ) { const char * value = ( const char * ) sqlite3_column_text( pStmt, i ); if ( value != 0 ) attributes_[ name ] = Date::parse( value ); } else { stringstream error; error << "Unhandled data type: " << type; throw ActiveRecordException( error.str(), __FILE__, __LINE__ ); } } }
bool Connection::sqlite_initialize( string database_path_name ) { int nResult = sqlite3_open( database_path_name.c_str(), &db_ ); if( nResult ) { stringstream error; error << "Can't open database '" << database_path_name << "'"; error << sqlite3_errmsg( db_ ); sqlite3_close( db_ ); throw ActiveRecordException( error.str(), __FILE__, __LINE__ ); } return true; }
void TableSet::update_table( Table &required ) { log( "TableSet::update_table" ); log( required.table_name() ); Table existing = table_data( required.connection(), required.table_name() ); Fields missing = required.fields() - existing.fields(); Fields remove = existing.fields() - required.fields(); for( Fields::iterator it = missing.begin(); it != missing.end(); ++it ) existing.add_field( *it ); for( Fields::iterator it = remove.begin(); it != remove.end(); ++it ) { throw ActiveRecordException( "Table::remove_field not yet implemented", __FILE__, __LINE__ ); //existing.remove_field( *it ); } }
bool Attribute::operator==( const Attribute& other ) const { if( which() != other.which() ) return false; switch( which() ) { case 0: return boost::get< int >( *this ) == boost::get< int >( other ); case 1: return boost::get< string >( *this ) == boost::get< string >( other ); case 2: return boost::get< double >( *this ) == boost::get< double >( other ); case 3: return boost::get< Date >( *this ) == boost::get< Date >( other ); default: throw ActiveRecordException( "Unexpected Attribute type", __FILE__, __LINE__ ); } }
Table TableSet::table_data( Connection * connection, const string &table_name ) { stringstream row_query; row_query << "PRAGMA table_info( \"" << table_name << "\" );"; Table td( connection, table_name ); RowSet rows = td.connection()->select_all( row_query.str() ); for( RowSet::iterator it = rows.begin(); it != rows.end(); ++it ) { // cid | name | type | notnull | dflt_value | pk // 0 | bar | INTEGER | 0 | | 0 string name = it->get_text( "name" ); string type_name = it->get_text( "type" ); ActiveRecord::Type type = ActiveRecord::to_type( type_name ); if( type == ActiveRecord::unknown ) { stringstream error; error << "Unknown type: " << type_name; throw ActiveRecordException( error.str(), __FILE__, __LINE__ ); } td.fields().push_back( Field( name, type ) ); } return td; }