module Sequel::SQLite::DatasetMethods

Constants

CONSTANT_MAP
EXTRACT_MAP
INSERT_CONFLICT_RESOLUTIONS

The allowed values for insert_conflict

Public Instance Methods

cast_sql_append(sql, expr, type) click to toggle source
Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
583 def cast_sql_append(sql, expr, type)
584   if type == Time or type == DateTime
585     sql << "datetime("
586     literal_append(sql, expr)
587     sql << ')'
588   elsif type == Date
589     sql << "date("
590     literal_append(sql, expr)
591     sql << ')'
592   else
593     super
594   end
595 end
complex_expression_sql_append(sql, op, args) click to toggle source

SQLite doesn’t support a NOT LIKE b, you need to use NOT (a LIKE b). It doesn’t support xor, power, or the extract function natively, so those have to be emulated.

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
599 def complex_expression_sql_append(sql, op, args)
600   case op
601   when :"NOT LIKE", :"NOT ILIKE"
602     sql << 'NOT '
603     complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args)
604   when :^
605     complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.lit(["((~(", " & ", ")) & (", " | ", "))"], a, b, a, b)}
606   when :**
607     unless (exp = args[1]).is_a?(Integer)
608       raise(Sequel::Error, "can only emulate exponentiation on SQLite if exponent is an integer, given #{exp.inspect}")
609     end
610     case exp
611     when 0
612       sql << '1'
613     else
614       sql << '('
615       arg = args[0]
616       if exp < 0
617         invert = true
618         exp = exp.abs
619         sql << '(1.0 / ('
620       end
621       (exp - 1).times do 
622         literal_append(sql, arg)
623         sql << " * "
624       end
625       literal_append(sql, arg)
626       sql << ')'
627       if invert
628         sql << "))"
629       end
630     end
631   when :extract
632     part = args[0]
633     raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
634     sql << "CAST(strftime(" << format << ', '
635     literal_append(sql, args[1])
636     sql << ') AS ' << (part == :second ? 'NUMERIC' : 'INTEGER') << ')'
637   else
638     super
639   end
640 end
constant_sql_append(sql, constant) click to toggle source

SQLite has CURRENT_TIMESTAMP and related constants in UTC instead of in localtime, so convert those constants to local time.

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
644 def constant_sql_append(sql, constant)
645   if (c = CONSTANT_MAP[constant]) && !db.current_timestamp_utc
646     sql << c
647   else
648     super
649   end
650 end
delete(&block) click to toggle source

SQLite performs a TRUNCATE style DELETE if no filter is specified. Since we want to always return the count of records, add a condition that is always true and then delete.

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
655 def delete(&block)
656   @opts[:where] ? super : where(1=>1).delete(&block)
657 end
empty?() click to toggle source

Always return false when using VALUES

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
660 def empty?
661   return false if @opts[:values]
662   super
663 end
explain(opts=nil) click to toggle source

Return an array of strings specifying a query explanation for a SELECT of the current dataset. Currently, the options are ignored, but it accepts options to be compatible with other adapters.

    # File lib/sequel/adapters/shared/sqlite.rb
668 def explain(opts=nil)
669   # Load the PrettyTable class, needed for explain output
670   Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
671 
672   ds = db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}")
673   rows = ds.all
674   Sequel::PrettyTable.string(rows, ds.columns)
675 end
having(*cond) click to toggle source

HAVING requires GROUP BY on SQLite

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
678 def having(*cond)
679   raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset") if !@opts[:group] && db.sqlite_version < 33900
680   super
681 end
insert_conflict(opts = :ignore) click to toggle source

Handle uniqueness violations when inserting, by using a specified resolution algorithm. With no options, uses INSERT OR REPLACE. SQLite supports the following conflict resolution algoriths: ROLLBACK, ABORT, FAIL, IGNORE and REPLACE.

On SQLite 3.24.0+, you can pass a hash to use an ON CONFLICT clause. With out :update option, uses ON CONFLICT DO NOTHING. Options:

:conflict_where

The index filter, when using a partial index to determine uniqueness.

:target

The column name or expression to handle uniqueness violations on.

:update

A hash of columns and values to set. Uses ON CONFLICT DO UPDATE.

:update_where

