void SQLTransaction::openTransactionAndPreflight()
{
    ASSERT(!m_database->sqliteDatabase().transactionInProgress());
    ASSERT(m_lockAcquired);

    LOG(StorageAPI, "Opening and preflighting transaction %p", this);

    // If the database was deleted, jump to the error callback
    if (m_database->deleted()) {
        m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to open a transaction, because the user deleted the database");

        handleTransactionError();
        return;
    }

    // Set the maximum usage for this transaction if this transactions is not read-only
    if (!m_readOnly) {
        acquireOriginLock();
        m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize());
    }

    ASSERT(!m_sqliteTransaction);
    m_sqliteTransaction = std::make_unique<SQLiteTransaction>(m_database->sqliteDatabase(), m_readOnly);

    m_database->resetDeletes();
    m_database->disableAuthorizer();
    m_sqliteTransaction->begin();
    m_database->enableAuthorizer();

    // Spec 4.3.2.1+2: Open a transaction to the database, jumping to the error callback if that fails
    if (!m_sqliteTransaction->inProgress()) {
        ASSERT(!m_database->sqliteDatabase().transactionInProgress());
        m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to begin transaction", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg());
        m_sqliteTransaction = nullptr;

        handleTransactionError();
        return;
    }

    // Note: We intentionally retrieve the actual version even with an empty expected version.
    // In multi-process browsers, we take this opportinutiy to update the cached value for
    // the actual version. In single-process browsers, this is just a map lookup.
    String actualVersion;
    if (!m_database->getActualVersionForTransaction(actualVersion)) {
        m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to read version", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg());
        m_database->disableAuthorizer();
        m_sqliteTransaction = nullptr;
        m_database->enableAuthorizer();

        handleTransactionError();
        return;
    }

    m_hasVersionMismatch = !m_database->expectedVersion().isEmpty() && (m_database->expectedVersion() != actualVersion);

    // Spec 4.3.2.3: Perform preflight steps, jumping to the error callback if they fail
    if (m_wrapper && !m_wrapper->performPreflight(*this)) {
        m_database->disableAuthorizer();
        m_sqliteTransaction = nullptr;
        m_database->enableAuthorizer();
        m_transactionError = m_wrapper->sqlError();
        if (!m_transactionError)
            m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occurred during transaction preflight");

        handleTransactionError();
        return;
    }

    // Spec 4.3.2.4: Invoke the transaction callback with the new SQLTransaction object
    if (m_callbackWrapper.hasCallback()) {
        scheduleCallback(&SQLTransaction::deliverTransactionCallback);
        return;
    }

    // If we have no callback to make, skip pass to the state after:
    runStatements();
}
Beispiel #2
-1
static bool runStatement(ASTNode* node, MemoryStack* stack, Scope* scope, RuntimeError* error)
{
    switch (node->nodeType)
    {
        case AST_STATEMENT_TYPE_DEFINITION:
        {
            if (getTypeDefinition(scope, node->typeDefinition.identifier, false))
            {
                *error = RuntimeError{
                    RET_TYPE_ALREADY_DEFINED,
                    node->typeDefinition.identifier,
                    node->typeDefinition.lineNumber
                };

                return false;
            }
            else
            {
                TypeDefinition* typeDef = scopePushToList(scope, stack, &scope->types);
                typeDef->identifier = node->typeDefinition.identifier;
                typeDef->members = {};

                ListIterator<ASTNode> iterator = makeIterator(&node->typeDefinition.definitions);

                int currOffsetInBytes = 0;
                while (hasNext(&iterator))
                {
                    ASTNode* node = getNext(&iterator);

                    StructMember* member = scopePushToList(scope, stack, &typeDef->members);
                    member->identifier = node->variableDeclaration.identifier;
                    member->type = makeType(scope, node->variableDeclaration.typeIdentifier);
                    member->offsetInBytes = currOffsetInBytes;

                    currOffsetInBytes += member->type.definition->totalSizeInBytes;
                }

                typeDef->totalSizeInBytes = currOffsetInBytes;
                return true;
            }
        } break;

        case AST_STATEMENT_VARIABLE_DECLARATION:
        {
            if (getVariable(scope, node->variableDeclaration.identifier, false))
            {
                *error = RuntimeError{ RET_VARIABLE_ALREADY_DEFINED, node->variableDeclaration.identifier, node->variableDeclaration.lineNumber };
                return false;
            }
            else
            {
                Variable* var = defineAVariable(
                    node->variableDeclaration.identifier,
                    makeType(scope, node->variableDeclaration.typeIdentifier), stack, scope);

                if (node->variableDeclaration.expression)
                    return runExpression(node->variableDeclaration.expression, stack, scope, error, &var->value);
                else
                    return true; // TODO: set default value
            }
        } break;

        case AST_STATEMENT_FUNCTION_DEFINITION:
        {
            Function func;

            func.type = FT_INTERNAL;
            func.identifier.name = node->functionDefinition.identifier;
            func.identifier.arguments = {};

            bool stillWorking = true;
            if (!node->functionDefinition.returnType)
                func.returnType = Type{ nullptr, 0 };
            else
            {
                func.returnType = makeType(scope, node->functionDefinition.returnType);
                if (!func.returnType.definition)
                {
                    *error = RuntimeError{ RET_UNDEFINED_TYPE, node->functionDefinition.returnType->typeIdentifier.name, node->functionDefinition.lineNumber };
                    stillWorking = false;
                }
            }

            ListIterator<ASTNode> args = makeIterator(&node->functionDefinition.arguments);
            while (stillWorking && hasNext(&args))
            {
                ASTNode* arg = getNext(&args);

                Argument* argument = scopePushToList(scope, stack, &func.identifier.arguments);
                argument->identifier = arg->variableDeclaration.identifier;
                argument->type = makeType(scope, arg->variableDeclaration.typeIdentifier);

                if (!argument->type.definition)
                {
                    *error = RuntimeError{ RET_UNDEFINED_TYPE, arg->variableDeclaration.typeIdentifier->typeIdentifier.name, arg->variableDeclaration.lineNumber };
                    stillWorking = false;
                }
            }

            func.body = node->functionDefinition.body;

            Function* hasFunc = getFunction(scope, func.identifier, false);
            if (hasFunc)
            {
                *error = RuntimeError{ RET_FUNCTION_ALREADY_DEFINED, node->functionDefinition.identifier, node->functionDefinition.lineNumber };
                stillWorking = false;
            }
            else
            {
                *scopePushToList(scope, stack, &scope->functions) = func;
            }

            return stillWorking;
        } break;

        case AST_STATEMENT_IF:
        {
            Scope ifScope = makeScope(scope);
            Value conditionResult = pushValue(&ifScope, stack, Type{ getTypeDefinition(scope, makeSlice("s32")), false });

            bool stillWorking = runExpression(node->ifStatement.condition, stack, scope, error, &conditionResult);

            if (stillWorking)
            {
                if (*(int*)conditionResult.memory != 0)
                {
                    stillWorking = runStatement(node->ifStatement.ifCase, stack, &ifScope, error);
                }
                else if (node->ifStatement.elseCase != nullptr)
                {
                    stillWorking = runStatement(node->ifStatement.elseCase, stack, &ifScope, error);
                }
            }

            scopeFreeMemory(&ifScope, stack);
            return stillWorking;
        } break;

        case AST_STATEMENT_WHILE:
        {
            Scope whileScope = makeScope(scope);
            Value conditionResult = pushValue(&whileScope, stack, Type{ getTypeDefinition(scope, makeSlice("s32")), false });

            bool stillWorking = runExpression(node->whileStatement.condition, stack, scope, error, &conditionResult);
            if (stillWorking)
            {
                while (*(int*)conditionResult.memory != 0)
                {
                    if (!(stillWorking = runStatement(node->whileStatement.body, stack, &whileScope, error))) break;
                    if (!(stillWorking = runExpression(node->whileStatement.condition, stack, scope, error, &conditionResult))) break;
                }
            }

            scopeFreeMemory(&whileScope, stack);
            return stillWorking;
        } break;

        case AST_STATEMENT_ASSIGNMENT:
        {
            Value value; 
            if (getValue(scope, node->assignment.lValue, error, &value))
            {
                return runExpression(node->assignment.expression, stack, scope, error, &value);
            }
            else
                return false;
        } break;

        case AST_STATEMENTS_BLOCK:
        {
            Scope blockScope = makeScope(scope);
            bool result = runStatements(&node->statementsBlock.statements, stack, &blockScope, error);
            scopeFreeMemory(&blockScope, stack);

            return result;
        } break;

        case AST_FUNCTION_CALL:
        {
            return runFunctionCall(node, stack, scope, error, nullptr);
        } break;

        default:
        {
            assert(!"this is not a statement!");
            return false;
        } break;
    }
}