module Sequel::SQLite::DatasetMethods
def _truncate_sql(table)
def _truncate_sql(table) "DELETE FROM #{table}" end
def alias_qualified_column(col)
def alias_qualified_column(col) case col when Symbol t, c, a = split_symbol(col) if t && !a alias_qualified_column(SQL::QualifiedIdentifier.new(t, c)) else col end when SQL::QualifiedIdentifier SQL::AliasedExpression.new(col, col.column) else col end end
def as_sql_append(sql, aliaz)
def as_sql_append(sql, aliaz) aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier) sql << AS literal_append(sql, aliaz.to_s) end
def complex_expression_sql_append(sql, op, args)
SQLite is case insensitive (depending on pragma), so use LIKE for
SQLite does not support pattern matching via regular expressions.
def complex_expression_sql_append(sql, op, args) case op when :~, :'!~', :'~*', :'!~*' raise Error, "SQLite does not support pattern matching via regular expressions" when :ILIKE super(sql, :LIKE, args.map{|a| SQL::Function.new(:upper, a)}) when :"NOT LIKE", :"NOT ILIKE" sql << NOT_SPACE complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args) when :^ sql << complex_expression_arg_pairs(args) do |a, b| a = literal(a) b = literal(b) "((~(#{a} & #{b})) & (#{a} | #{b}))" end when :extract part = args.at(0) raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part] sql << EXTRACT_OPEN << format << COMMA literal_append(sql, args.at(1)) sql << EXTRACT_CLOSE << (part == :second ? NUMERIC : INTEGER) << PAREN_CLOSE else super end end
def constant_sql_append(sql, constant)
SQLite has CURRENT_TIMESTAMP and related constants in UTC instead
def constant_sql_append(sql, constant) if c = CONSTANT_MAP[constant] sql << c else super end end
def delete
Since we want to always return the count of records, add a condition
SQLite performs a TRUNCATE style DELETE if no filter is specified.
def delete @opts[:where] ? super : filter(1=>1).delete end
def explain
Return an array of strings specifying a query explanation for a SELECT of the
def explain db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}"). map{|x| "#{x[:addr]}|#{x[:opcode]}|#{(1..5).map{|i| x[:"p#{i}"]}.join('|')}|#{x[:comment]}"} end
def having(*cond)
def having(*cond) raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset") unless @opts[:group] super end
def identifier_list(columns)
def identifier_list(columns) columns.map{|i| quote_identifier(i)}.join(COMMA) end
def literal_blob_append(sql, v)
def literal_blob_append(sql, v) sql << BLOB_START << v.unpack(HSTAR).first << APOS end
def literal_false
def literal_false @db.integer_booleans ? '0' : "'f'" end
def literal_true
def literal_true @db.integer_booleans ? '1' : "'t'" end
def quoted_identifier_append(sql, c)
def quoted_identifier_append(sql, c) sql << BACKTICK << c.to_s << BACKTICK end
def select(*cols)
(including the qualifier) instead of just the column name. To
is a subselect, the column name used is the full qualified name
When a qualified column is selected on SQLite and the qualifier
def select(*cols) 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)}) super(*cols.map{|c| alias_qualified_column(c)}) else super end end
def select_clause_methods
def select_clause_methods SELECT_CLAUSE_METHODS end
def select_lock_sql(sql)
def select_lock_sql(sql) super unless @opts[:lock] == :update end
def supports_intersect_except_all?
def supports_intersect_except_all? false end
def supports_is_true?
def supports_is_true? false end
def supports_multiple_column_in?
def supports_multiple_column_in? false end
def supports_timestamp_timezones?
as text. But using timezones in timestamps breaks SQLite datetime
SQLite supports timezones in literal timestamps, since it stores them
def supports_timestamp_timezones? db.use_timestamp_timezones? end
def supports_where_true?
def supports_where_true? false end