Alien-SVN

 view release on metacpan or  search on metacpan

src/subversion/subversion/libsvn_subr/sqlite.c  view on Meta::CPAN

{
  {
    int flags;

    if (mode == svn_sqlite__mode_readonly)
      flags = SQLITE_OPEN_READONLY;
    else if (mode == svn_sqlite__mode_readwrite)
      flags = SQLITE_OPEN_READWRITE;
    else if (mode == svn_sqlite__mode_rwcreate)
      flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    else
      SVN_ERR_MALFUNCTION();

    /* Turn off SQLite's mutexes. All svn objects are single-threaded,
       so we can already guarantee that our use of the SQLite handle
       will be serialized properly.

       Note: in 3.6.x, we've already config'd SQLite into MULTITHREAD mode,
       so this is probably redundant, but if we are running in a process where
       somebody initialized SQLite before us it is needed anyway.  */
    flags |= SQLITE_OPEN_NOMUTEX;

#if !defined(WIN32) && !defined(SVN_SQLITE_INLINE)
    if (mode == svn_sqlite__mode_rwcreate)
      {
        svn_node_kind_t kind;

        /* Create the file before SQLite to avoid any permissions
           problems with an SQLite build that uses the default
           SQLITE_DEFAULT_FILE_PERMISSIONS of 644 modified by umask.
           We simply want umask permissions. */
        SVN_ERR(svn_io_check_path(path, &kind, scratch_pool));
        if (kind == svn_node_none)
          SVN_ERR(svn_io_file_create(path, "", scratch_pool));
      }
#endif

    /* Open the database. Note that a handle is returned, even when an error
       occurs (except for out-of-memory); thus, we can safely use it to
       extract an error message and construct an svn_error_t. */
    {
      /* We'd like to use SQLITE_ERR here, but we can't since it would
         just return an error and leave the database open.  So, we need to
         do this manually. */
      /* ### SQLITE_CANTOPEN */
      int err_code = sqlite3_open_v2(path, db3, flags, NULL);
      if (err_code != SQLITE_OK)
        {
          /* Save the error message before closing the SQLite handle. */
          char *msg = apr_pstrdup(scratch_pool, sqlite3_errmsg(*db3));

          /* We don't catch the error here, since we care more about the open
             error than the close error at this point. */
          sqlite3_close(*db3);

          SQLITE_ERR_MSG(err_code, msg);
        }
    }
  }

  /* Retry until timeout when database is busy. */
  SQLITE_ERR_MSG(sqlite3_busy_timeout(*db3, BUSY_TIMEOUT),
                 sqlite3_errmsg(*db3));

  return SVN_NO_ERROR;
}


/* APR cleanup function used to close the database when its pool is destroyed.
   DATA should be the svn_sqlite__db_t handle for the database. */
static apr_status_t
close_apr(void *data)
{
  svn_sqlite__db_t *db = data;
  svn_error_t *err = SVN_NO_ERROR;
  apr_status_t result;
  int i;

  /* Check to see if we've already closed this database. */
  if (db->db3 == NULL)
    return APR_SUCCESS;

  /* Finalize any existing prepared statements. */
  for (i = 0; i < db->nbr_statements; i++)
    {
      if (db->prepared_stmts[i])
        {
          if (db->prepared_stmts[i]->needs_reset)
            {
#ifdef SVN_DEBUG
              const char *stmt_text = db->statement_strings[i];
              stmt_text = stmt_text; /* Provide value for debugger */

              SVN_ERR_MALFUNCTION_NO_RETURN();
#else
              err = svn_error_compose_create(
                            err,
                            svn_sqlite__reset(db->prepared_stmts[i]));
#endif
            }
          err = svn_error_compose_create(
                        svn_sqlite__finalize(db->prepared_stmts[i]), err);
        }
    }
  /* And finalize any used internal statements */
  for (; i < db->nbr_statements + STMT_INTERNAL_LAST; i++)
    {
      if (db->prepared_stmts[i])
        {
          err = svn_error_compose_create(
                        svn_sqlite__finalize(db->prepared_stmts[i]), err);
        }
    }

  result = sqlite3_close(db->db3);

  /* If there's a pre-existing error, return it. */
  if (err)
    {
      result = err->apr_err;
      svn_error_clear(err);
      return result;

src/subversion/subversion/libsvn_subr/sqlite.c  view on Meta::CPAN

      err = svn_error_compose_create(err,
                                svn_sqlite__reset(db->prepared_stmts[i]));

  return err;
}

svn_error_t *
svn_sqlite__begin_transaction(svn_sqlite__db_t *db)
{
  svn_sqlite__stmt_t *stmt;

  SVN_ERR(get_internal_statement(&stmt, db,
                                 STMT_INTERNAL_BEGIN_TRANSACTION));
  SVN_ERR(svn_sqlite__step_done(stmt));
  return SVN_NO_ERROR;
}

svn_error_t *
svn_sqlite__begin_immediate_transaction(svn_sqlite__db_t *db)
{
  svn_sqlite__stmt_t *stmt;

  SVN_ERR(get_internal_statement(&stmt, db,
                                 STMT_INTERNAL_BEGIN_IMMEDIATE_TRANSACTION));
  SVN_ERR(svn_sqlite__step_done(stmt));
  return SVN_NO_ERROR;
}

svn_error_t *
svn_sqlite__begin_savepoint(svn_sqlite__db_t *db)
{
  svn_sqlite__stmt_t *stmt;

  SVN_ERR(get_internal_statement(&stmt, db,
                                 STMT_INTERNAL_SAVEPOINT_SVN));
  SVN_ERR(svn_sqlite__step_done(stmt));
  return SVN_NO_ERROR;
}

svn_error_t *
svn_sqlite__finish_transaction(svn_sqlite__db_t *db,
                               svn_error_t *err)
{
  svn_sqlite__stmt_t *stmt;

  /* Commit or rollback the sqlite transaction. */
  if (err)
    {
      svn_error_t *err2;

      err2 = get_internal_statement(&stmt, db,
                                    STMT_INTERNAL_ROLLBACK_TRANSACTION);
      if (!err2)
        err2 = svn_sqlite__step_done(stmt);

      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* ### Houston, we have a problem!

             We are trying to rollback but we can't because some
             statements are still busy. This leaves the database
             unusable for future transactions as the current transaction
             is still open.

             As we are returning the actual error as the most relevant
             error in the chain, our caller might assume that it can
             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
             in fact the SQLite database is unusable until the statements
             started within this transaction are reset and the transaction
             aborted.

             We try to compensate by resetting all prepared but unreset
             statements; but we leave the busy error in the chain anyway to
             help diagnosing the original error and help in finding where
             a reset statement is missing. */

          err2 = reset_all_statements(db, err2);
          err2 = svn_error_compose_create(
                      svn_sqlite__step_done(stmt),
                      err2);
        }

      return svn_error_compose_create(err,
                                      err2);
    }

  SVN_ERR(get_internal_statement(&stmt, db, STMT_INTERNAL_COMMIT_TRANSACTION));
  return svn_error_trace(svn_sqlite__step_done(stmt));
}

svn_error_t *
svn_sqlite__finish_savepoint(svn_sqlite__db_t *db,
                             svn_error_t *err)
{
  svn_sqlite__stmt_t *stmt;

  if (err)
    {
      svn_error_t *err2;

      err2 = get_internal_statement(&stmt, db,
                                    STMT_INTERNAL_ROLLBACK_TO_SAVEPOINT_SVN);

      if (!err2)
        err2 = svn_sqlite__step_done(stmt);

      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* Ok, we have a major problem. Some statement is still open, which
             makes it impossible to release this savepoint.

             ### See huge comment in svn_sqlite__finish_transaction for
                 further details */

          err2 = reset_all_statements(db, err2);
          err2 = svn_error_compose_create(svn_sqlite__step_done(stmt), err2);
        }

      err = svn_error_compose_create(err, err2);
      err2 = get_internal_statement(&stmt, db,
                                    STMT_INTERNAL_RELEASE_SAVEPOINT_SVN);

      if (!err2)
        err2 = svn_sqlite__step_done(stmt);

      return svn_error_trace(svn_error_compose_create(err, err2));
    }

  SVN_ERR(get_internal_statement(&stmt, db,
                                 STMT_INTERNAL_RELEASE_SAVEPOINT_SVN));

  return svn_error_trace(svn_sqlite__step_done(stmt));
}



( run in 0.667 second using v1.01-cache-2.11-cpan-140bd7fdf52 )