Ejemplo n.º 1
0
//======================================================================
//======================================================================
NvUIGraphic::NvUIGraphic(const std::string& texname, float dstw/*==0*/, float dsth/*==0*/)
{
    StaticInit();
    PrivateInit();
    LoadTexture(texname);
    if (dstw!=0)
        SetDimensions(dstw, dsth);
}
Ejemplo n.º 2
0
//======================================================================
//======================================================================
NvUIGraphic::NvUIGraphic(uint32_t texId, bool alpha,
                            uint32_t srcw, uint32_t srch,
                            float dstw/*==0*/, float dsth/*==0*/)
{
    StaticInit();
    PrivateInit();
    SetTextureID(texId, alpha, srcw, srch);
    if (dstw!=0)
        SetDimensions(dstw, dsth);
}
Ejemplo n.º 3
0
//======================================================================
//======================================================================
NvUIGraphic::NvUIGraphic(NvUITexture *uiTex, float dstw/*==0*/, float dsth/*==0*/)
{
    StaticInit();
    PrivateInit();
    m_tex = uiTex;
    m_tex->AddRef();
    if (dstw!=0)
        SetDimensions(dstw, dsth);
    else
        SetDimensions((float)m_tex->GetWidth(), (float)m_tex->GetHeight());
}
Ejemplo n.º 4
0
local void AggregateVarDeclEquals( SYMPTR sym, SYM_HANDLE sym_handle )
{
    SYM_HANDLE  sym2_handle;
    SYM_ENTRY   sym2;

    sym2_handle = MakeNewSym( &sym2, 'X', sym->sym_type, SC_STATIC );
    sym2.flags |= SYM_INITIALIZED;
    CompFlags.initializing_data = 1;
    StaticInit( &sym2, sym2_handle );
    CompFlags.initializing_data = 0;
    SymReplace( &sym2, sym2_handle );
    /* StaticInit will change sym2.sym_type if it is an incomplete array type */
    sym->sym_type = sym2.sym_type;
    AssignAggregate( VarLeaf( sym, sym_handle ),
                     VarLeaf( &sym2, sym2_handle ), sym->sym_type );
}
Ejemplo n.º 5
0
void VarDeclEquals( SYMPTR sym, SYM_HANDLE sym_handle )
{
    TYPEPTR     typ;

    if( SymLevel == 0  ||  sym->stg_class == SC_STATIC ) {
        if( sym->flags & SYM_INITIALIZED ) {
            CErrSymName( ERR_VAR_ALREADY_INITIALIZED, sym, sym_handle );
        }
        sym->flags |= SYM_INITIALIZED;
        CompFlags.initializing_data = 1;
        StaticInit( sym, sym_handle );
        CompFlags.initializing_data = 0;
    } else {
        SymReplace( sym, sym_handle );          /* 31-aug-88 */
        SrcLoc = TokenLoc;
        typ = sym->sym_type;
        SKIP_TYPEDEFS( typ );
        /* 07-jun-89  check for { before checking for array,struct
           or union  */
        if( CurToken != T_LEFT_BRACE  &&
            typ->decl_type != TYPE_ARRAY ) {            /* 27-jun-89 */
            AddStmt( AsgnOp( VarLeaf( sym, sym_handle ),
                   T_ASSIGN_LAST, CommaExpr() ) );
        } else if( typ->decl_type == TYPE_ARRAY ) {
            if( CurToken == T_LEFT_BRACE && CompFlags.auto_agg_inits ) {
                InitArrayVar( sym, sym_handle, typ );
            } else {
                AggregateVarDeclEquals( sym, sym_handle );
            }
        } else if( typ->decl_type == TYPE_STRUCT ||
                   typ->decl_type == TYPE_UNION ) {
            if( CurToken == T_LEFT_BRACE && CompFlags.auto_agg_inits && SimpleStruct( typ ) ) {
                NextToken();  //T_LEFT_BRACE
                InitStructVar( 0, sym, sym_handle, typ );
                NextToken(); //T_RIGHT_BRACE
            } else {
                AggregateVarDeclEquals( sym, sym_handle );
            }
        } else {
            NextToken();
            AddStmt( AsgnOp( VarLeaf( sym, sym_handle ),
                   T_ASSIGN_LAST, CommaExpr() ) );
            MustRecog( T_RIGHT_BRACE );
        }
    }
}
Ejemplo n.º 6
0
NvUIGraphicFrameRenderVK::NvUIGraphicFrameRenderVK(NvUIGraphicFrame* graphic)
{
	NvVkContext& vk = *NvUIVKctx().mVk;
	m_graphic = graphic;
    StaticInit();

	VkResult result;
	VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
	descriptorSetAllocateInfo.descriptorPool = ms_descriptorPool;
	descriptorSetAllocateInfo.descriptorSetCount = 1;
	descriptorSetAllocateInfo.pSetLayouts = &ms_descriptorSetLayout;
	result = vkAllocateDescriptorSets(vk.device(), &descriptorSetAllocateInfo, &m_descriptorSet);
	CHECK_VK_RESULT();

	VkDescriptorBufferInfo uboDesc;
	ms_ubo.GetDesc(uboDesc);

	VkDescriptorImageInfo texDesc = {};
	texDesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
	texDesc.imageView = ((NvUITextureRenderVK*)(m_graphic->GetTex()->GetRender()))->mTex.view;
	texDesc.sampler = ms_sampler;

	VkWriteDescriptorSet writeDescriptorSets[2];
	writeDescriptorSets[0] = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
	writeDescriptorSets[0].dstSet = m_descriptorSet;
	writeDescriptorSets[0].dstBinding = 0;
	writeDescriptorSets[0].dstArrayElement = 0;
	writeDescriptorSets[0].descriptorCount = 1;
	writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
	writeDescriptorSets[0].pBufferInfo = &uboDesc;
	writeDescriptorSets[1] = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
	writeDescriptorSets[1].dstSet = m_descriptorSet;
	writeDescriptorSets[1].dstBinding = 1;
	writeDescriptorSets[1].dstArrayElement = 0;
	writeDescriptorSets[1].descriptorCount = 1;
	writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
	writeDescriptorSets[1].pImageInfo = &texDesc;

	vkUpdateDescriptorSets(vk.device(), 2, writeDescriptorSets, 0, 0);
}
Ejemplo n.º 7
0
QSqlDatabase Database::Connect() {
    QMutexLocker l(&connect_mutex_);

    // Create the directory if it doesn't exist
    if (!QFile::exists(directory_)) {
        QDir dir;
        if (!dir.mkpath(directory_)) {
        }
    }

    const QString connection_id = QString("%1_thread_%2").arg(connection_id_).arg(
                                      reinterpret_cast<quint64>(QThread::currentThread()));

    // Try to find an existing connection for this thread
    QSqlDatabase db = QSqlDatabase::database(connection_id);
    if (db.isOpen()) {
        return db;
    }

    db = QSqlDatabase::addDatabase("QSQLITE", connection_id);

    if (!injected_database_name_.isNull())
        db.setDatabaseName(injected_database_name_);
    else
        db.setDatabaseName(directory_ + "/" + kDatabaseFilename);

    if (!db.open()) {
        app_->AddError("Database: " + db.lastError().text());
        return db;
    }

    // Find Sqlite3 functions in the Qt plugin.
    StaticInit();

    {
        QSqlQuery set_fts_tokenizer("SELECT fts3_tokenizer(:name, :pointer)", db);
        set_fts_tokenizer.bindValue(":name", "unicode");
        set_fts_tokenizer.bindValue(
            ":pointer", QByteArray(reinterpret_cast<const char*>(&sFTSTokenizer),
                                   sizeof(&sFTSTokenizer)));
        if (!set_fts_tokenizer.exec()) {
            qLog(Warning) << "Couldn't register FTS3 tokenizer";
        }
        // Implicit invocation of ~QSqlQuery() when leaving the scope
        // to release any remaining database locks!
    }

    if (db.tables().count() == 0) {
        // Set up initial schema
        qLog(Info) << "Creating initial database schema";
        UpdateDatabaseSchema(0, db);
    }

    // Attach external databases
    for (const QString& key : attached_databases_.keys()) {
        QString filename = attached_databases_[key].filename_;

        if (!injected_database_name_.isNull()) filename = injected_database_name_;

        // Attach the db
        QSqlQuery q("ATTACH DATABASE :filename AS :alias", db);
        q.bindValue(":filename", filename);
        q.bindValue(":alias", key);
        if (!q.exec()) {
            qFatal("Couldn't attach external database '%s'",
                   key.toAscii().constData());
        }
    }

    if (startup_schema_version_ == -1) {
        UpdateMainSchema(&db);
    }

    // We might have to initialise the schema in some attached databases now, if
    // they were deleted and don't match up with the main schema version.
    for (const QString& key : attached_databases_.keys()) {
        if (attached_databases_[key].is_temporary_ &&
                attached_databases_[key].schema_.isEmpty())
            continue;
        // Find out if there are any tables in this database
        QSqlQuery q(QString(
                        "SELECT ROWID FROM %1.sqlite_master"
                        " WHERE type='table'").arg(key),
                    db);
        if (!q.exec() || !q.next()) {
            q.finish();
            ExecSchemaCommandsFromFile(db, attached_databases_[key].schema_, 0);
        }
    }

    return db;
}
Ejemplo n.º 8
0
void FName::Init(const WIDECHAR* InName, int32 InNumber, EFindName FindType, bool bSplitName, int32 HardcodeIndex )
{
    check(FCString::Strlen(InName)<=NAME_SIZE);

    // initialize the name subsystem if necessary
    if (!GetIsInitialized())
    {
        StaticInit();
    }

    WIDECHAR TempBuffer[NAME_SIZE];
    int32 TempNumber;
    // if we were passed in a number, we can't split again, other wise, a_1_2_3_4 would change everytime
    // it was loaded in
    if (InNumber == NAME_NO_NUMBER_INTERNAL && bSplitName == true )
    {
        if (SplitNameWithCheck(InName, TempBuffer, ARRAY_COUNT(TempBuffer), TempNumber))
        {
            InName = TempBuffer;
            InNumber = NAME_EXTERNAL_TO_INTERNAL(TempNumber);
        }
    }

    check(InName);

    // If empty or invalid name was specified, return NAME_None.
    if( !InName[0] )
    {
        check(HardcodeIndex < 1); // if this is hardcoded, it better be zero
        ComparisonIndex = NAME_None;
#if WITH_CASE_PRESERVING_NAME
        DisplayIndex = NAME_None;
#endif
        Number = NAME_NO_NUMBER_INTERNAL;
        return;
    }


    //!!!! Caution, since these are set by static initializers from multiple threads, we must use local variables for this stuff until just before we return.

    bool bWasFoundOrAdded = true;
    int32 OutComparisonIndex = HardcodeIndex;
    int32 OutDisplayIndex = HardcodeIndex;

    const bool bIsPureAnsi = FCStringWide::IsPureAnsi( InName );
    if(bIsPureAnsi)
    {
        // Convert to an ansi display name
        ANSICHAR AnsiDisplayName[NAME_SIZE];
        FCStringAnsi::Strncpy(AnsiDisplayName, StringCast<ANSICHAR>(InName).Get(), ARRAY_COUNT(AnsiDisplayName));

        bWasFoundOrAdded = InitInternal_FindOrAdd<ANSICHAR>(AnsiDisplayName, FindType, HardcodeIndex, OutComparisonIndex, OutDisplayIndex);
    }
    else
    {
        bWasFoundOrAdded = InitInternal_FindOrAdd<WIDECHAR>(InName, FindType, HardcodeIndex, OutComparisonIndex, OutDisplayIndex);
    }

    if(bWasFoundOrAdded)
    {
        ComparisonIndex = OutComparisonIndex;
#if WITH_CASE_PRESERVING_NAME
        DisplayIndex = OutDisplayIndex;
#endif
        Number = InNumber;
    }
    else
    {
        ComparisonIndex = NAME_None;
#if WITH_CASE_PRESERVING_NAME
        DisplayIndex = NAME_None;
#endif
        Number = NAME_NO_NUMBER_INTERNAL;
    }
}
Ejemplo n.º 9
0
/**
 *  \brief Initilizes the groupname, hostname, and dirlist
 *
 *   First attempts to find the Storage Group defined with the specified name
 *   for the given host.  If not found, checks for the named Storage Group, as
 *   defined across all hosts.  If not found, tries the "Default" Storage Group
 *   for the given host.  If not found, tries the "Default" Storage Group, as
 *   defined across all hosts.
 *
 *  \param group    The name of the Storage Group
 *  \param hostname The host whose Storage Group definition is desired
 */
