System.Data.SQLite
Check-in [e9136a6d37]
Not logged in

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

Overview
Comment:Revise field offset handling in the virtual table marshalling code to deal with structure packing on 64-bit operating systems.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e9136a6d37ab2229171d660251752872907ca4f7
User & Date: mistachkin 2013-07-16 02:25:06
Context
2013-07-16
03:27
Modify the release batch tool to directly support the NativeOnlyStatic build configuration. check-in: 16adf7b3b1 user: mistachkin tags: trunk
02:25
Revise field offset handling in the virtual table marshalling code to deal with structure packing on 64-bit operating systems. check-in: e9136a6d37 user: mistachkin tags: trunk
2013-07-15
20:10
Fix marshalling of the sqlite3_index_info.estimatedCost field on 32-bit operating systems. check-in: 1e9d3b0b00 user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

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

1100
1101
1102
1103
1104
1105
1106
1107

1108
1109
1110
1111

1112
1113
1114
1115

1116
1117
1118
1119
1120
1121
1122
....
1192
1193
1194
1195
1196
1197
1198
1199
1200









1201
1202
1203
1204
1205
1206
1207
....
1212
1213
1214
1215
1216
1217
1218
1219

1220
1221
1222
1223
1224

1225
1226
1227
1228
1229

1230
1231
1232
1233
1234
1235
1236
1237

1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
....
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122






4123
4124
4125



4126
4127



4128


















4129









4130
4131
4132
4133
4134
4135
4136
....
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
....
5828
5829
5830
5831
5832
5833
5834
5835







5836
5837
5838
5839
5840
5841
5842
....
6069
6070
6071
6072
6073
6074
6075
6076

6077
6078
6079
6080

6081
6082
6083
6084
6085
6086
6087
            if (pIndex == IntPtr.Zero)
                return;

            int offset = 0;

            int nConstraint = SQLiteMarshal.ReadInt32(pIndex, offset);

            offset += SQLiteMarshal.SizeOfStructInt();


            IntPtr pConstraint = SQLiteMarshal.ReadIntPtr(pIndex, offset);

            offset += IntPtr.Size;


            int nOrderBy = SQLiteMarshal.ReadInt32(pIndex, offset);

            offset += SQLiteMarshal.SizeOfStructInt();


            IntPtr pOrderBy = SQLiteMarshal.ReadIntPtr(pIndex, offset);

            index = new SQLiteIndex(nConstraint, nOrderBy);

            Type indexConstraintType = typeof(
                UnsafeNativeMethods.sqlite3_index_constraint);
................................................................................

            if (nConstraint != index.Inputs.Constraints.Length)
                return;

            if (nConstraint != index.Outputs.ConstraintUsages.Length)
                return;

            offset += SQLiteMarshal.SizeOfStructInt() + IntPtr.Size +
                SQLiteMarshal.SizeOfStructInt() + IntPtr.Size;










            IntPtr pConstraintUsage = SQLiteMarshal.ReadIntPtr(pIndex, offset);

            int sizeOfConstraintUsageType = Marshal.SizeOf(typeof(
                UnsafeNativeMethods.sqlite3_index_constraint_usage));

            for (int iConstraint = 0; iConstraint < nConstraint; iConstraint++)
