1 /* 2 * Copyright (C) 2019, HuntLabs 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 module hunt.database.driver.postgresql.impl.codec.DataTypeCodec; 19 20 import hunt.database.driver.postgresql.impl.codec.DataType; 21 import hunt.database.driver.postgresql.impl.codec.DataTypeDesc; 22 23 import hunt.database.base.Tuple; 24 import hunt.database.base.Numeric; 25 // import hunt.database.driver.postgresql.data.*; 26 // import hunt.database.driver.postgresql.impl.util.UTF8StringEndDetector; 27 // import io.vertx.core.buffer.Buffer; 28 // import io.vertx.core.json.JsonArray; 29 // import io.vertx.core.json.JsonObject; 30 // import io.vertx.core.logging.Logger; 31 // import io.vertx.core.logging.LoggerFactory; 32 33 // import java.io.IOException; 34 // 35 // import java.time.*; 36 // import java.time.format.DateTimeFormatterBuilder; 37 // import java.time.temporal.ChronoField; 38 // import java.time.temporal.ChronoUnit; 39 // import java.util.ArrayList; 40 // import hunt.collection.Arrays; 41 // import hunt.collection.List; 42 // import java.util.UUID; 43 // import java.util.function.IntFunction; 44 // import java.util.stream.Collectors; 45 46 // import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; 47 // import static java.time.format.DateTimeFormatter.ISO_LOCAL_TIME; 48 // import static java.util.concurrent.TimeUnit.*; 49 50 import hunt.Byte; 51 import hunt.Exceptions; 52 import hunt.logging; 53 import hunt.net.buffer.ByteBuf; 54 import hunt.net.buffer.Unpooled; 55 import hunt.net.Exceptions; 56 import hunt.String; 57 import hunt.text.Charset; 58 59 import std.algorithm; 60 import std.array; 61 import std.ascii; 62 import std.concurrency : initOnce; 63 import std.conv; 64 import std.variant; 65 66 /** 67 * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> 68 * @author <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a> 69 */ 70 class DataTypeCodec { 71 72 // private static final String[] empty_string_array = new String[0]; 73 // private static final LocalDate[] empty_local_date_array = new LocalDate[0]; 74 // private static final LocalTime[] empty_local_time_array = new LocalTime[0]; 75 // private static final OffsetTime[] empty_offset_time_array = new OffsetTime[0]; 76 // private static final LocalDateTime[] empty_local_date_time_array = new LocalDateTime[0]; 77 // private static final OffsetDateTime[] empty_offset_date_time_array = new OffsetDateTime[0]; 78 // private static final Buffer[] empty_buffer_array = new Buffer[0]; 79 // private static final UUID[] empty_uuid_array = new UUID[0]; 80 // private static final Object[] empty_json_array = new Object[0]; 81 // private static final Numeric[] empty_numeric_array = new Numeric[0]; 82 // private static final Point[] empty_point_array = new Point[0]; 83 // private static final Line[] empty_line_array = new Line[0]; 84 // private static final LineSegment[] empty_lseg_array = new LineSegment[0]; 85 // private static final Box[] empty_box_array = new Box[0]; 86 // private static final Path[] empty_path_array = new Path[0]; 87 // private static final Polygon[] empty_polygon_array = new Polygon[0]; 88 // private static final Circle[] empty_circle_array = new Circle[0]; 89 // private static final Interval[] empty_interval_array = new Interval[0]; 90 // private static final bool[] empty_boolean_array = new bool[0]; 91 // private static final Integer[] empty_integer_array = new Integer[0]; 92 // private static final Short[] empty_short_array = new Short[0]; 93 // private static final Long[] empty_long_array = new Long[0]; 94 // private static final Float[] empty_float_array = new Float[0]; 95 // private static final Double[] empty_double_array = new Double[0]; 96 // private static final LocalDate LOCAL_DATE_EPOCH = LocalDate.of(2000, 1, 1); 97 // private static final LocalDateTime LOCAL_DATE_TIME_EPOCH = LocalDateTime.of(2000, 1, 1, 0, 0, 0); 98 // private static final OffsetDateTime OFFSET_DATE_TIME_EPOCH = LocalDateTime.of(2000, 1, 1, 0, 0, 0).atOffset(ZoneOffset.UTC); 99 100 // Sentinel used when an object is refused by the data type 101 static Object REFUSED_SENTINEL() { 102 __gshared Object inst; 103 return initOnce!inst(new Object()); 104 } 105 106 // private static final IntFunction!(bool[]) BOOLEAN_ARRAY_FACTORY = size -> size == 0 ? empty_boolean_array : new bool[size]; 107 // private static final IntFunction!(Short[]) SHORT_ARRAY_FACTORY = size -> size == 0 ? empty_short_array : new Short[size]; 108 // private static final IntFunction!(Integer[]) INTEGER_ARRAY_FACTORY = size -> size == 0 ? empty_integer_array : new Integer[size]; 109 // private static final IntFunction!(Long[]) LONG_ARRAY_FACTORY = size -> size == 0 ? empty_long_array : new Long[size]; 110 // private static final IntFunction!(Float[]) FLOAT_ARRAY_FACTORY = size -> size == 0 ? empty_float_array : new Float[size]; 111 // private static final IntFunction!(Double[]) DOUBLE_ARRAY_FACTORY = size -> size == 0 ? empty_double_array : new Double[size]; 112 // private static final IntFunction!(String[]) STRING_ARRAY_FACTORY = size -> size == 0 ? empty_string_array : new String[size]; 113 // private static final IntFunction!(LocalDate[]) LOCALDATE_ARRAY_FACTORY = size -> size == 0 ? empty_local_date_array : new LocalDate[size]; 114 // private static final IntFunction!(LocalTime[]) LOCALTIME_ARRAY_FACTORY = size -> size == 0 ? empty_local_time_array : new LocalTime[size]; 115 // private static final IntFunction!(OffsetTime[]) OFFSETTIME_ARRAY_FACTORY = size -> size == 0 ? empty_offset_time_array : new OffsetTime[size]; 116 // private static final IntFunction!(LocalDateTime[]) LOCALDATETIME_ARRAY_FACTORY = size -> size == 0 ? empty_local_date_time_array : new LocalDateTime[size]; 117 // private static final IntFunction!(OffsetDateTime[]) OFFSETDATETIME_ARRAY_FACTORY = size -> size == 0 ? empty_offset_date_time_array : new OffsetDateTime[size]; 118 // private static final IntFunction!(Buffer[]) BUFFER_ARRAY_FACTORY =size -> size == 0 ? empty_buffer_array : new Buffer[size]; 119 // private static final IntFunction!(UUID[]) UUID_ARRAY_FACTORY = size -> size == 0 ? empty_uuid_array : new UUID[size]; 120 // private static final IntFunction!(Object[]) JSON_ARRAY_FACTORY = size -> size == 0 ? empty_json_array : new Object[size]; 121 // private static final IntFunction!(Numeric[]) NUMERIC_ARRAY_FACTORY = size -> size == 0 ? empty_numeric_array : new Numeric[size]; 122 // private static final IntFunction!(Point[]) POINT_ARRAY_FACTORY = size -> size == 0 ? empty_point_array : new Point[size]; 123 // private static final IntFunction!(Line[]) LINE_ARRAY_FACTORY = size -> size == 0 ? empty_line_array : new Line[size]; 124 // private static final IntFunction!(LineSegment[]) LSEG_ARRAY_FACTORY = size -> size == 0 ? empty_lseg_array : new LineSegment[size]; 125 // private static final IntFunction!(Box[]) BOX_ARRAY_FACTORY = size -> size == 0 ? empty_box_array : new Box[size]; 126 // private static final IntFunction!(Path[]) PATH_ARRAY_FACTORY = size -> size == 0 ? empty_path_array : new Path[size]; 127 // private static final IntFunction!(Polygon[]) POLYGON_ARRAY_FACTORY = size -> size == 0 ? empty_polygon_array : new Polygon[size]; 128 // private static final IntFunction!(Circle[]) CIRCLE_ARRAY_FACTORY = size -> size == 0 ? empty_circle_array : new Circle[size]; 129 // private static final IntFunction!(Interval[]) INTERVAL_ARRAY_FACTORY = size -> size == 0 ? empty_interval_array : new Interval[size]; 130 131 // private static final java.time.format.DateTimeFormatter TIMETZ_FORMAT = new DateTimeFormatterBuilder() 132 // .parseCaseInsensitive() 133 // .append(ISO_LOCAL_TIME) 134 // .appendOffset("+HH:mm", "00:00") 135 // .toFormatter(); 136 137 // private static final java.time.format.DateTimeFormatter TIMESTAMP_FORMAT = new DateTimeFormatterBuilder() 138 // .parseCaseInsensitive() 139 // .append(ISO_LOCAL_DATE) 140 // .appendLiteral(' ') 141 // .append(ISO_LOCAL_TIME) 142 // .toFormatter(); 143 144 // private static final java.time.format.DateTimeFormatter TIMESTAMPTZ_FORMAT = new DateTimeFormatterBuilder() 145 // .append(TIMESTAMP_FORMAT) 146 // .appendOffset("+HH:mm", "00:00") 147 // .toFormatter(); 148 149 static void encodeText(DataType id, ref Variant value, ByteBuf buff) { 150 int index = buff.writerIndex(); 151 buff.writeInt(0); 152 textEncode(id, value, buff); 153 buff.setInt(index, buff.writerIndex() - index - 4); 154 } 155 156 private static void textEncode(DataType id, ref Variant value, ByteBuf buff) { 157 switch (id) { 158 case DataType.NUMERIC: 159 textEncodeNUMERIC(value, buff); 160 break; 161 case DataType.NUMERIC_ARRAY: 162 textEncodeNUMERIC_ARRAY(value, buff); 163 break; 164 case DataType.UNKNOWN: 165 //default to treating unknown as a string 166 buff.writeCharSequence(value.toString(), StandardCharsets.UTF_8); 167 break; 168 default: 169 warningf("Data type %s(%d) does not support text encoding", id, cast(int)id); 170 buff.writeCharSequence(value.toString(), StandardCharsets.UTF_8); 171 break; 172 } 173 } 174 175 static void encodeBinary(DataType id, ref Variant value, ByteBuf buff) { 176 switch (id) { 177 case DataType.BOOL: 178 binaryEncodeBOOL(value, buff); 179 break; 180 case DataType.BOOL_ARRAY: 181 binaryEncodeArray!(bool)(value, DataType.BOOL, buff); 182 break; 183 case DataType.INT2: 184 binaryEncodeINT2(value, buff); 185 break; 186 case DataType.INT2_ARRAY: 187 binaryEncodeArray!(short)(value, DataType.INT2, buff); 188 break; 189 case DataType.INT4: 190 binaryEncodeINT4(value, buff); 191 break; 192 case DataType.INT4_ARRAY: 193 binaryEncodeArray!(int)(value, DataType.INT4, buff); 194 break; 195 case DataType.INT8: 196 binaryEncodeINT8(value, buff); 197 break; 198 case DataType.INT8_ARRAY: 199 binaryEncodeArray!(long)(value, DataType.INT8, buff); 200 break; 201 case DataType.FLOAT4: 202 binaryEncodeFLOAT4(value, buff); 203 break; 204 case DataType.FLOAT4_ARRAY: 205 binaryEncodeArray!(float)(value, DataType.FLOAT4, buff); 206 break; 207 case DataType.FLOAT8: 208 binaryEncodeFLOAT8(value, buff); 209 break; 210 case DataType.FLOAT8_ARRAY: 211 binaryEncodeArray!(double)(value, DataType.FLOAT8, buff); 212 break; 213 case DataType.CHAR: 214 binaryEncodeCHAR(value, buff); 215 break; 216 case DataType.CHAR_ARRAY: 217 binaryEncodeArray!(string)(value, DataType.CHAR, buff); 218 break; 219 case DataType.VARCHAR: 220 binaryEncodeVARCHAR(value, buff); 221 break; 222 case DataType.VARCHAR_ARRAY: 223 binaryEncodeArray!(string)(value, DataType.VARCHAR, buff); 224 break; 225 case DataType.BPCHAR: 226 binaryEncodeBPCHAR(value, buff); 227 break; 228 case DataType.BPCHAR_ARRAY: 229 binaryEncodeArray!(string)(value, DataType.BPCHAR, buff); 230 break; 231 case DataType.TEXT: 232 binaryEncodeTEXT(value, buff); 233 break; 234 case DataType.TEXT_ARRAY: 235 binaryEncodeArray!(string)(value, DataType.TEXT, buff); 236 break; 237 case DataType.NAME: 238 binaryEncodeNAME(value, buff); 239 break; 240 case DataType.NAME_ARRAY: 241 binaryEncodeArray!(string)(value, DataType.NAME, buff); 242 break; 243 // case DataType.DATE: 244 // binaryEncodeDATE((LocalDate) value, buff); 245 // break; 246 // case DataType.DATE_ARRAY: 247 // binaryEncodeArray((LocalDate[]) value, DataType.DATE, buff); 248 // break; 249 // case DataType.TIME: 250 // binaryEncodeTIME((LocalTime) value, buff); 251 // break; 252 // case DataType.TIME_ARRAY: 253 // binaryEncodeArray((LocalTime[]) value, DataType.TIME, buff); 254 // break; 255 // case DataType.TIMETZ: 256 // binaryEncodeTIMETZ((OffsetTime) value, buff); 257 // break; 258 // case DataType.TIMETZ_ARRAY: 259 // binaryEncodeArray((OffsetTime[]) value, DataType.TIMETZ, buff); 260 // break; 261 // case DataType.TIMESTAMP: 262 // binaryEncodeTIMESTAMP((LocalDateTime) value, buff); 263 // break; 264 // case DataType.TIMESTAMP_ARRAY: 265 // binaryEncodeArray((LocalDateTime[]) value, DataType.TIMESTAMP, buff); 266 // break; 267 // case DataType.TIMESTAMPTZ: 268 // binaryEncodeTIMESTAMPTZ((OffsetDateTime) value, buff); 269 // break; 270 // case DataType.TIMESTAMPTZ_ARRAY: 271 // binaryEncodeArray((OffsetDateTime[]) value, DataType.TIMESTAMPTZ, buff); 272 // break; 273 case DataType.BYTEA: 274 binaryEncodeBYTEA(value, buff); 275 break; 276 case DataType.BYTEA_ARRAY: 277 binaryEncodeArray!(byte)(value, DataType.BYTEA, buff); 278 break; 279 // case DataType.UUID: 280 // binaryEncodeUUID((UUID) value, buff); 281 // break; 282 // case DataType.UUID_ARRAY: 283 // binaryEncodeArray((UUID[]) value, DataType.UUID, buff); 284 // break; 285 // case DataType.JSON: 286 // binaryEncodeJSON((Object) value, buff); 287 // break; 288 // case DataType.JSON_ARRAY: 289 // binaryEncodeArray((Object[]) value, DataType.JSON, buff); 290 // break; 291 // case DataType.JSONB: 292 // binaryEncodeJSONB((Object) value, buff); 293 // break; 294 // case DataType.JSONB_ARRAY: 295 // binaryEncodeArray((Object[]) value, DataType.JSONB, buff); 296 // break; 297 // case DataType.POINT: 298 // binaryEncodePoint((Point) value, buff); 299 // break; 300 // case DataType.POINT_ARRAY: 301 // binaryEncodeArray((Point[]) value, DataType.POINT, buff); 302 // break; 303 // case DataType.LINE: 304 // binaryEncodeLine((Line) value, buff); 305 // break; 306 // case DataType.LINE_ARRAY: 307 // binaryEncodeArray((Line[]) value, DataType.LINE, buff); 308 // break; 309 // case DataType.LSEG: 310 // binaryEncodeLseg((LineSegment) value, buff); 311 // break; 312 // case DataType.LSEG_ARRAY: 313 // binaryEncodeArray((LineSegment[]) value, DataType.LSEG, buff); 314 // break; 315 // case DataType.BOX: 316 // binaryEncodeBox((Box) value, buff); 317 // break; 318 // case DataType.BOX_ARRAY: 319 // binaryEncodeArray((Box[]) value, DataType.BOX, buff); 320 // break; 321 // case DataType.PATH: 322 // binaryEncodePath((Path) value, buff); 323 // break; 324 // case DataType.PATH_ARRAY: 325 // binaryEncodeArray((Path[]) value, DataType.PATH, buff); 326 // break; 327 // case DataType.POLYGON: 328 // binaryEncodePolygon((Polygon) value, buff); 329 // break; 330 // case DataType.POLYGON_ARRAY: 331 // binaryEncodeArray((Polygon[]) value, DataType.POLYGON, buff); 332 // break; 333 // case DataType.CIRCLE: 334 // binaryEncodeCircle((Circle) value, buff); 335 // break; 336 // case DataType.CIRCLE_ARRAY: 337 // binaryEncodeArray((Circle[]) value, DataType.CIRCLE, buff); 338 // break; 339 // case DataType.INTERVAL: 340 // binaryEncodeINTERVAL((Interval) value, buff); 341 // break; 342 // case DataType.INTERVAL_ARRAY: 343 // binaryEncodeArray((Interval[]) value, DataType.INTERVAL, buff); 344 // break; 345 default: 346 warningf("Data type %s(%d) does not support binary encoding", id, cast(int)id); 347 defaultEncodeBinary(value, buff); 348 break; 349 } 350 } 351 352 // static Variant decodeBinary(DataType id, int index, int len, ByteBuf buff) { 353 // byte[] buffer = new byte[len]; 354 // buff.getBytes(index, buffer); 355 356 // tracef("DataType: %d, data: %(%02X %)", id, buffer); 357 // implementationMissing(false); 358 359 // return new Bytes(buffer); 360 // } 361 362 static Variant decodeBinary(DataType id, int index, int len, ByteBuf buff) { 363 switch (id) { 364 case DataType.BOOL: 365 return binaryDecodeBOOL(index, len, buff).Variant(); 366 // case DataType.BOOL_ARRAY: 367 // return binaryDecodeArray(BOOLEAN_ARRAY_FACTORY, DataType.BOOL, index, len, buff).Variant(); 368 case DataType.INT2: 369 return binaryDecodeINT2(index, len, buff).Variant(); 370 // case DataType.INT2_ARRAY: 371 // return binaryDecodeArray(SHORT_ARRAY_FACTORY, DataType.INT2, index, len, buff).Variant(); 372 case DataType.INT4: 373 return binaryDecodeINT4(index, len, buff).Variant(); 374 // case DataType.INT4_ARRAY: 375 // return binaryDecodeArray(INTEGER_ARRAY_FACTORY, DataType.INT4, index, len, buff).Variant(); 376 case DataType.INT8: 377 return binaryDecodeINT8(index, len, buff).Variant(); 378 // case DataType.INT8_ARRAY: 379 // return binaryDecodeArray(LONG_ARRAY_FACTORY, DataType.INT8, index, len, buff).Variant(); 380 case DataType.FLOAT4: 381 return binaryDecodeFLOAT4(index, len, buff).Variant(); 382 // case DataType.FLOAT4_ARRAY: 383 // return binaryDecodeArray(FLOAT_ARRAY_FACTORY, DataType.FLOAT4, index, len, buff).Variant(); 384 case DataType.FLOAT8: 385 return binaryDecodeFLOAT8(index, len, buff).Variant(); 386 // case DataType.FLOAT8_ARRAY: 387 // return binaryDecodeArray(DOUBLE_ARRAY_FACTORY, DataType.FLOAT8, index, len, buff).Variant(); 388 case DataType.CHAR: 389 return binaryDecodeCHAR(index, len, buff).Variant(); 390 // case DataType.CHAR_ARRAY: 391 // return binaryDecodeArray(STRING_ARRAY_FACTORY, DataType.CHAR, index, len, buff).Variant(); 392 case DataType.VARCHAR: 393 return binaryDecodeVARCHAR(index, len, buff).Variant(); 394 // case DataType.VARCHAR_ARRAY: 395 // return binaryDecodeArray(STRING_ARRAY_FACTORY, DataType.VARCHAR, index, len, buff).Variant(); 396 case DataType.BPCHAR: 397 return binaryDecodeBPCHAR(index, len, buff).Variant(); 398 // case DataType.BPCHAR_ARRAY: 399 // return binaryDecodeArray(STRING_ARRAY_FACTORY, DataType.BPCHAR, index, len, buff).Variant(); 400 case DataType.TEXT: 401 return binaryDecodeTEXT(index, len, buff).Variant(); 402 // case DataType.TEXT_ARRAY: 403 // return binaryDecodeArray(STRING_ARRAY_FACTORY, DataType.TEXT, index, len, buff).Variant(); 404 case DataType.NAME: 405 return binaryDecodeNAME(index, len, buff).Variant(); 406 // case DataType.NAME_ARRAY: 407 // return binaryDecodeArray(STRING_ARRAY_FACTORY, DataType.NAME, index, len, buff).Variant(); 408 // case DataType.DATE: 409 // return binaryDecodeDATE(index, len, buff).Variant(); 410 // case DataType.DATE_ARRAY: 411 // return binaryDecodeArray(LOCALDATE_ARRAY_FACTORY, DataType.DATE, index, len, buff).Variant(); 412 // case DataType.TIME: 413 // return binaryDecodeTIME(index, len, buff).Variant(); 414 // case DataType.TIME_ARRAY: 415 // return binaryDecodeArray(LOCALTIME_ARRAY_FACTORY, DataType.TIME, index, len, buff).Variant(); 416 // case DataType.TIMETZ: 417 // return binaryDecodeTIMETZ(index, len, buff).Variant(); 418 // case DataType.TIMETZ_ARRAY: 419 // return binaryDecodeArray(OFFSETTIME_ARRAY_FACTORY, DataType.TIMETZ, index, len, buff).Variant(); 420 // case DataType.TIMESTAMP: 421 // return binaryDecodeTIMESTAMP(index, len, buff).Variant(); 422 // case DataType.TIMESTAMP_ARRAY: 423 // return binaryDecodeArray(LOCALDATETIME_ARRAY_FACTORY, DataType.TIMESTAMP, index, len, buff).Variant(); 424 // case DataType.TIMESTAMPTZ: 425 // return binaryDecodeTIMESTAMPTZ(index, len, buff).Variant(); 426 // case DataType.TIMESTAMPTZ_ARRAY: 427 // return binaryDecodeArray(OFFSETDATETIME_ARRAY_FACTORY, DataType.TIMESTAMPTZ, index, len, buff).Variant(); 428 case DataType.BYTEA: 429 return binaryDecodeBYTEA(index, len, buff).Variant(); 430 // case DataType.BYTEA_ARRAY: 431 // return binaryDecodeArray(BUFFER_ARRAY_FACTORY, DataType.BYTEA, index, len, buff).Variant(); 432 // case DataType.UUID: 433 // return binaryDecodeUUID(index, len, buff).Variant(); 434 // case DataType.UUID_ARRAY: 435 // return binaryDecodeArray(UUID_ARRAY_FACTORY, DataType.UUID, index, len, buff).Variant(); 436 // case DataType.JSON: 437 // return binaryDecodeJSON(index, len, buff).Variant(); 438 // case DataType.JSON_ARRAY: 439 // return binaryDecodeArray(JSON_ARRAY_FACTORY, DataType.JSON, index, len, buff).Variant(); 440 // case DataType.JSONB: 441 // return binaryDecodeJSONB(index, len, buff).Variant(); 442 // case DataType.JSONB_ARRAY: 443 // return binaryDecodeArray(JSON_ARRAY_FACTORY, DataType.JSONB, index, len, buff).Variant(); 444 // case DataType.POINT: 445 // return binaryDecodePoint(index, len, buff).Variant(); 446 // case DataType.POINT_ARRAY: 447 // return binaryDecodeArray(POINT_ARRAY_FACTORY, DataType.POINT, index, len, buff).Variant(); 448 // case DataType.LINE: 449 // return binaryDecodeLine(index, len, buff).Variant(); 450 // case DataType.LINE_ARRAY: 451 // return binaryDecodeArray(LINE_ARRAY_FACTORY, DataType.LINE, index, len, buff).Variant(); 452 // case DataType.LSEG: 453 // return binaryDecodeLseg(index, len, buff).Variant(); 454 // case DataType.LSEG_ARRAY: 455 // return binaryDecodeArray(LSEG_ARRAY_FACTORY, DataType.LSEG, index, len, buff).Variant(); 456 // case DataType.BOX: 457 // return binaryDecodeBox(index, len, buff).Variant(); 458 // case DataType.BOX_ARRAY: 459 // return binaryDecodeArray(BOX_ARRAY_FACTORY, DataType.BOX, index, len, buff).Variant(); 460 // case DataType.PATH: 461 // return binaryDecodePath(index, len, buff).Variant(); 462 // case DataType.PATH_ARRAY: 463 // return binaryDecodeArray(PATH_ARRAY_FACTORY, DataType.PATH, index, len, buff).Variant(); 464 // case DataType.POLYGON: 465 // return binaryDecodePolygon(index, len, buff).Variant(); 466 // case DataType.POLYGON_ARRAY: 467 // return binaryDecodeArray(POLYGON_ARRAY_FACTORY, DataType.POLYGON, index, len, buff).Variant(); 468 // case DataType.CIRCLE: 469 // return binaryDecodeCircle(index, len, buff).Variant(); 470 // case DataType.CIRCLE_ARRAY: 471 // return binaryDecodeArray(CIRCLE_ARRAY_FACTORY, DataType.CIRCLE, index, len, buff).Variant(); 472 // case DataType.INTERVAL: 473 // return binaryDecodeINTERVAL(index, len, buff).Variant(); 474 // case DataType.INTERVAL_ARRAY: 475 // return binaryDecodeArray(INTERVAL_ARRAY_FACTORY, DataType.INTERVAL, index, len, buff).Variant(); 476 default: 477 warningf("Data type %s(%d) does not support binary decoding", id, id); 478 return Variant(null); 479 // return defaultDecodeBinary(index, len, buff); 480 } 481 } 482 483 static Variant decodeText(DataType id, int index, int len, ByteBuf buff) { 484 switch (id) { 485 case DataType.BOOL: 486 return textDecodeBOOL(index, len, buff).Variant(); 487 // case DataType.BOOL_ARRAY: 488 // return textDecodeArray(BOOLEAN_ARRAY_FACTORY, DataType.BOOL, index, len, buff).Variant(); 489 case DataType.INT2: 490 return textDecodeINT2(index, len, buff).Variant(); 491 // case DataType.INT2_ARRAY: 492 // return textDecodeArray(SHORT_ARRAY_FACTORY, DataType.INT2, index, len, buff).Variant(); 493 case DataType.INT4: 494 return textDecodeINT4(index, len, buff).Variant(); 495 // case DataType.INT4_ARRAY: 496 // return textDecodeArray(INTEGER_ARRAY_FACTORY, DataType.INT4, index, len, buff).Variant(); 497 case DataType.INT8: 498 return textDecodeINT8(index, len, buff).Variant(); 499 // case DataType.INT8_ARRAY: 500 // return textDecodeArray(LONG_ARRAY_FACTORY, DataType.INT8, index, len, buff).Variant(); 501 case DataType.FLOAT4: 502 return textDecodeFLOAT4(index, len, buff).Variant(); 503 // case DataType.FLOAT4_ARRAY: 504 // return textDecodeArray(FLOAT_ARRAY_FACTORY, DataType.FLOAT4, index, len, buff).Variant(); 505 case DataType.FLOAT8: 506 return textDecodeFLOAT8(index, len, buff).Variant(); 507 // case DataType.FLOAT8_ARRAY: 508 // return textDecodeArray(DOUBLE_ARRAY_FACTORY, DataType.FLOAT8, index, len, buff).Variant(); 509 case DataType.CHAR: 510 return textDecodeCHAR(index, len, buff).Variant(); 511 // // case DataType.CHAR_ARRAY: 512 // // return textDecodeCHAR_ARRAY(len, buff).Variant(); 513 case DataType.VARCHAR: 514 return textDecodeVARCHAR(index, len, buff).Variant(); 515 // case DataType.VARCHAR_ARRAY: 516 // return textDecodeArray(STRING_ARRAY_FACTORY, DataType.VARCHAR, index, len, buff).Variant(); 517 case DataType.BPCHAR: 518 return textDecodeBPCHAR(index, len, buff).Variant(); 519 // case DataType.BPCHAR_ARRAY: 520 // return textDecodeArray(STRING_ARRAY_FACTORY, DataType.BPCHAR, index, len, buff).Variant(); 521 case DataType.TEXT: 522 return textdecodeTEXT(index, len, buff).Variant(); 523 // case DataType.TEXT_ARRAY: 524 // return textDecodeArray(STRING_ARRAY_FACTORY, DataType.TEXT, index, len, buff).Variant(); 525 case DataType.NAME: 526 return textDecodeNAME(index, len, buff).Variant(); 527 // case DataType.NAME_ARRAY: 528 // return textDecodeArray(STRING_ARRAY_FACTORY, DataType.NAME, index, len, buff).Variant(); 529 // case DataType.DATE: 530 // return textDecodeDATE(index, len, buff).Variant(); 531 // case DataType.DATE_ARRAY: 532 // return textDecodeArray(LOCALDATE_ARRAY_FACTORY, DataType.DATE, index, len, buff).Variant(); 533 // case DataType.TIME: 534 // return textDecodeTIME(index, len, buff).Variant(); 535 // case DataType.TIME_ARRAY: 536 // return textDecodeArray(LOCALTIME_ARRAY_FACTORY, DataType.TIME, index, len, buff).Variant(); 537 // case DataType.TIMETZ: 538 // return textDecodeTIMETZ(index, len, buff).Variant(); 539 // case DataType.TIMETZ_ARRAY: 540 // return textDecodeArray(OFFSETTIME_ARRAY_FACTORY, DataType.TIMETZ, index, len, buff).Variant(); 541 // case DataType.TIMESTAMP: 542 // return textDecodeTIMESTAMP(index, len, buff).Variant(); 543 // case DataType.TIMESTAMP_ARRAY: 544 // return textDecodeArray(LOCALDATETIME_ARRAY_FACTORY, DataType.TIMESTAMP, index, len, buff).Variant(); 545 // case DataType.TIMESTAMPTZ: 546 // return textDecodeTIMESTAMPTZ(index, len, buff).Variant(); 547 // case DataType.TIMESTAMPTZ_ARRAY: 548 // return textDecodeArray(OFFSETDATETIME_ARRAY_FACTORY, DataType.TIMESTAMPTZ, index, len, buff).Variant(); 549 case DataType.BYTEA: 550 return textDecodeBYTEA(index, len, buff).Variant(); 551 // case DataType.BYTEA_ARRAY: 552 // return textDecodeArray(BUFFER_ARRAY_FACTORY, DataType.BYTEA, index, len, buff).Variant(); 553 // case DataType.UUID: 554 // return textDecodeUUID(index, len, buff).Variant(); 555 // case DataType.UUID_ARRAY: 556 // return textDecodeArray(UUID_ARRAY_FACTORY, DataType.UUID, index, len, buff).Variant(); 557 case DataType.NUMERIC: 558 return textDecodeNUMERIC(index, len, buff).Variant(); 559 // case DataType.NUMERIC_ARRAY: 560 // return textDecodeArray(NUMERIC_ARRAY_FACTORY, DataType.NUMERIC, index, len, buff).Variant(); 561 // case DataType.JSON: 562 // return textDecodeJSON(index, len, buff).Variant(); 563 // case DataType.JSON_ARRAY: 564 // return textDecodeArray(JSON_ARRAY_FACTORY, DataType.JSON, index, len, buff).Variant(); 565 // case DataType.JSONB: 566 // return textDecodeJSONB(index, len, buff).Variant(); 567 // case DataType.JSONB_ARRAY: 568 // return textDecodeArray(JSON_ARRAY_FACTORY, DataType.JSONB, index, len, buff).Variant(); 569 // case DataType.POINT: 570 // return textDecodePOINT(index, len, buff).Variant(); 571 // case DataType.POINT_ARRAY: 572 // return textDecodeArray(POINT_ARRAY_FACTORY, DataType.POINT, index, len, buff).Variant(); 573 // case DataType.LINE: 574 // return textDecodeLine(index, len, buff).Variant(); 575 // case DataType.LINE_ARRAY: 576 // return textDecodeArray(LINE_ARRAY_FACTORY, DataType.LINE, index, len, buff).Variant(); 577 // case DataType.LSEG: 578 // return textDecodeLseg(index, len, buff).Variant(); 579 // case DataType.LSEG_ARRAY: 580 // return textDecodeArray(LSEG_ARRAY_FACTORY, DataType.LSEG, index, len, buff).Variant(); 581 // case DataType.BOX: 582 // return textDecodeBox(index, len, buff).Variant(); 583 // case DataType.BOX_ARRAY: 584 // return textDecodeBoxArray(BOX_ARRAY_FACTORY, index, len, buff).Variant(); 585 // case DataType.PATH: 586 // return textDecodePath(index, len, buff).Variant(); 587 // case DataType.PATH_ARRAY: 588 // return textDecodeArray(PATH_ARRAY_FACTORY, DataType.PATH, index, len, buff).Variant(); 589 // case DataType.POLYGON: 590 // return textDecodePolygon(index, len, buff).Variant(); 591 // case DataType.POLYGON_ARRAY: 592 // return textDecodeArray(POLYGON_ARRAY_FACTORY, DataType.POLYGON, index, len, buff).Variant(); 593 // case DataType.CIRCLE: 594 // return textDecodeCircle(index, len, buff).Variant(); 595 // case DataType.CIRCLE_ARRAY: 596 // return textDecodeArray(CIRCLE_ARRAY_FACTORY, DataType.CIRCLE, index, len, buff).Variant(); 597 // case DataType.INTERVAL: 598 // return textDecodeINTERVAL(index, len, buff).Variant(); 599 // case DataType.INTERVAL_ARRAY: 600 // return textDecodeArray(INTERVAL_ARRAY_FACTORY, DataType.INTERVAL, index, len, buff).Variant(); 601 default: 602 warningf("Data type %s(%d) does not support text decoding", id, id); 603 return defaultDecodeText(index, len, buff); 604 } 605 } 606 607 static bool isNumber(TypeInfo info) { 608 return info == typeid(short) || 609 info == typeid(ushort) || 610 info == typeid(int) || 611 info == typeid(uint) || 612 info == typeid(long) || 613 info == typeid(ulong) || 614 info == typeid(float) || 615 info == typeid(double) ; 616 } 617 618 static Variant prepare(DataTypeDesc type, ref Variant value) { 619 TypeInfo valueType = value.type; 620 621 switch (cast(DataType)type.id) { 622 case DataType.JSON: 623 case DataType.JSONB: 624 if (!value.hasValue() || valueType == typeid(null) || 625 valueType == typeid(string) || 626 valueType == typeid(bool) || 627 isNumber(valueType)) { // value instanceof JsonObject || value instanceof JsonArray 628 return value; 629 } else { 630 return REFUSED_SENTINEL.Variant(); 631 } 632 633 case DataType.UNKNOWN: 634 if (valueType == typeid(string[])) { 635 // return Arrays.stream((String[]) value).collect(Collectors.joining(",", "{", "}")); 636 throw new NotImplementedException(); 637 } else if (!value.hasValue() || valueType == typeid(null) || valueType == typeid(string)) { 638 return value; 639 } else { 640 return REFUSED_SENTINEL.Variant(); 641 } 642 643 default: 644 if (!value.hasValue() || valueType == typeid(null) || 645 type.decodingType.empty() || type.decodingType.canFind(valueType.toString())) 646 return value; 647 else 648 return REFUSED_SENTINEL.Variant(); 649 // FIXME: Needing refactor or cleanup -@zxp at 8/28/2019, 3:31:47 PM 650 // 651 // Class<?> javaType = type.decodingType; 652 // return !value.hasValue() || valueType == typeid(null) || javaType.isInstance(value) ? value : REFUSED_SENTINEL; 653 } 654 } 655 656 private static Variant defaultDecodeText(int index, int len, ByteBuf buff) { 657 // decode unknown text values as text or as an array if it begins with `{` 658 // if (len > 1 && buff.getByte(index) == '{') { 659 // return textDecodeArray(STRING_ARRAY_FACTORY, DataType.TEXT, index, len, buff); 660 // } 661 // FIXME: Needing refactor or cleanup -@zxp at 8/28/2019, 10:34:26 AM 662 // 663 implementationMissing(false); 664 return textdecodeTEXT(index, len, buff).Variant(); 665 } 666 667 private static void defaultEncodeBinary(ref Variant value, ByteBuf buff) { 668 // Default to null 669 buff.writeInt(-1); 670 } 671 672 // private static Object defaultDecodeBinary(int index, int len, ByteBuf buff) { 673 // // Default to null 674 // return null; 675 // } 676 677 private static void binaryEncodeBOOL(ref Variant value, ByteBuf buff) { 678 assert(value.type == typeid(bool)); 679 buff.writeBoolean(value.get!(bool)); 680 } 681 682 private static bool binaryDecodeBOOL(int index, int len, ByteBuf buff) { 683 return buff.getBoolean(index); 684 } 685 686 private static bool textDecodeBOOL(int index, int len, ByteBuf buff) { 687 if(buff.getByte(index) == 't') { 688 return true; 689 } else { 690 return false; 691 } 692 } 693 694 private static short textDecodeINT2(int index, int len, ByteBuf buff) { 695 return cast(short) DataTypeCodec.decodeDecStringToLong(index, len, buff); 696 } 697 698 private static short binaryDecodeINT2(int index, int len, ByteBuf buff) { 699 return buff.getShort(index); 700 } 701 702 private static void binaryEncodeINT2(ref Variant value, ByteBuf buff) { 703 assert(value.type == typeid(short) || value.type == typeid(ushort)); 704 buff.writeShort(value.get!(int)()); 705 } 706 707 private static int textDecodeINT4(int index, int len, ByteBuf buff) { 708 return cast(int) decodeDecStringToLong(index, len, buff); 709 } 710 711 private static int binaryDecodeINT4(int index, int len, ByteBuf buff) { 712 return buff.getInt(index); 713 } 714 715 private static void binaryEncodeINT4(ref Variant value, ByteBuf buff) { 716 assert(value.type == typeid(int) || value.type == typeid(uint)); 717 buff.writeInt(value.get!(int)); 718 } 719 720 private static long textDecodeINT8(int index, int len, ByteBuf buff) { 721 return decodeDecStringToLong(index, len, buff); 722 } 723 724 private static long binaryDecodeINT8(int index, int len, ByteBuf buff) { 725 return buff.getLong(index); 726 } 727 728 private static void binaryEncodeINT8(ref Variant value, ByteBuf buff) { 729 assert(value.type == typeid(long) || value.type == typeid(ulong)); 730 buff.writeLong(value.get!(long)); 731 } 732 733 private static float textDecodeFLOAT4(int index, int len, ByteBuf buff) { 734 CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 735 return cs.to!float(); 736 } 737 738 private static float binaryDecodeFLOAT4(int index, int len, ByteBuf buff) { 739 return buff.getFloat(index); 740 } 741 742 private static void binaryEncodeFLOAT4(ref Variant value, ByteBuf buff) { 743 assert(value.type == typeid(float)); 744 buff.writeFloat(value.get!(float)()); 745 } 746 747 private static void binaryEncodeFLOAT8(ref Variant value, ByteBuf buff) { 748 assert(value.type == typeid(double)); 749 buff.writeDouble(value.get!(double)()); 750 } 751 752 private static double binaryDecodeFLOAT8(int index, int len, ByteBuf buff) { 753 return buff.getDouble(index); 754 } 755 756 private static double textDecodeFLOAT8(int index, int len, ByteBuf buff) { 757 CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 758 return cs.to!double(); 759 } 760 761 private static double textDecodeNUMERIC(int index, int len, ByteBuf buff) { 762 // Todo optimize that 763 CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 764 // return Numeric.parse(cs.toString()); 765 double v = 0; 766 767 try { 768 v = cs.to!double(); 769 } catch (Exception ex) { 770 warningf("Not a number: %s", cs); 771 } 772 773 return v; 774 } 775 776 // private static Point textDecodePOINT(int index, int len, ByteBuf buff) { 777 // // Point representation: (x,y) 778 // int idx = ++index; 779 // int s = buff.indexOf(idx, idx + len, (byte) ','); 780 // int t = s - idx; 781 // double x = textDecodeFLOAT8(idx, t, buff); 782 // double y = textDecodeFLOAT8(s + 1, len - t - 3, buff); 783 // return new Point(x, y); 784 // } 785 786 // private static Line textDecodeLine(int index, int len, ByteBuf buff) { 787 // // Line representation: {a,b,c} 788 // int idxOfFirstSeparator = buff.indexOf(index, index + len, (byte) ','); 789 // int idxOfLastSeparator = buff.indexOf(index + len, index, (byte) ','); 790 791 // int idx = index + 1; 792 // double a = textDecodeFLOAT8(idx, idxOfFirstSeparator - idx, buff); 793 // double b = textDecodeFLOAT8(idxOfFirstSeparator + 1, idxOfLastSeparator - idxOfFirstSeparator - 1, buff); 794 // double c = textDecodeFLOAT8(idxOfLastSeparator + 1, index + len - idxOfLastSeparator - 2, buff); 795 // return new Line(a, b, c); 796 // } 797 798 // private static LineSegment textDecodeLseg(int index, int len, ByteBuf buff) { 799 // // Lseg representation: [p1,p2] 800 // int idxOfPointsSeparator = buff.indexOf(index, index+len, (byte) ')') + 1; 801 // int lenOfP1 = idxOfPointsSeparator - index - 1; 802 // Point p1 = textDecodePOINT(index + 1, lenOfP1, buff); 803 // Point p2 = textDecodePOINT(idxOfPointsSeparator + 1, len - lenOfP1 - 3, buff); 804 // return new LineSegment(p1, p2); 805 // } 806 807 // private static Box textDecodeBox(int index, int len, ByteBuf buff) { 808 // // Box representation: p1,p2 809 // int idxOfPointsSeparator = buff.indexOf(index, index+len, (byte) ')') + 1; 810 // int lenOfUpperRightCornerPoint = idxOfPointsSeparator - index; 811 // Point upperRightCorner = textDecodePOINT(index, lenOfUpperRightCornerPoint, buff); 812 // Point lowerLeftCorner = textDecodePOINT(idxOfPointsSeparator + 1, len - lenOfUpperRightCornerPoint - 1, buff); 813 // return new Box(upperRightCorner, lowerLeftCorner); 814 // } 815 816 // private static Box[] textDecodeBoxArray(IntFunction!(Box[]) supplier, int index, int len, ByteBuf buff) { 817 // // Box Array representation: {box1;box2;...boxN} 818 // List!(Box) boxes = new ArrayList<>(); 819 // int start = index + 1; 820 // int end = index + len - 1; 821 // while (start < end) { 822 // int idxOfBoxSeparator = buff.indexOf(start, end + 1, (byte) ';'); 823 // if (idxOfBoxSeparator == -1) { 824 // // the last box 825 // Box box = textDecodeBox(start, end - start, buff); 826 // boxes.add(box); 827 // break; 828 // } 829 // int lenOfBox = idxOfBoxSeparator - start; 830 // Box box = textDecodeBox(start, lenOfBox, buff); 831 // boxes.add(box); 832 // start = idxOfBoxSeparator + 1; 833 // } 834 // return boxes.toArray(supplier.apply(boxes.size())); 835 // } 836 837 // private static Path textDecodePath(int index, int len, ByteBuf buff) { 838 // // Path representation: (p1,p2...pn) or [p1,p2...pn] 839 // byte first = buff.getByte(index); 840 // byte last = buff.getByte(index + len - 1); 841 // bool isOpen; 842 // if (first == '(' && last == ')') { 843 // isOpen = false; 844 // } else if (first == '[' && last == ']') { 845 // isOpen = true; 846 // } else { 847 // throw new DecoderException("Decoding Path is in wrong syntax"); 848 // } 849 // List!(Point) points = textDecodeMultiplePoints(index + 1, len - 2, buff); 850 // return new Path(isOpen, points); 851 // } 852 853 // private static Polygon textDecodePolygon(int index, int len, ByteBuf buff) { 854 // // Polygon representation: (p1,p2...pn) 855 // List!(Point) points = textDecodeMultiplePoints(index + 1, len - 2, buff); 856 // return new Polygon(points); 857 // } 858 859 // // this might be useful for decoding Lseg, Box, Path, Polygon Data Type. 860 // private static List!(Point) textDecodeMultiplePoints(int index, int len, ByteBuf buff) { 861 // // representation: p1,p2,p3...pn 862 // List!(Point) points = new ArrayList<>(); 863 // int start = index; 864 // int end = index + len - 1; 865 // while (start < end) { 866 // int rightParenthesis = buff.indexOf(start, end + 1, (byte) ')'); 867 // int idxOfPointSeparator = rightParenthesis + 1; 868 // int lenOfPoint = idxOfPointSeparator - start; 869 // Point point = textDecodePOINT(start, lenOfPoint, buff); 870 // points.add(point); 871 // start = idxOfPointSeparator + 1; 872 // } 873 // return points; 874 // } 875 876 // private static Circle textDecodeCircle(int index, int len, ByteBuf buff) { 877 // // Circle representation: <p,r> 878 // int idxOfLastComma = buff.indexOf(index + len - 1, index, (byte) ','); 879 // int lenOfPoint = idxOfLastComma - index - 1; 880 // Point center = textDecodePOINT(index + 1, lenOfPoint, buff); 881 // int lenOfRadius = len - lenOfPoint - 3; 882 // double radius = textDecodeFLOAT8(idxOfLastComma + 1, lenOfRadius, buff); 883 // return new Circle(center, radius); 884 // } 885 886 // private static Interval textDecodeINTERVAL(int index, int len, ByteBuf buff) { 887 // CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 888 // String value = cs.toString(); 889 // int years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0, microseconds = 0; 890 // final List!(String) chunks = new ArrayList<>(7); 891 // int idx = 0; 892 // for (;;) { 893 // int newIdx = value.indexOf(' ', idx); 894 // if (newIdx == -1) { 895 // chunks.add(value.substring(idx)); 896 // break; 897 // } 898 // chunks.add(value.substring(idx, newIdx)); 899 // idx = newIdx + 1; 900 // } 901 // bool hasTime = chunks.size() % 2 == 1; 902 // int dateChunkMax = hasTime ? chunks.size() - 1 : chunks.size(); 903 // for (int i = 0; i < dateChunkMax; i += 2) { 904 // int val = Integer.parseInt(chunks.get(i)); 905 // switch (chunks.get(i + 1)) { 906 // case "year": 907 // case "years": 908 // years = val; 909 // break; 910 // case "mon": 911 // case "mons": 912 // months = val; 913 // break; 914 // case "day": 915 // case "days": 916 // days = val; 917 // break; 918 // } 919 // } 920 // if (hasTime) { 921 // String timeChunk = chunks.get(chunks.size() - 1); 922 // bool isNeg = timeChunk.charAt(0) == '-'; 923 // if (isNeg) timeChunk = timeChunk.substring(1); 924 // int sidx = 0; 925 // for (;;) { 926 // int newIdx = timeChunk.indexOf(':', sidx); 927 // if (newIdx == -1) { 928 // int m = timeChunk.substring(sidx).indexOf('.'); 929 // if(m == -1) { 930 // // seconds without microseconds 931 // seconds = isNeg ? -Integer.parseInt(timeChunk.substring(sidx)) 932 // : Integer.parseInt(timeChunk.substring(sidx)); 933 // } else { 934 // // seconds with microseconds 935 // seconds = isNeg ? -Integer.parseInt(timeChunk.substring(sidx).substring(0, m)) 936 // : Integer.parseInt(timeChunk.substring(sidx).substring(0, m)); 937 // microseconds = isNeg ? -Integer.parseInt(timeChunk.substring(sidx).substring(m + 1)) 938 // : Integer.parseInt(timeChunk.substring(sidx).substring(m + 1)); 939 // } 940 // break; 941 // } 942 // // hours 943 // if(sidx == 0) { 944 // hours = isNeg ? -Integer.parseInt(timeChunk.substring(sidx, newIdx)) 945 // : Integer.parseInt(timeChunk.substring(sidx, newIdx)); 946 // } else { 947 // // minutes 948 // minutes = isNeg ? -Integer.parseInt(timeChunk.substring(sidx, newIdx)) 949 // : Integer.parseInt(timeChunk.substring(sidx, newIdx)); 950 // } 951 // sidx = newIdx + 1; 952 // } 953 // } 954 // return new Interval(years, months, days, hours, minutes, seconds, microseconds); 955 // } 956 957 private static void textEncodeNUMERIC(ref Variant value, ByteBuf buff) { 958 // assert(value.type == typeid(int)); 959 string s = value.toString(); 960 buff.writeCharSequence(s, StandardCharsets.UTF_8); 961 } 962 963 private static void textEncodeNUMERIC_ARRAY(ref Variant value, ByteBuf buff) { 964 if(value.type == typeid(int[])) { 965 textEncodeArray!(int)(value, DataType.NUMERIC, buff); 966 } if(value.type == typeid(long[])) { 967 textEncodeArray!(long)(value, DataType.NUMERIC, buff); 968 } if(value.type == typeid(float[])) { 969 textEncodeArray!(float)(value, DataType.NUMERIC, buff); 970 } if(value.type == typeid(double[])) { 971 textEncodeArray!(double)(value, DataType.NUMERIC, buff); 972 } else { 973 throw new Exception("Can't handle numeric array: " ~ value.type.toString()); 974 } 975 } 976 977 private static void binaryEncodeCHAR(ref Variant value, ByteBuf buff) { 978 binaryEncodeTEXT(value, buff); 979 } 980 981 private static void binaryEncodeVARCHAR(ref Variant value, ByteBuf buff) { 982 assert(value.type == typeid(string)); 983 buff.writeCharSequence(value.get!(string), StandardCharsets.UTF_8); 984 } 985 alias binaryEncodeNAME = binaryEncodeVARCHAR; 986 alias binaryEncodeBPCHAR = binaryEncodeVARCHAR; 987 988 private static string textDecodeVARCHAR(int index, int len, ByteBuf buff) { 989 return buff.getCharSequence(index, len, StandardCharsets.UTF_8); 990 } 991 alias textDecodeCHAR = textDecodeVARCHAR; 992 alias textDecodeBPCHAR = textDecodeVARCHAR; 993 alias textdecodeTEXT = textDecodeVARCHAR; 994 alias textDecodeNAME = textDecodeVARCHAR; 995 996 alias binaryDecodeCHAR = textDecodeVARCHAR; 997 alias binaryDecodeNAME = textDecodeVARCHAR; 998 alias binaryDecodeBPCHAR = textDecodeVARCHAR; 999 alias binaryDecodeTEXT = textDecodeVARCHAR; 1000 1001 private static string binaryDecodeVARCHAR(int index, int len, ByteBuf buff) { 1002 return buff.getCharSequence(index, len, StandardCharsets.UTF_8); 1003 } 1004 1005 1006 private static void binaryEncodeTEXT(ref Variant value, ByteBuf buff) { 1007 assert(value.type == typeid(string)); 1008 string s = value.toString(); 1009 buff.writeCharSequence(s, StandardCharsets.UTF_8); 1010 } 1011 1012 1013 // private static void binaryEncodeDATE(LocalDate value, ByteBuf buff) { 1014 // buff.writeInt((int) -value.until(LOCAL_DATE_EPOCH, ChronoUnit.DAYS)); 1015 // } 1016 1017 // private static LocalDate binaryDecodeDATE(int index, int len, ByteBuf buff) { 1018 // return LOCAL_DATE_EPOCH.plus(buff.getInt(index), ChronoUnit.DAYS); 1019 // } 1020 1021 // private static LocalDate textDecodeDATE(int index, int len, ByteBuf buff) { 1022 // CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 1023 // return LocalDate.parse(cs); 1024 // } 1025 1026 // private static void binaryEncodeTIME(LocalTime value, ByteBuf buff) { 1027 // buff.writeLong(value.getLong(ChronoField.MICRO_OF_DAY)); 1028 // } 1029 1030 // private static LocalTime binaryDecodeTIME(int index, int len, ByteBuf buff) { 1031 // // micros to nanos 1032 // return LocalTime.ofNanoOfDay(buff.getLong(index) * 1000); 1033 // } 1034 1035 // private static LocalTime textDecodeTIME(int index, int len, ByteBuf buff) { 1036 // CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 1037 // return LocalTime.parse(cs); 1038 // } 1039 1040 // private static void binaryEncodeTIMETZ(OffsetTime value, ByteBuf buff) { 1041 // buff.writeLong(value.toLocalTime().getLong(ChronoField.MICRO_OF_DAY)); 1042 // // zone offset in seconds (should we change it to UTC ?) 1043 // buff.writeInt(-value.getOffset().getTotalSeconds()); 1044 // } 1045 1046 // private static OffsetTime binaryDecodeTIMETZ(int index, int len, ByteBuf buff) { 1047 // // micros to nanos 1048 // return OffsetTime.of(LocalTime.ofNanoOfDay(buff.getLong(index) * 1000), 1049 // // zone offset in seconds (should we change it to UTC ?) 1050 // ZoneOffset.ofTotalSeconds(-buff.getInt(index + 8))); 1051 // } 1052 1053 // private static OffsetTime textDecodeTIMETZ(int index, int len, ByteBuf buff) { 1054 // CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 1055 // return OffsetTime.parse(cs, TIMETZ_FORMAT); 1056 // } 1057 1058 // private static void binaryEncodeTIMESTAMP(LocalDateTime value, ByteBuf buff) { 1059 // buff.writeLong(-value.until(LOCAL_DATE_TIME_EPOCH, ChronoUnit.MICROS)); 1060 // } 1061 1062 // private static LocalDateTime binaryDecodeTIMESTAMP(int index, int len, ByteBuf buff) { 1063 // return LOCAL_DATE_TIME_EPOCH.plus(buff.getLong(index), ChronoUnit.MICROS); 1064 // } 1065 1066 // private static LocalDateTime textDecodeTIMESTAMP(int index, int len, ByteBuf buff) { 1067 // CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 1068 // return LocalDateTime.parse(cs, TIMESTAMP_FORMAT); 1069 // } 1070 1071 // private static OffsetDateTime binaryDecodeTIMESTAMPTZ(int index, int len, ByteBuf buff) { 1072 // return OFFSET_DATE_TIME_EPOCH.plus(buff.getLong(index), ChronoUnit.MICROS); 1073 // } 1074 1075 // private static void binaryEncodeTIMESTAMPTZ(OffsetDateTime value, ByteBuf buff) { 1076 // buff.writeLong(-value.until(OFFSET_DATE_TIME_EPOCH, ChronoUnit.MICROS)); 1077 // } 1078 1079 // private static OffsetDateTime textDecodeTIMESTAMPTZ(int index, int len, ByteBuf buff) { 1080 // CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 1081 // return OffsetDateTime.parse(cs, TIMESTAMPTZ_FORMAT); 1082 // } 1083 1084 private static byte[] textDecodeBYTEA(int index, int len, ByteBuf buff) { 1085 if (isHexFormat(index, len, buff)) { 1086 // hex format 1087 // Shift 2 bytes: skip \x prolog 1088 return decodeHexStringToBytes(index + 2, len - 2, buff); 1089 } else { 1090 // escape format 1091 return decodeEscapeByteaStringToBuffer(index, len, buff); 1092 } 1093 } 1094 1095 private static void binaryEncodeBYTEA(ref Variant value, ByteBuf buff) { 1096 assert(value.type == typeid(byte[]) || value.type == typeid(ubyte[])); 1097 buff.writeBytes(value.get!(byte[])()); 1098 } 1099 1100 private static byte[] binaryDecodeBYTEA(int index, int len, ByteBuf buff) { 1101 ByteBuf buffer = buff.copy(index, len); 1102 return buffer.getReadableBytes(); 1103 } 1104 1105 // private static void binaryEncodeUUID(UUID uuid, ByteBuf buff) { 1106 // buff.writeLong(uuid.getMostSignificantBits()); 1107 // buff.writeLong(uuid.getLeastSignificantBits()); 1108 // } 1109 1110 // private static void binaryEncodePoint(Point point, ByteBuf buff) { 1111 // binaryEncodeFLOAT8(point.x, buff); 1112 // binaryEncodeFLOAT8(point.y, buff); 1113 // } 1114 1115 // private static Point binaryDecodePoint(int index, int len, ByteBuf buff) { 1116 // double x = binaryDecodeFLOAT8(index, 8, buff); 1117 // double y = binaryDecodeFLOAT8(index + 8, 8, buff); 1118 // return new Point(x, y); 1119 // } 1120 1121 // private static void binaryEncodeLine(Line line, ByteBuf buff) { 1122 // binaryEncodeFLOAT8(line.getA(), buff); 1123 // binaryEncodeFLOAT8(line.getB(), buff); 1124 // binaryEncodeFLOAT8(line.getC(), buff); 1125 // } 1126 1127 // private static Line binaryDecodeLine(int index, int len, ByteBuf buff) { 1128 // double a = binaryDecodeFLOAT8(index, 8, buff); 1129 // double b = binaryDecodeFLOAT8(index + 8, 8, buff); 1130 // double c = binaryDecodeFLOAT8(index + 16, 8, buff); 1131 // return new Line(a, b, c); 1132 // } 1133 1134 // private static void binaryEncodeLseg(LineSegment lseg, ByteBuf buff) { 1135 // binaryEncodePoint(lseg.getP1(), buff); 1136 // binaryEncodePoint(lseg.getP2(), buff); 1137 // } 1138 1139 // private static LineSegment binaryDecodeLseg(int index, int len, ByteBuf buff) { 1140 // Point p1 = binaryDecodePoint(index, 16, buff); 1141 // Point p2 = binaryDecodePoint(index + 16, 16, buff); 1142 // return new LineSegment(p1, p2); 1143 // } 1144 1145 // private static void binaryEncodeBox(Box box, ByteBuf buff) { 1146 // binaryEncodePoint(box.getUpperRightCorner(), buff); 1147 // binaryEncodePoint(box.getLowerLeftCorner(), buff); 1148 // } 1149 1150 // private static Box binaryDecodeBox(int index, int len, ByteBuf buff) { 1151 // Point upperRightCorner = binaryDecodePoint(index, 16, buff); 1152 // Point lowerLeftCorner = binaryDecodePoint(index + 16, 16, buff); 1153 // return new Box(upperRightCorner, lowerLeftCorner); 1154 // } 1155 1156 // private static void binaryEncodePath(Path path, ByteBuf buff) { 1157 // if (path.isOpen()) { 1158 // buff.writeByte(0); 1159 // } else { 1160 // buff.writeByte(1); 1161 // } 1162 // List!(Point) points = path.getPoints(); 1163 // binaryEncodeINT4(points.size(), buff); 1164 // for (Point point : points) { 1165 // binaryEncodePoint(point, buff); 1166 // } 1167 // } 1168 1169 // private static Path binaryDecodePath(int index, int len, ByteBuf buff) { 1170 // byte first = buff.getByte(index); 1171 // bool isOpen; 1172 // if (first == 0) { 1173 // isOpen = true; 1174 // } else if (first == 1) { 1175 // isOpen = false; 1176 // } else { 1177 // throw new DecoderException("Decoding Path exception"); 1178 // } 1179 // int idx = ++index; 1180 // int numberOfPoints = binaryDecodeINT4(idx, 4, buff); 1181 // idx += 4; 1182 // List!(Point) points = new ArrayList<>(); 1183 // // maybe we need some check? 1184 // for (int i = 0; i < numberOfPoints; i++) { 1185 // points.add(binaryDecodePoint(idx, 16, buff)); 1186 // idx += 16; 1187 // } 1188 // return new Path(isOpen, points); 1189 // } 1190 1191 // private static void binaryEncodePolygon(Polygon polygon, ByteBuf buff) { 1192 // List!(Point) points = polygon.getPoints(); 1193 // int numberOfPoints = points.size(); 1194 // binaryEncodeINT4(numberOfPoints, buff); 1195 // for (Point point : points) { 1196 // binaryEncodeFLOAT8(point.x, buff); 1197 // binaryEncodeFLOAT8(point.y, buff); 1198 // } 1199 // } 1200 1201 // private static Polygon binaryDecodePolygon(int index, int len, ByteBuf buff) { 1202 // int idx = index; 1203 // int numberOfPoints = binaryDecodeINT4(index, 4, buff); 1204 // idx += 4; 1205 // List!(Point) points = new ArrayList<>(); 1206 // for (int i = 0; i < numberOfPoints; i++) { 1207 // points.add(binaryDecodePoint(idx, 16, buff)); 1208 // idx += 16; 1209 // } 1210 // return new Polygon(points); 1211 // } 1212 1213 // private static void binaryEncodeCircle(Circle circle, ByteBuf buff) { 1214 // binaryEncodePoint(circle.getCenterPoint(), buff); 1215 // binaryEncodeFLOAT8(circle.getRadius(), buff); 1216 // } 1217 1218 // private static Circle binaryDecodeCircle(int index, int len, ByteBuf buff) { 1219 // Point center = binaryDecodePoint(index, 16, buff); 1220 // double radius = binaryDecodeFLOAT8(index + 16, 8, buff); 1221 // return new Circle(center, radius); 1222 // } 1223 1224 // private static void binaryEncodeINTERVAL(Interval interval, ByteBuf buff) { 1225 // Duration duration = Duration 1226 // .ofHours(interval.getHours()) 1227 // .plusMinutes(interval.getMinutes()) 1228 // .plusSeconds(interval.getSeconds()) 1229 // .plus(interval.getMicroseconds(), ChronoUnit.MICROS); 1230 // // days won't be changed 1231 // Period monthYear = Period.of(interval.getYears(), interval.getMonths(), interval.getDays()).normalized(); 1232 // binaryEncodeINT8(NANOSECONDS.toMicros(duration.toNanos()), buff); 1233 // binaryEncodeINT4(monthYear.getDays(), buff); 1234 // binaryEncodeINT4((int) monthYear.toTotalMonths(), buff); 1235 // } 1236 1237 // private static Interval binaryDecodeINTERVAL(int index, int len, ByteBuf buff) { 1238 // Duration duration = Duration.of(buff.getLong(index), ChronoUnit.MICROS); 1239 // final long hours = duration.toHours(); 1240 // duration = duration.minusHours(hours); 1241 // final long minutes = duration.toMinutes(); 1242 // duration = duration.minusMinutes(minutes); 1243 // final long seconds = NANOSECONDS.toSeconds(duration.toNanos()); 1244 // duration = duration.minusSeconds(seconds); 1245 // final long microseconds = NANOSECONDS.toMicros(duration.toNanos()); 1246 // int days = buff.getInt(index + 8); 1247 // int months = buff.getInt(index + 12); 1248 // Period monthYear = Period.of(0, months, days).normalized(); 1249 // return new Interval(monthYear.getYears(), monthYear.getMonths(), monthYear.getDays(), 1250 // (int) hours, (int) minutes, (int) seconds, (int) microseconds); 1251 // } 1252 1253 // private static UUID binaryDecodeUUID(int index, int len, ByteBuf buff) { 1254 // return new UUID(buff.getLong(index), buff.getLong(index + 8)); 1255 // } 1256 1257 // private static UUID textDecodeUUID(int index, int len, ByteBuf buff) { 1258 // return java.util.UUID.fromString(buff.getCharSequence(index, len, StandardCharsets.UTF_8).toString()); 1259 // } 1260 1261 // private static Object textDecodeJSON(int index, int len, ByteBuf buff) { 1262 // return textDecodeJSONB(index, len, buff); 1263 // } 1264 1265 // private static Object binaryDecodeJSON(int index, int len, ByteBuf buff) { 1266 // return textDecodeJSONB(index, len, buff); 1267 // } 1268 1269 // private static void binaryEncodeJSON(Object value, ByteBuf buff) { 1270 // String s; 1271 // if (value == Tuple.JSON_NULL) { 1272 // s = "null"; 1273 // } else { 1274 // s = io.vertx.core.json.Json.encode(value); 1275 // } 1276 // buff.writeCharSequence(s, StandardCharsets.UTF_8); 1277 // } 1278 1279 // private static Object textDecodeJSONB(int index, int len, ByteBuf buff) { 1280 1281 // // Try to do without the intermediary String (?) 1282 // CharSequence cs = buff.getCharSequence(index, len, StandardCharsets.UTF_8); 1283 // Object value = null; 1284 // String s = cs.toString(); 1285 // int pos = 0; 1286 // while (pos < s.length() && Character.isWhitespace(s.charAt(pos))) { 1287 // pos++; 1288 // } 1289 // if (pos == s.length()) { 1290 // return null; 1291 // } else if (s.charAt(pos) == '{') { 1292 // value = new JsonObject(s); 1293 // } else if (s.charAt(pos) == '[') { 1294 // value = new JsonArray(s); 1295 // } else { 1296 // try { 1297 // JsonNode json = Json.mapper.readTree(s); 1298 // if (json.isNumber()) { 1299 // return json.numberValue(); 1300 // } else if (json.isBoolean()) { 1301 // return json.booleanValue(); 1302 // } else if (json.isTextual()) { 1303 // return json.textValue(); 1304 // } else if (json.isNull()) { 1305 // return Tuple.JSON_NULL; 1306 // } else { 1307 // return null; 1308 // } 1309 // } catch (IOException e) { 1310 // // do nothing 1311 // } 1312 // } 1313 // return value; 1314 // } 1315 1316 // private static Object binaryDecodeJSONB(int index, int len, ByteBuf buff) { 1317 // // Skip 1 byte for version (which is 1) 1318 // return textDecodeJSONB(index + 1, len - 1, buff); 1319 // } 1320 1321 // private static void binaryEncodeJSONB(Object value, ByteBuf buff) { 1322 // buff.writeByte(1); // version 1323 // binaryEncodeJSON(value, buff); 1324 // } 1325 1326 /** 1327 * Decode the specified {@code buff} formatted as a decimal string starting at the readable index 1328 * with the specified {@code length} to a long. 1329 * 1330 * @param index the hex string index 1331 * @param len the hex string length 1332 * @param buff the byte buff to read from 1333 * @return the decoded value as a long 1334 */ 1335 private static long decodeDecStringToLong(int index, int len, ByteBuf buff) { 1336 long value = 0; 1337 string v = textdecodeTEXT(index, len, buff); 1338 return v.to!long(); 1339 // if (len > 0) { 1340 // int to = index + len; 1341 // bool neg = false; 1342 // if (buff.getByte(index) == '-') { 1343 // neg = true; 1344 // index++; 1345 // } 1346 // while (index < to) { 1347 // byte ch = buff.getByte(index++); 1348 // byte nibble = cast(byte)(ch - '0'); 1349 // value = value * 10 + nibble; 1350 // } 1351 // if (neg) { 1352 // value = -value; 1353 // } 1354 // } 1355 // return value; 1356 } 1357 1358 /** 1359 * Decode the specified {@code buff} formatted as an hex string starting at the buffer readable index 1360 * with the specified {@code length} to a {@link Buffer}. 1361 * 1362 * @param len the hex string length 1363 * @param buff the byte buff to read from 1364 * @return the decoded value as a Buffer 1365 */ 1366 private static byte[] decodeHexStringToBytes(int index, int len, ByteBuf buff) { 1367 len = len >> 1; 1368 byte[] buffer = new byte[len]; 1369 for (int i = 0; i < len; i++) { 1370 byte b0 = decodeHexChar(buff.getByte(index++)); 1371 byte b1 = decodeHexChar(buff.getByte(index++)); 1372 // buffer.appendByte((byte) (b0 * 16 + b1)); 1373 buffer[i] = cast(byte) (b0 * 16 + b1); 1374 } 1375 return buffer; 1376 } 1377 1378 private static byte decodeHexChar(byte ch) { 1379 return cast(byte)(((ch & 0x1F) + ((ch >> 6) * 0x19) - 0x10) & 0x0F); 1380 } 1381 1382 private static bool isHexFormat(int index, int len, ByteBuf buff) { 1383 return len >= 2 && buff.getByte(index) == '\\' && buff.getByte(index + 1) == 'x'; 1384 } 1385 1386 private static byte[] decodeEscapeByteaStringToBuffer(int index, int len, ByteBuf buff) { 1387 // Buffer buffer = Buffer.buffer(); 1388 Appender!(byte[]) buffer; 1389 buffer.reserve(len); 1390 1391 int pos = 0; 1392 while (pos < len) { 1393 byte current = buff.getByte(pos + index); 1394 1395 if (current == '\\') { 1396 if (pos + 2 <= len && buff.getByte(pos + index + 1) == '\\') { 1397 // check double backslashes 1398 buffer.put(cast(byte) '\\'); 1399 pos += 2; 1400 } else if (pos + 4 <= len) { 1401 // a preceded backslash with three-digit octal value 1402 // int high = Character.digit(buff.getByte(pos + index + 1), 8) << 6; 1403 // int medium = Character.digit(buff.getByte(pos + index + 2), 8) << 3; 1404 // int low = Character.digit(buff.getByte(pos + index + 3), 8); 1405 // int escapedValue = high + medium + low; 1406 byte[] data = new byte[3]; 1407 buff.getBytes(pos + index + 1, data); 1408 short escapedValue = to!short(cast(string)data, 8); 1409 1410 buffer.put(cast(byte) escapedValue); 1411 pos += 4; 1412 } else { 1413 throw new DecoderException("Decoding unexpected BYTEA escape format"); 1414 } 1415 } else { 1416 // printable octets 1417 buffer.put(current); 1418 pos++; 1419 } 1420 } 1421 1422 return buffer.data(); 1423 } 1424 1425 // private static <T> T[] binaryDecodeArray(IntFunction!(T[]) supplier, DataType type, int index, int len, ByteBuf buff) { 1426 // if (len == 12) { 1427 // return supplier.apply(0); 1428 // } 1429 // int dim = buff.getInt(index); // read ndim 1430 // index += 4; 1431 // index += 4; // skip dataoffset 1432 // index += 4; // skip elemtype 1433 // int length = buff.getInt(index); // read dimensions 1434 // index += 4; 1435 // index += 4; // skip lower bnds 1436 // if (dim != 1) { 1437 // logger.warn("Only arrays of dimension 1 are supported"); 1438 // return null; 1439 // } 1440 // T[] array = supplier.apply(length); 1441 // for (int i = 0; i < array.length; i++) { 1442 // int l = buff.getInt(index); 1443 // index += 4; 1444 // if (l != -1) { 1445 // array[i] = (T) decodeBinary(type, index, l, buff); 1446 // index += l; 1447 // } 1448 // } 1449 // return array; 1450 // } 1451 1452 private static void binaryEncodeArray(T)(ref Variant data, DataType type, ByteBuf buff){ 1453 assert(data.type == typeid(T[])); 1454 T[] values = data.get!(T[])(); 1455 1456 int startIndex = buff.writerIndex(); 1457 buff.writeInt(1); // ndim 1458 buff.writeInt(0); // dataoffset 1459 buff.writeInt(cast(int)type); // elemtype 1460 buff.writeInt(cast(int)values.length); // dimension 1461 buff.writeInt(1); // lower bnds 1462 bool hasNulls = false; 1463 foreach (T value ; values) { 1464 static if(is(T == class) || is(T == interface)) { 1465 if (value is null) { 1466 hasNulls = true; 1467 buff.writeInt(-1); 1468 continue; 1469 } 1470 } 1471 1472 int idx = buff.writerIndex(); 1473 buff.writeInt(0); 1474 static if(is(T == Variant)) { 1475 encodeBinary(type, value, buff); 1476 } else { 1477 Variant v = value; 1478 encodeBinary(type, v, buff); 1479 } 1480 buff.setInt(idx, buff.writerIndex() - idx - 4); 1481 } 1482 if (hasNulls) { 1483 buff.setInt(startIndex + 4, 1); 1484 } 1485 } 1486 1487 // private static T[] textDecodeArray(T)(IntFunction!(T[]) supplier, DataType type, int index, int len, ByteBuf buff) { 1488 // List!(T) list = new ArrayList<>(); 1489 // int from = index + 1; // Set index after '{' 1490 // int to = index + len - 1; // Set index before '}' 1491 // while (from < to) { 1492 // // Escaped content ? 1493 // bool escaped = buff.getByte(from) == '"'; 1494 // int idx; 1495 // if (escaped) { 1496 // idx = buff.forEachByte(from, to - from, new UTF8StringEndDetector()); 1497 // idx = buff.indexOf(idx, to, (byte) ','); // SEE iF WE CAN GET RID oF IT 1498 // } else { 1499 // idx = buff.indexOf(from, to, (byte) ','); 1500 // } 1501 // if (idx == -1) { 1502 // idx = to; 1503 // } 1504 // T elt = textDecodeArrayElement(type, from, idx - from, buff); 1505 // list.add(elt); 1506 // from = idx + 1; 1507 // } 1508 // return list.toArray(supplier.apply(list.size())); 1509 // } 1510 1511 // private static T textDecodeArrayElement(T)(DataType type, int index, int len, ByteBuf buff) { 1512 // if (len == 4 1513 // && toUpper(buff.getByte(index)) == 'N' 1514 // && toUpper(buff.getByte(index + 1)) == 'U' 1515 // && toUpper(buff.getByte(index + 2)) == 'L' 1516 // && toUpper(buff.getByte(index + 3)) == 'L' ) { 1517 // return null; 1518 // } else { 1519 // bool escaped = buff.getByte(index) == '"'; 1520 // if (escaped) { 1521 // // Some escaping - improve that later... 1522 // string s = buff.toString(index + 1, len - 2, StandardCharsets.UTF_8); 1523 // Appender!string sb; // = new StringBuilder(); 1524 // sb.reserve(s.length); 1525 // for (int i = 0;i < cast(int)s.length;i++) { 1526 // char c = s[i]; 1527 // if (c == '\\') { 1528 // c = s[++i]; 1529 // } 1530 // sb.put(c); 1531 // } 1532 // buff = Unpooled.copiedBuffer(sb.data, StandardCharsets.UTF_8); 1533 // index = 0; 1534 // len = buff.readableBytes(); 1535 // } 1536 // return cast(T) decodeText(type, index, len, buff); 1537 // } 1538 // } 1539 1540 private static void textEncodeArray(T)(ref Variant data, DataType type, ByteBuf buff){ 1541 assert(data.type == typeid(T[])); 1542 T[] values = data.get!(T[])(); 1543 1544 buff.writeByte('{'); 1545 int len = cast(int)values.length; 1546 for (int i = 0; i < len; i++) { 1547 if (i > 0) { 1548 buff.writeByte(','); 1549 } 1550 T value = values[i]; 1551 static if(is(T == class) || is(T == interface)) { 1552 if (value is null) { 1553 buff.writeByte('N'); 1554 buff.writeByte('U'); 1555 buff.writeByte('L'); 1556 buff.writeByte('L'); 1557 continue; 1558 } 1559 } 1560 1561 Variant v = value; 1562 textEncode(type, v, buff); 1563 } 1564 buff.writeByte('}'); 1565 } 1566 }