void StorageGroup::Init(const QString group, const QString hostname,
                        const bool allowFallback)
{
    bool found = false;
    m_groupname = group;    m_groupname.detach();
    m_hostname  = hostname; m_hostname.detach();
    m_allowFallback = allowFallback;
    m_dirlist.clear();

    StaticInit();

    found = FindDirs(m_groupname, m_hostname, &m_dirlist);

    if (!found && m_builtinGroups.contains(group))
    {
        QDir testdir(m_builtinGroups[group]);
        if (!testdir.exists())
            testdir.mkpath(m_builtinGroups[group]);

        if (testdir.exists())
        {
            m_dirlist.prepend(testdir.absolutePath());
            found = true;
        }
    }

    if ((!found) && m_allowFallback && (m_groupname != "LiveTV") &&
        (!hostname.isEmpty()))
    {
        LOG(VB_FILE, LOG_NOTICE, LOC +
            QString("Unable to find any directories for the local "
                    "storage group '%1' on '%2', trying directories on "
                    "all hosts!").arg(group).arg(hostname));
        found = FindDirs(m_groupname, "", &m_dirlist);
        if (found)
        {
            m_hostname = "";
            m_hostname.detach();
        }
    }
    if ((!found) && m_allowFallback && (group != "Default"))
    {
        LOG(VB_FILE, LOG_NOTICE, LOC +
            QString("Unable to find storage group '%1', trying "
                    "'Default' group!").arg(group));
        found = FindDirs("Default", m_hostname, &m_dirlist);
        if(found)
        {
            m_groupname = "Default";
            m_groupname.detach();
        }
        else if (!hostname.isEmpty())
        {
            LOG(VB_FILE, LOG_NOTICE, LOC +
                QString("Unable to find any directories for the local "
                        "Default storage group on '%1', trying directories "
                        "in all Default groups!").arg(hostname));
            found = FindDirs("Default", "", &m_dirlist);
            if(found)
            {
                m_groupname = "Default";
                m_hostname = "";
                m_groupname.detach();
                m_hostname.detach();
            }
        }
    }

    if (allowFallback && !m_dirlist.size())
    {
        QString msg = "Unable to find any Storage Group Directories.  ";
        QString tmpDir = gCoreContext->GetSetting("RecordFilePrefix");
        if (tmpDir != "")
        {
            msg += QString("Using old 'RecordFilePrefix' value of '%1'")
                           .arg(tmpDir);
        }
        else
        {
            tmpDir = kDefaultStorageDir;
            msg += QString("Using hardcoded default value of '%1'")
                           .arg(kDefaultStorageDir);
        }
        LOG(VB_GENERAL, LOG_ERR, LOC + msg);
        m_dirlist << tmpDir;
    }
}
Ejemplo n.º 10
0
/**
 *  \brief Finds and and optionally initialize a directory list
 *         associated with a Storage Group
 *
 *  \param group    The name of the Storage Group
 *  \param hostname The host whose directory list should be checked, first
 *  \param dirlist  Optional pointer to a QStringList to hold found dir list
 *  \return         true if directories were found
 */