A WHERE condition to use for the update.

Examples:

DB[:table].insert_conflict.insert(a: 1, b: 2)
# INSERT OR IGNORE INTO TABLE (a, b) VALUES (1, 2)

DB[:table].insert_conflict(:replace).insert(a: 1, b: 2)
# INSERT OR REPLACE INTO TABLE (a, b) VALUES (1, 2)

DB[:table].insert_conflict({}).insert(a: 1, b: 2)
# INSERT INTO TABLE (a, b) VALUES (1, 2)
# ON CONFLICT DO NOTHING

DB[:table].insert_conflict(target: :a).insert(a: 1, b: 2)
# INSERT INTO TABLE (a, b) VALUES (1, 2)
# ON CONFLICT (a) DO NOTHING

DB[:table].insert_conflict(target: :a, conflict_where: {c: true}).insert(a: 1, b: 2)
# INSERT INTO TABLE (a, b) VALUES (1, 2)
# ON CONFLICT (a) WHERE (c IS TRUE) DO NOTHING

DB[:table].insert_conflict(target: :a, update: {b: Sequel[:excluded][:b]}).insert(a: 1, b: 2)
# INSERT INTO TABLE (a, b) VALUES (1, 2)
# ON CONFLICT (a) DO UPDATE SET b = excluded.b

DB[:table].insert_conflict(target: :a,
  update: {b: Sequel[:excluded][:b]}, update_where: {Sequel[:table][:status_id] => 1}).insert(a: 1, b: 2)
# INSERT INTO TABLE (a, b) VALUES (1, 2)
# ON CONFLICT (a) DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
    # File lib/sequel/adapters/shared/sqlite.rb
756 def insert_conflict(opts = :ignore)
757   case opts
758   when Symbol, String
759     unless INSERT_CONFLICT_RESOLUTIONS.include?(opts.to_s.upcase)
760       raise Error, "Invalid symbol or string passed to Dataset#insert_conflict: #{opts.inspect}.  The allowed values are: :rollback, :abort, :fail, :ignore, or :replace"
761     end
762     clone(:insert_conflict => opts)
763   when Hash
764     clone(:insert_on_conflict => opts)
765   else
766     raise Error, "Invalid value passed to Dataset#insert_conflict: #{opts.inspect}, should use a symbol or a hash"
767   end
768 end
insert_ignore() click to toggle source

Ignore uniqueness/exclusion violations when inserting, using INSERT OR IGNORE. Exists mostly for compatibility to MySQL’s insert_ignore. Example:

DB[:table].insert_ignore.insert(a: 1, b: 2)
# INSERT OR IGNORE INTO TABLE (a, b) VALUES (1, 2)
    # File lib/sequel/adapters/shared/sqlite.rb
775 def insert_ignore
776   insert_conflict(:ignore)
777 end
insert_select(*values) click to toggle source

Support insert select for associations, so that the model code can use returning instead of a separate query.

    # File lib/sequel/adapters/shared/sqlite.rb
685 def insert_select(*values)
686   return unless supports_insert_select?
687   # Handle case where query does not return a row
688   server?(:default).with_sql_first(insert_select_sql(*values)) || false
689 end
insert_select_sql(*values) click to toggle source

The SQL to use for an insert_select, adds a RETURNING clause to the insert unless the RETURNING clause is already present.

    # File lib/sequel/adapters/shared/sqlite.rb
693 def insert_select_sql(*values)
694   ds = opts[:returning] ? self : returning
695   ds.insert_sql(*values)
696 end
quoted_identifier_append(sql, c) click to toggle source

SQLite uses the nonstandard ‘ (backtick) for quoting identifiers.

    # File lib/sequel/adapters/shared/sqlite.rb
699 def quoted_identifier_append(sql, c)
700   sql << '`' << c.to_s.gsub('`', '``') << '`'
701 end
returning(*values) click to toggle source

Automatically add aliases to RETURNING values to work around SQLite bug.

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
780 def returning(*values)
781   return super if values.empty?
782   raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
783   clone(:returning=>_returning_values(values).freeze)
784 end
select(*cols) click to toggle source