................................................................................

                Marshal.StructureToPtr(
                    constraintUsage, SQLiteMarshal.IntPtrForOffset(
                    pConstraintUsage, iConstraint * sizeOfConstraintUsageType),
                    false);
            }

            offset += IntPtr.Size;


            SQLiteMarshal.WriteInt32(pIndex, offset,
                index.Outputs.IndexNumber);

            offset += SQLiteMarshal.SizeOfStructInt();


            SQLiteMarshal.WriteIntPtr(pIndex, offset,
                SQLiteString.Utf8IntPtrFromString(index.Outputs.IndexString));

            offset += IntPtr.Size;


            //
            // NOTE: We just allocated the IndexString field; therefore, we
            //       need to set the NeedToFreeIndexString field to non-zero.
            //
            SQLiteMarshal.WriteInt32(pIndex, offset, 1);

            offset += SQLiteMarshal.SizeOfStructInt();


            SQLiteMarshal.WriteInt32(pIndex, offset,
                index.Outputs.OrderByConsumed);

            offset += SQLiteMarshal.SizeOfStructInt();

            if (offset % sizeof(double) != 0)
                offset += SQLiteMarshal.SizeOfStructInt();

            SQLiteMarshal.WriteDouble(pIndex, offset,
                index.Outputs.EstimatedCost);
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////
................................................................................
        {
            return new IntPtr(pointer.ToInt64() + offset);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Determines the size of a <see cref="Int32" /> when it resides
        /// inside of a native structure.
        /// </summary>






        /// <returns>
        /// The size of the <see cref="Int32" /> type, in bytes, when it
        /// resides inside a native structure.



        /// </returns>
        public static int SizeOfStructInt()



        {


















            return IntPtr.Size;









        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Marshal Read Helper Methods
        /// <summary>
................................................................................
                //       sqlite_module structure when running on the .NET
                //       Compact Framework; therefore, just base the size
                //       on what we know:
                //
                //       There is one integer member.
                //       There are 22 function pointer members.
                //
                pNativeModule = SQLiteMemory.Allocate(
                    SQLiteMarshal.SizeOfStructInt() + (22 * IntPtr.Size));

                if (pNativeModule == IntPtr.Zero)
                    throw new OutOfMemoryException("sqlite3_module");
            }

            return pNativeModule;
        }
................................................................................
            {
                // do nothing.
            }

            if (pVtab == IntPtr.Zero)
                return false;

            int offset = IntPtr.Size + SQLiteMarshal.SizeOfStructInt();







            IntPtr pError = SQLiteMarshal.ReadIntPtr(pVtab, offset);

            if (pError != IntPtr.Zero)
            {
                SQLiteMemory.Free(pError); pError = IntPtr.Zero;
                SQLiteMarshal.WriteIntPtr(pVtab, offset, pError);
            }
................................................................................
            if (pVtab == IntPtr.Zero)
                return;

            int offset = 0;

            SQLiteMarshal.WriteIntPtr(pVtab, offset, IntPtr.Zero);

            offset += IntPtr.Size;


            SQLiteMarshal.WriteInt32(pVtab, offset, 0);

            offset += SQLiteMarshal.SizeOfStructInt();


            SQLiteMarshal.WriteIntPtr(pVtab, offset, IntPtr.Zero);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>







|
>



|
>



|
>







 







|
|
>
>
>
>
>
>
>
>
>







 







|
>




|
>




|
>







|
>




|
<
|
<







 







|
<

>
>
>
>
>
>

<
<
>
>
>

|
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>







 







|
<







 







|
>
>
>
>
>
>
>







 







|
>



|
>







1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
....
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
....
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258

1259

1260
1261
1262
1263
1264
1265
1266
....
4127
4128
4129
4130
4131
4132
4133
4134

4135
4136
4137
4138
4139
4140
4141
4142


4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
....
5412
5413
5414
5415
5416
5417
5418
5419

5420
5421
5422
5423
5424
5425
5426
....
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
....
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
            if (pIndex == IntPtr.Zero)
                return;

            int offset = 0;

            int nConstraint = SQLiteMarshal.ReadInt32(pIndex, offset);

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                IntPtr.Size);

            IntPtr pConstraint = SQLiteMarshal.ReadIntPtr(pIndex, offset);

            offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size,
                sizeof(int));

            int nOrderBy = SQLiteMarshal.ReadInt32(pIndex, offset);

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                IntPtr.Size);

            IntPtr pOrderBy = SQLiteMarshal.ReadIntPtr(pIndex, offset);

            index = new SQLiteIndex(nConstraint, nOrderBy);

            Type indexConstraintType = typeof(
                UnsafeNativeMethods.sqlite3_index_constraint);
................................................................................

            if (nConstraint != index.Inputs.Constraints.Length)
                return;

            if (nConstraint != index.Outputs.ConstraintUsages.Length)
                return;

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                IntPtr.Size);

            offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size,
                sizeof(int));

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                IntPtr.Size);

            offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size,
                sizeof(int));

            IntPtr pConstraintUsage = SQLiteMarshal.ReadIntPtr(pIndex, offset);

            int sizeOfConstraintUsageType = Marshal.SizeOf(typeof(
                UnsafeNativeMethods.sqlite3_index_constraint_usage));

            for (int iConstraint = 0; iConstraint < nConstraint; iConstraint++)
