1 module hunt.database.driver.mysql.impl.codec.RowResultDecoder; 2 3 import hunt.database.driver.mysql.impl.codec.CommandCodec; 4 import hunt.database.driver.mysql.impl.codec.ColumnDefinition; 5 import hunt.database.driver.mysql.impl.codec.CommandType; 6 import hunt.database.driver.mysql.impl.codec.DataFormat; 7 import hunt.database.driver.mysql.impl.codec.DataType; 8 import hunt.database.driver.mysql.impl.codec.DataTypeCodec; 9 import hunt.database.driver.mysql.impl.codec.MySQLEncoder; 10 import hunt.database.driver.mysql.impl.codec.MySQLRowDesc; 11 import hunt.database.driver.mysql.impl.codec.Packets; 12 13 import hunt.database.driver.mysql.impl.MySQLCollation; 14 import hunt.database.driver.mysql.impl.MySQLRowImpl; 15 16 import hunt.database.base.Row; 17 import hunt.database.base.impl.RowDecoder; 18 import hunt.database.base.impl.RowSetImpl; 19 20 import hunt.Exceptions; 21 import hunt.Functions; 22 import hunt.logging; 23 import hunt.net.buffer.ByteBuf; 24 import hunt.text.Charset; 25 26 import std.variant; 27 28 29 /** 30 * 31 */ 32 class RowResultDecoder(R) : RowDecoder { 33 private enum int NULL = 0xFB; 34 35 private int _size; 36 private RowSetImpl container; 37 private Row row; 38 private bool singleton; 39 MySQLRowDesc rowDesc; 40 41 this(bool singleton, MySQLRowDesc rowDesc) { 42 this.singleton = singleton; 43 this.rowDesc = rowDesc; 44 } 45 46 int size() { 47 return _size; 48 } 49 50 override 51 void decodeRow(int len, ByteBuf inBuffer) { 52 if (container is null) { 53 container = new RowSetImpl(); 54 } 55 56 if (singleton) { 57 if (row is null) { 58 row = new MySQLRowImpl(rowDesc); 59 } else { 60 row.clear(); 61 } 62 } else { 63 row = new MySQLRowImpl(rowDesc); 64 } 65 66 version(HUNT_DB_DEBUG_MORE) infof("row: %d", _size+1); 67 Row row = new MySQLRowImpl(rowDesc); 68 if (rowDesc.dataFormat() == DataFormat.BINARY) { 69 // BINARY row decoding 70 // 0x00 packet header 71 // null_bitmap 72 int nullBitmapLength = (len + 7 + 2) >> 3; 73 int nullBitmapIdx = 1 + inBuffer.readerIndex(); 74 inBuffer.skipBytes(1 + nullBitmapLength); 75 76 // values 77 for (int c = 0; c < len; c++) { 78 int val = c + 2; 79 int bytePos = val >> 3; 80 int bitPos = val & 7; 81 byte mask = cast(byte) (1 << bitPos); 82 byte nullByte = cast(byte) (inBuffer.getByte(nullBitmapIdx + bytePos) & mask); 83 Variant decoded = null; 84 if (nullByte == 0) { 85 // non-null 86 ColumnDefinition columnDesc = rowDesc.columnDefinitions()[c]; 87 DataType dataType = columnDesc.type(); 88 int collationId = rowDesc.columnDefinitions()[c].characterSet(); 89 Charset charset = (MySQLCollation.valueOfId(collationId).mappedCharsetName()); // Charset.forName 90 int columnDefinitionFlags = columnDesc.flags(); 91 92 version(HUNT_DB_DEBUG_MORE) { 93 tracef(" column[%d]: name=%s, type=%s, flags=%d, charset=%s", 94 c, columnDesc.name(), dataType, columnDefinitionFlags, charset); 95 } 96 97 decoded = DataTypeCodec.decodeBinary(dataType, charset, columnDefinitionFlags, inBuffer); 98 99 version(HUNT_DB_DEBUG_MORE) { 100 tracef(" column[%d]: value=%s", c, decoded.toString()); 101 } 102 } 103 row.addValue(decoded); 104 } 105 } else { 106 // TEXT row decoding 107 for (int c = 0; c < len; c++) { 108 Variant decoded = null; 109 if (inBuffer.getUnsignedByte(inBuffer.readerIndex()) == NULL) { 110 inBuffer.skipBytes(1); 111 } else { 112 ColumnDefinition columnDesc = rowDesc.columnDefinitions()[c]; 113 114 DataType dataType = columnDesc.type(); 115 int columnDefinitionFlags = columnDesc.flags(); 116 int collationId = columnDesc.characterSet(); 117 Charset charset = (MySQLCollation.valueOfId(collationId).mappedCharsetName()); // Charset.forName 118 119 version(HUNT_DB_DEBUG_MORE) { 120 infof(" column[%d]: name=%s, type=%s, flags=%d, charset=%s", 121 c, columnDesc.name(), dataType, columnDefinitionFlags, charset); 122 } 123 124 decoded = DataTypeCodec.decodeText(dataType, charset, columnDefinitionFlags, inBuffer); 125 126 version(HUNT_DB_DEBUG_MORE) { 127 tracef(" colum[%d]: value=%s", c, decoded.toString()); 128 } 129 } 130 row.addValue(decoded); 131 } 132 } 133 container.append(row); 134 _size++; 135 } 136 137 R complete() { 138 if (container is null) { 139 container = new RowSetImpl(); 140 } 141 return container; 142 } 143 144 void reset() { 145 container = null; 146 _size = 0; 147 } 148 } 149