System.Data.SQLite
Check-in [12c508890c]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add experimental support for interfacing with the authorizer callback mechanism in the SQLite core library.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 12c508890cd3486713263e359466636d3b5db892
User & Date: mistachkin 2013-09-18 02:10:34
Context
2013-09-18
02:31
Simplify and cleanup authorizer tests. Update version history docs. check-in: 441ccabcc6 user: mistachkin tags: trunk
02:10
Add experimental support for interfacing with the authorizer callback mechanism in the SQLite core library. check-in: 12c508890c user: mistachkin tags: trunk
2013-09-17
08:00
Add some simple tests of the new properties. check-in: 06c39db73a user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to Setup/verify.lst.

   403    403     testlinq/Properties/
   404    404     testlinq/Properties/AssemblyInfo.cs
   405    405     testlinq/testlinq.2008.csproj
   406    406     testlinq/testlinq.2010.csproj
   407    407     testlinq/testlinq.2012.csproj
   408    408     Tests/
   409    409     Tests/all.eagle
          410  +  Tests/authorizer.eagle
   410    411     Tests/backup.eagle
   411    412     Tests/basic.eagle
   412    413     Tests/common.eagle
   413    414     Tests/empty.eagle
   414    415     Tests/installer.eagle
   415    416     Tests/Installer_Test_Vs2005.log
   416    417     Tests/Installer_Test_Vs2008.log

Changes to System.Data.SQLite/SQLite3.cs.

  2041   2041   
  2042   2042       internal override void ChangePassword(byte[] newPasswordBytes)
  2043   2043       {
  2044   2044         SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length);
  2045   2045         if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
  2046   2046       }
  2047   2047   #endif
         2048  +
         2049  +    internal override void SetAuthorizerHook(SQLiteAuthorizerCallback func)
         2050  +    {
         2051  +      UnsafeNativeMethods.sqlite3_set_authorizer(_sql, func, IntPtr.Zero);
         2052  +    }
  2048   2053   
  2049   2054       internal override void SetUpdateHook(SQLiteUpdateCallback func)
  2050   2055       {
  2051   2056         UnsafeNativeMethods.sqlite3_update_hook(_sql, func, IntPtr.Zero);
  2052   2057       }
  2053   2058   
  2054   2059       internal override void SetCommitHook(SQLiteCommitCallback func)

Changes to System.Data.SQLite/SQLiteBase.cs.

   359    359       internal abstract void LogMessage(SQLiteErrorCode iErrCode, string zMessage);
   360    360   
   361    361   #if INTEROP_CODEC
   362    362       internal abstract void SetPassword(byte[] passwordBytes);
   363    363       internal abstract void ChangePassword(byte[] newPasswordBytes);
   364    364   #endif
   365    365   
          366  +    internal abstract void SetAuthorizerHook(SQLiteAuthorizerCallback func);
   366    367       internal abstract void SetUpdateHook(SQLiteUpdateCallback func);
   367    368       internal abstract void SetCommitHook(SQLiteCommitCallback func);
   368    369       internal abstract void SetTraceCallback(SQLiteTraceCallback func);
   369    370       internal abstract void SetRollbackHook(SQLiteRollbackCallback func);
   370    371       internal abstract SQLiteErrorCode SetLogCallback(SQLiteLogCallback func);
   371    372   
   372    373       /// <summary>

Changes to System.Data.SQLite/SQLiteConnection.cs.

   474    474       /// </summary>
   475    475       private bool _parseViaFramework;
   476    476   
   477    477       internal bool _binaryGuid;
   478    478   
   479    479       internal long _version;
   480    480   
          481  +    private event SQLiteAuthorizerEventHandler _authorizerHandler;
   481    482       private event SQLiteUpdateEventHandler _updateHandler;
   482    483       private event SQLiteCommitHandler _commitHandler;
   483    484       private event SQLiteTraceEventHandler _traceHandler;
   484    485       private event EventHandler _rollbackHandler;
   485    486   
          487  +    private SQLiteAuthorizerCallback _authorizerCallback;
   486    488       private SQLiteUpdateCallback _updateCallback;
   487    489       private SQLiteCommitCallback _commitCallback;
   488    490       private SQLiteTraceCallback _traceCallback;
   489    491       private SQLiteRollbackCallback _rollbackCallback;
   490    492       #endregion
   491    493   
   492    494       ///////////////////////////////////////////////////////////////////////////////////////////////
................................................................................
  2220   2222                     {
  2221   2223                         cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA foreign_keys={0}", boolValue ? "ON" : "OFF");
  2222   2224                         cmd.ExecuteNonQuery();
  2223   2225                     }
  2224   2226                 }
  2225   2227             }
  2226   2228   
         2229  +          if (_authorizerHandler != null)
         2230  +              _sql.SetAuthorizerHook(_authorizerCallback);
         2231  +
  2227   2232             if (_commitHandler != null)
  2228   2233               _sql.SetCommitHook(_commitCallback);
  2229   2234   
  2230   2235             if (_updateHandler != null)
  2231   2236               _sql.SetUpdateHook(_updateCallback);
  2232   2237   
  2233   2238             if (_rollbackHandler != null)