When a qualified column is selected on SQLite and the qualifier is a subselect, the column name used is the full qualified name (including the qualifier) instead of just the column name. To get correct column names, you must use an alias.

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
707 def select(*cols)
708   if ((f = @opts[:from]) && f.any?{|t| t.is_a?(Dataset) || (t.is_a?(SQL::AliasedExpression) && t.expression.is_a?(Dataset))}) || ((j = @opts[:join]) && j.any?{|t| t.table.is_a?(Dataset)})
709     super(*cols.map{|c| alias_qualified_column(c)})
710   else
711     super
712   end
713 end
supports_cte?(type=:select) click to toggle source

SQLite 3.8.3+ supports common table expressions.

    # File lib/sequel/adapters/shared/sqlite.rb
787 def supports_cte?(type=:select)
788   db.sqlite_version >= 30803
789 end
supports_cte_in_subqueries?() click to toggle source

SQLite supports CTEs in subqueries if it supports CTEs.

    # File lib/sequel/adapters/shared/sqlite.rb
792 def supports_cte_in_subqueries?
793   supports_cte?
794 end
supports_deleting_joins?() click to toggle source

SQLite does not support deleting from a joined dataset

    # File lib/sequel/adapters/shared/sqlite.rb
802 def supports_deleting_joins?
803   false
804 end
supports_derived_column_lists?() click to toggle source

SQLite does not support table aliases with column aliases

    # File lib/sequel/adapters/shared/sqlite.rb
797 def supports_derived_column_lists?
798   false
799 end
supports_intersect_except_all?() click to toggle source

SQLite does not support INTERSECT ALL or EXCEPT ALL

    # File lib/sequel/adapters/shared/sqlite.rb
807 def supports_intersect_except_all?
808   false
809 end
supports_is_true?() click to toggle source

SQLite does not support IS TRUE

    # File lib/sequel/adapters/shared/sqlite.rb
812 def supports_is_true?
813   false
814 end
supports_modifying_joins?() click to toggle source

SQLite 3.33.0 supports modifying joined datasets

    # File lib/sequel/adapters/shared/sqlite.rb
817 def supports_modifying_joins?
818   db.sqlite_version >= 33300
819 end
supports_multiple_column_in?() click to toggle source

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

    # File lib/sequel/adapters/shared/sqlite.rb
822 def supports_multiple_column_in?
823   false
824 end
supports_returning?(_) click to toggle source

SQLite 3.35.0 supports RETURNING on INSERT/UPDATE/DELETE.

    # File lib/sequel/adapters/shared/sqlite.rb
827 def supports_returning?(_)
828   db.sqlite_version >= 33500
829 end
supports_timestamp_timezones?() click to toggle source

SQLite supports timezones in literal timestamps, since it stores them as text. But using timezones in timestamps breaks SQLite datetime functions, so we allow the user to override the default per database.

    # File lib/sequel/adapters/shared/sqlite.rb
834 def supports_timestamp_timezones?
835   db.use_timestamp_timezones?
836 end
supports_where_true?() click to toggle source

SQLite cannot use WHERE ‘t’.

    # File lib/sequel/adapters/shared/sqlite.rb
839 def supports_where_true?
840   false
841 end
supports_window_clause?() click to toggle source

SQLite 3.28+ supports the WINDOW clause.

    # File lib/sequel/adapters/shared/sqlite.rb
844 def supports_window_clause?
845   db.sqlite_version >= 32800
846 end
supports_window_function_frame_option?(option) click to toggle source

SQLite 3.28.0+ supports all window frame options that Sequel supports

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
857 def supports_window_function_frame_option?(option)
858   db.sqlite_version >= 32800 ? true : super
859 end
supports_window_functions?() click to toggle source

SQLite 3.25+ supports window functions. However, support is only enabled on SQLite 3.26.0+ because internal Sequel usage of window functions to implement eager loading of limited associations triggers an SQLite crash bug in versions 3.25.0-3.25.3.

    # File lib/sequel/adapters/shared/sqlite.rb
852 def supports_window_functions?
853   db.sqlite_version >= 32600
854 end

Private Instance Methods

_returning_values(values) click to toggle source

Add aliases to symbols and identifiers to work around SQLite bug.

    # File lib/sequel/adapters/shared/sqlite.rb
