private long GetBytes(int i, long fieldOffset, byte[] buf, int len, NativeStatement _stmt)
        {
            if (GetLength() > BufferLength)//data truncation
            {
                MYSQL_BIND[] newbind = new MYSQL_BIND[1];
                newbind[0] = new MYSQL_BIND();
                var ft = new MYSQL_FIELD();
                ft.Type      = enum_field_types.MYSQL_TYPE_BLOB;
                ft.MaxLength = (uint)len;
                newbind[0].InitForBind(ft, _stmt._nativeConnection);

                sbyte errorCode = _stmt.mysql_stmt_fetch_column(newbind, (uint)i, (uint)fieldOffset);
                if (errorCode != 0)
                {
                    throw new MySqlException(_stmt);
                }

                long result = Math.Min(len, newbind[0].GetLength() - fieldOffset);
                newbind[0].GetBytes(buf, (uint)result);
                newbind[0].Dispose();
                return(result);
            }
            else
            {
                GetBytes(buf, (uint)len);
                return(GetLength());
            }
        }
 /// <summary>
 /// Inits structure for binding.
 /// </summary>
 public void InitForBind(MYSQL_FIELD fieldMetadata, NativeConnection nativeConnection)
 {
     buffer_type = fieldMetadata.Type;
     if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_DATETIME || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_DATE || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_DATETIME2 || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_TIME || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_TIME2 || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_TIMESTAMP || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_TIMESTAMP2 || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_NEWDATE)
     {
         SetBuffer(new byte[Marshal.SizeOf <MYSQL_TIME>()]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_TINY)
     {
         SetBuffer(new byte[sizeof(byte)]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_SHORT || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_YEAR)
     {
         SetBuffer(new byte[sizeof(ushort)]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_INT24 || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_LONG)
     {
         SetBuffer(new byte[sizeof(uint)]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_BIT || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_LONGLONG)
     {
         SetBuffer(new byte[sizeof(ulong)]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_DOUBLE)
     {
         SetBuffer(new byte[sizeof(double)]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_FLOAT)
     {
         SetBuffer(new byte[sizeof(float)]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_JSON || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_TINY_BLOB || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_BLOB || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_LONG_BLOB || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_MEDIUM_BLOB)
     {
         SetBuffer(new byte[1024]);
     }
     else if (fieldMetadata.Type == enum_field_types.MYSQL_TYPE_VARCHAR || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_STRING || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_VAR_STRING || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_DECIMAL || fieldMetadata.Type == enum_field_types.MYSQL_TYPE_NEWDECIMAL)
     {
         // set buffer including ending null
         SetBuffer(new byte[(fieldMetadata.Length + 1) * nativeConnection.mysql_get_character_set_info().mbmaxlen]);
     }
     else
     {
         throw new NotSupportedException();
     }
     length      = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)));
     is_null     = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(sbyte)));
     is_unsigned = (byte)(fieldMetadata.Flags.HasFlag(MySqlFieldFlags.UNSIGNED_FLAG) ? 1 : 0);
     // TODO: not all fields are filled so in many cases it may respond failing
 }
        public object GetValue(int columnIndex, NativeStatement nativeStatement, MYSQL_FIELD fieldMetadata)
        {
            if (GetIsNull())
            {
                return(DBNull.Value);
            }

            switch (buffer_type)
            {
            case enum_field_types.MYSQL_TYPE_NULL:
                return(DBNull.Value);

            case enum_field_types.MYSQL_TYPE_TINY when(fieldMetadata.Flags& MySqlFieldFlags.UNSIGNED_FLAG) == 0 && fieldMetadata.length == 1:
                return(Marshal.ReadByte(buffer) != 0);

            case enum_field_types.MYSQL_TYPE_TINY when(fieldMetadata.Flags& MySqlFieldFlags.UNSIGNED_FLAG) != 0:
                return(Marshal.ReadByte(buffer));

            case enum_field_types.MYSQL_TYPE_TINY:
                return(unchecked ((sbyte)Marshal.ReadByte(buffer)));

            case enum_field_types.MYSQL_TYPE_LONGLONG when is_unsigned != 0:
                return(BitConverter.ToUInt64(BitConverter.GetBytes(Marshal.ReadInt64(buffer)), 0));

            case enum_field_types.MYSQL_TYPE_LONGLONG:
                return(Marshal.ReadInt64(buffer));

            case enum_field_types.MYSQL_TYPE_LONG when is_unsigned != 0:
                return(BitConverter.ToUInt32(BitConverter.GetBytes(Marshal.ReadInt32(buffer)), 0));

            case enum_field_types.MYSQL_TYPE_LONG:
                return(Marshal.ReadInt32(buffer));

            case enum_field_types.MYSQL_TYPE_SHORT when is_unsigned != 0:
                return(BitConverter.ToUInt16(BitConverter.GetBytes(Marshal.ReadInt16(buffer)), 0));

            case enum_field_types.MYSQL_TYPE_SHORT:
                return(Marshal.ReadInt16(buffer));

            case enum_field_types.MYSQL_TYPE_INT24:
            {
                var readInt16 = Marshal.ReadInt16(buffer);
                var readByte  = Marshal.ReadByte(buffer, 2);
                var b         = BitConverter.GetBytes(readInt16).Concat(BitConverter.GetBytes(readByte)).Concat(new byte[] { (byte)(readByte > 127 ? 0xFF : 0) }).ToArray();
                if (is_unsigned != 0)
                {
                    return(BitConverter.ToUInt32(b, 0));
                }
                else
                {
                    return(BitConverter.ToInt32(b, 0));
                }
            }

            case enum_field_types.MYSQL_TYPE_LONG_BLOB:
            case enum_field_types.MYSQL_TYPE_MEDIUM_BLOB:
            case enum_field_types.MYSQL_TYPE_TINY_BLOB:
            case enum_field_types.MYSQL_TYPE_BLOB:
            case enum_field_types.MYSQL_TYPE_JSON:
            {
                var x = GetAllBytes(columnIndex, nativeStatement);
                if (x == null)
                {
                    return(DBNull.Value);
                }

                if ((fieldMetadata.Flags & MySqlFieldFlags.BINARY_FLAG) != 0 && buffer_type != enum_field_types.MYSQL_TYPE_JSON)
                {
                    return(x);
                }

                var encoding = CollationEntries.TryGetEncoding((int)fieldMetadata.charsetnr) ?? Encoding.UTF8;

                return(encoding.GetString(x));
            }

            case enum_field_types.MYSQL_TYPE_DATE:
            case enum_field_types.MYSQL_TYPE_NEWDATE:
            {
                MYSQL_TIME time = (MYSQL_TIME)Marshal.PtrToStructure(buffer, typeof(MYSQL_TIME));
                return(new DateTime((int)time.year, (int)time.month, (int)time.day));
            }

            case enum_field_types.MYSQL_TYPE_TIME:
            case enum_field_types.MYSQL_TYPE_TIME2:
            {
                MYSQL_TIME time = (MYSQL_TIME)Marshal.PtrToStructure(buffer, typeof(MYSQL_TIME));
                time.year  = 1;
                time.month = 1;
                time.day   = 1;

                /*
                 * There is one exception to this rule though if this structure holds time
                 * value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold
                 * bigger values
                 */
                return(new DateTime((int)time.year, (int)time.month, (int)time.day, (int)time.hour % 24, (int)time.minute, (int)time.second, (int)(time.second_part / 1000.0)));
            }

            case enum_field_types.MYSQL_TYPE_DATETIME:
            case enum_field_types.MYSQL_TYPE_DATETIME2:
            case enum_field_types.MYSQL_TYPE_TIMESTAMP:
            case enum_field_types.MYSQL_TYPE_TIMESTAMP2:
            {
                MYSQL_TIME time = (MYSQL_TIME)Marshal.PtrToStructure(buffer, typeof(MYSQL_TIME));

                return(new DateTime((int)time.year, (int)time.month, (int)time.day, (int)time.hour, (int)time.minute, (int)time.second, (int)(time.second_part / 1000.0)));
            }

            case enum_field_types.MYSQL_TYPE_YEAR:
                return(new DateTime(Marshal.ReadInt16(buffer), 1, 1, 0, 0, 0, 0));

            case enum_field_types.MYSQL_TYPE_FLOAT:
                return(BitConverter.ToSingle(BitConverter.GetBytes(Marshal.ReadInt32(buffer)), 0));

            case enum_field_types.MYSQL_TYPE_DOUBLE:
                return(BitConverter.ToDouble(BitConverter.GetBytes(Marshal.ReadInt64(buffer)), 0));

            case enum_field_types.MYSQL_TYPE_BIT:
            {
                //  string string_data = Marshal.PtrToStringAnsi(buffer/*, (int)GetLength()*/);
                var blen = this.buffer_length;
                var len  = this.GetLength();
                //return BitConverter.ToUInt64(BitConverter.GetBytes(Marshal.ReadInt64(buffer)), 0);
                var byteCnt = (7 + fieldMetadata.length) / 8;
                var b       = new byte[sizeof(ulong)];
                Marshal.Copy(buffer, b, 0, (int)byteCnt);
                return(BitConverter.ToUInt64(b, 0));
            }

            case enum_field_types.MYSQL_TYPE_SET:
            case enum_field_types.MYSQL_TYPE_STRING:
            case enum_field_types.MYSQL_TYPE_VARCHAR:
            case enum_field_types.MYSQL_TYPE_VAR_STRING:
            case enum_field_types.MYSQL_TYPE_ENUM:
            {
                string string_data = Marshal.PtrToStringAnsi(buffer, (int)GetLength());

                // if trailing null is added read up to this null
                int index = string_data.IndexOf('\0');
                if (index >= 0)
                {
                    string_data = string_data.Substring(0, index);
                }

                // pad
                if (buffer_type == enum_field_types.MYSQL_TYPE_STRING && string_data.Length < buffer_length && (fieldMetadata.Flags & MySqlFieldFlags.ZEROFILL_FLAG) != 0)
                {
                    string_data = string_data.PadRight((int)buffer_length);
                }

                return(string_data);
            }

            case enum_field_types.MYSQL_TYPE_DECIMAL:
            case enum_field_types.MYSQL_TYPE_NEWDECIMAL:
            {
                string string_data = Marshal.PtrToStringAnsi(buffer, (int)GetLength());
                int    index       = string_data.IndexOf('\0');
                if (index >= 0)
                {
                    string_data = string_data.Substring(0, index);
                }
                return(decimal.Parse(string_data, CultureInfo.InvariantCulture));
            }

            case enum_field_types.MYSQL_TYPE_GEOMETRY:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            throw new NotSupportedException();
            //Type ret;
            //switch (buffer_type)
            //{
            //    case enum_field_types.MYSQL_TYPE_BIT:
            //        ret = typeof(ulong);
            //        break;

            //    default:
            //        Console.WriteLine("Warning MySQLToNetType could not map type: " + buffer_type);
            //        ret = typeof(string);
            //        break;
            //        //case FieldTypes5.MYSQL_TYPE_YEAR: return typeof(long);
            //}

            //Type type = ret;
            //if (type == typeof(string))
            //{
            //    string string_data = Marshal.PtrToStringAnsi(buffer, (int)GetLength());
            //    int index = string_data.IndexOf('\0');
            //    if (index >= 0)
            //        string_data = string_data.Substring(0, index);
            //    if (((enum_field_types)buffer_type) == enum_field_types.MYSQL_TYPE_STRING && string_data.Length < buffer_length)
            //    {
            //        string_data = string_data.PadRight((int)buffer_length);
            //    }

            //    return string_data;
            //}
            //else if (type == typeof(sbyte[]))
            //{
            //    uint len = GetLength();
            //    if (buffer_length < len)
            //        len = buffer_length;
            //    byte[] result = new byte[len];
            //    if (len > 0)
            //    {
            //        Marshal.Copy(buffer, result, 0, (int)len);
            //    }

            //    return result;
            //}
            //else if (type == typeof(MYSQL_TIME))
            //{
            //    MYSQL_TIME time = (MYSQL_TIME)Marshal.PtrToStructure(buffer, typeof(MYSQL_TIME));
            //    try
            //    {
            //        return new DateTime((int)time.year, (int)time.month, (int)time.day, (int)time.hour, (int)time.minute, (int)time.second, (int)(time.second_part / 1000.0));
            //    }
            //    catch
            //    {
            //        return MySQLUtils.MYSQL_NULL_DATE;
            //    }
            //}
            //else
            //{
            //    return Marshal.PtrToStructure(buffer, type);
            //}
        }