................................................................................
  3933   3938         }
  3934   3939   
  3935   3940         tbl.EndLoadData();
  3936   3941         tbl.AcceptChanges();
  3937   3942   
  3938   3943         return tbl;
  3939   3944       }
         3945  +
         3946  +    /// <summary>
         3947  +    /// This event is raised whenever SQLite encounters an action covered by the
         3948  +    /// authorizer during query preparation.  Changing the value of the
         3949  +    /// <see cref="AuthorizerEventArgs.ReturnCode" /> property will determine if
         3950  +    /// the specific action will be allowed, ignored, or denied.  For the entire
         3951  +    /// duration of the event, the associated connection and statement objects
         3952  +    /// must not be modified, either directly or indirectly, by the called code.
         3953  +    /// </summary>
         3954  +    public event SQLiteAuthorizerEventHandler Authorize
         3955  +    {
         3956  +        add
         3957  +        {
         3958  +            CheckDisposed();
         3959  +
         3960  +            if (_authorizerHandler == null)
         3961  +            {
         3962  +                _authorizerCallback = new SQLiteAuthorizerCallback(AuthorizerCallback);
         3963  +                if (_sql != null) _sql.SetAuthorizerHook(_authorizerCallback);
         3964  +            }
         3965  +            _authorizerHandler += value;
         3966  +        }
         3967  +        remove
         3968  +        {
         3969  +            CheckDisposed();
         3970  +
         3971  +            _authorizerHandler -= value;
         3972  +            if (_authorizerHandler == null)
         3973  +            {
         3974  +                if (_sql != null) _sql.SetAuthorizerHook(null);
         3975  +                _authorizerCallback = null;
         3976  +            }
         3977  +        }
         3978  +    }
  3940   3979   
  3941   3980       /// <summary>
  3942   3981       /// This event is raised whenever SQLite makes an update/delete/insert into the database on
  3943   3982       /// this connection.  It only applies to the given connection.
  3944   3983       /// </summary>
  3945   3984       public event SQLiteUpdateEventHandler Update
  3946   3985       {
................................................................................
  3963   4002           if (_updateHandler == null)
  3964   4003           {
  3965   4004             if (_sql != null) _sql.SetUpdateHook(null);
  3966   4005             _updateCallback = null;
  3967   4006           }
  3968   4007         }
  3969   4008       }
         4009  +
         4010  +    private SQLiteAuthorizerReturnCode AuthorizerCallback(
         4011  +        IntPtr pUserData,
         4012  +        SQLiteAuthorizerActionCode actionCode,
         4013  +        IntPtr pArgument1,
         4014  +        IntPtr pArgument2,
         4015  +        IntPtr pDatabase,
         4016  +        IntPtr pAuthContext)
         4017  +    {
         4018  +        AuthorizerEventArgs eventArgs = new AuthorizerEventArgs(pUserData, actionCode,
         4019  +            SQLiteBase.UTF8ToString(pArgument1, -1), SQLiteBase.UTF8ToString(pArgument2, -1),
         4020  +            SQLiteBase.UTF8ToString(pDatabase, -1), SQLiteBase.UTF8ToString(pAuthContext, -1),
         4021  +            SQLiteAuthorizerReturnCode.Ok);
         4022  +
         4023  +        if (_authorizerHandler != null)
         4024  +            _authorizerHandler(this, eventArgs);
         4025  +
         4026  +        return eventArgs.ReturnCode;
         4027  +    }
  3970   4028   
  3971   4029       private void UpdateCallback(IntPtr puser, int type, IntPtr database, IntPtr table, Int64 rowid)
  3972   4030       {
  3973   4031         _updateHandler(this, new UpdateEventArgs(
  3974   4032           SQLiteBase.UTF8ToString(database, -1),
  3975   4033           SQLiteBase.UTF8ToString(table, -1),
  3976   4034           (UpdateEventType)type,
................................................................................
  4104   4162       /// Use the default operating system's file flushing, SQLite does not explicitly flush the file buffers after writing
  4105   4163       /// </summary>
  4106   4164       Off = 2,
  4107   4165     }
  4108   4166   
  4109   4167   #if !PLATFORM_COMPACTFRAMEWORK
  4110   4168     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         4169  +#endif
         4170  +  internal delegate SQLiteAuthorizerReturnCode SQLiteAuthorizerCallback(
         4171  +    IntPtr pUserData,
         4172  +    SQLiteAuthorizerActionCode actionCode,
         4173  +    IntPtr pArgument1,
         4174  +    IntPtr pArgument2,
         4175  +    IntPtr pDatabase,
         4176  +    IntPtr pAuthContext
         4177  +    );
         4178  +
         4179  +#if !PLATFORM_COMPACTFRAMEWORK
         4180  +  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  4111   4181   #endif
  4112   4182     internal delegate void SQLiteUpdateCallback(IntPtr puser, int type, IntPtr database, IntPtr table, Int64 rowid);
  4113   4183   
  4114   4184   #if !PLATFORM_COMPACTFRAMEWORK
  4115   4185     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  4116   4186   #endif
  4117   4187     internal delegate int SQLiteCommitCallback(IntPtr puser);
................................................................................
  4122   4192     internal delegate void SQLiteTraceCallback(IntPtr puser, IntPtr statement);
  4123   4193   
  4124   4194   #if !PLATFORM_COMPACTFRAMEWORK
  4125   4195     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  4126   4196   #endif
  4127   4197     internal delegate void SQLiteRollbackCallback(IntPtr puser);
  4128   4198   
         4199  +  /// <summary>
         4200  +  /// Raised when authorization is required to perform an action contained
         4201  +  /// within a SQL query.
         4202  +  /// </summary>
         4203  +  /// <param name="sender">The connection performing the action.</param>
         4204  +  /// <param name="e">A <see cref="AuthorizerEventArgs" /> that contains the
         4205  +  /// event data.</param>
         4206  +  public delegate void SQLiteAuthorizerEventHandler(object sender, AuthorizerEventArgs e);
         4207  +
  4129   4208     /// <summary>
  4130   4209     /// Raised when a transaction is about to be committed.  To roll back a transaction, set the
  4131   4210     /// rollbackTrans boolean value to true.
  4132   4211     /// </summary>
  4133   4212     /// <param name="sender">The connection committing the transaction</param>
  4134   4213     /// <param name="e">Event arguments on the transaction</param>
  4135   4214     public delegate void SQLiteCommitHandler(object sender, CommitEventArgs e);
................................................................................
  4190   4269       string destinationName,
  4191   4270       int pages,
  4192   4271       int remainingPages,
  4193   4272       int totalPages,
  4194   4273       bool retry
  4195   4274     );
  4196   4275     #endregion
         4276  +
         4277  +  ///////////////////////////////////////////////////////////////////////////////////////////////
         4278  +
         4279  +  /// <summary>
         4280  +  /// The data associated with a call into the authorizer.
         4281  +  /// </summary>
         4282  +  public class AuthorizerEventArgs : EventArgs
         4283  +  {
         4284  +      /// <summary>
         4285  +      /// The user-defined native data associated with this event.  Currently,
         4286  +      /// this will always contain the value of <see cref="IntPtr.Zero" />.
         4287  +      /// </summary>
         4288  +      public readonly IntPtr UserData;
         4289  +
         4290  +      /// <summary>
         4291  +      /// The action code responsible for the current call into the authorizer.
         4292  +      /// </summary>
         4293  +      public readonly SQLiteAuthorizerActionCode ActionCode;
         4294  +
         4295  +      /// <summary>
         4296  +      /// The first string argument for the current call into the authorizer.
         4297  +      /// The exact value will vary based on the action code, see the
         4298  +      /// <see cref="SQLiteAuthorizerActionCode" /> enumeration for possible
         4299  +      /// values.
         4300  +      /// </summary>
         4301  +      public readonly string Argument1;
         4302  +
         4303  +      /// <summary>
         4304  +      /// The second string argument for the current call into the authorizer.
         4305  +      /// The exact value will vary based on the action code, see the
         4306  +      /// <see cref="SQLiteAuthorizerActionCode" /> enumeration for possible
         4307  +      /// values.
         4308  +      /// </summary>
         4309  +      public readonly string Argument2;
         4310  +
         4311  +      /// <summary>
         4312  +      /// The database name for the current call into the authorizer, if
         4313  +      /// applicable.
         4314  +      /// </summary>
         4315  +      public readonly string Database;
         4316  +
         4317  +      /// <summary>
         4318  +      /// The name of the inner-most trigger or view that is responsible for
         4319  +      /// the access attempt or a null value if this access attempt is directly
         4320  +      /// from top-level SQL code.
         4321  +      /// </summary>
         4322  +      public readonly string Context;
         4323  +
         4324  +      /// <summary>
         4325  +      /// The return code for the current call into the authorizer.
         4326  +      /// </summary>
         4327  +      public SQLiteAuthorizerReturnCode ReturnCode;
         4328  +
         4329  +      ///////////////////////////////////////////////////////////////////////////////////////////
         4330  +
         4331  +      /// <summary>
         4332  +      /// Constructs an instance of this class with default property values.
         4333  +      /// </summary>
         4334  +      private AuthorizerEventArgs()
         4335  +      {
         4336  +          this.UserData = IntPtr.Zero;
         4337  +          this.ActionCode = SQLiteAuthorizerActionCode.None;
         4338  +          this.Argument1 = null;
         4339  +          this.Argument2 = null;
         4340  +          this.Database = null;
         4341  +          this.Context = null;
         4342  +          this.ReturnCode = SQLiteAuthorizerReturnCode.Ok;
         4343  +      }
         4344  +
         4345  +      ///////////////////////////////////////////////////////////////////////////////////////////
         4346  +
         4347  +      /// <summary>
         4348  +      /// Constructs an instance of this class with specific property values.
         4349  +      /// </summary>
         4350  +      /// <param name="pUserData">
         4351  +      /// The user-defined native data associated with this event.
         4352  +      /// </param>
         4353  +      /// <param name="actionCode">
         4354  +      /// The authorizer action code.
         4355  +      /// </param>
         4356  +      /// <param name="argument1">
         4357  +      /// The first authorizer argument.
         4358  +      /// </param>
         4359  +      /// <param name="argument2">
         4360  +      /// The second authorizer argument.
         4361  +      /// </param>
         4362  +      /// <param name="database">
         4363  +      /// The database name, if applicable.
         4364  +      /// </param>
         4365  +      /// <param name="context">
         4366  +      /// The name of the inner-most trigger or view that is responsible for
         4367  +      /// the access attempt or a null value if this access attempt is directly
         4368  +      /// from top-level SQL code.
         4369  +      /// </param>
         4370  +      /// <param name="returnCode">
         4371  +      /// The authorizer return code.
         4372  +      /// </param>
         4373  +      internal AuthorizerEventArgs(
         4374  +          IntPtr pUserData,
         4375  +          SQLiteAuthorizerActionCode actionCode,
         4376  +          string argument1,
         4377  +          string argument2,
         4378  +          string database,
         4379  +          string context,
         4380  +          SQLiteAuthorizerReturnCode returnCode
         4381  +          )
         4382  +          : this()
         4383  +      {
         4384  +          this.UserData = pUserData;
         4385  +          this.ActionCode = actionCode;
         4386  +          this.Argument1 = argument1;
         4387  +          this.Argument2 = argument2;
         4388  +          this.Database = database;
         4389  +          this.Context = context;
         4390  +          this.ReturnCode = returnCode;
         4391  +      }
         4392  +  }
  4197   4393   
  4198   4394     ///////////////////////////////////////////////////////////////////////////////////////////////
  4199   4395   
  4200   4396     /// <summary>
  4201   4397     /// Whenever an update event is triggered on a connection, this enum will indicate
  4202   4398     /// exactly what type of operation is being performed.
  4203   4399     /// </summary>

Changes to System.Data.SQLite/SQLiteConvert.cs.

  1498   1498   
  1499   1499         /// <summary>
  1500   1500         /// Use the default command execution type.  Using this value is the same
  1501   1501         /// as using the <see cref="SQLiteExecuteType.NonQuery" /> value.
  1502   1502         /// </summary>
  1503   1503         Default = NonQuery /* TODO: Good default? */
  1504   1504     }
         1505  +
         1506  +  /// <summary>
         1507  +  /// The action code responsible for the current call into the authorizer.
         1508  +  /// </summary>
         1509  +  public enum SQLiteAuthorizerActionCode
         1510  +  {
         1511  +      /// <summary>
         1512  +      /// No action is being performed.  This value should not be used from
         1513  +      /// external code.
         1514  +      /// </summary>
         1515  +      None = -1,
         1516  +
         1517  +      /// <summary>
         1518  +      /// No longer used.
         1519  +      /// </summary>
         1520  +      Copy = 0,
         1521  +
         1522  +      /// <summary>
         1523  +      /// An index will be created.  The action-specific arguments are the
         1524  +      /// index name and the table name.
         1525  +      /// 
         1526  +      /// </summary>
         1527  +      CreateIndex = 1,
         1528  +
         1529  +      /// <summary>
         1530  +      /// A table will be created.  The action-specific arguments are the
         1531  +      /// table name and a null value.
         1532  +      /// </summary>
         1533  +      CreateTable = 2,
         1534  +
         1535  +      /// <summary>
         1536  +      /// A temporary index will be created.  The action-specific arguments
         1537  +      /// are the index name and the table name.
         1538  +      /// </summary>
         1539  +      CreateTempIndex = 3,
         1540  +
         1541  +      /// <summary>
         1542  +      /// A temporary table will be created.  The action-specific arguments
         1543  +      /// are the table name and a null value.
         1544  +      /// </summary>
         1545  +      CreateTempTable = 4,
         1546  +
         1547  +      /// <summary>
         1548  +      /// A temporary trigger will be created.  The action-specific arguments
         1549  +      /// are the trigger name and the table name.
         1550  +      /// </summary>
         1551  +      CreateTempTrigger = 5,
         1552  +
         1553  +      /// <summary>
         1554  +      /// A temporary view will be created.  The action-specific arguments are
         1555  +      /// the view name and a null value.
         1556  +      /// </summary>
         1557  +      CreateTempView = 6,
         1558  +
         1559  +      /// <summary>
         1560  +      /// A trigger will be created.  The action-specific arguments are the
         1561  +      /// trigger name and the table name.
         1562  +      /// </summary>
         1563  +      CreateTrigger = 7,
         1564  +
         1565  +      /// <summary>
         1566  +      /// A view will be created.  The action-specific arguments are the view
         1567  +      /// name and a null value.
         1568  +      /// </summary>
         1569  +      CreateView = 8,
         1570  +
         1571  +      /// <summary>
         1572  +      /// A DELETE statement will be executed.  The action-specific arguments
         1573  +      /// are the table name and a null value.
         1574  +      /// </summary>
         1575  +      Delete = 9,
         1576  +
         1577  +      /// <summary>
         1578  +      /// An index will be dropped.  The action-specific arguments are the
         1579  +      /// index name and the table name.
         1580  +      /// </summary>
         1581  +      DropIndex = 10,
         1582  +
         1583  +      /// <summary>
         1584  +      /// A table will be dropped.  The action-specific arguments are the tables
         1585  +      /// name and a null value.
         1586  +      /// </summary>
         1587  +      DropTable = 11,
         1588  +
         1589  +      /// <summary>
         1590  +      /// A temporary index will be dropped.  The action-specific arguments are
         1591  +      /// the index name and the table name.
         1592  +      /// </summary>
         1593  +      DropTempIndex = 12,
         1594  +
         1595  +      /// <summary>
         1596  +      /// A temporary table will be dropped.  The action-specific arguments are
         1597  +      /// the table name and a null value.
         1598  +      /// </summary>
         1599  +      DropTempTable = 13,
         1600  +
         1601  +      /// <summary>
         1602  +      /// A temporary trigger will be dropped.  The action-specific arguments
         1603  +      /// are the trigger name and the table name.
         1604  +      /// </summary>
         1605  +      DropTempTrigger = 14,
         1606  +
         1607  +      /// <summary>
         1608  +      /// A temporary view will be dropped.  The action-specific arguments are
         1609  +      /// the view name and a null value.
         1610  +      /// </summary>
         1611  +      DropTempView = 15,
         1612  +
         1613  +      /// <summary>
         1614  +      /// A trigger will be dropped.  The action-specific arguments are the
         1615  +      /// trigger name and the table name.
         1616  +      /// </summary>
         1617  +      DropTrigger = 16,
         1618  +
         1619  +      /// <summary>
         1620  +      /// A view will be dropped.  The action-specific arguments are the view
         1621  +      /// name and a null value.
         1622  +      /// </summary>
         1623  +      DropView = 17,
         1624  +
         1625  +      /// <summary>
         1626  +      /// An INSERT statement will be executed.  The action-specific arguments
         1627  +      /// are the table name and a null value.
         1628  +      /// </summary>
         1629  +      Insert = 18,
         1630  +
         1631  +      /// <summary>
         1632  +      /// A PRAGMA statement will be executed.  The action-specific arguments
         1633  +      /// are the name of the PRAGMA and the new value or a null value.
         1634  +      /// </summary>
         1635  +      Pragma = 19,
         1636  +
         1637  +      /// <summary>
         1638  +      /// A table column will be read.  The action-specific arguments are the
         1639  +      /// table name and the column name.
         1640  +      /// </summary>
         1641  +      Read = 20,
         1642  +
         1643  +      /// <summary>
         1644  +      /// A SELECT statement will be executed.  The action-specific arguments
         1645  +      /// are both null values.
         1646  +      /// </summary>
         1647  +      Select = 21,
         1648  +
         1649  +      /// <summary>
         1650  +      /// A transaction will be started, committed, or rolled back.  The
         1651  +      /// action-specific arguments are the name of the operation (BEGIN,
         1652  +      /// COMMIT, or ROLLBACK) and a null value.
         1653  +      /// </summary>
         1654  +      Transaction = 22,
         1655  +
         1656  +      /// <summary>
         1657  +      /// An UPDATE statement will be executed.  The action-specific arguments
         1658  +      /// are the table name and the column name.
         1659  +      /// </summary>
         1660  +      Update = 23,
         1661  +
         1662  +      /// <summary>
         1663  +      /// A database will be attached to the connection.  The action-specific
         1664  +      /// arguments are the database file name and a null value.
         1665  +      /// </summary>
         1666  +      Attach = 24,
         1667  +
         1668  +      /// <summary>
         1669  +      /// A database will be detached from the connection.  The action-specific
         1670  +      /// arguments are the database name and a null value.
         1671  +      /// </summary>
         1672  +      Detach = 25,
         1673  +
         1674  +      /// <summary>
         1675  +      /// The schema of a table will be altered.  The action-specific arguments
         1676  +      /// are the database name and the table name.
         1677  +      /// </summary>
         1678  +      AlterTable = 26,
         1679  +
         1680  +      /// <summary>
         1681  +      /// An index will be deleted and then recreated.  The action-specific
         1682  +      /// arguments are the index name and a null value.
         1683  +      /// </summary>
         1684  +      Reindex = 27,
         1685  +
         1686  +      /// <summary>
         1687  +      /// A table will be analyzed to gathers statistics about it.  The
         1688  +      /// action-specific arguments are the table name and a null value.
         1689  +      /// </summary>
         1690  +      Analyze = 28,
         1691  +
         1692  +      /// <summary>
         1693  +      /// A virtual table will be created.  The action-specific arguments are
         1694  +      /// the table name and the module name.
         1695  +      /// </summary>
         1696  +      CreateVtable = 29,
         1697  +
         1698  +      /// <summary>
         1699  +      /// A virtual table will be dropped.  The action-specific arguments are
         1700  +      /// the table name and the module name.
         1701  +      /// </summary>
         1702  +      DropVtable = 30,
         1703  +
         1704  +      /// <summary>
         1705  +      /// A SQL function will be called.  The action-specific arguments are a
         1706  +      /// null value and the function name.
         1707  +      /// </summary>
         1708  +      Function = 31,
         1709  +
         1710  +      /// <summary>
         1711  +      /// A savepoint will be created, released, or rolled back.  The
         1712  +      /// action-specific arguments are the name of the operation (BEGIN,
         1713  +      /// RELEASE, or ROLLBACK) and the savepoint name.
         1714  +      /// </summary>
         1715  +      Savepoint = 32
         1716  +  }
         1717  +
         1718  +  /// <summary>
         1719  +  /// The return code for the current call into the authorizer.
         1720  +  /// </summary>
         1721  +  public enum SQLiteAuthorizerReturnCode
         1722  +  {
         1723  +      /// <summary>
         1724  +      /// The action will be allowed.
         1725  +      /// </summary>
         1726  +      Ok = 0,
         1727  +
         1728  +      /// <summary>
         1729  +      /// The overall action will be disallowed and an error message will be
         1730  +      /// returned from the query preparation method.
         1731  +      /// </summary>
         1732  +      Deny = 1,
         1733  +
         1734  +      /// <summary>
         1735  +      /// The specific action will be disallowed; however, the overall action
         1736  +      /// will continue.  The exact effects of this return code vary depending
         1737  +      /// on the specific action, please refer to the SQLite core library
         1738  +      /// documentation for futher details.
         1739  +      /// </summary>
         1740  +      Ignore = 2
         1741  +  }
  1505   1742   
  1506   1743     /// <summary>
  1507   1744     /// Class used internally to determine the datatype of a column in a resultset
  1508   1745     /// </summary>
  1509   1746     internal sealed class SQLiteType
  1510   1747     {
  1511   1748       /// <summary>

Changes to System.Data.SQLite/UnsafeNativeMethods.cs.

  1465   1465       [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
  1466   1466   #else
  1467   1467       [DllImport(SQLITE_DLL)]
  1468   1468   #endif
  1469   1469       internal static extern SQLiteErrorCode sqlite3_rekey(IntPtr db, byte[] key, int keylen);
  1470   1470   #endif
  1471   1471   
         1472  +#if !PLATFORM_COMPACTFRAMEWORK
         1473  +    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
         1474  +#else
         1475  +    [DllImport(SQLITE_DLL)]
         1476  +#endif
         1477  +    internal static extern IntPtr sqlite3_set_authorizer(IntPtr db, SQLiteAuthorizerCallback func, IntPtr pvUser);
         1478  +
  1472   1479   #if !PLATFORM_COMPACTFRAMEWORK
  1473   1480       [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
  1474   1481   #else
  1475   1482       [DllImport(SQLITE_DLL)]
  1476   1483   #endif
  1477   1484       internal static extern IntPtr sqlite3_update_hook(IntPtr db, SQLiteUpdateCallback func, IntPtr pvUser);
  1478   1485   

Added Tests/authorizer.eagle.

            1  +###############################################################################
            2  +#
            3  +# authorizer.eagle --
            4  +#
            5  +# Written by Joe Mistachkin.
            6  +# Released to the public domain, use at your own risk!
            7  +#
            8  +###############################################################################
            9  +
           10  +package require Eagle
           11  +package require Eagle.Library
           12  +package require Eagle.Test
           13  +
           14  +runTestPrologue
           15  +
           16  +###############################################################################
           17  +
           18  +package require System.Data.SQLite.Test
           19  +runSQLiteTestPrologue
           20  +
           21  +###############################################################################
           22  +
           23  +runTest {test authorizer-1.1 {SQLiteConnection Authorize event} -setup {
           24  +  proc onAuthorize { sender e } {
           25  +    #
           26  +    # NOTE: Filter out the "noise" by allowing all standard
           27  +    #       events on the "sqlite_*" tables.
           28  +    #
           29  +    set noiseActionCodes [list \
           30  +        CreateTable CreateIndex Read Insert Update Delete]
           31  +
           32  +    if {[$e ActionCode] in $noiseActionCodes && \
           33  +        [string match "sqlite_*" [$e Argument1]]} then {
           34  +      return
           35  +    }
           36  +
           37  +    lappend ::data [list \
           38  +        [$e UserData] [$e ActionCode] [$e Argument1] \
           39  +        [$e Argument2] [$e Database] [$e Context]]
           40  +
           41  +    if {[$e ActionCode] eq "CreateTable" && \
           42  +        [$e Argument1] eq "tDeny"} then {
           43  +      $e ReturnCode Deny
           44  +    }
           45  +  }
           46  +
           47  +  setupDb [set fileName authorizer-1.1.db]
           48  +} -body {
           49  +  set connection [getDbConnection]
           50  +
           51  +  set callback onAuthorize
           52  +  object invoke $connection add_Authorize $callback
           53  +
           54  +  set results [list]
           55  +
           56  +  set sql [list \
           57  +    CreateTable       {CREATE TABLE t1(x);} \
           58  +    CreateIndex       {CREATE INDEX i1 ON t1(x);} \
           59  +    CreateTrigger     {CREATE TRIGGER tr1 BEFORE INSERT ON t1
           60  +                       BEGIN
           61  +                         SELECT RAISE(IGNORE);
           62  +                       END;} \
           63  +    CreateView        {CREATE VIEW v1 AS SELECT * FROM t1;} \
           64  +    CreateTempTable   {CREATE TEMPORARY TABLE t2(x);} \
           65  +    CreateTempIndex   {CREATE INDEX i2 ON t2(x);} \
           66  +    CreateTempTrigger {CREATE TEMPORARY TRIGGER tr2 BEFORE INSERT ON t2
           67  +                       BEGIN
           68  +                         SELECT RAISE(IGNORE);
           69  +                       END;} \
           70  +    CreateTempView    {CREATE TEMPORARY VIEW v2 AS SELECT * FROM t2;} \
           71  +    Pragma            {PRAGMA journal_mode=WAL;} \
           72  +    Function          {SELECT julianday('now');} \
           73  +    Read              {SELECT x FROM t1;} \
           74  +    Select            {SELECT * FROM t1;} \
           75  +    Insert            {INSERT INTO t1(x) VALUES(1);} \
           76  +    Update            {UPDATE t1 SET x = x - 1;} \
           77  +    Delete            {DELETE FROM t1;} \
           78  +    AlterTable        {ALTER TABLE t1 ADD COLUMN y;} \
           79  +    Reindex           {REINDEX t1;} \
           80  +    Analyze           {ANALYZE t1;} \
           81  +    DropTempView      {DROP VIEW v2;} \
           82  +    DropTempTrigger   {DROP TRIGGER tr2;} \
           83  +    DropTempIndex     {DROP INDEX i2;} \
           84  +    DropTempTable     {DROP TABLE t2;} \
           85  +    DropView          {DROP VIEW v1;} \
           86  +    DropTrigger       {DROP TRIGGER tr1;} \
           87  +    DropIndex         {DROP INDEX i1;} \
           88  +    DropTable         {DROP TABLE t1;} \
           89  +    Transaction       {BEGIN; SELECT 0; COMMIT;} \
           90  +    Savepoint         {SAVEPOINT s1; RELEASE SAVEPOINT s1;} \
           91  +    Attach            {ATTACH DATABASE ':memory:' AS d1;} \
           92  +    Detach            {DETACH DATABASE d1;} \
           93  +    CreateVtable      {CREATE VIRTUAL TABLE t3 USING fts4(x TEXT);} \
           94  +    DropVtable        {DROP TABLE t3;} \
           95  +    CreateTable       {CREATE TABLE tDeny(x);}]
           96  +
           97  +  foreach {name value} $sql {
           98  +    set data [list]; set code [catch {sql execute $db $value} result]
           99  +    set result [lindex [split [string map [list \r\n \n] $result] \n] 0]
          100  +    lappend results [list $name $data $code $result]
          101  +  }
          102  +  lappend results [isTableInDb tDeny]
          103  +
          104  +  set results
          105  +} -cleanup {
          106  +  catch {object invoke $connection remove_Authorize $callback}
          107  +  catch {object removecallback $callback}
          108  +
          109  +  cleanupDb $fileName
          110  +
          111  +  freeDbConnection
          112  +
          113  +  unset -nocomplain data result code value name sql results callback \
          114  +      connection db fileName
          115  +
          116  +  rename onAuthorize ""
          117  +} -constraints \
          118  +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \
          119  +{{CreateTable {{0 CreateTable t1 {} main {}}} 0 0} {CreateIndex {{0 CreateIndex\
          120  +i1 t1 main {}} {0 Reindex i1 {} main {}}} 0 0} {CreateTrigger {{0 CreateTrigger\
          121  +tr1 t1 main {}}} 0 0} {CreateView {{0 CreateView v1 {} main {}}} 0 0}\
          122  +{CreateTempTable {{0 CreateTempTable t2 {} temp {}}} 0 0} {CreateTempIndex {{0\
          123  +CreateTempIndex i2 t2 temp {}} {0 Reindex i2 {} temp {}}} 0 0}\
          124  +{CreateTempTrigger {{0 CreateTempTrigger tr2 t2 temp {}}} 0 0} {CreateTempView\
          125  +{{0 CreateTempView v2 {} temp {}}} 0 0} {Pragma {{0 Pragma journal_mode WAL {}\
          126  +{}}} 0 0} {Function {{0 Select {} {} {} {}} {0 Function {} julianday {} {}}} 0\
          127  +0} {Read {{0 Select {} {} {} {}} {0 Read t1 x main {}}} 0 0} {Select {{0 Select\
          128  +{} {} {} {}} {0 Read t1 x main {}}} 0 0} {Insert {{0 Insert t1 {} main {}} {0\
          129  +Select {} {} {} tr1}} 0 0} {Update {{0 Read t1 x main {}} {0 Update t1 x main\
          130  +{}}} 0 0} {Delete {{0 Delete t1 {} main {}}} 0 0} {AlterTable {{0 AlterTable\
          131  +main t1 {} {}} {0 Function {} substr {} {}} {0 Function {} substr {} {}}} 0 0}\
          132  +{Reindex {{0 Reindex i1 {} main {}}} 0 0} {Analyze {{0 Analyze t1 {} main {}}\
          133  +{0 Select {} {} {} {}} {0 Select {} {} {} {}} {0 Function {} count {} {}} {0\
          134  +Select {} {} {} {}}} 0 0} {DropTempView {{0 DropTempView v2 {} temp {}} {0\
          135  +Delete v2 {} temp {}}} 0 0} {DropTempTrigger {{0 DropTempTrigger tr2 t2 temp\
          136  +{}}} 0 0} {DropTempIndex {{0 DropTempIndex i2 t2 temp {}}} 0 0} {DropTempTable\
          137  +{{0 DropTempTable t2 {} temp {}} {0 Delete t2 {} temp {}}} 0 0} {DropView {{0\
          138  +DropView v1 {} main {}} {0 Delete v1 {} main {}}} 0 0} {DropTrigger {{0\
          139  +DropTrigger tr1 t1 main {}}} 0 0} {DropIndex {{0 DropIndex i1 t1 main {}}} 0 0}\
          140  +{DropTable {{0 DropTable t1 {} main {}} {0 Delete t1 {} main {}}} 0 0}\
          141  +{Transaction {{0 Transaction BEGIN {} {} {}} {0 Select {} {} {} {}} {0\
          142  +Transaction COMMIT {} {} {}}} 0 0} {Savepoint {{0 Savepoint BEGIN s1 {} {}} {0\
          143  +Savepoint RELEASE s1 {} {}}} 0 0} {Attach {{0 Attach :memory: {} {} {}}} 0 0}\
          144  +{Detach {{0 Detach d1 {} {} {}}} 0 0} {CreateVtable {{0 CreateVtable t3 fts4\
          145  +main {}} {0 CreateTable t3_content {} main {}} {0 CreateTable t3_segments {}\
          146  +main {}} {0 CreateTable t3_segdir {} main {}} {0 CreateTable t3_docsize {} main\
          147  +{}} {0 CreateTable t3_stat {} main {}} {0 Pragma page_size {} main {}}} 0 0}\
          148  +{DropVtable {{0 DropVtable t3 fts4 main {}} {0 Delete t3 {} main {}} {0\
          149  +DropTable t3_content {} main {}} {0 Delete t3_content {} main {}} {0 DropTable\
          150  +t3_segments {} main {}} {0 Delete t3_segments {} main {}} {0 DropTable\
          151  +t3_segdir {} main {}} {0 Delete t3_segdir {} main {}} {0 DropTable t3_docsize\
          152  +{} main {}} {0 Delete t3_docsize {} main {}} {0 DropTable t3_stat {} main {}}\
          153  +{0 Delete t3_stat {} main {}}} 0 0} {CreateTable {{0 CreateTable tDeny {} main\
          154  +{}}} 1 {System.Data.SQLite.SQLiteException (0x80004005): authorization denied}}\
          155  +False}}
          156  +
          157  +###############################################################################
          158  +
          159  +runSQLiteTestEpilogue
          160  +runTestEpilogue

Changes to Tests/common.eagle.

   995    995         # NOTE: Execute the SQL query against the sqlite_master table to check if
   996    996         #       the named table is present and return non-zero if it is.
   997    997         #
   998    998         return [expr {[sql execute -execute scalar $db \
   999    999             "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = ?;" \
  1000   1000             [list param1 String $name]] > 0}]
  1001   1001       }
         1002  +
         1003  +    proc trimSql { sql } {
         1004  +      set result [string map [list \r\n " " \r " " \n " "] $sql]
         1005  +
         1006  +      while {[string first "  " $result] != -1} {
         1007  +        set result [string map [list "  " " "] $result]
         1008  +      }
         1009  +
         1010  +      return $result
         1011  +    }
  1002   1012   
  1003   1013       proc executeSql { sql {execute none} {fileName ""} } {
  1004   1014         if {[string length $fileName] == 0} then {set fileName :memory:}
  1005   1015         setupDb $fileName "" "" "" "" "" false false false false memDb
  1006   1016   
  1007   1017         try {
  1008   1018           return [sql execute -execute $execute $memDb $sql]