864 def _returning_values(values)
865   values.map do |v|
866     case v
867     when Symbol
868       _, c, a = split_symbol(v)
869       a ? v : Sequel.as(v, c)
870     when SQL::Identifier, SQL::QualifiedIdentifier
871       Sequel.as(v, unqualified_column_for(v))
872     else
873       v
874     end
875   end
876 end
_truncate_sql(table) click to toggle source

SQLite treats a DELETE with no WHERE clause as a TRUNCATE

     # File lib/sequel/adapters/shared/sqlite.rb
1036 def _truncate_sql(table)
1037   "DELETE FROM #{table}"
1038 end
aggreate_dataset_use_from_self?() click to toggle source

Use from_self for aggregate dataset using VALUES.

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
879 def aggreate_dataset_use_from_self?
880   super || @opts[:values]
881 end
alias_qualified_column(col) click to toggle source

If col is a qualified column, alias it to the same as the column name

    # File lib/sequel/adapters/shared/sqlite.rb
892 def alias_qualified_column(col)
893   case col
894   when Symbol
895     t, c, a = split_symbol(col)
896     if t && !a
897       alias_qualified_column(SQL::QualifiedIdentifier.new(t, c))
898     else
899       col
900     end
901   when SQL::QualifiedIdentifier
902     SQL::AliasedExpression.new(col, col.column)
903   else
904     col
905   end
906 end
as_sql_append(sql, aliaz, column_aliases=nil) click to toggle source

SQLite uses string literals instead of identifiers in AS clauses.

    # File lib/sequel/adapters/shared/sqlite.rb
884 def as_sql_append(sql, aliaz, column_aliases=nil)
885   raise Error, "sqlite does not support derived column lists" if column_aliases
886   aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier)
887   sql << ' AS '
888   literal_append(sql, aliaz.to_s)
889 end
check_delete_allowed!()
check_insert_allowed!() click to toggle source

Raise an InvalidOperation exception if insert is not allowed for this dataset.

    # File lib/sequel/adapters/shared/sqlite.rb
909 def check_insert_allowed!
910   raise(InvalidOperation, "Grouped datasets cannot be modified") if opts[:group]
911   raise(InvalidOperation, "Joined datasets cannot be modified") if joined_dataset?
912 end
Also aliased as: check_delete_allowed!
default_import_slice() click to toggle source

SQLite supports a maximum of 500 rows in a VALUES clause.

    # File lib/sequel/adapters/shared/sqlite.rb
916 def default_import_slice
917   500
918 end
default_timestamp_format() click to toggle source

The strftime format to use when literalizing the time.

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
921 def default_timestamp_format
922   db.use_timestamp_timezones? ? "'%Y-%m-%d %H:%M:%S.%6N%z'" : super
923 end
identifier_list(columns) click to toggle source

SQL fragment specifying a list of identifiers

    # File lib/sequel/adapters/shared/sqlite.rb
926 def identifier_list(columns)
927   columns.map{|i| quote_identifier(i)}.join(', ')
928 end
insert_conflict_sql(sql) click to toggle source

Add OR clauses to SQLite INSERT statements

    # File lib/sequel/adapters/shared/sqlite.rb
931 def insert_conflict_sql(sql)
932   if resolution = @opts[:insert_conflict]
933     sql << " OR " << resolution.to_s.upcase
934   end
935 end
insert_on_conflict_sql(sql) click to toggle source

Add ON CONFLICT clause if it should be used

    # File lib/sequel/adapters/shared/sqlite.rb
938 def insert_on_conflict_sql(sql)
939   if opts = @opts[:insert_on_conflict]
940     sql << " ON CONFLICT"
941 
942     if target = opts[:constraint] 
943       sql << " ON CONSTRAINT "
944       identifier_append(sql, target)
945     elsif target = opts[:target]
946       sql << ' '
947       identifier_append(sql, Array(target))
948       if conflict_where = opts[:conflict_where]
949         sql << " WHERE "
950         literal_append(sql, conflict_where)
951       end
952     end
953 
954     if values = opts[:update]
955       sql << " DO UPDATE SET "
956       update_sql_values_hash(sql, values)
957       if update_where = opts[:update_where]
958         sql << " WHERE "
959         literal_append(sql, update_where)
960       end
961     else
962       sql << " DO NOTHING"
963     end
964   end
965 end
literal_blob_append(sql, v) click to toggle source

SQLite uses a preceding X for hex escaping strings

    # File lib/sequel/adapters/shared/sqlite.rb
968 def literal_blob_append(sql, v)
969   sql <<  "X'" << v.unpack("H*").first << "'"
970 end
literal_false() click to toggle source

Respect the database integer_booleans setting, using 0 or ‘f’.

    # File lib/sequel/adapters/shared/sqlite.rb
973 def literal_false
974   @db.integer_booleans ? '0' : "'f'"
975 end
literal_true() click to toggle source

Respect the database integer_booleans setting, using 1 or ‘t’.

    # File lib/sequel/adapters/shared/sqlite.rb
978 def literal_true
979   @db.integer_booleans ? '1' : "'t'"
980 end
multi_insert_sql_strategy() click to toggle source

SQLite only supporting multiple rows in the VALUES clause starting in 3.7.11. On older versions, fallback to using a UNION.

    # File lib/sequel/adapters/shared/sqlite.rb
984 def multi_insert_sql_strategy
985   db.sqlite_version >= 30711 ? :values : :union
986 end
native_function_name(emulated_function) click to toggle source

Emulate the char_length function with length

Calls superclass method
    # File lib/sequel/adapters/shared/sqlite.rb
989 def native_function_name(emulated_function)
990   if emulated_function == :char_length
991     'length'
992   else
993     super
994   end
995 end
requires_emulating_nulls_first?() click to toggle source

SQLite supports NULLS FIRST/LAST natively in 3.30+.

     # File lib/sequel/adapters/shared/sqlite.rb
 998 def requires_emulating_nulls_first?
 999   db.sqlite_version < 33000
1000 end
select_lock_sql(sql) click to toggle source

SQLite does not support FOR UPDATE, but silently ignore it instead of raising an error for compatibility with other databases.

Calls superclass method
     # File lib/sequel/adapters/shared/sqlite.rb
1005 def select_lock_sql(sql)
1006   super unless @opts[:lock] == :update
1007 end
select_only_offset_sql(sql) click to toggle source
     # File lib/sequel/adapters/shared/sqlite.rb
1009 def select_only_offset_sql(sql)
1010   sql << " LIMIT -1 OFFSET "
1011   literal_append(sql, @opts[:offset])
1012 end
select_values_sql(sql) click to toggle source

Support VALUES clause instead of the SELECT clause to return rows.

     # File lib/sequel/adapters/shared/sqlite.rb
1015 def select_values_sql(sql)
1016   sql << "VALUES "
1017   expression_list_append(sql, opts[:values])
1018 end
supports_cte_in_compounds?() click to toggle source

SQLite does not support CTEs directly inside UNION/INTERSECT/EXCEPT.

     # File lib/sequel/adapters/shared/sqlite.rb
1021 def supports_cte_in_compounds?
1022   false
1023 end
supports_filtered_aggregates?() click to toggle source

SQLite 3.30 supports the FILTER clause for aggregate functions.

     # File lib/sequel/adapters/shared/sqlite.rb
1026 def supports_filtered_aggregates?
1027   db.sqlite_version >= 33000
1028 end
supports_quoted_function_names?() click to toggle source

SQLite supports quoted function names.

     # File lib/sequel/adapters/shared/sqlite.rb
1031 def supports_quoted_function_names?
1032   true
1033 end
update_from_sql(sql) click to toggle source

Use FROM to specify additional tables in an update query

     # File lib/sequel/adapters/shared/sqlite.rb
1041 def update_from_sql(sql)
1042   if(from = @opts[:from][1..-1]).empty?
1043     raise(Error, 'Need multiple FROM tables if updating/deleting a dataset with JOINs') if @opts[:join]
1044   else
1045     sql << ' FROM '
1046     source_list_append(sql, from)
1047     select_join_sql(sql)
1048   end
1049 end
update_table_sql(sql) click to toggle source

Only include the primary table in the main update clause

     # File lib/sequel/adapters/shared/sqlite.rb
1052 def update_table_sql(sql)
1053   sql << ' '
1054   source_list_append(sql, @opts[:from][0..0])
1055 end