Ejemplo n.º 1
0
static int cdbi_connect_database (cdbi_database_t *db) /* {{{ */
{
  dbi_driver driver;
  dbi_conn connection;
  size_t i;
  int status;

  if (db->connection != NULL)
  {
    status = dbi_conn_ping (db->connection);
    if (status != 0) /* connection is alive */
      return (0);

    dbi_conn_close (db->connection);
    db->connection = NULL;
  }

  driver = dbi_driver_open_r (db->driver, dbi_instance);
  if (driver == NULL)
  {
    ERROR ("dbi plugin: cdbi_connect_database: dbi_driver_open_r (%s) failed.",
        db->driver);
    INFO ("dbi plugin: Maybe the driver isn't installed? "
        "Known drivers are:");
    for (driver = dbi_driver_list_r (NULL, dbi_instance);
        driver != NULL;
        driver = dbi_driver_list_r (driver, dbi_instance))
    {
      INFO ("dbi plugin: * %s", dbi_driver_get_name (driver));
    }
    return (-1);
  }

  connection = dbi_conn_open (driver);
  if (connection == NULL)
  {
    ERROR ("dbi plugin: cdbi_connect_database: dbi_conn_open (%s) failed.",
        db->driver);
    return (-1);
  }

  /* Set all the driver options. Because this is a very very very generic
   * interface, the error handling is kind of long. If an invalid option is
   * encountered, it will get a list of options understood by the driver and
   * report that as `INFO'. This way, users hopefully don't have too much
   * trouble finding out how to configure the plugin correctly.. */
  for (i = 0; i < db->driver_options_num; i++)
  {
    if (db->driver_options[i].is_numeric)
    {
      status = dbi_conn_set_option_numeric (connection,
          db->driver_options[i].key, db->driver_options[i].value.numeric);
      if (status != 0)
      {
        char errbuf[1024];
        ERROR ("dbi plugin: cdbi_connect_database (%s): "
            "dbi_conn_set_option_numeric (\"%s\", %i) failed: %s.",
            db->name,
            db->driver_options[i].key, db->driver_options[i].value.numeric,
            cdbi_strerror (connection, errbuf, sizeof (errbuf)));
      }
    }
    else
    {
      status = dbi_conn_set_option (connection,
          db->driver_options[i].key, db->driver_options[i].value.string);
      if (status != 0)
      {
        char errbuf[1024];
        ERROR ("dbi plugin: cdbi_connect_database (%s): "
            "dbi_conn_set_option (\"%s\", \"%s\") failed: %s.",
            db->name,
            db->driver_options[i].key, db->driver_options[i].value.string,
            cdbi_strerror (connection, errbuf, sizeof (errbuf)));
      }
    }

    if (status != 0)
    {
      char const *opt;

      INFO ("dbi plugin: This is a list of all options understood "
          "by the `%s' driver:", db->driver);
      for (opt = dbi_conn_get_option_list (connection, NULL);
          opt != NULL;
          opt = dbi_conn_get_option_list (connection, opt))
      {
        INFO ("dbi plugin: * %s", opt);
      }

      dbi_conn_close (connection);
      return (-1);
    }
  } /* for (i = 0; i < db->driver_options_num; i++) */

  status = dbi_conn_connect (connection);
  if (status != 0)
  {
    char errbuf[1024];
    ERROR ("dbi plugin: cdbi_connect_database (%s): "
        "dbi_conn_connect failed: %s",
        db->name, cdbi_strerror (connection, errbuf, sizeof (errbuf)));
    dbi_conn_close (connection);
    return (-1);
  }

  if (db->select_db != NULL)
  {
    status = dbi_conn_select_db (connection, db->select_db);
    if (status != 0)
    {
      char errbuf[1024];
      WARNING ("dbi plugin: cdbi_connect_database (%s): "
          "dbi_conn_select_db (%s) failed: %s. Check the `SelectDB' option.",
          db->name, db->select_db,
          cdbi_strerror (connection, errbuf, sizeof (errbuf)));
      dbi_conn_close (connection);
      return (-1);
    }
  }

  db->connection = connection;
  return (0);
} /* }}} int cdbi_connect_database */
Ejemplo n.º 2
0
template <DbType T> void
gnc_dbi_session_begin (QofBackend* qbe, QofSession* session,
                             const char* book_id, gboolean ignore_lock,
                             gboolean create, gboolean force)
{
    GncDbiBackend* be = (GncDbiBackend*)qbe;
    GncDbiTestResult dbi_test_result = GNC_DBI_PASS;
    PairVec options;

    g_return_if_fail (qbe != nullptr);
    g_return_if_fail (session != nullptr);
    g_return_if_fail (book_id != nullptr);

    ENTER (" ");

    /* Split the book-id
     * Format is protocol://username:password@hostname:port/dbname
     where username, password and port are optional) */
    UriStrings uri(book_id);

    if (T == DbType::DBI_PGSQL)
    {
        if (uri.m_portnum == 0)
            uri.m_portnum = PGSQL_DEFAULT_PORT;
        /* Postgres's SQL interface coerces identifiers to lower case, but the
         * C interface is case-sensitive. This results in a mixed-case dbname
         * being created (with a lower case name) but then dbi can't conect to
         * it. To work around this, coerce the name to lowercase first. */
        auto lcname = g_utf8_strdown (uri.dbname(), -1);
        uri.m_dbname = std::string{lcname};
        g_free(lcname);
    }
    be->connect(nullptr);

    auto conn = conn_setup<T>(qbe, options, uri);
    if (conn == nullptr)
    {
        LEAVE("Error");
        return;
    }

    be->set_exists(true); //May be unset in the error handler.
    auto result = dbi_conn_connect (conn);
    if (result == 0)
    {
        if (T == DbType::DBI_MYSQL)
            adjust_sql_options (conn);
        if(!conn_test_dbi_library(conn, qbe))
        {
            dbi_conn_close(conn);
            LEAVE("Error");
            return;
        }
        if (create && !force && save_may_clobber_data (conn,
                                                       uri.quote_dbname(T)))
        {
            qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS);
            PWARN ("Databse already exists, Might clobber it.");
            dbi_conn_close(conn);
            LEAVE("Error");
            return;
        }

    }
    else
    {

        if (be->exists())
        {
            PERR ("Unable to connect to database '%s'\n", uri.dbname());
            qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR);
            dbi_conn_close(conn);
            LEAVE("Error");
            return;
        }

        if (create)
        {
            if (!create_database(T, qbe, conn, uri.quote_dbname(T).c_str()))
            {
                dbi_conn_close(conn);
                LEAVE("Error");
                return;
            }
            conn = conn_setup<T>(qbe, options, uri);
            result = dbi_conn_connect (conn);
            if (result < 0)
            {
                PERR ("Unable to create database '%s'\n", uri.dbname());
                qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR);
                dbi_conn_close(conn);
                LEAVE("Error");
                return;
            }
            if (T == DbType::DBI_MYSQL)
                adjust_sql_options (conn);
            if (!conn_test_dbi_library(conn, qbe))
            {
                if (T == DbType::DBI_PGSQL)
                    dbi_conn_select_db (conn, "template1");
                dbi_conn_queryf (conn, "DROP DATABASE %s",
                                 uri.quote_dbname(T).c_str());
                dbi_conn_close(conn);
                return;
            }
        }
        else
        {
            qof_backend_set_error (qbe, ERR_BACKEND_NO_SUCH_DB);
            qof_backend_set_message (qbe, "Database %s not found", uri.dbname());
        }
    }

    be->connect(nullptr);
    try
    {
        be->connect(new GncDbiSqlConnection(T, qbe, conn, ignore_lock));
    }
    catch (std::runtime_error& err)
    {
        return;
    }
    /* We should now have a proper session set up.
     * Let's start logging */
    auto translog_path = gnc_build_translog_path (uri.basename().c_str());
    xaccLogSetBaseName (translog_path);
    PINFO ("logpath=%s", translog_path ? translog_path : "(null)");
    g_free (translog_path);

    LEAVE (" ");
}