Rails database 添加 application_name 问题

clarkyi · 2016年10月09日 · 最后由 clarkyi 回复于 2016年10月10日 · 2284 次阅读




在 config/database.yml 中添加如下配置

  adapter: postgresql
  database: dbname
  application_name: 'app_name'
  username: dbuser
  password: dbpwd
  host: ip
  port: 5432
  encoding: utf-8
  pool: 5

在 console 中执行

PGconn.connect({:application_name=>"app_name", :host=>"ip", :password=>"pwd", :user=>"dbuser", :dbname=>"dbname"})


PG::ConnectionBad: invalid connection option "application_name"
from /opt/rails_apps/app_name/shared/bundle/ruby/2.0.0/gems/railties-4.2.4/lib/rails/commands/console.rb:110:in `start'
from /opt/rails_apps/app_name/shared/bundle/ruby/2.0.0/gems/railties-4.2.4/lib/rails/commands/console.rb:9:in `start'
from /opt/rails_apps/app_name/shared/bundle/ruby/2.0.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:68:in `console'
from /opt/rails_apps/app_name/shared/bundle/ruby/2.0.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /opt/rails_apps/app_name/shared/bundle/ruby/2.0.0/gems/railties-4.2.4/lib/rails/commands.rb:17:in `<top (required)>'

查看 active_record postgresql_adapter 源码

# Establishes a connection to the database that's used by all Active Record objects
def postgresql_connection(config)
  ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)

再看实例化 ConnectionAdapters::PostgreSQLAdapter 的代码

class StatementPool < ConnectionAdapters::StatementPool
   # Initializes and connects a PostgreSQL adapter.
   def initialize(connection, logger, connection_parameters, config)

再看 postgresql adpater 的 connect 方法

       # Connects to a PostgreSQL server and sets up the adapter depending on the
# connected server's characteristics.
def connect
  @connection = PGconn.connect(@connection_parameters)

  # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
  # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
  # should know about this but can't detect it there, so deal with it here.
  OID::Money.precision = (postgresql_version >= 80300) ? 19 : 10

rescue ::PG::Error => error
  if error.message.include?("does not exist")
    raise ActiveRecord::NoDatabaseError.new(error.message, error)

ok,到这里已经知道这里调用了 pg gem 的 connect 方法,所以这里打开 pg 源码

def self::connect( *args )
  return PG::Connection.new( *args )

这里再打开 pg 的 connection.rb 文件发现以下代码

### Parse the connection +args+ into a connection-parameter string. See PG::Connection.new
### for valid arguments.
def self::parse_connect_args( *args )
  return '' if args.empty?
  hash_arg = args.last.is_a?( Hash ) ? args.pop : {}
  option_string = ''
  options = {}

  # Parameter 'fallback_application_name' was introduced in PostgreSQL 9.0
  # together with PQescapeLiteral().
  if PG::Connection.instance_methods.find {|m| m.to_sym == :escape_literal }
    options[:fallback_application_name] = $0.sub( /^(.{30}).{4,}(.{30})$/ ){ $1+"..."+$2 }

这里会对 application_name 做处理,详细情况看Postgresql 9.0 于是在 rails c 中执行

PG::Connection.instance_methods.find {|m| m.to_sym == :escape_literal }

这里返回空值,为什么没有这个方法呢?escape_literal 方法在哪里定义呢? 最后在扩展包 pg_connection.c 里面发现了如下代码:

 * call-seq:
 *    conn.escape_literal( str ) -> String
 * Escape an arbitrary String +str+ as a literal.
static VALUE
pgconn_escape_literal(VALUE self, VALUE string)
  PGconn *conn = pg_get_pgconn(self);
  escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
  if (escaped == NULL)
    return Qnil;
  return result;

不懂 C 语言,根据代码猜测应该是如果定义了 HAVE_PQESCAPELITERAL 就应该可以通过 conn 调用 escape_literal 方法,返回一个 string 而刚才在控制台中执行的

PG::Connection.instance_methods.find {|m| m.to_sym == :escape_literal }

返回了 nil,也就是说在 pg_connection.c 的 pgconn_escape_literal 返回了空,所以 escaped 返回了空值 Qnil(猜的) 那么在 PQescapeLiteral 中是做了什么事情呢?原文


sql char *PQescapeLiteral(PGconn *conn, const char *str, size_t length);

PQescapeLiteral escapes a string for use within an SQL command. This is useful when inserting data values as literal constants in SQL commands. Certain characters (such

as quotes and backslashes) must be escaped to prevent them from being interpreted specially by the SQL parser. PQescapeLiteral performs this operation.

PQescapeLiteral returns an escaped version of the str parameter in memory allocated with malloc(). This memory should be freed using PQfreemem() when the result is no

longer needed. A terminating zero byte is not required, and should not be counted in length. (If a terminating zero byte is found before length bytes are processed,

PQescapeLiteral stops at the zero; the behavior is thus rather like strncpy.) The return string has all special characters replaced so that they can be properly processed by the

PostgreSQL string literal parser. A terminating zero byte is also added. The single quotes that must surround PostgreSQL string literals are included in the result string.

On error, PQescapeLiteral returns NULL and a suitable message is stored in the conn object.

Tip: It is especially important to do proper escaping when handling strings that were received from an untrustworthy source. Otherwise there is a security risk: you are

vulnerable to "SQL injection" attacks wherein unwanted SQL commands are fed to your database.

Note that it is not necessary nor correct to do escaping when a data value is passed as a separate parameter in PQexecParams or its sibling routines.


bundle config 配置情况

bundle config
Settings are listed in order of priority. The top value will be used.
Set for the current user (/home/tester/.bundle/config): "--with-pg-config=/usr/pgsql-9.2/bin/pg_config"

Set for your local app (/opt/rails_apps/tester/release/appname-product- "1"

Set for your local app (/opt/rails_apps/tester/release/appname-product- "/opt/rails_apps/appname/shared/bundle"

Set for your local app (/opt/rails_apps/tester/release/appname-product- "development:test"

Set for your local app (/opt/rails_apps/tester/release/appname-product- "1"

ruby 版本:ruby 2.0.0p643 (2015-02-25 revision 49749) [x86_64-linux]

rails 版本:rails-4.2.4

pg 版本:pg-0.18.3

系统版本:CentOS release 6.5 (Final)



bundle config build.pg --with-pg-config=/usr/pgsql-9.2/bin/pg_config

step 2

gem uninstall pg
bundle install

step 3

vim Gemfile
#gem ‘pg'

step 4

bundle install

step 5

vim Gemfile
gem ‘pg'

step 6

bundle install

验证 RAILS_ENV=test rails c :

 PGconn.connect({:application_name=>”name", :host=>”ip", :password=>”pwd", :user=>”user", :dbname=>”dbname"})
=> #<PG::Connection:0x00000006c65b78>


clarkyi 关闭了讨论 10月10日 11:39
clarkyi 重新开启了讨论 10月10日 11:39

问题解决 由 bundle install --path /opt/rails_apps/appname/shared/bundle --without development test --deployment --quiet改为 bundle install --without development test --no-deployment --quiet

clarkyi 关闭了讨论 10月10日 11:45
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册