**
******************************************************************************
**
-** This SQLite extension implements functions that compute SHA1 hashes.
-** Two SQL functions are implemented:
+** This SQLite extension implements a function that computes SHA1 hash.
**
** sha1(X)
-** sha1_query(Y)
**
** The sha1(X) function computes the SHA1 hash of the input X, or NULL if
** X is NULL.
-**
-** The sha1_query(Y) function evalutes all queries in the SQL statements of Y
-** and returns a hash of their results.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
-#include <stdarg.h>
/******************************************************************************
** The Hash Engine
(void)memcpy(&p->buffer[j], &data[i], len - i);
}
-/* Compute a string using sqlite3_vsnprintf() and hash it */
-static void hash_step_vformat(
- SHA1Context *p, /* Add content to this context */
- const char *zFormat,
- ...
-){
- va_list ap;
- int n;
- char zBuf[50];
- va_start(ap, zFormat);
- sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
- va_end(ap);
- n = (int)strlen(zBuf);
- hash_step(p, (unsigned char*)zBuf, n);
-}
-
-
/* Add padding and compute the message digest. Render the
** message digest as lower-case hexadecimal and put it into
** zOut[]. zOut[] must be at least 41 bytes long. */
** Implementation of the sha1(X) function.
**
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
-** argument X. If X is a BLOB, it is hashed as is. For all other
-** types of input, X is converted into a UTF-8 string and the string
-** is hash without the trailing 0x00 terminator. The hash of a NULL
-** value is NULL.
+** argument X. X is converted into a UTF-8 string and the string is hashed
+** without the trailing 0x00 terminator. The hash of a NULL value is NULL.
*/
static void sha1Func(
sqlite3_context *context,
sqlite3_value **argv
){
SHA1Context cx;
- int eType = sqlite3_value_type(argv[0]);
+ __attribute__((unused)) int eType = sqlite3_value_type(argv[0]);
int nByte = sqlite3_value_bytes(argv[0]);
char zOut[44];
assert( argc==1 );
- if( eType==SQLITE_NULL ) return;
- hash_init(&cx);
- if( eType==SQLITE_BLOB ){
- hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
- }else{
- hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
- }
- hash_finish(&cx, zOut);
- sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
-}
-
-/*
-** Implementation of the sha1_query(SQL) function.
-**
-** This function compiles and runs the SQL statement(s) given in the
-** argument. The results are hashed using SHA1 and that hash is returned.
-**
-** The original SQL text is included as part of the hash.
-**
-** The hash is not just a concatenation of the outputs. Each query
-** is delimited and each row and value within the query is delimited,
-** with all values being marked with their datatypes.
-*/
-static void sha1QueryFunc(
- sqlite3_context *context,
- __attribute__((unused)) int argc,
- sqlite3_value **argv
-){
- sqlite3 *db = sqlite3_context_db_handle(context);
- const char *zSql = (const char*)sqlite3_value_text(argv[0]);
- sqlite3_stmt *pStmt = 0;
- int nCol; /* Number of columns in the result set */
- int i; /* Loop counter */
- int rc;
- int n;
- const char *z;
- SHA1Context cx;
- char zOut[44];
-
- assert( argc==1 );
- if( zSql==0 ) return;
+ assert( eType==SQLITE_TEXT );
hash_init(&cx);
- while( zSql[0] ){
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
- if( rc ){
- char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
- zSql, sqlite3_errmsg(db));
- sqlite3_finalize(pStmt);
- sqlite3_result_error(context, zMsg, -1);
- sqlite3_free(zMsg);
- return;
- }
- if( !sqlite3_stmt_readonly(pStmt) ){
- char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
- sqlite3_finalize(pStmt);
- sqlite3_result_error(context, zMsg, -1);
- sqlite3_free(zMsg);
- return;
- }
- nCol = sqlite3_column_count(pStmt);
- z = sqlite3_sql(pStmt);
- n = (int)strlen(z);
- hash_step_vformat(&cx,"S%d:",n);
- hash_step(&cx,(unsigned char*)z,n);
-
- /* Compute a hash over the result of the query */
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- hash_step(&cx,(const unsigned char*)"R",1);
- for(i=0; i<nCol; i++){
- switch( sqlite3_column_type(pStmt,i) ){
- case SQLITE_NULL: {
- hash_step(&cx, (const unsigned char*)"N",1);
- break;
- }
- case SQLITE_INTEGER: {
- sqlite3_uint64 u;
- int j;
- unsigned char x[9];
- sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
- memcpy(&u, &v, 8);
- for(j=8; j>=1; j--){
- x[j] = u & 0xff;
- u >>= 8;
- }
- x[0] = 'I';
- hash_step(&cx, x, 9);
- break;
- }
- case SQLITE_FLOAT: {
- sqlite3_uint64 u;
- int j;
- unsigned char x[9];
- double r = sqlite3_column_double(pStmt,i);
- memcpy(&u, &r, 8);
- for(j=8; j>=1; j--){
- x[j] = u & 0xff;
- u >>= 8;
- }
- x[0] = 'F';
- hash_step(&cx,x,9);
- break;
- }
- case SQLITE_TEXT: {
- int n2 = sqlite3_column_bytes(pStmt, i);
- const unsigned char *z2 = sqlite3_column_text(pStmt, i);
- hash_step_vformat(&cx,"T%d:",n2);
- hash_step(&cx, z2, n2);
- break;
- }
- case SQLITE_BLOB: {
- int n2 = sqlite3_column_bytes(pStmt, i);
- const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
- hash_step_vformat(&cx,"B%d:",n2);
- hash_step(&cx, z2, n2);
- break;
- }
- }
- }
- }
- sqlite3_finalize(pStmt);
- }
+ hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
hash_finish(&cx, zOut);
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
}
-
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-int sqlite3_sha_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- int rc = SQLITE_OK;
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "sha1", 1,
- SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
- 0, sha1Func, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha1_query", 1,
- SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
- sha1QueryFunc, 0, 0);
- }
- return rc;
-}
-
int sqlite3_extension_init(sqlite3 *db, char **err, const sqlite3_api_routines *api)
{
- return sqlite3_sha_init(db, err, api);
+ SQLITE_EXTENSION_INIT2(api);
+ (void)err; /* Unused parameter */
+ return sqlite3_create_function(db, "sha1", 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, sha1Func, 0, 0);
}