Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add Dataset/Database#mssql_unicode_strings accessor when connecting t…

…o MSSQL to control string literalization

This is just a cleanup of the previous commit.

By default, Sequel uses N'' for string literalization on MSSQL.
However, it can be faster to use just '', though that does not
work correctly in all cases.  This allows the user to use one
of the following to change the string literalzation to use '':

  DB.mssql_unicode_strings = false # default for datasets
  dataset.mssql_unicode_strings = false # just this dataset

You can also use the :mssql_unicode_strings option when connecting
to the database.

For more details on the difference between N'' and '', see
http://support.microsoft.com/kb/239530.
  • Loading branch information...
commit 7885ea6286a7b067fa79b5a7b20606c9231884c6 1 parent b24da42
@jeremyevans authored
View
2  CHANGELOG
@@ -1,5 +1,7 @@
=== HEAD
+* Add Dataset/Database#mssql_unicode_strings accessor when connecting to MSSQL to control string literalization (semmons99, jeremyevans)
+
* Fix ODBC::Time instance handling in the odbc adapter (jeremyevans)
* Use Sequel.application_timezone when connecting in the oracle adapter to set the connection's session's timezone (jmthomas)
View
18 lib/sequel/adapters/ado.rb
@@ -6,11 +6,6 @@ module ADO
class Database < Sequel::Database
set_adapter_scheme :ado
- # Whether all strings should be prefixed with "N" to imply treat as
- # unicode strings. True by default, can be set to false to greatly
- # increase performance depending on your database configuration.
- attr_accessor :mssql_unicode_strings
-
def initialize(opts)
super
case @opts[:conn_string]
@@ -23,9 +18,9 @@ def initialize(opts)
when 'SQL Server'
Sequel.ts_require 'adapters/ado/mssql'
extend Sequel::ADO::MSSQL::DatabaseMethods
+ set_mssql_unicode_strings
end
end
- @mssql_unicode_strings = typecast_value_boolean(@opts.fetch(:mssql_unicode_strings, true))
end
# In addition to the usual database options,
@@ -98,17 +93,6 @@ def disconnect_connection(conn)
end
class Dataset < Sequel::Dataset
- # Whether all strings should be prefixed with "N" to imply treat as
- # unicode strings. True by default, can be set to false to greatly
- # increase performance depending on your database configuration.
- attr_accessor :mssql_unicode_strings
-
- # Use the mssql_unicode_strings default setting from the database
- def initialize(db, opts={})
- @mssql_unicode_strings = db.mssql_unicode_strings
- super
- end
-
def fetch_rows(sql)
execute(sql) do |s|
@columns = cols = s.Fields.extend(Enumerable).map{|column| output_identifier(column.Name)}
View
17 lib/sequel/adapters/jdbc.rb
@@ -55,11 +55,13 @@ module JavaxNaming
:sqlserver=>proc do |db|
Sequel.ts_require 'adapters/jdbc/mssql'
db.extend(Sequel::JDBC::MSSQL::DatabaseMethods)
+ db.send(:set_mssql_unicode_strings)
com.microsoft.sqlserver.jdbc.SQLServerDriver
end,
:jtds=>proc do |db|
Sequel.ts_require 'adapters/jdbc/mssql'
db.extend(Sequel::JDBC::MSSQL::DatabaseMethods)
+ db.send(:set_mssql_unicode_strings)
JDBC.load_gem('jtds')
Java::net.sourceforge.jtds.jdbc.Driver
end,
@@ -102,11 +104,6 @@ class Database < Sequel::Database
# fetching rows.
attr_accessor :convert_types
- # Whether all strings should be prefixed with "N" to imply treat as
- # unicode strings. True by default, can be set to false to greatly
- # increase performance depending on your database configuration.
- attr_accessor :mssql_unicode_strings
-
# Call the DATABASE_SETUP proc directly after initialization,
# so the object always uses sub adapter specific code. Also,
# raise an error immediately if the connection doesn't have a
@@ -114,7 +111,6 @@ class Database < Sequel::Database
def initialize(opts)
super
@convert_types = typecast_value_boolean(@opts.fetch(:convert_types, true))
- @mssql_unicode_strings = typecast_value_boolean(@opts.fetch(:mssql_unicode_strings, true))
raise(Error, "No connection string specified") unless uri
resolved_uri = jndi? ? get_uri_from_jndi : uri
@@ -537,16 +533,9 @@ def execute_insert(sql, opts={}, &block)
# double performance when fetching rows.
attr_accessor :convert_types
- # Whether all strings should be prefixed with "N" to imply treat as
- # unicode strings. True by default, can be set to false to greatly
- # increase performance depending on your database configuration.
- attr_accessor :mssql_unicode_strings
-
- # Use the convert_types default setting from the database
- # Use the mssql_unicode_strings default setting from the database
+ # Use the convert_types default setting from the database.
def initialize(db, opts={})
@convert_types = db.convert_types
- @mssql_unicode_strings = db.mssql_unicode_strings
super
end
View
18 lib/sequel/adapters/odbc.rb
@@ -9,22 +9,17 @@ class Database < Sequel::Database
DRV_NAME_GUARDS = '{%s}'.freeze
DISCONNECT_ERRORS = /\A08S01/.freeze
- # Whether all strings should be prefixed with "N" to imply treat as
- # unicode strings. True by default, can be set to false to greatly
- # increase performance depending on your database configuration.
- attr_accessor :mssql_unicode_strings
-
def initialize(opts)
super
case @opts[:db_type]
when 'mssql'
Sequel.ts_require 'adapters/odbc/mssql'
extend Sequel::ODBC::MSSQL::DatabaseMethods
+ set_mssql_unicode_strings
when 'progress'
Sequel.ts_require 'adapters/shared/progress'
extend Sequel::Progress::DatabaseMethods
end
- @mssql_unicode_strings = typecast_value_boolean(@opts.fetch(:mssql_unicode_strings, true))
end
def connect(server)
@@ -93,17 +88,6 @@ class Dataset < Sequel::Dataset
ODBC_DATE_FORMAT = "{d '%Y-%m-%d'}".freeze
TIMESTAMP_FORMAT="{ts '%Y-%m-%d %H:%M:%S'}".freeze
- # Whether all strings should be prefixed with "N" to imply treat as
- # unicode strings. True by default, can be set to false to greatly
- # increase performance depending on your database configuration.
- attr_accessor :mssql_unicode_strings
-
- # Use the mssql_unicode_strings default setting from the database
- def initialize(db, opts={})
- @mssql_unicode_strings = db.mssql_unicode_strings
- super
- end
-
def fetch_rows(sql)
execute(sql) do |s|
i = -1
View
24 lib/sequel/adapters/shared/mssql.rb
@@ -11,6 +11,12 @@ module DatabaseMethods
SQL_ROLLBACK_TO_SAVEPOINT = 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION autopoint_%d'.freeze
SQL_SAVEPOINT = 'SAVE TRANSACTION autopoint_%d'.freeze
+ # Whether to use N'' to quote strings, which allows unicode characters inside the
+ # strings. True by default for compatibility, can be set to false for a possible
+ # performance increase. This sets the default for all datasets created from this
+ # Database object.
+ attr_accessor :mssql_unicode_strings
+
# The types to check for 0 scale to transform :decimal types
# to :integer.
DECIMAL_TYPE_RE = /number|numeric|decimal/io
@@ -163,6 +169,11 @@ def schema_parse_table(table_name, opts)
[m.call(row.delete(:column)), row]
end
end
+
+ # Set the mssql_unicode_strings settings from the given options.
+ def set_mssql_unicode_strings
+ @mssql_unicode_strings = typecast_value_boolean(@opts.fetch(:mssql_unicode_strings, true))
+ end
# MSSQL has both datetime and timestamp classes, most people are going
# to want datetime
@@ -211,6 +222,15 @@ module DatasetMethods
WILDCARD = LiteralString.new('*').freeze
CONSTANT_MAP = {:CURRENT_DATE=>'CAST(CURRENT_TIMESTAMP AS DATE)'.freeze, :CURRENT_TIME=>'CAST(CURRENT_TIMESTAMP AS TIME)'.freeze}
+ # Allow overriding of the mssql_unicode_strings option at the dataset level.
+ attr_accessor :mssql_unicode_strings
+
+ # Copy the mssql_unicode_strings option from the +db+ object.
+ def initialize(db, opts={})
+ super
+ @mssql_unicode_strings = db.mssql_unicode_strings
+ end
+
# MSSQL uses + for string concatenation, and LIKE is case insensitive by default.
def complex_expression_sql(op, args)
case op
@@ -444,9 +464,7 @@ def literal_blob(v)
# Optionally use unicode string syntax for all strings. Don't double
# backslashes.
def literal_string(v)
- str = "'#{v.gsub(/'/, "''")}'"
- str = "N#{str}" unless @mssql_unicode_strings == false
- str
+ "#{'N' if mssql_unicode_strings}'#{v.gsub(/'/, "''")}'"
end
# Use 0 for false on MSSQL
View
3  lib/sequel/adapters/tinytds.rb
@@ -13,6 +13,7 @@ def connect(server)
opts = server_opts(server)
opts[:dataserver] = opts[:host]
opts[:username] = opts[:user]
+ set_mssql_unicode_strings
TinyTds::Client.new(opts)
end
@@ -118,7 +119,7 @@ def fetch_rows(sql)
# Properly escape the given string +v+.
def literal_string(v)
- db.synchronize{|c| "N'#{c.escape(v)}'"}
+ s = db.synchronize{|c| "#{'N' if mssql_unicode_strings}'#{c.escape(v)}'"}
end
end
end
View
54 spec/adapters/mssql_opts_spec.rb
@@ -1,54 +0,0 @@
-require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
-
-if RUBY_PLATFORM =~ /java/
- describe "JDBC" do
- context "mssql_unicode_strings is default/true" do
- let(:db) { Sequel.jdbc("jdbc:sqlserver://localhost") }
- subject { db[:tb1].filter(:col1 => "test").sql }
-
- it { should == "SELECT * FROM TB1 WHERE (COL1 = N'test')" }
- end
-
- context "mssql_unicode_strings is false" do
- let(:db) { Sequel.jdbc("jdbc:sqlserver://localhost",
- :mssql_unicode_strings => false) }
- subject { db[:tb1].filter(:col1 => "test").sql }
-
- it { should == "SELECT * FROM TB1 WHERE (COL1 = 'test')" }
- end
- end
-else
- describe "ADO" do
- context "mssql_unicode_strings is default/true" do
- let(:db) { Sequel.ado(:conn_string => "dummy connection string") }
- subject { db[:tb1].filter(:col1 => "test").sql }
-
- it { should == "SELECT * FROM TB1 WHERE (COL1 = N'test')" }
- end
-
- context "mssql_unicode_strings is false" do
- let(:db) { Sequel.ado(:conn_string => "dummy connection string",
- :mssql_unicode_strings => false) }
- subject { db[:tb1].filter(:col1 => "test").sql }
-
- it { should == "SELECT * FROM TB1 WHERE (COL1 = 'test')" }
- end
- end
-
- describe "ODBC" do
- context "mssql_unicode_strings is default/true" do
- let(:db) { Sequel.odbc("dummy", :db_type => "mssql") }
- subject { db[:tb1].filter(:col1 => "test").sql }
-
- it { should == "SELECT * FROM TB1 WHERE (COL1 = N'test')" }
- end
-
- context "mssql_unicode_strings is false" do
- let(:db) { Sequel.odbc("dummy", :db_type => "mssql",
- :mssql_unicode_strings => false) }
- subject { db[:tb1].filter(:col1 => "test").sql }
-
- it { should == "SELECT * FROM TB1 WHERE (COL1 = 'test')" }
- end
- end
-end
View
28 spec/adapters/mssql_spec.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
require ENV['SEQUEL_MSSQL_SPEC_REQUIRE'] if ENV['SEQUEL_MSSQL_SPEC_REQUIRE']
@@ -448,3 +449,30 @@ def transaction(opts={})
MSSQL_DB[:items].select_map(:name).should == ["foo"]
end
end
+
+describe "MSSQL::Database#mssql_unicode_strings = false" do
+ before do
+ MSSQL_DB.mssql_unicode_strings = false
+ end
+ after do
+ MSSQL_DB.drop_table(:items)
+ MSSQL_DB.mssql_unicode_strings = true
+ end
+
+ specify "should work correctly" do
+ MSSQL_DB.create_table!(:items){String :name}
+ MSSQL_DB[:items].mssql_unicode_strings.should == false
+ MSSQL_DB[:items].insert(:name=>'foo')
+ MSSQL_DB[:items].select_map(:name).should == ['foo']
+ end
+
+ specify "should be overridable at the dataset level" do
+ MSSQL_DB.create_table!(:items){String :name}
+ ds = MSSQL_DB[:items]
+ ds.mssql_unicode_strings.should == false
+ ds.mssql_unicode_strings = true
+ ds.mssql_unicode_strings.should == true
+ ds.insert(:name=>'foo')
+ ds.select_map(:name).should == ['foo']
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.