template <typename StorageSet,typename ReadSet> void mergeKeysFromStorageSet(StorageSet &ss, const ReadSet&other) {
    int len = other.reads_size();    
    int sslen = ss.reads_size();    
    int i;
    for (i=0;i<sslen;++i) {
        mergeStorageKey(ss.mutable_reads(i),other.reads(i));
    }
    for (;i<len;++i) {
        ss.add_reads();
        mergeStorageKey(ss.mutable_reads(i),other.reads(i));
    }
}
template <class ReadSet> SQLiteObjectStorage::Error SQLiteObjectStorage::applyReadSet(const SQLiteDBPtr& db, const ReadSet& rs, Protocol::Response&retval) {

    int num_reads=rs.reads_size();
    retval.clear_reads();
    while (retval.reads_size()<num_reads)
        retval.add_reads();
    SQLiteObjectStorage::Error databaseError=None;
    for (int rs_it=0;rs_it<num_reads;++rs_it) {
        String object_hex = getTableName(rs.reads(rs_it));
        String key_name = getKeyName(rs.reads(rs_it));

        String value_query = "SELECT value FROM ";
        value_query += "\"" TABLE_NAME "\"";
        value_query += " WHERE object == x\'" + object_hex + "\' AND key == ?";
        int rc;
        char* remain;
        sqlite3_stmt* value_query_stmt;
        bool newStep=true;
        bool locked=false;
        rc = sqlite3_prepare_v2(db->db(), value_query.c_str(), -1, &value_query_stmt, (const char**)&remain);
        SQLite::check_sql_error(db->db(), rc, NULL, "Error preparing value query statement");
        if (rc==SQLITE_OK) {
            rc = sqlite3_bind_text(value_query_stmt, 1, key_name.data(), (int)key_name.size(), SQLITE_TRANSIENT);
            SQLite::check_sql_error(db->db(), rc, NULL, "Error binding key name to value query statement");
            if (rc==SQLITE_OK) {
                int step_rc = sqlite3_step(value_query_stmt);
                while(step_rc == SQLITE_ROW) {
                    newStep=false;
                    retval.reads(rs_it).set_data((const char*)sqlite3_column_text(value_query_stmt, 0),sqlite3_column_bytes(value_query_stmt, 0));
                    step_rc = sqlite3_step(value_query_stmt);
                }
                if (step_rc != SQLITE_DONE) {
                    // reset the statement so it'll clean up properly
                    rc = sqlite3_reset(value_query_stmt);
                    SQLite::check_sql_error(db->db(), rc, NULL, "Error finalizing value query statement");
                    if (rc==SQLITE_LOCKED||rc==SQLITE_BUSY)
                        locked=true;
                }         
                
            }
        }
        rc = sqlite3_finalize(value_query_stmt);
        SQLite::check_sql_error(db->db(), rc, NULL, "Error finalizing value query statement");
        if (locked||rc == SQLITE_LOCKED||rc==SQLITE_BUSY) {
            retval.clear_reads();
            return DatabaseLocked;
        }

        if (newStep) {
            retval.reads(rs_it).clear_data();
            retval.reads(rs_it).set_return_status(Protocol::StorageElement::KEY_MISSING);
        }
        if(rs.reads(rs_it).has_index()) {
            retval.reads(rs_it).set_index(rs.reads(rs_it).index());
        }
    }
    if (rs.has_options()&&(rs.options()&Protocol::ReadWriteSet::RETURN_READ_NAMES)!=0) {
        // make sure read set is clear before each attempt
        mergeKeysFromStorageSet( retval, rs );
    }
    return databaseError;
}