bool StorageGroup::FindDirs(const QString group, const QString hostname,
                            QStringList *dirlist)
{
    bool found = false;
    QString dirname;
    MSqlQuery query(MSqlQuery::InitCon());

    StaticInit();

    QString sql = "SELECT DISTINCT dirname "
                  "FROM storagegroup ";

    if (!group.isEmpty())
    {
        sql.append("WHERE groupname = :GROUP");
        if (!hostname.isEmpty())
            sql.append(" AND hostname = :HOSTNAME");
    }

    query.prepare(sql);
    if (!group.isEmpty())
    {
        query.bindValue(":GROUP", group);
        if (!hostname.isEmpty())
            query.bindValue(":HOSTNAME", hostname);
    }

    if (!query.exec() || !query.isActive())
        MythDB::DBError("StorageGroup::StorageGroup()", query);
    else if (query.next())
    {
        do
        {
            /* The storagegroup.dirname column uses utf8_bin collation, so Qt
             * uses QString::fromAscii() for toString(). Explicitly convert the
             * value using QString::fromUtf8() to prevent corruption. */
            dirname = QString::fromUtf8(query.value(0)
                                        .toByteArray().constData());
            dirname.replace(QRegExp("^\\s*"), "");
            dirname.replace(QRegExp("\\s*$"), "");
            if (dirname.right(1) == "/")
                dirname.remove(dirname.length() - 1, 1);

            if (dirlist)
                (*dirlist) << dirname;
            else
                return true;
        }
        while (query.next());
        found = true;
    }

    if (m_builtinGroups.contains(group))
    {
        QDir testdir(m_builtinGroups[group]);
        if (testdir.exists())
        {
            if (dirlist && !dirlist->contains(testdir.absolutePath()))
                dirlist->prepend(testdir.absolutePath());
            found = true;
        }
    }

    return found;
}
Ejemplo n.º 11
0
/**
 *  \brief Returns the relative pathname of a file by comparing the filename
 *         against all Storage Group directories (and MythVideo's startupdir)
 *
 *  \param filename The full pathname of the file to use
 *  \return         The relative path if it can be determined, otherwise the
 *                  full input filename is returned back to the caller.
 */
QString StorageGroup::GetRelativePathname(const QString &filename)
{
    QString result = filename;
    MSqlQuery query(MSqlQuery::InitCon());

    LOG(VB_FILE, LOG_DEBUG,
        QString("StorageGroup::GetRelativePathname(%1)").arg(filename));

    StaticInit();

    if (filename.startsWith("myth://"))
    {
        QUrl qurl(filename);

        if (qurl.hasFragment())
            result = qurl.path() + "#" + qurl.fragment();
        else
            result = qurl.path();

        if (result.startsWith("/"))
            result.replace(0, 1, "");

        return result;
    }

    query.prepare("SELECT DISTINCT dirname FROM storagegroup "
                      "ORDER BY dirname DESC;");
    if (query.exec())
    {
        QString dirname;
        while (query.next())
        {
            /* The storagegroup.dirname column uses utf8_bin collation, so Qt
             * uses QString::fromAscii() for toString(). Explicitly convert the
             * value using QString::fromUtf8() to prevent corruption. */
            dirname = QString::fromUtf8(query.value(0)
                                        .toByteArray().constData());
            if (filename.startsWith(dirname))
            {
                result = filename;
                result.replace(0, dirname.length(), "");
                if (result.startsWith("/"))
                    result.replace(0, 1, "");

                LOG(VB_FILE, LOG_DEBUG, 
                    QString("StorageGroup::GetRelativePathname(%1) = '%2'")
                        .arg(filename).arg(result));
                return result;
            }
        }
    }

    query.prepare("SELECT DISTINCT data FROM settings WHERE "
                  "value = 'VideoStartupDir';");
    if (query.exec())
    {
        while (query.next())
        {
            QString videostartupdir = query.value(0).toString();
            QStringList videodirs = videostartupdir.split(':',
                                            QString::SkipEmptyParts);
            QString directory;
            for (QStringList::Iterator it = videodirs.begin();
                                       it != videodirs.end(); ++it)
            {
                directory = *it;
                if (filename.startsWith(directory))
                {
                    result = filename;
                    result.replace(0, directory.length(), "");
                    if (result.startsWith("/"))
                        result.replace(0, 1, "");

                    LOG(VB_FILE, LOG_DEBUG,
                        QString("StorageGroup::GetRelativePathname(%1) = '%2'")
                            .arg(filename).arg(result));
                    return result;
                }
            }
        }
    }

    QMap<QString, QString>::iterator it = m_builtinGroups.begin();
    for (; it != m_builtinGroups.end(); ++it)
    {
        QDir qdir(it.value());
        if (!qdir.exists())
            qdir.mkpath(it.value());

        QString directory = it.value();
        if (filename.startsWith(directory))
        {
            result = filename;
            result.replace(0, directory.length(), "");
            if (result.startsWith("/"))
                result.replace(0, 1, "");

            LOG(VB_FILE, LOG_DEBUG,
                QString("StorageGroup::GetRelativePathname(%1) = '%2'")
                    .arg(filename).arg(result));
            return result;
        }
    }

    return result;
}
Ejemplo n.º 12
0
QSqlDatabase Database::Connect() {
  QMutexLocker l(&connect_mutex_);

  // Create the directory if it doesn't exist
  if (!QFile::exists(directory_)) {
    QDir dir;
    if (!dir.mkpath(directory_)) {
    }
  }

  const QString connection_id = QString("%1_thread_%2").arg(connection_id_).arg(
      reinterpret_cast<quint64>(QThread::currentThread()));

  // Try to find an existing connection for this thread
  QSqlDatabase db = QSqlDatabase::database(connection_id);
  if (db.isOpen()) {
    return db;
  }

  db = QSqlDatabase::addDatabase("QSQLITE", connection_id);

  if (!injected_database_name_.isNull())
    db.setDatabaseName(injected_database_name_);
  else
    db.setDatabaseName(directory_ + "/" + kDatabaseFilename);

  if (!db.open()) {
    app_->AddError("Database: " + db.lastError().text());
    return db;
  }

  // Find Sqlite3 functions in the Qt plugin.
  StaticInit();

  {

#ifdef SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    // In case sqlite>=3.12 is compiled without -DSQLITE_ENABLE_FTS3_TOKENIZER (generally a good idea 
    // due to security reasons) the fts3 support should be enabled explicitly.
    // see https://github.com/clementine-player/Clementine/issues/5297
    //
    // See https://www.sqlite.org/fts3.html#custom_application_defined_tokenizers
    QVariant v = db.driver()->handle();
    if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0) {
      sqlite3* handle = *static_cast<sqlite3**>(v.data());
      if (!handle || sqlite3_db_config(handle, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, nullptr) != SQLITE_OK) {
        qLog(Fatal) << "Failed to enable FTS3 tokenizer";
      }
    }
#endif

    QSqlQuery set_fts_tokenizer("SELECT fts3_tokenizer(:name, :pointer)", db);
    set_fts_tokenizer.bindValue(":name", "unicode");
    set_fts_tokenizer.bindValue(
        ":pointer", QByteArray(reinterpret_cast<const char*>(&sFTSTokenizer),
                               sizeof(&sFTSTokenizer)));
    if (!set_fts_tokenizer.exec()) {
      qLog(Warning) << "Couldn't register FTS3 tokenizer";
    }
    // Implicit invocation of ~QSqlQuery() when leaving the scope
    // to release any remaining database locks!
  }

  if (db.tables().count() == 0) {
    // Set up initial schema
    qLog(Info) << "Creating initial database schema";
    UpdateDatabaseSchema(0, db);
  }

  // Attach external databases
  for (const QString& key : attached_databases_.keys()) {
    QString filename = attached_databases_[key].filename_;

    if (!injected_database_name_.isNull()) filename = injected_database_name_;

    // Attach the db
    QSqlQuery q("ATTACH DATABASE :filename AS :alias", db);
    q.bindValue(":filename", filename);
    q.bindValue(":alias", key);
    if (!q.exec()) {
      qFatal("Couldn't attach external database '%s'",
             key.toAscii().constData());
    }
  }

  if (startup_schema_version_ == -1) {
    UpdateMainSchema(&db);
  }

  // We might have to initialise the schema in some attached databases now, if
  // they were deleted and don't match up with the main schema version.
  for (const QString& key : attached_databases_.keys()) {
    if (attached_databases_[key].is_temporary_ &&
        attached_databases_[key].schema_.isEmpty())
      continue;
    // Find out if there are any tables in this database
    QSqlQuery q(QString(
                    "SELECT ROWID FROM %1.sqlite_master"
                    " WHERE type='table'").arg(key),
                db);
    if (!q.exec() || !q.next()) {
      q.finish();
      ExecSchemaCommandsFromFile(db, attached_databases_[key].schema_, 0);
    }
  }

  return db;
}