⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fastdbfields.cs

📁 最新版本!fastdb是高效的内存数据库系统
💻 CS
📖 第 1 页 / 共 3 页
字号:
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 + -