................................................................................

                Marshal.StructureToPtr(
                    constraintUsage, SQLiteMarshal.IntPtrForOffset(
                    pConstraintUsage, iConstraint * sizeOfConstraintUsageType),
                    false);
            }

            offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size,
                sizeof(int));

            SQLiteMarshal.WriteInt32(pIndex, offset,
                index.Outputs.IndexNumber);

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                IntPtr.Size);

            SQLiteMarshal.WriteIntPtr(pIndex, offset,
                SQLiteString.Utf8IntPtrFromString(index.Outputs.IndexString));

            offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size,
                sizeof(int));

            //
            // NOTE: We just allocated the IndexString field; therefore, we
            //       need to set the NeedToFreeIndexString field to non-zero.
            //
            SQLiteMarshal.WriteInt32(pIndex, offset, 1);

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                sizeof(int));

            SQLiteMarshal.WriteInt32(pIndex, offset,
                index.Outputs.OrderByConsumed);

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),

                sizeof(double));


            SQLiteMarshal.WriteDouble(pIndex, offset,
                index.Outputs.EstimatedCost);
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////
................................................................................
        {
            return new IntPtr(pointer.ToInt64() + offset);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Rounds up an integer size to the next multiple of the alignment.

        /// </summary>
        /// <param name="size">
        /// The size, in bytes, to be rounded up.
        /// </param>
        /// <param name="alignment">
        /// The required alignment for the return value.
        /// </param>
        /// <returns>


        /// The size, in bytes, rounded up to the next multiple of the
        /// alignment.  This value may end up being the same as the original
        /// size.
        /// </returns>
        public static int RoundUp(
            int size,
            int alignment
            )
        {
            int alignmentMinusOne = alignment - 1;
            return ((size + alignmentMinusOne) & ~alignmentMinusOne);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Determines the offset, in bytes, of the next structure member.
        /// </summary>
        /// <param name="offset">
        /// The offset, in bytes, of the current structure member.
        /// </param>
        /// <param name="size">
        /// The size, in bytes, of the current structure member.
        /// </param>
        /// <param name="alignment">
        /// The alignment, in bytes, of the next structure member.
        /// </param>
        /// <returns>
        /// The offset, in bytes, of the next structure member.
        /// </returns>
        public static int NextOffsetOf(
            int offset,
            int size,
            int alignment
            )
        {
            return RoundUp(offset + size, alignment);
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Marshal Read Helper Methods
        /// <summary>
................................................................................
                //       sqlite_module structure when running on the .NET
                //       Compact Framework; therefore, just base the size
                //       on what we know:
                //
                //       There is one integer member.
                //       There are 22 function pointer members.
                //
                pNativeModule = SQLiteMemory.Allocate(23 * IntPtr.Size);


                if (pNativeModule == IntPtr.Zero)
                    throw new OutOfMemoryException("sqlite3_module");
            }

            return pNativeModule;
        }
................................................................................
            {
                // do nothing.
            }

            if (pVtab == IntPtr.Zero)
                return false;

            int offset = 0;

            offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size,
                sizeof(int));

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                IntPtr.Size);

            IntPtr pError = SQLiteMarshal.ReadIntPtr(pVtab, offset);

            if (pError != IntPtr.Zero)
            {
                SQLiteMemory.Free(pError); pError = IntPtr.Zero;
                SQLiteMarshal.WriteIntPtr(pVtab, offset, pError);
            }
................................................................................
            if (pVtab == IntPtr.Zero)
                return;

            int offset = 0;

            SQLiteMarshal.WriteIntPtr(pVtab, offset, IntPtr.Zero);

            offset = SQLiteMarshal.NextOffsetOf(offset, IntPtr.Size,
                sizeof(int));

            SQLiteMarshal.WriteInt32(pVtab, offset, 0);

            offset = SQLiteMarshal.NextOffsetOf(offset, sizeof(int),
                IntPtr.Size);

            SQLiteMarshal.WriteIntPtr(pVtab, offset, IntPtr.Zero);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>

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

2092
2093
2094
2095
2096
2097
2098


2099
2100
2101
2102
2103
2104
2105
        public int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
        public int orderByConsumed;  /* True if output is already ordered */
        public double estimatedCost; /* Estimated cost of using this index */
    }
#endif
    #endregion
  }



