/// <summary> /// Escapes the given row recursively (child rows are also escaped). /// </summary> /// <remarks> /// After calling this method it is safe to use row and column names directly in SQL. /// </remarks> /// <param name="row">Row to escape recursively.</param> private void EscapeRow(CapDataRow row) { row.Table = EscapeName(row.Table); if (row.Columns.Count > 0) { Dictionary <string, object> escapedColumns = new Dictionary <string, object>(); foreach (KeyValuePair <string, object> column in row.Columns) { escapedColumns[EscapeName(column.Key)] = column.Value; } row.Columns = escapedColumns; } foreach (CapDataRow childRow in row.ChildRows) { EscapeRow(childRow); } }
/// <summary> /// Writes a single data row. /// </summary> /// <remarks> /// This method queues the given row to be written asynchronously. /// </remarks> /// <param name="row">Row to write.</param> public override void WriteRow(CapDataRow row) { while (true) { EnsureWriteAsyncActive(); if (allowEnqueue.Wait(500)) { break; } } lock (backlog) { backlog.Enqueue(row); if (backlog.Count >= MaxBacklog) { allowEnqueue.Reset(); } Monitor.PulseAll(backlog); } }
/// <summary> /// Called internally by the asynchronous row writing thread to recursively insert a row and all its children into the database. /// </summary> /// <param name="parent">Parent row, or null if none.</param> /// <param name="row">Row to insert.</param> /// <param name="rowInfo">Additional row information accumulated during recursion, or null if none.</param> private void WriteRowInternal(CapDataRow parent, CapDataRow row, RowInfo rowInfo) { bool includeRowInfo = (rowInfo != null); if (rowInfo == null && row.Table.Equals("geninfo", StringComparison.OrdinalIgnoreCase)) { string path = Convert.ToString(row.Columns["file"]); long number = Convert.ToInt64(row.Columns["num"]); DateTime timestamp = TSharkTypeParser.ParseDateTime(Convert.ToString(row.Columns["timestamp"])); rowInfo = CreateRowInfo(path, number, timestamp); } if (Filter != null) { if (Filter.FilterTable(row.Table) == DataFilterType.Deny) { foreach (CapDataRow childRow in row.ChildRows) { WriteRowInternal(parent, childRow, rowInfo); } return; } } TableDefinition tableDefinition = GetTableDefinition(row.Table); List <string> columnNames = new List <string>(); List <object> columnValues = new List <object>(); string parentColumnName = null; bool createForeignKey = false; bool createSourceFileForeignKey = false; int generatedColumnCount = 0; int truncated; List <string> truncatedColumns = null; if (includeRowInfo) { createSourceFileForeignKey = !tableDefinition.Columns.ContainsKey("_sourcefileid"); columnNames.Add("_sourcefileid"); columnNames.Add("_number"); columnNames.Add("_timestamp"); ColumnDefinition columnInfo; columnInfo = CreateOrUpdateColumnDefinition(tableDefinition, "_sourcefileid", ColumnType.Integer64Bit, 0); columnValues.Add(ConvertColumnValue(rowInfo.SourceFileID, columnInfo.SqlType, columnInfo.SqlPrecision, out truncated)); columnInfo = CreateOrUpdateColumnDefinition(tableDefinition, "_number", ColumnType.Integer64Bit, 0); columnValues.Add(ConvertColumnValue(rowInfo.Number, columnInfo.SqlType, columnInfo.SqlPrecision, out truncated)); columnInfo = CreateOrUpdateColumnDefinition(tableDefinition, "_timestamp", ColumnType.DateTime, 0); columnValues.Add(ConvertColumnValue(rowInfo.Timestamp, columnInfo.SqlType, columnInfo.SqlPrecision, out truncated)); generatedColumnCount += 3; } if (parent != null) { parentColumnName = string.Format("parent_{0}", parent.Table); createForeignKey = !tableDefinition.Columns.ContainsKey(parentColumnName); ColumnDefinition columnInfo = CreateOrUpdateColumnDefinition(tableDefinition, parentColumnName, ColumnType.Integer64Bit, 0); columnNames.Add(parentColumnName); columnValues.Add(ConvertColumnValue(parent.ID, columnInfo.SqlType, columnInfo.SqlPrecision, out truncated)); generatedColumnCount++; } foreach (KeyValuePair <string, object> column in row.Columns) { bool dropColumn = false; // comment out the next if-block to enable storage of binary data in the database, this can be very storage intensive // binary data is stored in the database as variable length strings and may be arbitrarily truncated to fit if (column.Value is byte[]) { dropColumn = true; } if (Filter != null) { if (Filter.FilterColumn(row.Table, column.Key) == DataFilterType.Deny) { dropColumn = true; } } if (!dropColumn) { ColumnType sqlType; int sqlPrecision; GetSqlTypeAndPrecision(column.Value, out sqlType, out sqlPrecision); ColumnDefinition columnInfo = CreateOrUpdateColumnDefinition(tableDefinition, column.Key, sqlType, sqlPrecision); object convertedColumnValue = ConvertColumnValue(column.Value, columnInfo.SqlType, columnInfo.SqlPrecision, out truncated); if (truncated > 0) { if (truncatedColumns == null) { truncatedColumns = new List <string>(); } truncatedColumns.Add(column.Key); } columnNames.Add(column.Key); columnValues.Add(convertedColumnValue); } } if (!tableDefinition.Committed) { CreateTable(tableDefinition); } if (!disableForeignKeys) { if (createForeignKey) { //Log.WriteInfo("Creating foreign key.\nFrom table: {0}\nTo table: {1}", row.Table, parent.Table); CreateForeignKey(row.Table, parentColumnName, parent.Table); } if (createSourceFileForeignKey) { CreateSourceFileForeignKey(row.Table); } } row.ID = InsertRow(tableDefinition, columnNames, columnValues); if (truncatedColumns != null) { foreach (string truncatedColumn in truncatedColumns) { Log.WriteWarning("Truncated column value.\nTable: {0}\nID: {1}\nColumn: {2}", tableDefinition.Name, row.ID, truncatedColumn); } } foreach (CapDataRow childRow in row.ChildRows) { WriteRowInternal(row, childRow, rowInfo); } }
/// <summary> /// Writes a single data row. /// </summary> /// <param name="row">Row to write.</param> public abstract void WriteRow(CapDataRow row);