module Sequel::SQLite::DatasetMethods

def _truncate_sql(table)

SQLite treats a DELETE with no WHERE clause as a TRUNCATE
def _truncate_sql(table)
  "DELETE FROM #{table}"
end

def alias_qualified_column(col)

If col is a qualified column, alias it to the same as the column name
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)

SQLite uses string literals instead of identifiers in AS clauses.
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)

ILIKE.
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)

of in localtime, so convert those constants to local time.
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

that is always true and then 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

current dataset.
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)

HAVING requires GROUP BY on SQLite
def having(*cond)
  raise(InvalidOperation, "Can only specify a HAVING clause on a grouped dataset") unless @opts[:group]
  super
end

def identifier_list(columns)

SQL fragment specifying a list of identifiers
def identifier_list(columns)
  columns.map{|i| quote_identifier(i)}.join(COMMA)
end

def literal_blob_append(sql, v)

SQLite uses a preceding X for hex escaping strings
def literal_blob_append(sql, v)
  sql << BLOB_START << v.unpack(HSTAR).first << APOS
end

def literal_false

Respect the database integer_booleans setting, using 0 or 'f'.
def literal_false
  @db.integer_booleans ? '0' : "'f'"
end

def literal_true

Respect the database integer_booleans setting, using 1 or 't'.
def literal_true
  @db.integer_booleans ? '1' : "'t'"
end

def quoted_identifier_append(sql, c)

SQLite uses the nonstandard ` (backtick) for quoting identifiers.
def quoted_identifier_append(sql, c)
  sql << BACKTICK << c.to_s << BACKTICK
end

def select(*cols)

get correct column names, you must use an alias.
(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

SQLite does not support the SQL WITH clause
def select_clause_methods
  SELECT_CLAUSE_METHODS
end

def select_lock_sql(sql)

Support FOR SHARE locking when using the :share lock style.
def select_lock_sql(sql)
  super unless @opts[:lock] == :update
end

def supports_intersect_except_all?

SQLite does not support INTERSECT ALL or EXCEPT ALL
def supports_intersect_except_all?
  false
end

def supports_is_true?

SQLite does not support IS TRUE
def supports_is_true?
  false
end

def supports_multiple_column_in?

SQLite does not support multiple columns for the IN/NOT IN operators
def supports_multiple_column_in?
  false
end

def supports_timestamp_timezones?

functions, so we allow the user to override the default per database.
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?

SQLite cannot use WHERE 't'.
def supports_where_true?
  false
end