#if PLATFORM_COMPACTFRAMEWORK
  internal abstract class CriticalHandle : IDisposable
  {
    private bool _isClosed;
    protected IntPtr handle;








>
>







2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
        public int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
        public int orderByConsumed;  /* True if output is already ordered */
        public double estimatedCost; /* Estimated cost of using this index */
    }
#endif
    #endregion
  }

  /////////////////////////////////////////////////////////////////////////////

#if PLATFORM_COMPACTFRAMEWORK
  internal abstract class CriticalHandle : IDisposable
  {
    private bool _isClosed;
    protected IntPtr handle;

Changes to Tests/vtab.eagle.

1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
....
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107





































































































1108
1109
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
\{\} 0 \{\{\} t\d+ \{\} x\d+\}$}]}

###############################################################################

runTest {test vtab-1.7 {virtual table xBestIndex marshalling} -setup {
  set fileName vtab-1.7.db
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

  set sql(1) { \
    CREATE TABLE t${id}(y CHAR(10) NOT NULL PRIMARY KEY); \
................................................................................

  unset -nocomplain result code results errors sql dataSource id fileName
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
\{\} 0 \{0 5 two three one 5\.0 4\}$}]}

###############################################################################






































































































runSQLiteTestEpilogue
runTestEpilogue







|







 










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
....
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
\{\} 0 \{\{\} t\d+ \{\} x\d+\}$}]}

###############################################################################

runTest {test vtab-1.7 {virtual table xBestIndex marshalling (1)} -setup {
  set fileName vtab-1.7.db
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

  set sql(1) { \
    CREATE TABLE t${id}(y CHAR(10) NOT NULL PRIMARY KEY); \
................................................................................

  unset -nocomplain result code results errors sql dataSource id fileName
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
\{\} 0 \{0 5 two three one 5\.0 4\}$}]}

###############################################################################

runTest {test vtab-1.8 {virtual table xBestIndex marshalling (2)} -setup {
  set fileName vtab-1.8.db
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

  set sql(1) { \
    CREATE TABLE t${id}(y CHAR(10) NOT NULL PRIMARY KEY); \
    CREATE VIRTUAL TABLE u${id} USING mod${id}; \
  }

  set sql(2) { \
    INSERT INTO t${id} SELECT x FROM u${id}; \
  }

  set sql(3) { \
    SELECT v${id}.y FROM t${id} v${id} LEFT OUTER JOIN \
    u${id} ON u${id}.x = v${id}.y WHERE u${id}.x IS NOT NULL \
    AND u${id}.x BETWEEN 'one' and 'three' ORDER BY u${id}.x ASC, \
    u${id}.x DESC; \
  }

  unset -nocomplain results errors

  set code [compileCSharpWith [subst {
    using System;
    using System.Data.SQLite;
    using Eagle._Containers.Public;

    namespace _Dynamic${id}
    {
      public static class Test${id}
      {
        public static StringList GetList(params string\[\] strings)
        {
          StringList result = new StringList();

          using (SQLiteConnection connection = new SQLiteConnection(
              "Data Source=${dataSource};"))
          {
            connection.Open();

            connection.CreateModule(new SQLiteModuleEnumerable(
              "mod${id}", strings));

            using (SQLiteCommand command = connection.CreateCommand())
            {
              command.CommandText = "[subst ${sql(1)}]";
              result.Add(command.ExecuteNonQuery().ToString());
            }

            using (SQLiteCommand command = connection.CreateCommand())
            {
              command.CommandText = "[subst ${sql(2)}]";
              result.Add(command.ExecuteNonQuery().ToString());
            }

            using (SQLiteCommand command = connection.CreateCommand())
            {
              command.CommandText = "[subst ${sql(3)}]";

              using (SQLiteDataReader dataReader = command.ExecuteReader())
              {
                while (dataReader.Read())
                  result.Add(dataReader\[0\].ToString());
              }
            }

            connection.Close();
          }

          return result;
        }

        ///////////////////////////////////////////////////////////////////////

        public static void Main()
        {
          // do nothing.
        }
      }
    }
  }] true true true results errors [list System.Data.SQLite.dll Eagle.dll]]

  list $code $results \
      [expr {[info exists errors] ? $errors : ""}] \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} GetList one two three 4 5.0
      } result] : [set result ""]}] $result
} -cleanup {
  cleanupDb $fileName

  unset -nocomplain result code results errors sql dataSource id fileName
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
\{\} 0 \{0 5 one three\}$}]}

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue