module Sequel::MSSQL::DatasetMethods

  1. lib/sequel/adapters/shared/mssql.rb
Parent: MSSQL

Included modules

  1. EmulateOffsetWithRowNumber

Constants

APOS = Dataset::APOS  
APOS_RE = Dataset::APOS_RE  
BACKSLASH_CRLF_RE = /\\((?:\r\n)|\n)/.freeze  
BACKSLASH_CRLF_REPLACE = '\\\\\\\\\\1\\1'.freeze  
BOOL_FALSE = '0'.freeze  
BOOL_TRUE = '1'.freeze  
BRACKET_CLOSE = Dataset::BRACKET_CLOSE  
BRACKET_OPEN = Dataset::BRACKET_OPEN  
CASE_INSENSITIVE_COLLATION = 'Latin1_General_CI_AS'.freeze  
CASE_SENSITIVE_COLLATION = 'Latin1_General_CS_AS'.freeze  
COMMA = Dataset::COMMA  
COMMA_SEPARATOR = ', '.freeze  
CONSTANT_MAP = {:CURRENT_DATE=>'CAST(CURRENT_TIMESTAMP AS DATE)'.freeze, :CURRENT_TIME=>'CAST(CURRENT_TIMESTAMP AS TIME)'.freeze}  
CROSS_APPLY = 'CROSS APPLY'.freeze  
DATEPART_OPEN = "datepart(".freeze  
DATEPART_SECOND_CLOSE = ")/1000000000.0) AS double precision)".freeze  
DATEPART_SECOND_MIDDLE = ') + datepart(ns, '.freeze  
DATEPART_SECOND_OPEN = "CAST((datepart(".freeze  
DEFAULT_TIMESTAMP_FORMAT = "'%Y-%m-%dT%H:%M:%S%N%z'".freeze  
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'with delete from output from2 where')  
DOUBLE_APOS = Dataset::DOUBLE_APOS  
DOUBLE_BRACKET_CLOSE = ']]'.freeze  
EXTRACT_MAP = {:year=>"yy", :month=>"m", :day=>"d", :hour=>"hh", :minute=>"n", :second=>"s"}  
FORMAT_DATE = "'%Y%m%d'".freeze  
FROM = Dataset::FROM  
HEX_START = '0x'.freeze  
HSTAR = "H*".freeze  
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'with insert into columns output values')  
INTO = Dataset::INTO  
NOLOCK = ' WITH (NOLOCK)'.freeze  
OUTER_APPLY = 'OUTER APPLY'.freeze  
OUTPUT = " OUTPUT ".freeze  
OUTPUT_INSERTED = " OUTPUT INSERTED.*".freeze  
PAREN_CLOSE = Dataset::PAREN_CLOSE  
PAREN_SPACE_OPEN = Dataset::PAREN_SPACE_OPEN  
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with select distinct limit columns into from lock join where group having order compounds')  
SELECT_SPACE = 'SELECT '.freeze  
SPACE = Dataset::SPACE  
TIMESTAMP_USEC_FORMAT = ".%03d".freeze  
TOP = " TOP ".freeze  
TOP_PAREN = " TOP (".freeze  
UNICODE_STRING_START = "N'".freeze  
UNION_ALL = ' UNION ALL '.freeze  
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'with update limit table set output from where')  
UPDATE_CLAUSE_METHODS_2000 = Dataset.clause_methods(:update, %w'update table set output from where')  
UPDLOCK = ' WITH (UPDLOCK)'.freeze  
WILDCARD = LiteralString.new('*').freeze  

Attributes

mssql_unicode_strings [W]

Allow overriding of the #mssql_unicode_strings option at the dataset level.

Public Instance methods

complex_expression_sql_append (sql, op, args)

