Commit c6b1a343 authored by DrKLO's avatar DrKLO

Updated database structure, updated sqlite (don't use this source code, it may be changed)

parent 43674c48
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.8.4.1"
#define SQLITE_VERSION_NUMBER 3008004
#define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0"
#define SQLITE_VERSION "3.8.6"
#define SQLITE_VERSION_NUMBER 3008006
#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e"
/*
** CAPI3REF: Run-Time Library Version Numbers
......@@ -269,7 +269,7 @@ typedef sqlite_uint64 sqlite3_uint64;
**
** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
** for the [sqlite3] object.
** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if
** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if
** the [sqlite3] object is successfully destroyed and all associated
** resources are deallocated.
**
......@@ -277,7 +277,7 @@ typedef sqlite_uint64 sqlite3_uint64;
** statements or unfinished sqlite3_backup objects then sqlite3_close()
** will leave the database connection open and return [SQLITE_BUSY].
** ^If sqlite3_close_v2() is called with unfinalized prepared statements
** and unfinished sqlite3_backups, then the database connection becomes
** and/or unfinished sqlite3_backups, then the database connection becomes
** an unusable "zombie" which will automatically be deallocated when the
** last prepared statement is finalized or the last sqlite3_backup is
** finished. The sqlite3_close_v2() interface is intended for use with
......@@ -290,7 +290,7 @@ typedef sqlite_uint64 sqlite3_uint64;
** with the [sqlite3] object prior to attempting to close the object. ^If
** sqlite3_close_v2() is called on a [database connection] that still has
** outstanding [prepared statements], [BLOB handles], and/or
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
** of resources is deferred until all [prepared statements], [BLOB handles],
** and [sqlite3_backup] objects are also destroyed.
**
......@@ -386,16 +386,14 @@ SQLITE_API int sqlite3_exec(
/*
** CAPI3REF: Result Codes
** KEYWORDS: SQLITE_OK {error code} {error codes}
** KEYWORDS: {result code} {result codes}
** KEYWORDS: {result code definitions}
**
** Many SQLite functions return an integer result code from the set shown
** here in order to indicate success or failure.
**
** New error codes may be added in future versions of SQLite.
**
** See also: [SQLITE_IOERR_READ | extended result codes],
** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
** See also: [extended result code definitions]
*/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
......@@ -433,26 +431,19 @@ SQLITE_API int sqlite3_exec(
/*
** CAPI3REF: Extended Result Codes
** KEYWORDS: {extended error code} {extended error codes}
** KEYWORDS: {extended result code} {extended result codes}
** KEYWORDS: {extended result code definitions}
**
** In its default configuration, SQLite API routines return one of 26 integer
** [SQLITE_OK | result codes]. However, experience has shown that many of
** In its default configuration, SQLite API routines return one of 30 integer
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
** address this, newer versions of SQLite (version 3.3.8 and later) include
** support for additional result codes that provide more detailed information
** about errors. The extended result codes are enabled or disabled
** about errors. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
** [sqlite3_extended_result_codes()] API.
**
** Some of the available extended result codes are listed here.
** One may expect the number of extended result codes will increase
** over time. Software that uses extended result codes should expect
** to see new result codes in future releases of SQLite.
**
** The SQLITE_OK result code will never be extended. It will always
** be exactly zero.
** [sqlite3_extended_result_codes()] API. Or, the extended code for
** the most recent error can be obtained using
** [sqlite3_extended_errcode()].
*/
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
......@@ -560,7 +551,10 @@ SQLITE_API int sqlite3_exec(
** file that were written at the application level might have changed
** and that adjacent bytes, even bytes within the same sector are
** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
** flag indicate that a file cannot be deleted when open.
** flag indicate that a file cannot be deleted when open. The
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
** read-only media and cannot be changed even by processes with
** elevated privileges.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
......@@ -575,6 +569,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
/*
** CAPI3REF: File Locking Levels
......@@ -681,7 +676,7 @@ struct sqlite3_file {
** locking strategy (for example to use dot-file locks), to inquire
** about the status of a lock, or to break stale locks. The SQLite
** core reserves all opcodes less than 100 for its own use.
** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
** A [file control opcodes | list of opcodes] less than 100 is available.
** Applications that define a custom xFileControl method should use opcodes
** greater than 100 to avoid conflicts. VFS implementations should
** return [SQLITE_NOTFOUND] for file control opcodes that they do not
......@@ -754,6 +749,7 @@ struct sqlite3_io_methods {
/*
** CAPI3REF: Standard File Control Opcodes
** KEYWORDS: {file control opcodes} {file control opcode}
**
** These integer constants are opcodes for the xFileControl method
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
......@@ -943,6 +939,12 @@ struct sqlite3_io_methods {
** on whether or not the file has been renamed, moved, or deleted since it
** was first opened.
**
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
** opcode causes the xFileControl method to swap the file handle with the one
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
......@@ -966,6 +968,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_HAS_MOVED 20
#define SQLITE_FCNTL_SYNC 21
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
/*
** CAPI3REF: Mutex Handle
......@@ -2026,27 +2029,33 @@ SQLITE_API int sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
**
** ^This routine sets a callback function that might be invoked whenever
** an attempt is made to open a database table that another thread
** or process has locked.
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
** that might be invoked with argument P whenever
** an attempt is made to access a database table associated with
** [database connection] D when another thread
** or process has the table locked.
** The sqlite3_busy_handler() interface is used to implement
** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout].
**
** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]
** ^If the busy callback is NULL, then [SQLITE_BUSY]
** is returned immediately upon encountering the lock. ^If the busy callback
** is not NULL, then the callback might be invoked with two arguments.
**
** ^The first argument to the busy handler is a copy of the void* pointer which
** is the third argument to sqlite3_busy_handler(). ^The second argument to
** the busy handler callback is the number of times that the busy handler has
** been invoked for this locking event. ^If the
** been invoked for the same locking event. ^If the
** busy callback returns 0, then no additional attempts are made to
** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
** access the database and [SQLITE_BUSY] is returned
** to the application.
** ^If the callback returns non-zero, then another attempt
** is made to open the database for reading and the cycle repeats.
** is made to access the database and the cycle repeats.
**
** The presence of a busy handler does not guarantee that it will be invoked
** when there is lock contention. ^If SQLite determines that invoking the busy
** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler.
** to the application instead of invoking the
** busy handler.
** Consider a scenario where one process is holding a read lock that
** it is trying to promote to a reserved lock and
** a second process is holding a reserved lock that it is trying
......@@ -2060,28 +2069,15 @@ SQLITE_API int sqlite3_complete16(const void *sql);
**
** ^The default busy callback is NULL.
**
** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
** when SQLite is in the middle of a large transaction where all the
** changes will not fit into the in-memory cache. SQLite will
** already hold a RESERVED lock on the database file, but it needs
** to promote this lock to EXCLUSIVE so that it can spill cache
** pages into the database file without harm to concurrent
** readers. ^If it is unable to promote the lock, then the in-memory
** cache will be left in an inconsistent state and so the error
** code is promoted from the relatively benign [SQLITE_BUSY] to
** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion
** forces an automatic rollback of the changes. See the
** <a href="/cvstrac/wiki?p=CorruptionFollowingBusyError">
** CorruptionFollowingBusyError</a> wiki page for a discussion of why
** this is important.
**
** ^(There can only be a single busy handler defined for each
** [database connection]. Setting a new busy handler clears any
** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()]
** will also set or clear the busy handler.
** or evaluating [PRAGMA busy_timeout=N] will change the
** busy handler and thus clear any previously set busy handler.
**
** The busy callback should not take any actions which modify the
** database connection that invoked the busy handler. Any such actions
** database connection that invoked the busy handler. In other words,
** the busy handler is not reentrant. Any such actions
** result in undefined behavior.
**
** A busy handler must not close the database connection
......@@ -2097,7 +2093,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
** will sleep multiple times until at least "ms" milliseconds of sleeping
** have accumulated. ^After at least "ms" milliseconds of sleeping,
** the handler returns 0 which causes [sqlite3_step()] to return
** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
** [SQLITE_BUSY].
**
** ^Calling this routine with an argument less than or equal to zero
** turns off all busy handlers.
......@@ -2106,6 +2102,8 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
** [database connection] any any given moment. If another busy handler
** was defined (using [sqlite3_busy_handler()]) prior to calling
** this routine, that other busy handler is cleared.)^
**
** See also: [PRAGMA busy_timeout]
*/
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
......@@ -2507,8 +2505,8 @@ SQLITE_API int sqlite3_set_authorizer(
** [sqlite3_set_authorizer | authorizer documentation] for additional
** information.
**
** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
** from the [sqlite3_vtab_on_conflict()] interface.
** Note that SQLITE_IGNORE is also used as a [conflict resolution mode]
** returned from the [sqlite3_vtab_on_conflict()] interface.
*/
#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
......@@ -2779,6 +2777,30 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
** a URI filename, its value overrides any behavior requested by setting
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
**
** <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
** "1") or "false" (or "off" or "no" or "0") to indicate that the
** [powersafe overwrite] property does or does not apply to the
** storage media on which the database file resides. ^The psow query
** parameter only works for the built-in unix and Windows VFSes.
**
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
** which if set disables file locking in rollback journal modes. This
** is useful for accessing a database on a filesystem that does not
** support locking. Caution: Database corruption might result if two
** or more processes write to the same database and any one of those
** processes uses nolock=1.
**
** <li> <b>immutable</b>: ^The immutable parameter is a boolean query
** parameter that indicates that the database file is stored on
** read-only media. ^When immutable is set, SQLite assumes that the
** database file cannot be changed, even by a process with higher
** privilege, and so the database is opened read-only and all locking
** and change detection is disabled. Caution: Setting the immutable
** property on a database file that does in fact change can result
** in incorrect query results and/or [SQLITE_CORRUPT] errors.
** See also: [SQLITE_IOCAP_IMMUTABLE].
**
** </ul>
**
** ^Specifying an unknown parameter in the query component of a URI is not an
......@@ -2808,8 +2830,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** Open file "data.db" in the current directory for read-only access.
** Regardless of whether or not shared-cache mode is enabled by
** default, use a private cache.
** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td>
** Open file "/home/fred/data.db". Use the special VFS "unix-nolock".
** <tr><td> file:/home/fred/data.db?vfs=unix-dotfile <td>
** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile"
** that uses dot-files in place of posix advisory locking.
** <tr><td> file:data.db?mode=readonly <td>
** An error. "readonly" is not a valid option for the "mode" parameter.
** </table>
......@@ -4670,6 +4693,13 @@ SQLITE_API int sqlite3_sleep(int);
** is a NULL pointer, then SQLite performs a search for an appropriate
** temporary file directory.
**
** Applications are strongly discouraged from using this global variable.
** It is required to set a temporary folder on Windows Runtime (WinRT).
** But for all other platforms, it is highly recommended that applications
** neither read nor write this variable. This global variable is a relic
** that exists for backwards compatibility of legacy applications and should
** be avoided in new projects.
**
** It is not safe to read or modify this variable in more than one
** thread at a time. It is not safe to read or modify this variable
** if a [database connection] is being used at the same time in a separate
......@@ -4688,6 +4718,11 @@ SQLITE_API int sqlite3_sleep(int);
** Hence, if this variable is modified directly, either it should be
** made NULL or made to point to memory obtained from [sqlite3_malloc]
** or else the use of the [temp_store_directory pragma] should be avoided.
** Except when requested by the [temp_store_directory pragma], SQLite
** does not free the memory that sqlite3_temp_directory points to. If
** the application wants that memory to be freed, it must do
** so itself, taking care to only do so after all [database connection]
** objects have been destroyed.
**
** <b>Note to Windows Runtime users:</b> The temporary directory must be set
** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various
......@@ -5822,10 +5857,12 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
** <li> SQLITE_MUTEX_STATIC_LRU2
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** </ul>)^
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
......@@ -6029,6 +6066,9 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
/*
** CAPI3REF: Retrieve the mutex for a database connection
......@@ -6123,7 +6163,9 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_LAST 21
#define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_LAST 23
/*
** CAPI3REF: SQLite Runtime Status
......@@ -7107,6 +7149,9 @@ SQLITE_API void *sqlite3_wal_hook(
** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
** from SQL.
**
** ^Checkpoints initiated by this mechanism are
** [sqlite3_wal_checkpoint_v2|PASSIVE].
**
** ^Every new [database connection] defaults to having the auto-checkpoint
** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
** pages. The use of this interface
......@@ -7123,6 +7168,10 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
** empty string, then a checkpoint is run on all databases of
** connection D. ^If the database connection D is not in
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
** or RESET checkpoint.
**
** ^The [wal_checkpoint pragma] can be used to invoke this interface
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
......@@ -7145,10 +7194,12 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
** Checkpoint as many frames as possible without waiting for any database
** readers or writers to finish. Sync the db file if all frames in the log
** are checkpointed. This mode is the same as calling
** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked.
** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
** is never invoked.
**
** <dt>SQLITE_CHECKPOINT_FULL<dd>
** This mode blocks (calls the busy-handler callback) until there is no
** This mode blocks (it invokes the
** [sqlite3_busy_handler|busy-handler callback]) until there is no
** database writer and all readers are reading from the most recent database
** snapshot. It then checkpoints all frames in the log file and syncs the
** database file. This call blocks database writers while it is running,
......@@ -7156,7 +7207,8 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
**
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
** checkpointing the log file it blocks (calls the busy-handler callback)
** checkpointing the log file it blocks (calls the
** [sqlite3_busy_handler|busy-handler callback])
** until all readers are reading from the database file only. This ensures
** that the next client to write to the database file restarts the log file
** from the beginning. This call blocks database writers while it is running,
......@@ -7294,6 +7346,7 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
**
** These constants are returned by [sqlite3_vtab_on_conflict()] to
** inform a [virtual table] implementation what the [ON CONFLICT] mode
......@@ -7346,6 +7399,16 @@ extern "C" {
#endif
typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
/* The double-precision datatype used by RTree depends on the
** SQLITE_RTREE_INT_ONLY compile-time option.
*/
#ifdef SQLITE_RTREE_INT_ONLY
typedef sqlite3_int64 sqlite3_rtree_dbl;
#else
typedef double sqlite3_rtree_dbl;
#endif
/*
** Register a geometry callback named zGeom that can be used as part of an
......@@ -7356,11 +7419,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
#ifdef SQLITE_RTREE_INT_ONLY
int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
#else
int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
#endif
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
void *pContext
);
......@@ -7372,11 +7431,60 @@ SQLITE_API int sqlite3_rtree_geometry_callback(
struct sqlite3_rtree_geometry {
void *pContext; /* Copy of pContext passed to s_r_g_c() */
int nParam; /* Size of array aParam[] */
double *aParam; /* Parameters passed to SQL geom function */
sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */
void *pUser; /* Callback implementation user data */
void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */
};
/*
** Register a 2nd-generation geometry callback named zScore that can be
** used as part of an R-Tree geometry query as follows:
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
SQLITE_API int sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
void *pContext,
void (*xDestructor)(void*)
);
/*
** A pointer to a structure of the following type is passed as the
** argument to scored geometry callback registered using
** sqlite3_rtree_query_callback().
**
** Note that the first 5 fields of this structure are identical to
** sqlite3_rtree_geometry. This structure is a subclass of
** sqlite3_rtree_geometry.
*/
struct sqlite3_rtree_query_info {
void *pContext; /* pContext from when function registered */
int nParam; /* Number of function parameters */
sqlite3_rtree_dbl *aParam; /* value of function parameters */
void *pUser; /* callback can use this, if desired */
void (*xDelUser)(void*); /* function to free pUser */
sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */
unsigned int *anQueue; /* Number of pending entries in the queue */
int nCoord; /* Number of coordinates */
int iLevel; /* Level of current node or entry */
int mxLevel; /* The largest iLevel value in the tree */
sqlite3_int64 iRowid; /* Rowid for current entry */
sqlite3_rtree_dbl rParentScore; /* Score of parent node */
int eParentWithin; /* Visibility of parent node */
int eWithin; /* OUT: Visiblity */
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
};
/*
** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin.
*/
#define NOT_WITHIN 0 /* Object completely outside of query region */
#define PARTLY_WITHIN 1 /* Object partially overlaps query region */
#define FULLY_WITHIN 2 /* Object fully contained within query region */
#ifdef __cplusplus
} /* end of the 'extern "C"' block */
......
......@@ -236,7 +236,7 @@ public class ContactsController {
ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver();
HashMap<String, Contact> shortContacts = new HashMap<String, Contact>();
String ids = "";
StringBuilder ids = new StringBuilder();
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projectionPhones, null, null, null);
if (pCur != null) {
if (pCur.getCount() > 0) {
......@@ -262,9 +262,9 @@ public class ContactsController {
Integer id = pCur.getInt(0);
if (ids.length() != 0) {
ids += ",";
ids.append(",");
}
ids += id;
ids.append(id);
int type = pCur.getInt(2);
Contact contact = contactsMap.get(id);
......@@ -299,7 +299,7 @@ public class ContactsController {
pCur.close();
}
pCur = cr.query(ContactsContract.Data.CONTENT_URI, projectionNames, ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " IN (" + ids + ") AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'", null, null);
pCur = cr.query(ContactsContract.Data.CONTENT_URI, projectionNames, ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " IN (" + ids.toString() + ") AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'", null, null);
if (pCur != null && pCur.getCount() > 0) {
while (pCur.moveToNext()) {
int id = pCur.getInt(0);
......@@ -844,14 +844,14 @@ public class ContactsController {
return 0;
}
});
String ids = "";
StringBuilder ids = new StringBuilder();
for (TLRPC.TL_contact aContactsArr : contactsArr) {
if (ids.length() != 0) {
ids += ",";
ids.append(",");
}
ids += aContactsArr.user_id;
ids.append(aContactsArr.user_id);
}
UserConfig.contactsHash = Utilities.MD5(ids);
UserConfig.contactsHash = Utilities.MD5(ids.toString());
UserConfig.saveConfig(false);
}
......@@ -1084,7 +1084,7 @@ public class ContactsController {
});
}
String ids = "";
StringBuilder ids = new StringBuilder();
final HashMap<String, ArrayList<TLRPC.TL_contact>> sectionsDict = new HashMap<String, ArrayList<TLRPC.TL_contact>>();
final ArrayList<String> sortedSectionsArray = new ArrayList<String>();
......@@ -1114,11 +1114,11 @@ public class ContactsController {
}
arr.add(value);
if (ids.length() != 0) {
ids += ",";
ids.append(",");
}
ids += value.user_id;
ids.append(value.user_id);
}
UserConfig.contactsHash = Utilities.MD5(ids);
UserConfig.contactsHash = Utilities.MD5(ids.toString());
UserConfig.saveConfig(false);
Collections.sort(sortedSectionsArray, new Comparator<String>() {
......@@ -1189,8 +1189,8 @@ public class ContactsController {
}
FileLog.e("tmessages", "process update - contacts add = " + newC.size() + " delete = " + contactsTD.size());
String toAdd = "";
String toDelete = "";
StringBuilder toAdd = new StringBuilder();
StringBuilder toDelete = new StringBuilder();
boolean reloadContacts = false;
for (TLRPC.TL_contact newContact : newC) {
......@@ -1216,9 +1216,9 @@ public class ContactsController {
}
}
if (toAdd.length() != 0) {
toAdd += ",";
toAdd.append(",");
}
toAdd += user.phone;
toAdd.append(user.phone);
}
for (final Integer uid : contactsTD) {
......@@ -1252,14 +1252,14 @@ public class ContactsController {
}
}
if (toDelete.length() != 0) {
toDelete += ",";
toDelete.append(",");
}
toDelete += user.phone;
toDelete.append(user.phone);
}
}
if (toAdd.length() != 0 || toDelete.length() != 0) {
MessagesStorage.getInstance().applyPhoneBookUpdates(toAdd, toDelete);
MessagesStorage.getInstance().applyPhoneBookUpdates(toAdd.toString(), toDelete.toString());
}
if (reloadContacts) {
......
......@@ -69,7 +69,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
private boolean gettingNewDeleteTask = false;
private int currentDeletingTaskTime = 0;
private Long currentDeletingTask = null;
private ArrayList<Integer> currentDeletingTaskMids = null;
public int totalDialogsCount = 0;
......@@ -322,7 +321,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
currentDeletingTaskTime = 0;
currentDeletingTaskMids = null;
gettingNewDeleteTask = false;
currentDeletingTask = null;
loadingDialogs = false;
dialogsEndReached = false;
gettingDifference = false;
......@@ -508,14 +506,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (currentDeletingTask == null && !gettingNewDeleteTask || currentDeletingTaskTime != 0 && minDate < currentDeletingTaskTime) {
if (currentDeletingTaskMids == null && !gettingNewDeleteTask || currentDeletingTaskTime != 0 && minDate < currentDeletingTaskTime) {
getNewDeleteTask(null);
}
}
});
}
public void getNewDeleteTask(final Long oldTask) {
public void getNewDeleteTask(final ArrayList<Integer> oldTask) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
......@@ -528,7 +526,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
private void checkDeletingTask() {
int currentServerTime = ConnectionsManager.getInstance().getCurrentTime();
if (currentDeletingTask != null && currentDeletingTaskTime != 0 && currentDeletingTaskTime <= currentServerTime) {
if (currentDeletingTaskMids != null && currentDeletingTaskTime != 0 && currentDeletingTaskTime <= currentServerTime) {
currentDeletingTaskTime = 0;
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
......@@ -538,9 +536,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
getNewDeleteTask(currentDeletingTask);
getNewDeleteTask(currentDeletingTaskMids);
currentDeletingTaskTime = 0;
currentDeletingTask = null;
currentDeletingTaskMids = null;
}
});
}
......@@ -548,20 +546,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
public void processLoadedDeleteTask(final Long taskId, final int taskTime, final ArrayList<Integer> messages) {
public void processLoadedDeleteTask(final int taskTime, final ArrayList<Integer> messages) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
gettingNewDeleteTask = false;
if (taskId != null) {
if (messages != null) {
currentDeletingTaskTime = taskTime;
currentDeletingTask = taskId;
currentDeletingTaskMids = messages;
checkDeletingTask();
} else {
currentDeletingTaskTime = 0;
currentDeletingTask = null;
currentDeletingTaskMids = null;
}
}
......@@ -1275,10 +1271,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
public void loadMessages(final long dialog_id, final int count, final int max_id, boolean fromCache, int midDate, final int classGuid, boolean from_unread, boolean forward) {
public void loadMessages(final long dialog_id, final int count, final int max_id, boolean fromCache, int midDate, final int classGuid, boolean from_unread, boolean forward, final Semaphore semaphore) {
int lower_part = (int)dialog_id;
if (fromCache || lower_part == 0) {
MessagesStorage.getInstance().getMessages(dialog_id, count, max_id, midDate, classGuid, from_unread, forward);
MessagesStorage.getInstance().getMessages(dialog_id, count, max_id, midDate, classGuid, from_unread, forward, semaphore);
} else {
TLRPC.TL_messages_getHistory req = new TLRPC.TL_messages_getHistory();
if (lower_part < 0) {
......@@ -1303,7 +1299,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
final TLRPC.messages_Messages res = (TLRPC.messages_Messages) response;
processLoadedMessages(res, dialog_id, count, max_id, false, classGuid, 0, 0, 0, 0, false);
processLoadedMessages(res, dialog_id, count, max_id, false, classGuid, 0, 0, 0, 0, false, semaphore);
}
}
});
......@@ -1311,7 +1307,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
public void processLoadedMessages(final TLRPC.messages_Messages messagesRes, final long dialog_id, final int count, final int max_id, final boolean isCache, final int classGuid, final int first_unread, final int last_unread, final int unread_count, final int last_date, final boolean isForward) {
public void processLoadedMessages(final TLRPC.messages_Messages messagesRes, final long dialog_id, final int count, final int max_id, final boolean isCache, final int classGuid, final int first_unread, final int last_unread, final int unread_count, final int last_date, final boolean isForward, final Semaphore semaphore) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
......@@ -1320,10 +1316,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter
MessagesStorage.getInstance().putMessages(messagesRes, dialog_id);
}
if (lower_id != 0 && isCache && messagesRes.messages.size() == 0 && !isForward) {
if (semaphore != null) {
semaphore.release();
}
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
loadMessages(dialog_id, count, max_id, false, 0, classGuid, false, false);
loadMessages(dialog_id, count, max_id, false, 0, classGuid, false, false, null);
}
});
return;
......@@ -1337,14 +1336,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter
message.dialog_id = dialog_id;
objects.add(new MessageObject(message, usersLocal, 2));
}
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
putUsers(messagesRes.users, isCache);
putChats(messagesRes.chats, isCache);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread, last_unread, unread_count, last_date, isForward);
}
});
if (semaphore != null) {
putUsers(messagesRes.users, isCache);
putChats(messagesRes.chats, isCache);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread, last_unread, unread_count, last_date, isForward);
semaphore.release();
} else {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
putUsers(messagesRes.users, isCache);
putChats(messagesRes.chats, isCache);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread, last_unread, unread_count, last_date, isForward);
}
});
}
}
});
}
......
......@@ -11,6 +11,7 @@ package org.telegram.android;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.Html;
import android.text.TextUtils;
import android.util.SparseArray;
import org.telegram.PhoneFormat.PhoneFormat;
......@@ -90,7 +91,7 @@ public class MessagesStorage {
database.executeFast("PRAGMA temp_store = 1").stepThis().dispose();
if (createTable) {
database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER)").stepThis().dispose();
......@@ -101,7 +102,7 @@ public class MessagesStorage {
database.executeFast("CREATE TABLE media_counts(uid INTEGER PRIMARY KEY, count INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE wallpapers(uid INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE randoms(random_id INTEGER PRIMARY KEY, mid INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE enc_tasks(date INTEGER, data BLOB)").stepThis().dispose();
database.executeFast("CREATE TABLE enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose();
database.executeFast("CREATE TABLE params(id INTEGER PRIMARY KEY, seq INTEGER, pts INTEGER, date INTEGER, qts INTEGER, lsv INTEGER, sg INTEGER, pbytes BLOB)").stepThis().dispose();
database.executeFast("INSERT INTO params VALUES(1, 0, 0, 0, 0, 0, 0, NULL)").stepThis().dispose();
database.executeFast("CREATE TABLE user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
......@@ -122,7 +123,7 @@ public class MessagesStorage {
database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_dialogs ON dialogs(date);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks ON enc_tasks(date);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_idx_dialogs ON dialogs(last_mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose();
......@@ -135,7 +136,7 @@ public class MessagesStorage {
database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("PRAGMA user_version = 4").stepThis().dispose();
database.executeFast("PRAGMA user_version = 6").stepThis().dispose();
} else {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1");
......@@ -167,8 +168,8 @@ public class MessagesStorage {
}
int version = database.executeInt("PRAGMA user_version");
if (version < 4) {
updateDbToVersion4();
if (version < 6) {
updateDbToLastVersion(version);
}
}
} catch (Exception e) {
......@@ -177,82 +178,113 @@ public class MessagesStorage {
loadUnreadMessages();
}
public void updateDbToVersion4() {
public void updateDbToLastVersion(final int currentVersion) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
if (currentVersion < 4) {
database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_media ON media(mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_media ON media(uid, date, mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_media ON media(mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_media ON media(uid, date, mid);").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose();
database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose();
database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose();
database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose();
database.executeFast("PRAGMA user_version = 4").stepThis().dispose();
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
ArrayList<Integer> ids = new ArrayList<Integer>();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
Map<String, ?> values = preferences.getAll();
for (Map.Entry<String, ?> entry : values.entrySet()) {
String key = entry.getKey();
if (key.startsWith("notify2_")) {
Integer value = (Integer)entry.getValue();
if (value == 2) {
key = key.replace("notify2_", "");
try {
ids.add(Integer.parseInt(key));
} catch (Exception e) {
e.printStackTrace();
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
ArrayList<Integer> ids = new ArrayList<Integer>();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
Map<String, ?> values = preferences.getAll();
for (Map.Entry<String, ?> entry : values.entrySet()) {
String key = entry.getKey();
if (key.startsWith("notify2_")) {
Integer value = (Integer) entry.getValue();
if (value == 2) {
key = key.replace("notify2_", "");
try {
ids.add(Integer.parseInt(key));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
try {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)");
for (Integer id : ids) {
state.requery();
state.bindLong(1, id);
state.bindInteger(2, 1);
state.step();
}
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
try {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)");
for (Integer id : ids) {
});
}
if (currentVersion < 6) {
database.executeFast("CREATE TABLE IF NOT EXISTS enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose();
database.beginTransaction();
SQLiteCursor cursor = database.queryFinalized("SELECT date, data FROM enc_tasks WHERE 1");
SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)");
if (cursor.next()) {
int date = cursor.intValue(0);
int length = 0;
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1));
if ((length = cursor.byteBufferValue(1, data.buffer)) != 0) {
for (int a = 0; a < length / 4; a++) {
state.requery();
state.bindLong(1, id);
state.bindInteger(2, 1);
state.bindInteger(1, data.readInt32());
state.bindInteger(2, date);
state.step();
}
state.dispose();
database.commitTransaction();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
buffersStorage.reuseFreeBuffer(data);
}
});
state.dispose();
cursor.dispose();
database.commitTransaction();
database.executeFast("DROP INDEX IF EXISTS date_idx_enc_tasks;").stepThis().dispose();
database.executeFast("DROP TABLE IF EXISTS enc_tasks;").stepThis().dispose();
database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER").stepThis().dispose();
database.executeFast("PRAGMA user_version = 6").stepThis().dispose();
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
......@@ -368,16 +400,16 @@ public class MessagesStorage {
try {
final HashMap<Long, Integer> pushDialogs = new HashMap<Long, Integer>();
SQLiteCursor cursor = database.queryFinalized("SELECT d.did, d.unread_count, s.flags FROM dialogs as d LEFT JOIN dialog_settings as s ON d.did = s.did WHERE d.unread_count != 0");
String ids = "";
StringBuilder ids = new StringBuilder();
while (cursor.next()) {
if (cursor.isNull(2) || cursor.intValue(2) != 1) {
long did = cursor.longValue(0);
int count = cursor.intValue(1);
pushDialogs.put(did, count);
if (ids.length() != 0) {
ids += ",";
ids.append(",");
}
ids += did;
ids.append(did);
}
}
cursor.dispose();
......@@ -391,7 +423,7 @@ public class MessagesStorage {
ArrayList<Integer> chatIds = new ArrayList<Integer>();
ArrayList<Integer> encryptedChatIds = new ArrayList<Integer>();
cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid FROM messages WHERE uid IN (" + ids + ") AND out = 0 AND read_state = 0 ORDER BY date DESC LIMIT 50");
cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid FROM messages WHERE uid IN (" + ids.toString() + ") AND out = 0 AND read_state = 0 ORDER BY date DESC LIMIT 50");
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1));
if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) {
......@@ -449,14 +481,8 @@ public class MessagesStorage {
}
cursor.dispose();
String stringToLoad = "";
if (!encryptedChatIds.isEmpty()) {
for (int uid : encryptedChatIds) {
if (stringToLoad.length() != 0) {
stringToLoad += ",";
}
stringToLoad += uid;
}
String stringToLoad = TextUtils.join(",", encryptedChatIds);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", stringToLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -477,13 +503,7 @@ public class MessagesStorage {
}
if (!userIds.isEmpty()) {
stringToLoad = "";
for (Integer uid : userIds) {
if (stringToLoad.length() != 0) {
stringToLoad += ",";
}
stringToLoad += uid;
}
String stringToLoad = TextUtils.join(",", userIds);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", stringToLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -500,13 +520,7 @@ public class MessagesStorage {
}
if (!chatIds.isEmpty()) {
stringToLoad = "";
for (Integer cid : chatIds) {
if (stringToLoad.length() != 0) {
stringToLoad += ",";
}
stringToLoad += cid;
}
String stringToLoad = TextUtils.join(",", chatIds);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -593,19 +607,19 @@ public class MessagesStorage {
ArrayList<Integer> ids = new ArrayList<Integer>();
ArrayList<TLRPC.User> users = new ArrayList<TLRPC.User>();
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM blocked_users WHERE 1"));
String usersToLoad = "";
StringBuilder usersToLoad = new StringBuilder();
while (cursor.next()) {
int user_id = cursor.intValue(0);
ids.add(user_id);
if (usersToLoad.length() != 0) {
usersToLoad += ",";
usersToLoad.append(",");
}
usersToLoad += user_id;
usersToLoad.append(user_id);
}
cursor.dispose();
if (usersToLoad.length() != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString()));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
......@@ -793,34 +807,28 @@ public class MessagesStorage {
});
}
public void getNewTask(final Long oldTask) {
public void getNewTask(final ArrayList<Integer> oldTask) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
if (oldTask != null) {
database.executeFast("DELETE FROM enc_tasks WHERE rowid = " + oldTask).stepThis().dispose();
String ids = TextUtils.join(",", oldTask);
database.executeFast(String.format(Locale.US, "DELETE FROM enc_tasks_v2 WHERE mid IN(%s)", ids)).stepThis().dispose();
}
Long taskId = null;
int date = 0;
ArrayList<Integer> arr = null;
SQLiteCursor cursor = database.queryFinalized("SELECT rowid, date, data FROM enc_tasks ORDER BY date ASC LIMIT 1");
if (cursor.next()) {
taskId = cursor.longValue(0);
SQLiteCursor cursor = database.queryFinalized("SELECT mid, date FROM enc_tasks_v2 WHERE date = (SELECT min(date) FROM enc_tasks_v2)");
while (cursor.next()) {
Integer mid = cursor.intValue(0);
date = cursor.intValue(1);
int length = 0;
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(2));
if ((length = cursor.byteBufferValue(2, data.buffer)) != 0) {
if (arr == null) {
arr = new ArrayList<Integer>();
for (int a = 0; a < length / 4; a++) {
arr.add(data.readInt32());
}
}
buffersStorage.reuseFreeBuffer(data);
arr.add(mid);
}
cursor.dispose();
MessagesController.getInstance().processLoadedDeleteTask(taskId, date, arr);
MessagesController.getInstance().processLoadedDeleteTask(date, arr);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
......@@ -835,13 +843,11 @@ public class MessagesStorage {
try {
int minDate = Integer.MAX_VALUE;
SparseArray<ArrayList<Integer>> messages = new SparseArray<ArrayList<Integer>>();
String mids = "";
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl, read_state FROM messages WHERE uid = %d AND out = %d AND ttl > 0 AND date <= %d AND send_state = 0", ((long)chat_id) << 32, isOut, time));
StringBuilder mids = new StringBuilder();
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state = 1 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long)chat_id) << 32, isOut, time));
while (cursor.next()) {
int mid = cursor.intValue(0);
int ttl = cursor.intValue(1);
int read_state = cursor.intValue(2);
int date = readTime + ttl;
int date = readTime + cursor.intValue(1);
minDate = Math.min(minDate, date);
ArrayList<Integer> arr = messages.get(date);
if (arr == null) {
......@@ -849,38 +855,28 @@ public class MessagesStorage {
messages.put(date, arr);
}
if (mids.length() != 0) {
mids += ",";
mids.append(",");
}
mids += "" + mid;
mids.append(mid);
arr.add(mid);
}
cursor.dispose();
if (messages.size() != 0) {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("INSERT INTO enc_tasks VALUES(?, ?)");
SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)");
for (int a = 0; a < messages.size(); a++) {
int key = messages.keyAt(a);
ArrayList<Integer> arr = messages.get(key);
ByteBufferDesc data = buffersStorage.getFreeBuffer(404);
int count = 0;
for (int b = 0; b < arr.size(); b++) {
int mid = arr.get(b);
data.writeInt32(mid);
count++;
if (b == arr.size() - 1 || b != 0 && b % 100 == 0) {
state.requery();
data.limit(count * 4);
state.bindInteger(1, key);
state.bindByteBuffer(2, data.buffer);
state.step();
count = 0;
}
for (Integer mid : arr) {
state.requery();
state.bindInteger(1, mid);
state.bindInteger(2, key);
state.step();
}
buffersStorage.reuseFreeBuffer(data);
}
state.dispose();
database.commitTransaction();
database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids.toString())).stepThis().dispose();
MessagesController.getInstance().didAddedNewTask(minDate);
}
} catch (Exception e) {
......@@ -896,15 +892,9 @@ public class MessagesStorage {
}
try {
HashMap<Long, Integer> dialogsToUpdate = new HashMap<Long, Integer>();
String dialogsToReload = "";
if (messages != null && !messages.isEmpty()) {
String ids = "";
for (int uid : messages) {
if (ids.length() != 0) {
ids += ",";
}
ids += uid;
}
StringBuilder dialogsToReload = new StringBuilder();
String ids = TextUtils.join(",", messages);
int totalCount = 0;
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, read_state, out FROM messages WHERE mid IN(%s)", ids));
while (cursor.next()) {
......@@ -922,20 +912,16 @@ public class MessagesStorage {
if (currentCount == null) {
dialogsToUpdate.put(uid, 1);
if (dialogsToReload.length() != 0) {
dialogsToReload += ",";
dialogsToReload.append(",");
}
dialogsToReload += uid;
dialogsToReload.append(uid);
} else {
dialogsToUpdate.put(uid, currentCount + 1);
}
}
cursor.dispose();
if (totalCount != messages.size()) {
FileLog.e("tmessages", "messages read mismatch!");
}
cursor = database.queryFinalized(String.format(Locale.US, "SELECT did, unread_count FROM dialogs WHERE did IN(%s)", dialogsToReload));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT did, unread_count FROM dialogs WHERE did IN(%s)", dialogsToReload.toString()));
while (cursor.next()) {
long did = cursor.longValue(0);
int count = cursor.intValue(1);
......@@ -1098,7 +1084,7 @@ public class MessagesStorage {
if (info != null) {
boolean modified = false;
ArrayList<Integer> usersArr = new ArrayList<Integer>();
String usersToLoad = "";
StringBuilder usersToLoad = new StringBuilder();
for (int a = 0; a < info.participants.size(); a++) {
TLRPC.TL_chatParticipant c = info.participants.get(a);
if (usersArr.contains(c.user_id)) {
......@@ -1107,14 +1093,14 @@ public class MessagesStorage {
a--;
} else {
if (usersToLoad.length() != 0) {
usersToLoad += ",";
usersToLoad.append(",");
}
usersArr.add(c.user_id);
usersToLoad += c.user_id;
usersToLoad.append(c.user_id);
}
}
if (usersToLoad.length() != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString()));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
......@@ -1322,13 +1308,7 @@ public class MessagesStorage {
@Override
public void run() {
try {
String ids = "";
for (Integer uid : uids) {
if (ids.length() != 0) {
ids += ",";
}
ids += "" + uid;
}
String ids = TextUtils.join(",", uids);
database.executeFast("DELETE FROM contacts WHERE uid IN(" + ids + ")").stepThis().dispose();
} catch (Exception e) {
FileLog.e("tmessages", e);
......@@ -1446,7 +1426,7 @@ public class MessagesStorage {
ArrayList<TLRPC.User> users = new ArrayList<TLRPC.User>();
try {
SQLiteCursor cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1");
String uids = "";
StringBuilder uids = new StringBuilder();
while (cursor.next()) {
int user_id = cursor.intValue(0);
if (user_id == UserConfig.getClientUserId()) {
......@@ -1456,15 +1436,15 @@ public class MessagesStorage {
contact.user_id = user_id;
contact.mutual = cursor.intValue(1) == 1;
if (uids.length() != 0) {
uids += ",";
uids.append(",");
}
contacts.add(contact);
uids += contact.user_id;
uids.append(contact.user_id);
}
cursor.dispose();
if (uids.length() != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", uids));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", uids.toString()));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
......@@ -1574,18 +1554,18 @@ public class MessagesStorage {
}
cursor.dispose();
String usersToLoad = "";
StringBuilder usersToLoad = new StringBuilder();
for (int uid : fromUser) {
if (!loadedUsers.contains(uid)) {
if (usersToLoad.length() != 0) {
usersToLoad += ",";
usersToLoad.append(",");
}
usersToLoad += uid;
usersToLoad.append(uid);
loadedUsers.add(uid);
}
}
if (usersToLoad.length() != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString()));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
......@@ -1722,14 +1702,9 @@ public class MessagesStorage {
}
cursor.dispose();
String stringToLoad = "";
if (!encryptedChatIds.isEmpty()) {
for (int uid : encryptedChatIds) {
if (stringToLoad.length() != 0) {
stringToLoad += ",";
}
stringToLoad += uid;
}
String stringToLoad = TextUtils.join(",", encryptedChatIds);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", stringToLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -1751,13 +1726,7 @@ public class MessagesStorage {
if (!userIds.isEmpty()) {
stringToLoad = "";
for (Integer uid : userIds) {
if (stringToLoad.length() != 0) {
stringToLoad += ",";
}
stringToLoad += uid;
}
String stringToLoad = TextUtils.join(",", userIds);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", stringToLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -1774,20 +1743,20 @@ public class MessagesStorage {
}
if (!chatIds.isEmpty() || !broadcastIds.isEmpty()) {
stringToLoad = "";
StringBuilder stringToLoad = new StringBuilder();
for (Integer cid : chatIds) {
if (stringToLoad.length() != 0) {
stringToLoad += ",";
stringToLoad.append(",");
}
stringToLoad += cid;
stringToLoad.append(cid);
}
for (Integer cid : broadcastIds) {
if (stringToLoad.length() != 0) {
stringToLoad += ",";
stringToLoad.append(",");
}
stringToLoad += (-cid);
stringToLoad.append(-cid);
}
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", stringToLoad.toString()));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
......@@ -1807,7 +1776,7 @@ public class MessagesStorage {
});
}
public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final boolean from_unread, final boolean forward) {
public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final boolean from_unread, final boolean forward, final Semaphore semaphore) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
......@@ -1991,18 +1960,18 @@ public class MessagesStorage {
}
cursor.dispose();
String usersToLoad = "";
StringBuilder usersToLoad = new StringBuilder();
for (int uid : fromUser) {
if (!loadedUsers.contains(uid)) {
if (usersToLoad.length() != 0) {
usersToLoad += ",";
usersToLoad.append(",");
}
usersToLoad += uid;
usersToLoad.append(uid);
loadedUsers.add(uid);
}
}
if (usersToLoad.length() != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad.toString()));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
......@@ -2023,7 +1992,7 @@ public class MessagesStorage {
res.users.clear();
FileLog.e("tmessages", e);
} finally {
MessagesController.getInstance().processLoadedMessages(res, dialog_id, count_query, max_id, true, classGuid, min_unread_id, max_unread_id, count_unread, max_unread_date, forward);
MessagesController.getInstance().processLoadedMessages(res, dialog_id, count_query, max_id, true, classGuid, min_unread_id, max_unread_id, count_unread, max_unread_date, forward, semaphore);
}
}
});
......@@ -2448,6 +2417,18 @@ public class MessagesStorage {
});
}
private int getMessageMediaType(TLRPC.Message message) {
if (message.media == null) {
return 0;
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
return 1;
} else if (message.media instanceof TLRPC.TL_messageMediaVideo) {
return 2;
} else {
return 0;
}
}
private void putMessagesInternal(final ArrayList<TLRPC.Message> messages, final boolean withTransaction, final boolean isBroadcast, final int downloadMask) {
try {
if (withTransaction) {
......@@ -2458,9 +2439,9 @@ public class MessagesStorage {
HashMap<Long, Integer> mediaCounts = new HashMap<Long, Integer>();
HashMap<Integer, Long> messagesIdsMap = new HashMap<Integer, Long>();
HashMap<Integer, Long> messagesMediaIdsMap = new HashMap<Integer, Long>();
String messageIds = "";
String messageMediaIds = "";
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
StringBuilder messageIds = new StringBuilder();
StringBuilder messageMediaIds = new StringBuilder();
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)");
SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media VALUES(?, ?, ?, ?)");
SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO randoms VALUES(?, ?)");
SQLitePreparedStatement state4 = database.executeFast("REPLACE INTO download_queue VALUES(?, ?, ?, ?)");
......@@ -2477,23 +2458,23 @@ public class MessagesStorage {
if (message.unread && !message.out) {
if (messageIds.length() > 0) {
messageIds += ",";
messageIds.append(",");
}
messageIds += message.id;
messageIds.append(message.id);
messagesIdsMap.put(message.id, dialog_id);
}
if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) {
if (message.ttl == 0 && (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto)) {
if (messageMediaIds.length() > 0) {
messageMediaIds += ",";
messageMediaIds.append(",");
}
messageMediaIds += message.id;
messageMediaIds.append(message.id);
messagesMediaIdsMap.put(message.id, dialog_id);
}
}
if (messageIds.length() > 0) {
SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM messages WHERE mid IN(" + messageIds + ")");
SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM messages WHERE mid IN(" + messageIds.toString() + ")");
while (cursor.next()) {
int mid = cursor.intValue(0);
messagesIdsMap.remove(mid);
......@@ -2510,7 +2491,7 @@ public class MessagesStorage {
}
if (messageMediaIds.length() > 0) {
SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM media WHERE mid IN(" + messageMediaIds + ")");
SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM media WHERE mid IN(" + messageMediaIds.toString() + ")");
while (cursor.next()) {
int mid = cursor.intValue(0);
messagesMediaIdsMap.remove(mid);
......@@ -2557,6 +2538,7 @@ public class MessagesStorage {
state.bindByteBuffer(6, data.buffer);
state.bindInteger(7, (message.out ? 1 : 0));
state.bindInteger(8, message.ttl);
state.bindInteger(9, getMessageMediaType(message));
state.step();
if (message.random_id != 0) {
......@@ -2566,7 +2548,7 @@ public class MessagesStorage {
state3.step();
}
if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) {
if (message.ttl == 0 && (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto)) {
state2.requery();
state2.bindInteger(1, messageId);
state2.bindLong(2, dialog_id);
......@@ -2862,17 +2844,17 @@ public class MessagesStorage {
database.commitTransaction();
}
} else {
String ids = "";
StringBuilder ids = new StringBuilder();
HashMap<Integer, TLRPC.User> usersDict = new HashMap<Integer, TLRPC.User>();
for (TLRPC.User user : users) {
if (ids.length() != 0) {
ids += ",";
ids.append(",");
}
ids += user.id;
ids.append(user.id);
usersDict.put(user.id, user);
}
ArrayList<TLRPC.User> loadedUsers = new ArrayList<TLRPC.User>();
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", ids));
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", ids.toString()));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
......@@ -2950,13 +2932,7 @@ public class MessagesStorage {
}
try {
if (messages != null && !messages.isEmpty()) {
String ids = "";
for (int uid : messages) {
if (ids.length() != 0) {
ids += ",";
}
ids += uid;
}
String ids = TextUtils.join(",", messages);
database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 1 WHERE mid IN(%s)", ids)).stepThis().dispose();
}
if (encryptedMessages != null && !encryptedMessages.isEmpty()) {
......@@ -2997,13 +2973,7 @@ public class MessagesStorage {
@Override
public void run() {
try {
String ids = "";
for (long uid : messages) {
if (ids.length() != 0) {
ids += ",";
}
ids += uid;
}
String ids = TextUtils.join(",", messages);
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM randoms WHERE random_id IN(%s)", ids));
final ArrayList<Integer> mids = new ArrayList<Integer>();
while (cursor.next()) {
......@@ -3038,13 +3008,7 @@ public class MessagesStorage {
throw new RuntimeException("wrong db thread");
}
try {
String ids = "";
for (int uid : messages) {
if (ids.length() != 0) {
ids += ",";
}
ids += uid;
}
String ids = TextUtils.join(",", messages);
database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN(%s)", ids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "DELETE FROM media WHERE mid IN(%s)", ids)).stepThis().dispose();
database.executeFast("DELETE FROM media_counts WHERE 1").stepThis().dispose();
......@@ -3059,13 +3023,7 @@ public class MessagesStorage {
throw new RuntimeException("wrong db thread");
}
try {
String ids = "";
for (int uid : messages) {
if (ids.length() != 0) {
ids += ",";
}
ids += uid;
}
String ids = TextUtils.join(",", messages);
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE last_mid IN(%s)", ids));
ArrayList<Long> dialogsToUpdate = new ArrayList<Long>();
while (cursor.next()) {
......@@ -3084,13 +3042,7 @@ public class MessagesStorage {
state.dispose();
database.commitTransaction();
ids = "";
for (long uid : dialogsToUpdate) {
if (ids.length() != 0) {
ids += ",";
}
ids += uid;
}
ids = TextUtils.join(",", dialogsToUpdate);
TLRPC.messages_Dialogs dialogs = new TLRPC.messages_Dialogs();
ArrayList<TLRPC.EncryptedChat> encryptedChats = new ArrayList<TLRPC.EncryptedChat>();
......@@ -3157,13 +3109,7 @@ public class MessagesStorage {
cursor.dispose();
if (!encryptedToLoad.isEmpty()) {
String toLoad = "";
for (int uid : encryptedToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
String toLoad = TextUtils.join(",", encryptedToLoad);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -3184,13 +3130,7 @@ public class MessagesStorage {
}
if (!chatsToLoad.isEmpty()) {
String toLoad = "";
for (int uid : chatsToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
String toLoad = TextUtils.join(",", chatsToLoad);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -3204,13 +3144,7 @@ public class MessagesStorage {
}
if (!usersToLoad.isEmpty()) {
String toLoad = "";
for (int uid : usersToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
String toLoad = TextUtils.join(",", usersToLoad);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad));
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
......@@ -3276,7 +3210,7 @@ public class MessagesStorage {
try {
database.beginTransaction();
if (!messages.messages.isEmpty()) {
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)");
SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media VALUES(?, ?, ?, ?)");
for (TLRPC.Message message : messages.messages) {
state.requery();
......@@ -3290,6 +3224,7 @@ public class MessagesStorage {
state.bindByteBuffer(6, data.buffer);
state.bindInteger(7, (message.out ? 1 : 0));
state.bindInteger(8, 0);
state.bindInteger(9, getMessageMediaType(message));
state.step();
if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) {
......@@ -3430,13 +3365,7 @@ public class MessagesStorage {
cursor.dispose();
if (!encryptedToLoad.isEmpty()) {
String toLoad = "";
for (int uid : encryptedToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
String toLoad = TextUtils.join(",", encryptedToLoad);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad));
while (cursor.next()) {
try {
......@@ -3463,13 +3392,7 @@ public class MessagesStorage {
}
if (!chatsToLoad.isEmpty()) {
String toLoad = "";
for (int uid : chatsToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
String toLoad = TextUtils.join(",", chatsToLoad);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad));
while (cursor.next()) {
try {
......@@ -3489,13 +3412,7 @@ public class MessagesStorage {
}
if (!usersToLoad.isEmpty()) {
String toLoad = "";
for (int uid : usersToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
String toLoad = TextUtils.join(",", usersToLoad);
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad));
while (cursor.next()) {
try {
......@@ -3549,7 +3466,7 @@ public class MessagesStorage {
}
if (!dialogs.dialogs.isEmpty()) {
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)");
SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO dialogs(did, date, unread_count, last_mid) VALUES(?, ?, ?, ?)");
SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO media VALUES(?, ?, ?, ?)");
SQLitePreparedStatement state4 = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)");
......@@ -3574,6 +3491,7 @@ public class MessagesStorage {
state.bindByteBuffer(6, data.buffer);
state.bindInteger(7, (message.out ? 1 : 0));
state.bindInteger(8, 0);
state.bindInteger(9, getMessageMediaType(message));
state.step();
state2.bindLong(1, uid);
......@@ -3683,14 +3601,7 @@ public class MessagesStorage {
public ArrayList<TLRPC.User> getUsers(final ArrayList<Integer> uids, final boolean[] error) {
ArrayList<TLRPC.User> users = new ArrayList<TLRPC.User>();
try {
String uidsStr = "";
for (Integer uid : uids) {
if (uidsStr.length() != 0) {
uidsStr += ",";
}
uidsStr += uid;
}
String uidsStr = TextUtils.join(",", uids);
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN (%s)", uidsStr));
while (cursor.next()) {
......
......@@ -24,9 +24,9 @@ import java.util.zip.ZipFile;
public class NativeLoader {
private static final long sizes[] = new long[] {
946908, //armeabi
1028848, //armeabi-v7a
1603780, //x86
951052, //armeabi
1032992, //armeabi-v7a
1612020, //x86
0, //mips
};
......
......@@ -9000,6 +9000,41 @@ public class TLRPC {
}
}
public static class TL_message_secret extends TL_message {
public static int constructor = 0x555555F8;
public void readParams(AbsSerializedData stream) {
id = stream.readInt32();
from_id = stream.readInt32();
to_id = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
out = stream.readBool();
unread = stream.readBool();
date = stream.readInt32();
message = stream.readString();
media = (MessageMedia)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && message != null && message.length() != 0 && message.startsWith("-1"))) {
attachPath = stream.readString();
}
if (id < 0 && message.length() > 6 && media instanceof TL_messageMediaVideo) {
videoEditedInfo = new VideoEditedInfo();
videoEditedInfo.parseString(message);
}
}
public void serializeToStream(AbsSerializedData stream) {
stream.writeInt32(constructor);
stream.writeInt32(id);
stream.writeInt32(from_id);
to_id.serializeToStream(stream);
stream.writeBool(out);
stream.writeBool(unread);
stream.writeInt32(date);
stream.writeString(message);
media.serializeToStream(stream);
stream.writeString(attachPath);
}
}
public static class TL_messages_deleteMessages extends TLObject {
public static int constructor = 0x14f2dd0a;
......
......@@ -117,6 +117,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
private TypingDotsDrawable typingDotsDrawable;
private View emptyViewContainer;
private ArrayList<View> actionModeViews = new ArrayList<View>();
private Semaphore testSemaphore = new Semaphore(0);
private TextView bottomOverlayText;
......@@ -352,7 +353,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
super.onFragmentCreate();
loading = true;
MessagesController.getInstance().loadMessages(dialog_id, 30, 0, true, 0, classGuid, true, false);
MessagesController.getInstance().loadMessages(dialog_id, AndroidUtilities.isTablet() ? 30 : 20, 0, true, 0, classGuid, true, false, testSemaphore);
try {
testSemaphore.acquire();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
if (currentUser != null) {
userBlocked = MessagesController.getInstance().blockedUsers.contains(currentUser.id);
}
......@@ -766,16 +774,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
if (firstVisibleItem <= 4) {
if (!endReached && !loading) {
if (messagesByDays.size() != 0) {
MessagesController.getInstance().loadMessages(dialog_id, 20, maxMessageId, !cacheEndReaced, minDate, classGuid, false, false);
MessagesController.getInstance().loadMessages(dialog_id, 20, maxMessageId, !cacheEndReaced, minDate, classGuid, false, false, null);
} else {
MessagesController.getInstance().loadMessages(dialog_id, 20, 0, !cacheEndReaced, minDate, classGuid, false, false);
MessagesController.getInstance().loadMessages(dialog_id, 20, 0, !cacheEndReaced, minDate, classGuid, false, false, null);
}
loading = true;
}
}
if (firstVisibleItem + visibleItemCount >= totalItemCount - 6) {
if (!unread_end_reached && !loadingForward) {
MessagesController.getInstance().loadMessages(dialog_id, 20, minMessageId, true, maxDate, classGuid, false, true);
MessagesController.getInstance().loadMessages(dialog_id, 20, minMessageId, true, maxDate, classGuid, false, true, null);
loadingForward = true;
}
}
......@@ -896,7 +904,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
unread_end_reached = true;
loading = true;
chatAdapter.notifyDataSetChanged();
MessagesController.getInstance().loadMessages(dialog_id, 30, 0, true, 0, classGuid, true, false);
MessagesController.getInstance().loadMessages(dialog_id, 30, 0, true, 0, classGuid, true, false, null);
}
}
......@@ -2249,7 +2257,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
}
maxDate = Integer.MIN_VALUE;
minDate = 0;
MessagesController.getInstance().loadMessages(dialog_id, 30, 0, !cacheEndReaced, minDate, classGuid, false, false);
MessagesController.getInstance().loadMessages(dialog_id, 30, 0, !cacheEndReaced, minDate, classGuid, false, false, null);
loading = true;
}
}
......
......@@ -2138,7 +2138,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
float ai = -1;
if (System.currentTimeMillis() - animationStartTime < animationDuration) {
ai = interpolator.getInterpolation((float)(System.currentTimeMillis() - animationStartTime) / animationDuration);
if (ai >= 0.95) {
if (ai >= 0.999f) {
ai = -1;
}
}
......
<?xml version="1.0" encoding="utf-8"?>
<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="1.5" />
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="0.9"
android:fromYScale="0.9"
android:toXScale="1.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="150"/>
<alpha android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="150" />
<!--<scale-->
<!--android:fromXScale="0.9"-->
<!--android:fromYScale="0.9"-->
<!--android:toXScale="1.0"-->
<!--android:toYScale="1.0"-->
<!--android:pivotX="50%"-->
<!--android:pivotY="50%"-->
<!--android:interpolator="@android:anim/decelerate_interpolator"-->
<!--android:duration="220"/>-->
<!--<alpha android:fromAlpha="0.0"-->
<!--android:toAlpha="1.0"-->
<!--android:interpolator="@android:anim/decelerate_interpolator"-->
<!--android:duration="@android:integer/config_mediumAnimTime" />-->
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="@anim/decelerate_cubic"
android:duration="220"/>
<scale
android:fromXScale=".8" android:toXScale="1.0"
android:fromYScale=".8" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="50%p"
android:interpolator="@anim/decelerate_cubic"
android:duration="220"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0"
android:fromYScale="1.0"
android:toXScale="0.9"
android:toYScale="0.9"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="150"/>
<!--<scale-->
<!--android:fromXScale="1.0"-->
<!--android:fromYScale="1.0"-->
<!--android:toXScale="0.9"-->
<!--android:toYScale="0.9"-->
<!--android:pivotX="50%"-->
<!--android:pivotY="50%"-->
<!--android:interpolator="@android:anim/decelerate_interpolator"-->
<!--android:duration="220"/>-->
<!--<alpha-->
<!--android:fromAlpha="1.0"-->
<!--android:toAlpha="0.0"-->
<!--android:interpolator="@android:anim/decelerate_interpolator"-->
<!--android:duration="220" />-->
<alpha android:fromAlpha="1.0"
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="150" />
android:interpolator="@anim/decelerate_cubic"
android:duration="220"/>
<scale
android:fromXScale="1.0"
android:toXScale=".8"
android:fromYScale="1.0"
android:toYScale=".8"
android:pivotX="50%p"
android:pivotY="50%p"
android:interpolator="@anim/decelerate_cubic"
android:duration="220"/>
</set>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment