📄 fastdbfields.cs
字号:
using System;using System.Text;using System.Collections;using System.Runtime.InteropServices;using System.Diagnostics;namespace FastDbNet{ //------------------------------------------------------------------------- /// <summary> /// FastDbBuffer encapsulates a binding between a memory buffer and an /// object used to get/set data in the buffer. /// </summary> public class FastDbBuffer: IDisposable { public static readonly int MIN_CAPACITY = ALIGN(30); internal static int ALIGN(int size) { return size + size % Marshal.SizeOf(typeof(Int64)); } public IntPtr buffer; public string name; public int flags; // cli_field_flags public int bound_to_statement = -1; // Make sure the delegate stays alive while in unmanaged code internal unsafe static CLI.CliColumnGetEx doGetColumn = new CLI.CliColumnGetEx(GetColumn); internal unsafe static CLI.CliColumnSetEx doSetColumn = new CLI.CliColumnSetEx(SetColumn); private bool disposed; public unsafe FastDbBuffer(string name, CLI.FieldType var_type, CLI.FieldFlags idx_flags) { buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(CLI.UnmanagedBuffer))); ((CLI.UnmanagedBuffer*)buffer)->fetch_data = true; ((CLI.UnmanagedBuffer*)buffer)->type = (int)var_type; ((CLI.UnmanagedBuffer*)buffer)->size = CLI.SizeOfCliType[(int)var_type]; ((CLI.UnmanagedBuffer*)buffer)->capacity = 0; ((CLI.UnmanagedBuffer*)buffer)->data = Marshal.AllocCoTaskMem(MIN_CAPACITY); this.name = name; //Marshal.StringToHGlobalAnsi(name); this.flags = (int)idx_flags; disposed = false; } // Use C# destructor syntax for finalization code. // This destructor will run only if the Dispose method does not get called. // It gives the base class the opportunity to finalize. ~FastDbBuffer() { // Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability. Dispose(false); } internal unsafe static IntPtr GetColumn(int var_type, IntPtr var_ptr, ref int len, string column_name, int statement, void* user_data) { CLI.UnmanagedBuffer* buffer = (CLI.UnmanagedBuffer*)user_data; if (CLI.IsArrayType((CLI.FieldType)var_type)) len = buffer->size / CLI.SizeOfCliType[var_type - (int)CLI.FieldType.cli_array_of_oid]; else if (var_type == (int)CLI.FieldType.cli_asciiz || var_type == (int)CLI.FieldType.cli_pasciiz) len = buffer->size-1; else len = buffer->size; return buffer->data; } internal unsafe static IntPtr SetColumn(int var_type, IntPtr var_ptr, int len, string column_name, int statement, IntPtr data_ptr, void* user_data) { CLI.UnmanagedBuffer* buffer = (CLI.UnmanagedBuffer*)user_data; if (var_type == (int)CLI.FieldType.cli_asciiz || var_type == (int)CLI.FieldType.cli_pasciiz) { SetBufferTypeAndSize(buffer, (CLI.FieldType)var_type, len, true); return buffer->data; } else if (CLI.IsArrayType((CLI.FieldType)var_type)) { if (buffer->fetch_data) { SetBufferTypeAndSize(buffer, (CLI.FieldType)var_type, len*CLI.SizeOfCliType[(int)var_type - (int)CLI.FieldType.cli_array_of_oid], true); return buffer->data; } else return IntPtr.Zero; // FastDB won't fetch a field if we return nil } else // sanity check throw new CliError("Unsupported type: "+Enum.GetName(typeof(CLI.FieldType), buffer->type)); } protected unsafe static void SetBufferTypeAndSize(CLI.UnmanagedBuffer* buf, CLI.FieldType NewType, int NewSize, bool TypeCheck) { int n; if (!TypeCheck || CLI.IsArrayType(NewType)) n = NewSize; else if (NewType == CLI.FieldType.cli_asciiz || NewType == CLI.FieldType.cli_pasciiz) n = NewSize+1; else n = CLI.SizeOfCliType[(int)NewType]; if (buf->capacity != 0) { if (n > buf->capacity) { buf->data = Marshal.ReAllocCoTaskMem(buf->data, ALIGN(n)); buf->capacity = n; } } else { if (buf->size != n && n > MIN_CAPACITY) buf->data = Marshal.ReAllocCoTaskMem(buf->data, (n > MIN_CAPACITY) ? ALIGN(n) : MIN_CAPACITY); } buf->size = n; if (buf->type != (int)NewType) buf->type = (int)NewType; } /// <summary> /// Use Assign() method to copy the content of on FastDbBuffer to another. /// </summary> /// <param name="var">is the source FastDbBuffer to be copied from.</param> public unsafe virtual void Assign(FastDbBuffer var) { this.name = var.Name; this.Capacity = var.Capacity; this.bound_to_statement = var.StatementID; this.FetchData = var.FetchData; CopyBufferData(var.Type, var.Size, ((CLI.UnmanagedBuffer*)var.buffer.ToPointer())->data); } internal unsafe void CopyBufferData(CLI.FieldType type, int size, IntPtr data) { SetBufferTypeAndSize((CLI.UnmanagedBuffer*)buffer.ToPointer(), type, size, true); Int64* pend = (Int64*)((byte*)data.ToPointer() + ALIGN(size)); Int64* pfrom = (Int64*)data.ToPointer(); Int64* pto = (Int64*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(); while(pfrom < pend) *pto++ = *pfrom++; // for(int i=0; i < size; i++) // *pto++ = *pfrom++; // Note: buffers are always aligned to 8 bytes, so we can simply copy by // iterating over 8 byte integers. //if (type == CLI.FieldType.cli_asciiz || type == CLI.FieldType.cli_pasciiz) // *pto = (byte)'\0'; } /// <summary> /// Bind() abstract method binds a FastDbBuffer to a FastDb statement obtained by calling /// cli_statement() API function. The descendants are requiered to override this method. /// </summary> /// <param name="StatementID">integer value representing a FastDB statement</param> internal unsafe virtual void Bind(int StatementID) {} // bound_to_statement = StatementID; } /// <summary> /// Unbind() clears the buffer binding to a statement. /// </summary> internal virtual unsafe void UnBind() { bound_to_statement = -1; } // Note: since 0 is a valid statement we initialize this to a negative value /// <summary> /// Returns the name of this field/parameter. /// </summary> public unsafe string Name { get { return name; } } /// <summary> /// Capacity controls internally allocated memory for the buffer. /// By default minimum size of the buffer is 30 bytes, however, if you are /// reading/writing large arrays or string values, you may consider setting /// the Capacity field to a larger value in order to minimize memory reallocations. /// </summary> public unsafe int Capacity { get { return ((CLI.UnmanagedBuffer*)buffer.ToPointer())->capacity; } set { ((CLI.UnmanagedBuffer*)buffer.ToPointer())->capacity = value; } } /// <summary> /// Determines the size in bytes of current value in the buffer. /// </summary> public unsafe int Size { get { return ((CLI.UnmanagedBuffer*)buffer.ToPointer())->size; } } /// <summary> /// Returns the type of the value in the buffer. /// </summary> public unsafe CLI.FieldType Type { get { return (CLI.FieldType)((CLI.UnmanagedBuffer*)buffer.ToPointer())->type; } } /// <summary> /// Contains index flags indicating the types of indexes (hash/T-tree) on this field. /// </summary> public unsafe CLI.FieldFlags Flags { get { return (CLI.FieldFlags)flags; } } /// <summary> /// Internal statement's ID that this buffer is bound to. /// </summary> public unsafe int StatementID { get { return bound_to_statement; } } /// <summary> /// For array fields FetchData controls whether to copy the field's content /// to the buffer when a cursor is moved to another record. By setting this /// value to false, it may increase performance on queries that don't need to use /// the content of the array field. /// </summary> public unsafe bool FetchData { get { return ((CLI.UnmanagedBuffer*)buffer.ToPointer())->fetch_data; } set { ((CLI.UnmanagedBuffer*)buffer.ToPointer())->fetch_data = value; } } public bool asBoolean {get {return (bool)getValue(typeof(bool));} set {setValue(value);}} public Int16 asInt16 {get {return (Int16)getValue(typeof(Int16));} set {setValue(value);}} public int asInteger {get {return (int)getValue(typeof(int));} set {setValue(value);}} public uint asOID {get {return (uint)getValue(typeof(uint));} set {setValue(value);}} public Int64 asInt64 {get {return (Int64)getValue(typeof(Int64));} set {setValue(value);}} public double asDouble {get {return (double)getValue(typeof(double));} set {setValue(value);}} public string asString {get {return (string)getValue(typeof(string));} set {setValue(value);}} protected unsafe virtual Object getValue(Type t) { switch((CLI.FieldType)((CLI.UnmanagedBuffer*)buffer.ToPointer())->type) { case CLI.FieldType.cli_bool: case CLI.FieldType.cli_int1: return Convert.ChangeType(*(sbyte*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(), t); case CLI.FieldType.cli_int2: return Convert.ChangeType(*(short*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(), t); case CLI.FieldType.cli_oid: return Convert.ChangeType(*(uint*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(), t); case CLI.FieldType.cli_int4: return Convert.ChangeType(*(int*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(), t); case CLI.FieldType.cli_int8: return Convert.ChangeType(*(Int64*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(), t); case CLI.FieldType.cli_real4: return Convert.ChangeType(*(Single*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(), t); case CLI.FieldType.cli_datetime: case CLI.FieldType.cli_real8: return Convert.ChangeType(*(double*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer(), t); case CLI.FieldType.cli_asciiz: case CLI.FieldType.cli_pasciiz: return Convert.ChangeType(Marshal.PtrToStringAnsi(((CLI.UnmanagedBuffer*)buffer.ToPointer())->data), t); default: throw new CliError("getValue: Unsupported type!"+Enum.GetName(typeof(CLI.FieldType), ((CLI.UnmanagedBuffer*)buffer.ToPointer())->type)); } } protected unsafe void setValue(Object Value) { switch((CLI.FieldType)((CLI.UnmanagedBuffer*)buffer.ToPointer())->type) { case CLI.FieldType.cli_oid: *(uint*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer() = Convert.ToUInt32(Value); break; case CLI.FieldType.cli_int4: *(int*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer() = Convert.ToInt32(Value); break; case CLI.FieldType.cli_bool: case CLI.FieldType.cli_int1: *(sbyte*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer() = Convert.ToSByte(Value); break; case CLI.FieldType.cli_int2: *(Int16*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer() = Convert.ToInt16(Value); break; case CLI.FieldType.cli_int8: *(Int64*)((CLI.UnmanagedBuffer*)buffer.ToPointer())->data.ToPointer() = Convert.ToInt64(Value);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -