Add the SQLITE_TESTCTRL_PRNG_SEED test control.

FossilOrigin-Name: 3ac5723164ae801e209ce525a5d94692767136f9d06be2a84883dcea677d02da
diff --git a/src/global.c b/src/global.c
index b512e6f..79b1d42 100644
--- a/src/global.c
+++ b/src/global.c
@@ -260,6 +260,7 @@
    0,                         /* bInternalFunctions */
    0x7ffffffe,                /* iOnceResetThreshold */
    SQLITE_DEFAULT_SORTERREF_SIZE,   /* szSorterRef */
+   0,                         /* iPrngSeed */
 };
 
 /*
diff --git a/src/main.c b/src/main.c
index 6127006..81a76aa 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3824,13 +3824,13 @@
       break;
     }
 
-    /*
-    ** Reset the PRNG back to its uninitialized state.  The next call
-    ** to sqlite3_randomness() will reseed the PRNG using a single call
-    ** to the xRandomness method of the default VFS.
+    /*  sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, unsigned int);
+    **
+    ** Use the integer value as the seed for SQLite's internal PRNG.
+    ** rather than the VFS xRandomness() function.
     */
-    case SQLITE_TESTCTRL_PRNG_RESET: {
-      sqlite3_randomness(0,0);
+    case SQLITE_TESTCTRL_PRNG_SEED: {
+      sqlite3Config.iPrngSeed = va_arg(ap, unsigned int);
       break;
     }
 
diff --git a/src/os.c b/src/os.c
index 54b7fcf..0870102 100644
--- a/src/os.c
+++ b/src/os.c
@@ -258,7 +258,15 @@
 }
 #endif /* SQLITE_OMIT_LOAD_EXTENSION */
 int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
-  return pVfs->xRandomness(pVfs, nByte, zBufOut);
+  if( sqlite3Config.iPrngSeed ){
+    memset(zBufOut, 0, nByte);
+    if( nByte>sizeof(unsigned) ) nByte = sizeof(unsigned int);
+    memcpy(zBufOut, &sqlite3Config.iPrngSeed, nByte);
+    return SQLITE_OK;
+  }else{
+    return pVfs->xRandomness(pVfs, nByte, zBufOut);
+  }
+  
 }
 int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
   return pVfs->xSleep(pVfs, nMicro);
diff --git a/src/shell.c.in b/src/shell.c.in
index c5ca924..fa82cf2 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -9150,9 +9150,9 @@
       { "parser_coverage",    SQLITE_TESTCTRL_PARSER_COVERAGE, ""                 },
 #endif
       { "pending_byte",       SQLITE_TESTCTRL_PENDING_BYTE,  "OFFSET  "           },
-      { "prng_reset",         SQLITE_TESTCTRL_PRNG_RESET,    ""                   },
       { "prng_restore",       SQLITE_TESTCTRL_PRNG_RESTORE,  ""                   },
       { "prng_save",          SQLITE_TESTCTRL_PRNG_SAVE,     ""                   },
+      { "prng_seed",          SQLITE_TESTCTRL_PRNG_SEED,     "SEED"               },
       { "reserve",            SQLITE_TESTCTRL_RESERVE,       "BYTES-OF-RESERVE"   },
     };
     int testctrl = -1;
@@ -9227,6 +9227,7 @@
 
         /* sqlite3_test_control(int, uint) */
         case SQLITE_TESTCTRL_PENDING_BYTE:
+        case SQLITE_TESTCTRL_PRNG_SEED:
           if( nArg==3 ){
             unsigned int opt = (unsigned int)integerValue(azArg[2]);
             rc2 = sqlite3_test_control(testctrl, opt);
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 4dd14ac..5b3e5a1 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -7335,7 +7335,7 @@
 #define SQLITE_TESTCTRL_FIRST                    5
 #define SQLITE_TESTCTRL_PRNG_SAVE                5
 #define SQLITE_TESTCTRL_PRNG_RESTORE             6
-#define SQLITE_TESTCTRL_PRNG_RESET               7
+#define SQLITE_TESTCTRL_PRNG_RESET               7  /* NOT USED */
 #define SQLITE_TESTCTRL_BITVEC_TEST              8
 #define SQLITE_TESTCTRL_FAULT_INSTALL            9
 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS     10
@@ -7358,7 +7358,8 @@
 #define SQLITE_TESTCTRL_IMPOSTER                25
 #define SQLITE_TESTCTRL_PARSER_COVERAGE         26
 #define SQLITE_TESTCTRL_RESULT_INTREAL          27
-#define SQLITE_TESTCTRL_LAST                    27  /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_PRNG_SEED               28
+#define SQLITE_TESTCTRL_LAST                    28  /* Largest TESTCTRL */
 
 /*
 ** CAPI3REF: SQL Keyword Checking
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b41ba4e..166c465 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3464,6 +3464,7 @@
   int bInternalFunctions;           /* Internal SQL functions are visible */
   int iOnceResetThreshold;          /* When to reset OP_Once counters */
   u32 szSorterRef;                  /* Min size in bytes to use sorter-refs */
+  unsigned int iPrngSeed;           /* Alternative fixed seed for the PRNG */
 };
 
 /*
diff --git a/src/test1.c b/src/test1.c
index 02a7aad..c582bb3 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -6373,7 +6373,28 @@
   int objc,              /* Number of arguments */
   Tcl_Obj *CONST objv[]  /* Command arguments */
 ){
-  sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET);
+  sqlite3_randomness(0,0);
+  return TCL_OK;
+}
+/*
+** tclcmd:  prng_seed INT
+**
+** Establish TEXT as the seed for the PRNG
+*/
+static int SQLITE_TCLAPI prng_seed(
+  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  unsigned int i;
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "PRNG-SEED-TEXT");
+    return TCL_ERROR;
+  }
+  if( Tcl_GetIntFromObj(objv[0],&i) ) return TCL_ERROR;
+  sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, (unsigned int)i);
+  sqlite3_randomness(0,0);
   return TCL_OK;
 }
 
@@ -7923,6 +7944,7 @@
      { "save_prng_state",               save_prng_state,    0 },
      { "restore_prng_state",            restore_prng_state, 0 },
      { "reset_prng_state",              reset_prng_state,   0 },
+     { "prng_seed",                     prng_seed,          0 },
      { "database_never_corrupt",        database_never_corrupt, 0},
      { "database_may_be_corrupt",       database_may_be_corrupt, 0},
      { "optimization_control",          optimization_control,0},