Esempio n. 1
0
END_TEST

START_TEST (encode_encoding_test) {
  int res;
  const char *encoding;

  res = pr_encode_enable_encoding(NULL);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  encoding = "utf-8";
  res = pr_encode_enable_encoding(encoding);
  fail_unless(res == 0, "Failed to enable encoding '%s': %s", encoding,
    strerror(errno));

  encoding = "iso-8859-1";
  res = pr_encode_enable_encoding(encoding);
  fail_unless(res == 0, "Failed to enable encoding '%s': %s", encoding,
    strerror(errno));

  encoding = "foo";
  res = pr_encode_enable_encoding(encoding);
  fail_unless(res < 0, "Failed to handle bad encoding '%s'", encoding);
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  pr_encode_disable_encoding();

  encoding = "utf-8";
  res = pr_encode_enable_encoding(encoding);
  fail_unless(res == 0, "Failed to enable encoding '%s': %s", encoding,
    strerror(errno));

  encoding = pr_encode_get_encoding();
  fail_unless(encoding != NULL, "Failed to get encoding: %s", strerror(errno));
  fail_unless(strcasecmp(encoding, "utf-8") == 0,
    "Expected 'utf-8', got '%s'", encoding);
}
Esempio n. 2
0
/*
 * cmd_open: attempts to open a named connection to the database.
 *
 * Inputs:
 *  cmd->argv[0]: connection name
 *
 * Returns:
 *  either a properly filled error modret_t if a connection could not be
 *  opened, or a simple non-error modret_t.
 *
 * Notes:
 *  mod_sql depends on these semantics -- a backend should not open
 *  a connection unless mod_sql requests it, nor close one unless 
 *  mod_sql requests it.  Connection counting is *REQUIRED* for complete
 *  compatibility; a connection should not be closed unless the count
 *  reaches 0, and ideally will not need to be re-opened for counts > 1.
 */
MODRET cmd_open(cmd_rec *cmd) {
  conn_entry_t *entry = NULL;
  db_conn_t *conn = NULL;
  const char *server_version = NULL;

  sql_log(DEBUG_FUNC, "%s", "entering \tpostgres cmd_open");

  _sql_check_cmd(cmd, "cmd_open" );

  if (cmd->argc < 1) {
    sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
    return PR_ERROR_MSG(cmd, MOD_SQL_POSTGRES_VERSION, "badly formed request");
  }    

  /* get the named connection */

  if (!(entry = _sql_get_connection(cmd->argv[0]))) {
    sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
    return PR_ERROR_MSG(cmd, MOD_SQL_POSTGRES_VERSION,
      "unknown named connection");
  } 

  conn = (db_conn_t *) entry->data;

  /* if we're already open (connections > 0) increment connections 
   * reset our timer if we have one, and return HANDLED 
   */
  if (entry->connections > 0) { 
    if (PQstatus(conn->postgres) == CONNECTION_OK) {
      entry->connections++;

      if (entry->timer) {
        pr_timer_reset(entry->timer, &sql_postgres_module);
      }

      sql_log(DEBUG_INFO, "connection '%s' count is now %d", entry->name,
        entry->connections);
      sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
      return PR_HANDLED(cmd);

    } else {
      char *reason;
      size_t reason_len;

      /* Unless we've been told not to reconnect, try to reconnect now.
       * We only try once; if it fails, we return an error.
       */
      if (!(pr_sql_opts & SQL_OPT_NO_RECONNECT)) {
        PQreset(conn->postgres);

        if (PQstatus(conn->postgres) == CONNECTION_OK) {
          entry->connections++;

          if (entry->timer) {
            pr_timer_reset(entry->timer, &sql_postgres_module);
          }

          sql_log(DEBUG_INFO, "connection '%s' count is now %d", entry->name,
            entry->connections);
          sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
          return PR_HANDLED(cmd);
        }
      }

      reason = PQerrorMessage(conn->postgres);
      reason_len = strlen(reason);

      /* Postgres might give us an empty string as the reason; not helpful. */
      if (reason_len == 0) {
        reason = "(unknown)";
        reason_len = strlen(reason);
      }

      /* The error message returned by Postgres is usually appended with
       * a newline.  Let's prettify it by removing the newline.  Note
       * that yes, we are overwriting the pointer given to us by Postgres,
       * but it's OK.  The Postgres docs say that we're not supposed to
       * free the memory associated with the returned string anyway.
       */
      reason = pstrdup(session.pool, reason);

      if (reason[reason_len-1] == '\n') {
        reason[reason_len-1] = '\0';
        reason_len--;
      }

      sql_log(DEBUG_INFO, "lost connection to database: %s", reason);

      entry->connections = 0;
      if (entry->timer) {
        pr_timer_remove(entry->timer, &sql_postgres_module);
        entry->timer = 0;
      }

      sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
      return PR_ERROR_MSG(cmd, MOD_SQL_POSTGRES_VERSION,
        "lost connection to database");
    }
  }

  /* make sure we have a new conn struct */
  conn->postgres = PQconnectdb(conn->connectstring);
  
  if (PQstatus(conn->postgres) == CONNECTION_BAD) {
    /* if it didn't work, return an error */
    sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
    return _build_error( cmd, conn );
  }

#if defined(PG_VERSION_STR)
  sql_log(DEBUG_FUNC, "Postgres client: %s", PG_VERSION_STR);
#endif

  server_version = PQparameterStatus(conn->postgres, "server_version");
  if (server_version != NULL) {
    sql_log(DEBUG_FUNC, "Postgres server version: %s", server_version);
  }

#ifdef PR_USE_NLS
  if (pr_encode_get_encoding() != NULL) {
    const char *encoding;

    encoding = get_postgres_encoding(pr_encode_get_encoding());

    /* Configure the connection for the current local character set. */
    if (PQsetClientEncoding(conn->postgres, encoding) < 0) {
      /* if it didn't work, return an error */
      sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
      return _build_error(cmd, conn);
    }

    sql_log(DEBUG_FUNC, "Postgres connection character set now '%s' "
      "(from '%s')", pg_encoding_to_char(PQclientEncoding(conn->postgres)),
      pr_encode_get_encoding());
  }
#endif /* !PR_USE_NLS */

  /* bump connections */
  entry->connections++;

  if (pr_sql_conn_policy == SQL_CONN_POLICY_PERSESSION) {
    /* If the connection policy is PERSESSION... */
    if (entry->connections == 1) {
      /* ...and we are actually opening the first connection to the database;
       * we want to make sure this connection stays open, after this first use
       * (as per Bug#3290).  To do this, we re-bump the connection count.
       */
      entry->connections++;
    } 
 
  } else if (entry->ttl > 0) { 
    /* Set up our timer if necessary */

    entry->timer = pr_timer_add(entry->ttl, -1, &sql_postgres_module,
      sql_timer_cb, "postgres connection ttl");
    sql_log(DEBUG_INFO, "connection '%s' - %d second timer started",
      entry->name, entry->ttl);

    /* Timed connections get re-bumped so they don't go away when cmd_close
     * is called.
     */
    entry->connections++;
  }

  /* return HANDLED */
  sql_log(DEBUG_INFO, "connection '%s' opened", entry->name);

  sql_log(DEBUG_INFO, "connection '%s' count is now %d", entry->name,
    entry->connections);

  sql_log(DEBUG_FUNC, "%s", "exiting \tpostgres cmd_open");
  return PR_HANDLED(cmd);
}