# 2014 Dec 20
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests of the scalar fts5_rowid() and fts5_decode() functions.
#

source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5rowid

# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
  finish_test
  return
}

do_catchsql_test 1.1 {
  SELECT fts5_rowid()
} {1 {should be: fts5_rowid(subject, ....)}}

do_catchsql_test 1.2 {
  SELECT fts5_rowid('segment')
} {1 {should be: fts5_rowid('segment', segid, pgno))}}

do_execsql_test 1.3 {
  SELECT fts5_rowid('segment', 1, 1)
} {137438953473}

do_catchsql_test 1.4 {
  SELECT fts5_rowid('nosucharg');
} {1 {first arg to fts5_rowid() must be 'segment'}} 


#-------------------------------------------------------------------------
# Tests of the fts5_decode() function.
#
reset_db
do_execsql_test 2.1 { 
  CREATE VIRTUAL TABLE x1 USING fts5(a, b);
  INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
} {}

proc rnddoc {n} {
  set map [list 0 a  1 b  2 c  3 d  4 e  5 f  6 g  7 h  8 i  9 j]
  set doc [list]
  for {set i 0} {$i < $n} {incr i} {
    lappend doc [string map $map [format %.3d [expr int(rand()*100)]]]
  }
  set doc
}
db func rnddoc rnddoc

do_execsql_test 2.2 {
  WITH r(a, b) AS (
    SELECT rnddoc(6), rnddoc(6) UNION ALL
    SELECT rnddoc(6), rnddoc(6) FROM r
  )
  INSERT INTO x1 SELECT * FROM r LIMIT 10000;
  DELETE FROM x1 WHERE (rowid%2);
}

set res [db one {SELECT count(*) FROM x1_data}]
do_execsql_test 2.3 {
  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 2.4 {
  UPDATE x1_data SET block = X'';
  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res

do_execsql_test 2.5 {
  INSERT INTO x1(x1, rank) VALUES('pgsz', 1024);
  INSERT INTO x1(x1) VALUES('rebuild');
}

set res [db one {SELECT count(*) FROM x1_data}]
do_execsql_test 2.6 {
  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res

# This is really a corruption test...
#do_execsql_test 2.7 {
#  UPDATE x1_data SET block = X'';
#  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
#} $res

do_execsql_test 2.8 {
  SELECT fts5_decode(fts5_rowid('segment', 1000, 1), X'AB')
} {corrupt}

#-------------------------------------------------------------------------
# Tests with very large tokens.
#
set strlist [list \
  "[string repeat x 400]"                       \
  "[string repeat x 300][string repeat w 100]"  \
  "[string repeat x 300][string repeat y 100]"  \
  "[string repeat x 300][string repeat z 600]"  \
]
do_test 3.0 {
  execsql {
    BEGIN;
    CREATE VIRTUAL TABLE x2 USING fts5(a);
  }
  foreach str $strlist { execsql { INSERT INTO x2 VALUES($str) } }
  execsql COMMIT
} {}

for {set tn 0} {$tn<[llength $strlist]} {incr tn} {
  set str [lindex $strlist $tn]
  do_execsql_test 3.1.$tn {
    SELECT rowid FROM x2 WHERE x2 MATCH $str
  } [expr $tn+1]
}

set res [db one {SELECT count(*) FROM x2_data}]
do_execsql_test 3.2 {
  SELECT count(fts5_decode(rowid, block)) FROM x2_data;
} $res

#-------------------------------------------------------------------------
# Leaf pages with no terms or rowids at all.
#
set strlist [list \
  "[string repeat {w } 400]"  \
  "[string repeat {x } 400]"  \
  "[string repeat {y } 400]"  \
  "[string repeat {z } 400]"  \
]
do_test 4.0 {
  execsql {
    BEGIN;
    CREATE VIRTUAL TABLE x3 USING fts5(a);
    INSERT INTO x3(x3, rank) VALUES('pgsz', 32);
  }
  foreach str $strlist { execsql { INSERT INTO x3 VALUES($str) } }
  execsql COMMIT
} {}

for {set tn 0} {$tn<[llength $strlist]} {incr tn} {
  set str [lindex $strlist $tn]
  do_execsql_test 4.1.$tn {
    SELECT rowid FROM x3 WHERE x3 MATCH $str
  } [expr $tn+1]
}

set res [db one {SELECT count(*) FROM x3_data}]
do_execsql_test 4.2 {
  SELECT count(fts5_decode(rowid, block)) FROM x3_data;
} $res

#-------------------------------------------------------------------------
# Position lists with large values.
#
set strlist [list \
  "[string repeat {w } 400]a"  \
  "[string repeat {x } 400]a"  \
  "[string repeat {y } 400]a"  \
  "[string repeat {z } 400]a"  \
]
do_test 5.0 {
  execsql {
    BEGIN;
    CREATE VIRTUAL TABLE x4 USING fts5(a);
    INSERT INTO x4(x4, rank) VALUES('pgsz', 32);
  }
  foreach str $strlist { execsql { INSERT INTO x4 VALUES($str) } }
  execsql COMMIT
} {}

do_execsql_test 5.1 {
  SELECT rowid FROM x4 WHERE x4 MATCH 'a'
} {1 2 3 4}

set res [db one {SELECT count(*) FROM x4_data}]
do_execsql_test 5.2 {
  SELECT count(fts5_decode(rowid, block)) FROM x4_data;
} $res

#-------------------------------------------------------------------------
#

do_execsql_test 6.0 {
  CREATE VIRTUAL TABLE x5 USING fts5(x, detail=none);
  INSERT INTO x5(x5, rank) VALUES('pgsz', 32);
  INSERT INTO x5 VALUES('a b c d e f');
  INSERT INTO x5 VALUES('a b c d e f');
  INSERT INTO x5 VALUES('a b c d e f');
  BEGIN;
    WITH s(i) AS (
      SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
    ) INSERT INTO x5 SELECT 'a b c d e f' FROM s;
  COMMIT;
  SELECT count(fts5_decode_none(rowid, block)) FROM x5_data;
} {32}

do_execsql_test 6.1 {
  DELETE FROM x5 WHERE rowid <= 2;
  SELECT count(fts5_decode_none(rowid, block)) FROM x5_data;
} {34}

do_execsql_test 6.2 {
  UPDATE x5 SET x='a b c d e f' WHERE rowid=3;
  SELECT count(fts5_decode_none(rowid, block)) FROM x5_data;
} {36}

#db eval {SELECT rowid, fts5_decode_none(rowid, block) aS r FROM x5_data} {puts $r}



finish_test