MSSQL uses + for string concatenation, and LIKE is case insensitive by default.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 472
def complex_expression_sql_append(sql, op, args)
  case op
  when :'||'
    super(sql, :+, args)
  when :LIKE, :"NOT LIKE"
    super(sql, op, args.map{|a| LiteralString.new("(#{literal(a)} COLLATE #{CASE_SENSITIVE_COLLATION})")})
  when :ILIKE, :"NOT ILIKE"
    super(sql, (op == :ILIKE ? :LIKE : :"NOT LIKE"), args.map{|a| LiteralString.new("(#{literal(a)} COLLATE #{CASE_INSENSITIVE_COLLATION})")})
  when :<<
    sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
  when :>>
    sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
  when :extract
    part = args.at(0)
    raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
    if part == :second
      expr = literal(args.at(1))
      sql << DATEPART_SECOND_OPEN << format.to_s << COMMA << expr << DATEPART_SECOND_MIDDLE << expr << DATEPART_SECOND_CLOSE
    else
      sql << DATEPART_OPEN << format.to_s << COMMA
      literal_append(sql, args.at(1))
      sql << PAREN_CLOSE
    end
  else
    super
  end
end
constant_sql_append (sql, constant)

MSSQL doesn't support the SQL standard CURRENT_DATE or CURRENT_TIME

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 501
def constant_sql_append(sql, constant)
  if c = CONSTANT_MAP[constant]
    sql << c
  else
    super
  end
end
cross_apply (table)

Uses CROSS APPLY to join the given table into the current dataset.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 510
def cross_apply(table)
  join_table(:cross_apply, table)
end
disable_insert_output ()

Disable the use of INSERT OUTPUT

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 515
def disable_insert_output
  clone(:disable_insert_output=>true)
end
emulated_function_sql_append (sql, f)

There is no function on Microsoft SQL Server that does character length and respects trailing spaces (datalength respects trailing spaces, but counts bytes instead of characters). Use a hack to work around the trailing spaces issue.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 528
def emulated_function_sql_append(sql, f)
  case f.f
  when :char_length
    literal_append(sql, SQL::Function.new(:len, Sequel.join([f.args.first, 'x'])) - 1)
  when :trim
    literal_append(sql, SQL::Function.new(:ltrim, SQL::Function.new(:rtrim, f.args.first)))
  else
    super
  end
end
escape_like (string)

MSSQL treats [] as a metacharacter in LIKE expresions.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 520
def escape_like(string)
  string.gsub(/[\%_\[\]]/){|m| "\\#{m}"}
end
insert_select (*values)

Use the OUTPUT clause to get the value of all columns for the newly inserted record.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 546
def insert_select(*values)
  return unless supports_insert_select?
  naked.clone(default_server_opts(:sql=>output(nil, [SQL::ColumnAll.new(:inserted)]).insert_sql(*values))).single_record
end
into (table)

Specify a table for a SELECT … INTO query.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 552
def into(table)
  clone(:into => table)
end
mssql_unicode_strings ()

Use the database’s #mssql_unicode_strings setting if the dataset hasn’t overridden it.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 467
def mssql_unicode_strings
  defined?(@mssql_unicode_strings) ? @mssql_unicode_strings : (@mssql_unicode_strings = db.mssql_unicode_strings)
end
multi_insert_sql (columns, values)

MSSQL uses a UNION ALL statement to insert multiple values at once.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 557
def multi_insert_sql(columns, values)
  c = false
  sql = LiteralString.new('')
  u = UNION_ALL
  values.each do |v|
    sql << u if c
    sql << SELECT_SPACE
    expression_list_append(sql, v)
    c ||= true
  end
  [insert_sql(columns, sql)]
end
nolock ()

Allows you to do a dirty read of uncommitted data using WITH (NOLOCK).

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 571
def nolock
  lock_style(:dirty)
end
outer_apply (table)

Uses OUTER APPLY to join the given table into the current dataset.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 576
def outer_apply(table)
  join_table(:outer_apply, table)
end
output (into, values)

Include an OUTPUT clause in the eventual INSERT, UPDATE, or DELETE query.

The first argument is the table to output into, and the second argument is either an Array of column values to select, or a Hash which maps output column names to selected values, in the style of insert or update.

Output into a returned result set is not currently supported.

Examples:

dataset.output(:output_table, [:deleted__id, :deleted__name])
dataset.output(:output_table, :id => :inserted__id, :name => :inserted__name)
[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 592
def output(into, values)
  raise(Error, "SQL Server versions 2000 and earlier do not support the OUTPUT clause") unless supports_output_clause?
  output = {}
  case values
    when Hash
      output[:column_list], output[:select_list] = values.keys, values.values
    when Array
      output[:select_list] = values
  end
  output[:into] = into
  clone({:output => output})
end
quoted_identifier_append (sql, name)

MSSQL uses [] to quote identifiers.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 606
def quoted_identifier_append(sql, name)
  sql << BRACKET_OPEN << name.to_s.gsub(/\]/, DOUBLE_BRACKET_CLOSE) << BRACKET_CLOSE
end
server_version ()

The version of the database server.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 611
def server_version
  db.server_version(@opts[:server])
end
supports_group_cube? ()

MSSQL 2005+ supports GROUP BY CUBE.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 616
def supports_group_cube?
  is_2005_or_later?
end
supports_group_rollup? ()

MSSQL 2005+ supports GROUP BY ROLLUP

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 621
def supports_group_rollup?
  is_2005_or_later?
end
supports_insert_select? ()

MSSQL supports #insert_select via the OUTPUT clause.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 626
def supports_insert_select?
  supports_output_clause? && !opts[:disable_insert_output]
end
supports_intersect_except? ()

MSSQL 2005+ supports INTERSECT and EXCEPT

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 631
def supports_intersect_except?
  is_2005_or_later?
end
supports_is_true? ()

MSSQL does not support IS TRUE

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 636
def supports_is_true?
  false
end
supports_join_using? ()

MSSQL doesn't support JOIN USING

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 641
def supports_join_using?
  false
end
supports_modifying_joins? ()

MSSQL 2005+ supports modifying joined datasets

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 646
def supports_modifying_joins?
  is_2005_or_later?
end
supports_multiple_column_in? ()

MSSQL does not support multiple columns for the IN/NOT IN operators

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 651
def supports_multiple_column_in?
  false
end
supports_output_clause? ()

MSSQL 2005+ supports the output clause.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 656
def supports_output_clause?
  is_2005_or_later?
end
supports_where_true? ()

MSSQL cannot use WHERE 1.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 666
def supports_where_true?
  false
end
supports_window_functions? ()

MSSQL 2005+ supports window functions

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 661
def supports_window_functions?
  true
end

Protected Instance methods

_import (columns, values, opts=OPTS)

If returned primary keys are requested, use OUTPUT unless already set on the dataset. If OUTPUT is already set, use existing returning values. If OUTPUT is only set to return a single columns, return an array of just that column. Otherwise, return an array of hashes.

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 676
def _import(columns, values, opts=OPTS)
  if opts[:return] == :primary_key && !@opts[:output]
    output(nil, [SQL::QualifiedIdentifier.new(:inserted, first_primary_key)])._import(columns, values, opts)
  elsif @opts[:output]
    statements = multi_insert_sql(columns, values)
    @db.transaction(opts.merge(:server=>@opts[:server])) do
      statements.map{|st| with_sql(st)}
    end.first.map{|v| v.length == 1 ? v.values.first : v}
  else
    super
  end
end
aggregate_dataset ()

MSSQL does not allow ordering in sub-clauses unless 'top' (limit) is specified

[show source]
# File lib/sequel/adapters/shared/mssql.rb, line 690
def aggregate_dataset
  (options_overlap(Sequel::Dataset::COUNT_FROM_SELF_OPTS) && !options_overlap([:limit])) ? unordered.from_self : super
end