OmniSciDB  95562058bd
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DateTimeTest.java
Go to the documentation of this file.
1 package com.mapd.tests;
2 
3 import com.omnisci.thrift.server.TOmniSciException;
4 import com.omnisci.thrift.server.TTypeInfo;
5 
6 import org.apache.commons.math3.util.Pair;
7 
8 import java.time.LocalDateTime;
9 import java.time.ZoneOffset;
10 import java.time.format.DateTimeFormatter;
11 import java.time.temporal.ChronoField;
12 import java.time.temporal.ChronoUnit;
13 import java.util.Arrays;
14 import java.util.EnumSet;
15 import java.util.Random;
16 import java.util.function.Function;
17 
21 public class DateTimeTest {
22  static enum DateTruncUnit {
23  dtYEAR("YEAR", new Function<LocalDateTime, LocalDateTime>() {
24  @Override
25  public LocalDateTime apply(LocalDateTime t) {
26  t = t.withMonth(1);
27  t = t.withDayOfMonth(1);
28  t = t.truncatedTo(ChronoUnit.DAYS);
29  return t;
30  }
31  }),
32  dtQUARTER("QUARTER", new Function<LocalDateTime, LocalDateTime>() {
33  @Override
34  public LocalDateTime apply(LocalDateTime t) {
35  int month = t.getMonthValue();
36 
37  switch (month) {
38  case 12:
39  case 11:
40  case 10:
41  t = t.withMonth(10);
42  break;
43  case 9:
44  case 8:
45  case 7:
46  t = t.withMonth(7);
47  break;
48  case 6:
49  case 5:
50  case 4:
51  t = t.withMonth(4);
52  break;
53  case 3:
54  case 2:
55  case 1:
56  t = t.withMonth(1);
57  break;
58  };
59 
60  t = t.withDayOfMonth(1);
61  t = t.truncatedTo(ChronoUnit.DAYS);
62  return t;
63  }
64  }),
65  dtMONTH("MONTH", new Function<LocalDateTime, LocalDateTime>() {
66  @Override
67  public LocalDateTime apply(LocalDateTime t) {
68  t = t.withDayOfMonth(1);
69  t = t.truncatedTo(ChronoUnit.DAYS);
70  return t;
71  }
72  }),
73  dtDAY("DAY", new Function<LocalDateTime, LocalDateTime>() {
74  @Override
75  public LocalDateTime apply(LocalDateTime t) {
76  t = t.truncatedTo(ChronoUnit.DAYS);
77  return t;
78  }
79  }),
80  dtHOUR("HOUR", new Function<LocalDateTime, LocalDateTime>() {
81  @Override
82  public LocalDateTime apply(LocalDateTime t) {
83  t = t.truncatedTo(ChronoUnit.HOURS);
84  return t;
85  }
86  }),
87  dtMINUTE("MINUTE", new Function<LocalDateTime, LocalDateTime>() {
88  @Override
89  public LocalDateTime apply(LocalDateTime t) {
90  t = t.truncatedTo(ChronoUnit.MINUTES);
91  return t;
92  }
93  }),
94  dtSECOND("SECOND", new Function<LocalDateTime, LocalDateTime>() {
95  @Override
96  public LocalDateTime apply(LocalDateTime t) {
97  t = t.truncatedTo(ChronoUnit.SECONDS);
98  return t;
99  }
100  }),
101  // dtMILLENNIUM("MILLENNIUM", new Function<LocalDateTime, LocalDateTime>() {
102  // @Override
103  // public LocalDateTime apply(LocalDateTime t) {
104  // int year = t.getYear();
105  // int range = 1000;
106  // int diff = year % range;
107  // if (diff == 0) {
108  // diff = range;
109  // }
110  // year -= diff;
111  // t = t.withYear(year + 1);
112  // t = t.withMonth(1);
113  // t = t.withDayOfMonth(1);
114  // t = t.truncatedTo(ChronoUnit.DAYS);
115  // return t;
116  // }
117  // }),
118  dtCENTURY("CENTURY", new Function<LocalDateTime, LocalDateTime>() {
119  @Override
120  public LocalDateTime apply(LocalDateTime t) {
121  int year = t.getYear();
122  int range = 100;
123  int diff = year % range;
124  if (diff == 0) {
125  diff = range;
126  }
127  year -= diff;
128  t = t.withYear(year + 1);
129 
130  t = t.withMonth(1);
131  t = t.withDayOfMonth(1);
132  t = t.truncatedTo(ChronoUnit.DAYS);
133  return t;
134  }
135  }),
136  dtDECADE("DECADE", new Function<LocalDateTime, LocalDateTime>() {
137  @Override
138  public LocalDateTime apply(LocalDateTime t) {
139  int year = t.getYear();
140  int range = 10;
141  int diff = year % range;
142  year -= diff;
143  t = t.withYear(year);
144  t = t.withMonth(1);
145  t = t.withDayOfMonth(1);
146  t = t.truncatedTo(ChronoUnit.DAYS);
147  return t;
148  }
149  }),
150  dtMILLISECOND("MILLISECOND", new Function<LocalDateTime, LocalDateTime>() {
151  @Override
152  public LocalDateTime apply(LocalDateTime t) {
153  t = t.truncatedTo(ChronoUnit.MILLIS);
154  return t;
155  }
156  }),
157  dtMICROSECOND("MICROSECOND", new Function<LocalDateTime, LocalDateTime>() {
158  @Override
159  public LocalDateTime apply(LocalDateTime t) {
160  t = t.truncatedTo(ChronoUnit.MICROS);
161  return t;
162  }
163  }),
164  dtNANOSECOND("NANOSECOND", new Function<LocalDateTime, LocalDateTime>() {
165  @Override
166  public LocalDateTime apply(LocalDateTime t) {
167  t = t.truncatedTo(ChronoUnit.NANOS);
168  return t;
169  }
170  }),
171  dtWEEK("WEEK", new Function<LocalDateTime, LocalDateTime>() {
172  @Override
173  public LocalDateTime apply(LocalDateTime t) {
174  t = t.with(ChronoField.DAY_OF_WEEK, 1);
175  t = t.truncatedTo(ChronoUnit.DAYS);
176  return t;
177  }
178  }),
179  // dtQUARTERDAY("QUERTERDAY", new Function<LocalDateTime, LocalDateTime>()
180  //{
181  // @Override
182  // public LocalDateTime apply(LocalDateTime t) {
183  // int hour = t.getHour();
184  // hour /= 4;
185  //
186  // t = t.withHour(hour);
187  // t = t.truncatedTo(ChronoUnit.SECONDS);
188  // return t;
189  // }
190  // })
191  ;
192 
193  private String sqlToken;
194  Function<LocalDateTime, LocalDateTime> trunc;
195 
196  private DateTruncUnit(String token, Function<LocalDateTime, LocalDateTime> trunc) {
197  this.sqlToken = token;
198  this.trunc = trunc;
199  }
200  }
201  ;
202 
203  static enum DateExtractUnit {
204  daYEAR("YEAR", new Function<LocalDateTime, Long>() {
205  public Long apply(LocalDateTime t) {
206  return (long) t.get(ChronoField.YEAR);
207  }
208  }),
209  daQUARTER("QUARTER", new Function<LocalDateTime, Long>() {
210  @Override
211  public Long apply(LocalDateTime t) {
212  int month = t.get(ChronoField.MONTH_OF_YEAR);
213  switch (month) {
214  case 1:
215  case 2:
216  case 3:
217  return 1l;
218  case 4:
219  case 5:
220  case 6:
221  return 2l;
222  case 7:
223  case 8:
224  case 9:
225  return 3l;
226  case 10:
227  case 11:
228  case 12:
229  return 4l;
230  }
231  return -1l;
232  }
233  }),
234  daMONTH("MONTH", new Function<LocalDateTime, Long>() {
235  @Override
236  public Long apply(LocalDateTime t) {
237  return (long) t.get(ChronoField.MONTH_OF_YEAR);
238  }
239  }),
240  daDAY("DAY", new Function<LocalDateTime, Long>() {
241  @Override
242  public Long apply(LocalDateTime t) {
243  return (long) t.get(ChronoField.DAY_OF_MONTH);
244  }
245  }),
246  daHOUR("HOUR", new Function<LocalDateTime, Long>() {
247  @Override
248  public Long apply(LocalDateTime t) {
249  return (long) t.get(ChronoField.HOUR_OF_DAY);
250  }
251  }),
252  daMINUTE("MINUTE", new Function<LocalDateTime, Long>() {
253  @Override
254  public Long apply(LocalDateTime t) {
255  return (long) t.get(ChronoField.MINUTE_OF_HOUR);
256  }
257  }),
258  daSECOND("SECOND", new Function<LocalDateTime, Long>() {
259  @Override
260  public Long apply(LocalDateTime t) {
261  return (long) t.get(ChronoField.SECOND_OF_MINUTE);
262  }
263  }),
264  // daMILLENNIUM("MILLENNIUM", ChronoField.YEAR, 1000),
265  // daCENTURY("CENTURY", ChronoField.YEAR, 100),
266  // daDECADE("DECADE", ChronoField.YEAR, 10),
267  daMILLISECOND("MILLISECOND", new Function<LocalDateTime, Long>() {
268  @Override
269  public Long apply(LocalDateTime t) {
270  return t.get(ChronoField.MILLI_OF_SECOND)
271  + (1000L * t.get(ChronoField.SECOND_OF_MINUTE));
272  }
273  }),
274  daMICROSECOND("MICROSECOND", new Function<LocalDateTime, Long>() {
275  @Override
276  public Long apply(LocalDateTime t) {
277  return t.get(ChronoField.MICRO_OF_SECOND)
278  + (1000_000L * t.get(ChronoField.SECOND_OF_MINUTE));
279  }
280  }),
281  daNANOSECOND("NANOSECOND", new Function<LocalDateTime, Long>() {
282  @Override
283  public Long apply(LocalDateTime t) {
284  return t.get(ChronoField.NANO_OF_SECOND)
285  + (1000_000_000L * t.get(ChronoField.SECOND_OF_MINUTE));
286  }
287  }),
288  daWEEK("WEEK", new Function<LocalDateTime, Long>() {
289  @Override
290  public Long apply(LocalDateTime t) {
291  LocalDateTime year = DateTruncUnit.dtYEAR.trunc.apply(t);
292  // bring it to the 4th of Jan (as this is always in the first week of the year)
293  year = year.plusDays(3);
294 
295  // compute the start day of that week (the Monday)
296  LocalDateTime week = DateTruncUnit.dtWEEK.trunc.apply(year);
297 
298  if (week.compareTo(t) > 0) {
299  year = year.minusYears(1);
300  week = DateTruncUnit.dtWEEK.trunc.apply(year);
301  }
302 
303  int weeks = 0;
304  while (week.compareTo(t) <= 0) {
305  weeks++;
306  week = week.plusWeeks(1);
307  }
308 
309  return (long) weeks;
310  }
311  }),
312  // daQUARTERDAY("QUERTERDAY", new Function<LocalDateTime, Integer>() {
313  // @Override
314  // public Integer apply(LocalDateTime t) {
315  // return ((t.get(ChronoField.HOUR_OF_DAY) -1 ) / 4) + 1;
316  // }
317  // }),
318  // daWEEKDAY("WEEKDAYS", new Function<LocalDateTime, Integer>() {
319  // @Override
320  // public Integer apply(LocalDateTime t) {
321  // return t.get(ChronoField.DAY_OF_WEEK);
322  // }
323  // }),
324  daDAYOFYEAR("DOY", new Function<LocalDateTime, Long>() {
325  @Override
326  public Long apply(LocalDateTime t) {
327  return (long) t.get(ChronoField.DAY_OF_YEAR);
328  }
329  });
330 
331  private String sqlToken;
332  private Function<LocalDateTime, Long> extract;
333 
334  private DateExtractUnit(String token, Function<LocalDateTime, Long> f) {
335  this.sqlToken = token;
336  this.extract = f;
337  }
338  }
339  ;
340 
341  static enum DateDiffUnit {
342  daYEAR("YEAR", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
343  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
344  return d.getFirst().until(d.getSecond(), ChronoUnit.YEARS);
345  }
346  }),
347  daQUARTER("QUARTER", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
348  private Long applyCorrect(Pair<LocalDateTime, LocalDateTime> d) {
349  LocalDateTime start = d.getFirst();
350  LocalDateTime end = d.getSecond();
351 
352  int delta = 1;
353  if (start.compareTo(end) > 0) {
354  delta = -1;
355  start = end;
356  end = d.getFirst();
357  }
358 
359  start = DateTruncUnit.dtQUARTER.trunc.apply(start);
360  // end = DateTruncUnit.dtQUARTER.trunc.apply(end);
361  long rc = 0;
362 
363  while (start.compareTo(end) <= 0) {
364  rc += delta;
365  start = start.plusMonths(3);
366  }
367 
368  return rc;
369  }
370 
371  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
372  // this seems to be what mysql does
373  return d.getFirst().until(d.getSecond(), ChronoUnit.MONTHS) / 3;
374  }
375  }),
376  daMONTH("MONTH", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
377  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
378  return d.getFirst().until(d.getSecond(), ChronoUnit.MONTHS);
379  }
380  }),
381  daDAY("DAY", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
382  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
383  return d.getFirst().until(d.getSecond(), ChronoUnit.DAYS);
384  }
385  }),
386  daHOUR("HOUR", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
387  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
388  return d.getFirst().until(d.getSecond(), ChronoUnit.HOURS);
389  }
390  }),
391  daMINUTE("MINUTE", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
392  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
393  return d.getFirst().until(d.getSecond(), ChronoUnit.MINUTES);
394  }
395  }),
396  daSECOND("SECOND", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
397  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
398  return d.getFirst().until(d.getSecond(), ChronoUnit.SECONDS);
399  }
400  }),
401  // daMILLENNIUM("MILLENNIUM", ChronoField.YEAR, 1000),
402  // daCENTURY("CENTURY", ChronoField.YEAR, 100),
403  // daDECADE("DECADE", ChronoField.YEAR, 10),
405  "MILLISECOND", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
406  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
407  return d.getFirst().until(d.getSecond(), ChronoUnit.MILLIS);
408  }
409  }),
411  "MICROSECOND", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
412  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
413  return d.getFirst().until(d.getSecond(), ChronoUnit.MICROS);
414  }
415  }),
416  daNANOSECOND("NANOSECOND", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
417  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
418  return d.getFirst().until(d.getSecond(), ChronoUnit.NANOS);
419  }
420  }),
421  daWEEK("WEEK", new Function<Pair<LocalDateTime, LocalDateTime>, Long>() {
422  public Long apply(Pair<LocalDateTime, LocalDateTime> d) {
423  return d.getFirst().until(d.getSecond(), ChronoUnit.WEEKS);
424  }
425  }),
426  // daQUARTERDAY("QUERTERDAY", new Function<LocalDateTime, Integer>() {
427  // @Override
428  // public Integer apply(LocalDateTime t) {
429  // return ((t.get(ChronoField.HOUR_OF_DAY) -1 ) / 4) + 1;
430  // }
431  // }),
432  // daWEEKDAY("WEEKDAYS", new Function<LocalDateTime, Integer>() {
433  // @Override
434  // public Integer apply(LocalDateTime t) {
435  // return t.get(ChronoField.DAY_OF_WEEK);
436  // }
437  // }),
438  ;
439 
440  private String sqlToken;
441  private Function<Pair<LocalDateTime, LocalDateTime>, Long> diff;
442 
443  private DateDiffUnit(
444  String token, Function<Pair<LocalDateTime, LocalDateTime>, Long> diff) {
445  this.sqlToken = token;
446  this.diff = diff;
447  }
448  }
449  ;
450 
451  static enum DateAddUnit {
452  daYEAR("YEAR", 99, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
453  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
454  return t.getFirst().plus(t.getSecond(), ChronoUnit.YEARS);
455  }
456  }),
458  "QUARTER", 10 * 3, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
459  @Override
460  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
461  return t.getFirst().plus(t.getSecond() * 3, ChronoUnit.MONTHS);
462  }
463  }),
464  daMONTH("MONTH", 99, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
465  @Override
466  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
467  return t.getFirst().plus(t.getSecond(), ChronoUnit.MONTHS);
468  }
469  }),
470  daDAY("DAY", 99, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
471  @Override
472  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
473  return t.getFirst().plus(t.getSecond(), ChronoUnit.DAYS);
474  }
475  }),
476  daHOUR("HOUR", 99, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
477  @Override
478  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
479  return t.getFirst().plus(t.getSecond(), ChronoUnit.HOURS);
480  }
481  }),
482  daMINUTE("MINUTE", 99, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
483  @Override
484  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
485  return t.getFirst().plus(t.getSecond(), ChronoUnit.MINUTES);
486  }
487  }),
488  daSECOND("SECOND", 99, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
489  @Override
490  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
491  return t.getFirst().plus(t.getSecond(), ChronoUnit.SECONDS);
492  }
493  }),
494  // daMILLENNIUM("MILLENNIUM", ChronoField.YEAR, 1000),
495  // daCENTURY("CENTURY", ChronoField.YEAR, 100),
496  // daDECADE("DECADE", ChronoField.YEAR, 10),
497  daMILLISECOND("MILLISECOND",
498  12 * 30 * 24 * 60 * 60 * 1000L,
499  new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
500  @Override
501  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
502  return t.getFirst().plus(t.getSecond(), ChronoUnit.MILLIS);
503  }
504  }),
505  daMICROSECOND("MICROSECOND",
506  12 * 30 * 24 * 60 * 60 * 1000 * 1000,
507  new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
508  @Override
509  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
510  return t.getFirst().plus(t.getSecond(), ChronoUnit.MICROS);
511  }
512  }),
513  daNANOSECOND("NANOSECOND",
514  12 * 30 * 24 * 60 * 60 * 1000 * 1000 * 1000,
515  new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
516  @Override
517  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
518  return t.getFirst().plus(t.getSecond(), ChronoUnit.NANOS);
519  }
520  }),
521  daWEEK("WEEK", 53, new Function<Pair<LocalDateTime, Long>, LocalDateTime>() {
522  @Override
523  public LocalDateTime apply(Pair<LocalDateTime, Long> t) {
524  return t.getFirst().plus(t.getSecond(), ChronoUnit.WEEKS);
525  }
526  }),
527  // daQUARTERDAY("QUERTERDAY", new Function<LocalDateTime, Integer>() {
528  // @Override
529  // public Integer apply(LocalDateTime t) {
530  // return ((t.get(ChronoField.HOUR_OF_DAY) -1 ) / 4) + 1;
531  // }
532  // }),
533  // daWEEKDAY("WEEKDAYS", new Function<LocalDateTime, Integer>() {
534  // @Override
535  // public Integer apply(LocalDateTime t) {
536  // return t.get(ChronoField.DAY_OF_WEEK);
537  // }
538  // }),
539  ;
540 
541  private String sqlToken;
542  private Function<Pair<LocalDateTime, Long>, LocalDateTime> add;
543  private long max;
544 
545  private DateAddUnit(String token,
546  long max,
547  Function<Pair<LocalDateTime, Long>, LocalDateTime> f) {
548  this.sqlToken = token;
549  this.max = max;
550  this.add = f;
551  }
552  }
553  ;
554 
555  static LocalDateTime createRandomDateTime(Random r) {
556  try {
557  int year = 1900 + r.nextInt(200);
558  int month = 1 + r.nextInt(12);
559  int dayOfMonth = 1 + r.nextInt(31);
560  int hour = r.nextInt(24);
561  int minute = r.nextInt(60);
562  int second = r.nextInt(60);
563  int nanoOfSecond = r.nextInt(1000 * 1000 * 1000);
564 
565  return LocalDateTime.of(
566  year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
567  } catch (Exception e) {
568  return createRandomDateTime(r);
569  }
570  }
571 
572  static enum Encoding {
573  TIMESTAMP("TIMESTAMP",
574  "'TIMESTAMP' ''yyyy-MM-dd HH:mm:ss''",
575  ChronoUnit.SECONDS,
576  LocalDateTime.ofEpochSecond(-30610224000L, 0, ZoneOffset.UTC),
577  LocalDateTime.ofEpochSecond(29379542399L, 0, ZoneOffset.UTC)),
578  TIMESTAMP_0("TIMESTAMP(0)",
579  "'TIMESTAMP(0)' ''yyyy-MM-dd HH:mm:ss''",
580  ChronoUnit.SECONDS,
581  LocalDateTime.ofEpochSecond(-30610224000L, 0, ZoneOffset.UTC),
582  LocalDateTime.ofEpochSecond(29379542399L, 0, ZoneOffset.UTC)),
583  TIMESTAMP_3("TIMESTAMP(3)",
584  "'TIMESTAMP(3)' ''yyyy-MM-dd HH:mm:ss.SSS''",
585  ChronoUnit.MILLIS,
586  LocalDateTime.ofEpochSecond(-30610224000L, 0, ZoneOffset.UTC),
587  LocalDateTime.ofEpochSecond(29379542399L, 0, ZoneOffset.UTC)),
588  TIMESTAMP_6("TIMESTAMP(6)",
589  "'TIMESTAMP(6)' ''yyyy-MM-dd HH:mm:ss.SSSSSS''",
590  ChronoUnit.MICROS,
591  LocalDateTime.ofEpochSecond(-30610224000L, 0, ZoneOffset.UTC),
592  LocalDateTime.ofEpochSecond(29379542399L, 0, ZoneOffset.UTC)),
593  TIMESTAMP_9("TIMESTAMP(9)",
594  "'TIMESTAMP(9)' ''yyyy-MM-dd HH:mm:ss.SSSSSSSSS''",
595  ChronoUnit.NANOS,
596  LocalDateTime.ofEpochSecond(-9223372036L, 0, ZoneOffset.UTC),
597  LocalDateTime.ofEpochSecond(9223372036L, 0, ZoneOffset.UTC)),
598  TIMESTAMP_FIXED_32("TIMESTAMP ENCODING FIXED(32)",
599  "'TIMESTAMP' ''yyyy-MM-dd HH:mm:ss''",
600  ChronoUnit.SECONDS,
601  LocalDateTime.ofEpochSecond(Integer.MIN_VALUE + 1, 0, ZoneOffset.UTC),
602  LocalDateTime.ofEpochSecond(Integer.MAX_VALUE, 0, ZoneOffset.UTC)),
603  DATE("DATE",
604  "'DATE' ''yyyy-MM-dd''",
605  ChronoUnit.DAYS,
606  LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC).plusDays(-2147483648L),
607  LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC).plusDays(2147483647L)),
608  DATE_DAYS_16("DATE ENCODING DAYS(16)",
609  "'DATE' ''yyyy-MM-dd''",
610  ChronoUnit.DAYS,
611  LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC)
612  .plusDays(Short.MIN_VALUE + 1),
613  LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC).plusDays(Short.MAX_VALUE)),
614  DATE_DAYS_32("DATE ENCODING DAYS(32)",
615  "'DATE' ''yyyy-MM-dd''",
616  ChronoUnit.DAYS,
617  LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC).plusDays(-2147483648L),
618  LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC).plusDays(2147483647L));
619 
620  DateTimeFormatter formatter;
621  String sqlType;
622  ChronoUnit toClear;
623  LocalDateTime min;
624  LocalDateTime max;
625 
626  Encoding(String sqlType,
627  String pattern,
628  ChronoUnit unit,
629  LocalDateTime min,
630  LocalDateTime max) {
631  this.sqlType = sqlType;
632  formatter = DateTimeFormatter.ofPattern(pattern);
633  this.toClear = unit;
634  this.min = min;
635  this.max = max;
636  }
637 
638  public String toSqlColumn(String prefx, LocalDateTime val) {
639  if (null != val) return prefx + "_" + name() + " /* " + toSql(val) + " */";
640  return prefx + "_" + name();
641  }
642 
643  public String toSql(LocalDateTime d) {
644  return formatter.format(d);
645  }
646 
647  public LocalDateTime clear(LocalDateTime d) {
648  if (null != toClear) {
649  d = d.truncatedTo(toClear);
650  }
651 
652  return d;
653  }
654 
655  public LocalDateTime clearForDateAddResult(LocalDateTime d) {
656  if (null != toClear) {
657  if (toClear == ChronoUnit.DAYS) {
658  d = d.truncatedTo(ChronoUnit.SECONDS);
659  } else {
660  d = d.truncatedTo(toClear);
661  }
662  }
663 
664  return d;
665  }
666 
667  public boolean isValid(LocalDateTime t) {
668  return t.isAfter(min) && t.isBefore(max);
669  }
670  }
671 
672  static LocalDateTime getDateTimeFromQuery(MapdTestClient client, String sql)
673  throws Exception {
674  try {
675  com.omnisci.thrift.server.TQueryResult res = client.runSql(sql);
676  LocalDateTime r = null;
677  if (res.row_set.is_columnar) {
678  TTypeInfo tt = res.row_set.row_desc.get(0).col_type;
679  int pow = (int) Math.pow(10, tt.precision);
680  long val = res.row_set.columns.get(0).data.int_col.get(0);
681  int nanosPow = (int) Math.pow(10, 9 - tt.precision);
682  long nanos = (val % pow);
683  if (nanos < 0) {
684  nanos = pow + nanos;
685  }
686  nanos *= nanosPow;
687  r = LocalDateTime.ofEpochSecond(
688  Math.floorDiv(val, pow), (int) nanos, ZoneOffset.UTC);
689 
690  } else {
691  throw new RuntimeException("Unsupported!");
692  }
693 
694  return r;
695  } catch (TOmniSciException e) {
696  System.out.println("Query failed: " + sql + " -- " + e.error_msg);
697  return LocalDateTime.MIN;
698 
699  } catch (Exception e) {
700  System.out.println("Query failed: " + sql + " -- " + e.getMessage());
701  return LocalDateTime.MIN;
702  }
703  }
704 
705  static long getLongFromQuery(MapdTestClient client, String sql) throws Exception {
706  try {
707  com.omnisci.thrift.server.TQueryResult res = client.runSql(sql);
708  long r = -1;
709  if (res.row_set.is_columnar) {
710  long val = res.row_set.columns.get(0).data.int_col.get(0);
711  r = val;
712  } else {
713  throw new RuntimeException("Unsupported!");
714  }
715  return r;
716  } catch (TOmniSciException e) {
717  System.out.println("Query failed: " + sql + " -- " + e.error_msg);
718  return Long.MIN_VALUE;
719  } catch (Exception e) {
720  System.out.println("Query failed: " + sql + " -- " + e.getMessage());
721  return Long.MIN_VALUE;
722  }
723  }
724 
725  public static LocalDateTime testDateTrunc(
726  LocalDateTime d, DateTruncUnit f, MapdTestClient client, Encoding enc)
727  throws Exception {
728  if (!enc.isValid(d)) {
729  return d;
730  }
731 
732  String sql = "SELECT DATE_TRUNC('" + f.sqlToken + "', " + enc.toSql(d) + ");";
733  LocalDateTime r = getDateTimeFromQuery(client, sql);
734  LocalDateTime expected = f.trunc.apply(d);
735  expected = enc.clear(expected);
736 
737  Fuzzy rc = Fuzzy.compare(expected, r, enc);
738  if (resultsToDump.contains(rc)) {
739  System.out.println("Query " + rc + ": " + sql
740  + " -> expected: " + expected.toString() + " got " + r.toString());
741  }
742 
743  return testDateTruncTable(d, f, client, enc);
744  }
745 
746  private static void updateValues(MapdTestClient client, LocalDateTime a, Encoding aEnc)
747  throws Exception {
748  updateValues(client, a, aEnc, null, null);
749  }
750 
751  private static void updateValues(MapdTestClient client,
752  LocalDateTime a,
753  Encoding aEnc,
754  LocalDateTime b,
755  Encoding bEnc) throws Exception {
756  String sqlUpdate = "UPDATE DateTimeTest set " + aEnc.toSqlColumn("a", null) + " = "
757  + aEnc.toSql(a);
758 
759  if (null != b) {
760  sqlUpdate += ", " + bEnc.toSqlColumn("b", null) + " = " + bEnc.toSql(b);
761  }
762 
763  sqlUpdate += ";";
764 
765  try {
766  client.runSql(sqlUpdate);
767  } catch (TOmniSciException e) {
768  System.out.println("Update failed: " + sqlUpdate + " " + e.error_msg);
769  }
770  }
771 
772  public static LocalDateTime testDateTruncTable(
773  LocalDateTime d, DateTruncUnit f, MapdTestClient client, Encoding enc)
774  throws Exception {
775  updateValues(client, d, enc);
776  String sql = "SELECT DATE_TRUNC('" + f.sqlToken + "', " + enc.toSqlColumn("a", d)
777  + ") FROM DateTimeTest;";
778  LocalDateTime r = getDateTimeFromQuery(client, sql);
779  LocalDateTime expected = f.trunc.apply(d);
780  expected = enc.clear(expected);
781 
782  Fuzzy rc = Fuzzy.compare(expected, r, enc);
783  if (resultsToDump.contains(rc)) {
784  System.out.println("Query " + rc + ": " + sql
785  + " -> expected: " + expected.toString() + " got " + r.toString());
786  }
787 
788  return expected;
789  }
790 
791  public static void testDateExtract(
792  LocalDateTime d, DateExtractUnit f, MapdTestClient client, Encoding enc)
793  throws Exception {
794  String sql = "SELECT EXTRACT(" + f.sqlToken + " FROM " + enc.toSql(d) + ");";
795  long r = getLongFromQuery(client, sql);
796 
797  d = enc.clear(d);
798  long expected = f.extract.apply(d);
799 
800  Fuzzy rc = Fuzzy.compare(expected, r);
801  if (resultsToDump.contains(rc)) {
802  System.out.println(
803  "Query " + rc + ": " + sql + " -> expected: " + expected + " got " + r);
804  }
805 
806  testDateExtractTable(d, f, client, enc);
807  }
808 
809  public static void testDateExtractTable(
810  LocalDateTime d, DateExtractUnit f, MapdTestClient client, Encoding enc)
811  throws Exception {
812  if (!enc.isValid(d)) {
813  return;
814  }
815 
816  updateValues(client, d, enc);
817  String sql = "SELECT EXTRACT(" + f.sqlToken + " FROM " + enc.toSqlColumn("a", d)
818  + ") FROM DateTimeTest;";
819  long r = getLongFromQuery(client, sql);
820 
821  d = enc.clear(d);
822  long expected = f.extract.apply(d);
823 
824  Fuzzy rc = Fuzzy.compare(expected, r);
825  if (resultsToDump.contains(rc)) {
826  System.out.println(
827  "Query " + rc + ": " + sql + " -> expected: " + expected + " got " + r);
828  }
829  }
830 
831  public static void testDiff(String fn,
832  LocalDateTime d0,
833  LocalDateTime d1,
834  DateDiffUnit f,
835  MapdTestClient client,
836  Encoding enc0,
837  Encoding enc1) throws Exception {
838  String sql = "SELECT " + fn + "(" + f.sqlToken + ", " + enc0.toSql(d0) + ", "
839  + enc1.toSql(d1) + ");";
840  long r = getLongFromQuery(client, sql);
841  d0 = enc0.clear(d0);
842  d1 = enc1.clear(d1);
843 
844  long expected = f.diff.apply(Pair.create(d0, d1));
845 
846  Fuzzy rc = Fuzzy.compare(expected, r);
847  if (resultsToDump.contains(rc)) {
848  System.out.println(
849  "Query " + rc + ": " + sql + " -> expected: " + expected + " got " + r);
850  }
851 
852  testDiffTable(fn, d0, d1, f, client, enc0, enc1);
853  }
854 
855  public static void testDiffTable(String fn,
856  LocalDateTime d0,
857  LocalDateTime d1,
858  DateDiffUnit f,
859  MapdTestClient client,
860  Encoding enc0,
861  Encoding enc1) throws Exception {
862  if (!enc0.isValid(d0) || !enc1.isValid(d1)) {
863  return;
864  }
865 
866  updateValues(client, d0, enc0, d1, enc1);
867  String sql = "SELECT " + fn + "(" + f.sqlToken + ", " + enc0.toSqlColumn("a", d0)
868  + ", " + enc1.toSqlColumn("b", d1) + ") FROM DateTimeTest;";
869  long r = getLongFromQuery(client, sql);
870  d0 = enc0.clear(d0);
871  d1 = enc1.clear(d1);
872 
873  long expected = f.diff.apply(Pair.create(d0, d1));
874 
875  Fuzzy rc = Fuzzy.compare(expected, r);
876  if (resultsToDump.contains(rc)) {
877  System.out.println(
878  "Query " + rc + ": " + sql + " -> expected: " + expected + " got " + r);
879  }
880  }
881 
882  public static void testDateAdd(String fn,
883  LocalDateTime d,
884  DateAddUnit f,
885  long units,
886  MapdTestClient client,
887  Encoding enc) throws Exception {
888  String sql =
889  "SELECT " + fn + "(" + f.sqlToken + ", " + units + ", " + enc.toSql(d) + ");";
890  LocalDateTime r = getDateTimeFromQuery(client, sql);
891 
892  LocalDateTime expected = f.add.apply(Pair.create(enc.clear(d), units));
893  expected = enc.clearForDateAddResult(expected);
894 
895  Fuzzy rc = Fuzzy.compareDateAdd(expected, r, enc);
896  if (resultsToDump.contains(rc)) {
897  System.out.println("Query " + rc + ": " + sql
898  + " -> expected: " + expected.toString() + " got " + r.toString());
899  }
900 
901  testDateAddTable(fn, d, f, units, client, enc);
902  }
903 
904  public static void testDateAddTable(String fn,
905  LocalDateTime d,
906  DateAddUnit f,
907  long units,
908  MapdTestClient client,
909  Encoding enc) throws Exception {
910  if (!enc.isValid(d)) {
911  return;
912  }
913 
914  updateValues(client, d, enc);
915  String sql = "SELECT " + fn + "(" + f.sqlToken + ", " + units + ", "
916  + enc.toSqlColumn("a", d) + ") FROM DateTimeTest;";
917  LocalDateTime r = getDateTimeFromQuery(client, sql);
918 
919  LocalDateTime expected = f.add.apply(Pair.create(enc.clear(d), units));
920  expected = enc.clearForDateAddResult(expected);
921 
922  Fuzzy rc = Fuzzy.compareDateAdd(expected, r, enc);
923  if (resultsToDump.contains(rc)) {
924  System.out.println("Query " + rc + ": " + sql
925  + " -> expected: " + expected.toString() + " got " + r.toString());
926  }
927  }
928 
929  static EnumSet resultsToDump = EnumSet.of(Fuzzy.failed, Fuzzy.okish);
930 
931  static EnumSet addAllowed = EnumSet.allOf(DateAddUnit.class);
932 
933  static {
934  addAllowed.remove(DateAddUnit.daQUARTER);
935  addAllowed.remove(DateAddUnit.daMILLISECOND);
936  addAllowed.remove(DateAddUnit.daMICROSECOND);
937  addAllowed.remove(DateAddUnit.daNANOSECOND);
938  addAllowed.remove(DateAddUnit.daWEEK);
939  }
940 
941  public static void testAdd(
942  LocalDateTime d, DateAddUnit f, long units, MapdTestClient client, Encoding enc)
943  throws Exception {
944  if (!addAllowed.contains(f)) {
945  return;
946  }
947 
948  String sql =
949  "SELECT " + enc.toSql(d) + " + INTERVAL '" + units + "' " + f.sqlToken + " ;";
950  LocalDateTime r = getDateTimeFromQuery(client, sql);
951 
952  LocalDateTime expected = f.add.apply(Pair.create(enc.clear(d), units));
953  expected = enc.clearForDateAddResult(expected);
954 
955  Fuzzy rc = Fuzzy.compareDateAdd(expected, r, enc);
956  if (resultsToDump.contains(rc)) {
957  System.out.println("Query " + rc + ": " + sql
958  + " -> expected: " + expected.toString() + " got " + r.toString());
959  }
960  }
961 
962  public static void testSub(
963  LocalDateTime d, DateAddUnit f, long units, MapdTestClient client, Encoding enc)
964  throws Exception {
965  if (!addAllowed.contains(f)) {
966  return;
967  }
968 
969  long toSub = -units;
970 
971  String sql =
972  "SELECT " + enc.toSql(d) + " - INTERVAL '" + toSub + "' " + f.sqlToken + " ;";
973  LocalDateTime r = getDateTimeFromQuery(client, sql);
974 
975  LocalDateTime expected = f.add.apply(Pair.create(enc.clear(d), units));
976  expected = enc.clearForDateAddResult(expected);
977 
978  Fuzzy rc = Fuzzy.compareDateAdd(expected, r, enc);
979  if (resultsToDump.contains(rc)) {
980  System.out.println("Query " + rc + ": " + sql
981  + " -> expected: " + expected.toString() + " got " + r.toString());
982  }
983  }
984 
985  static enum Fuzzy {
986  ok,
989 
990  static Fuzzy compare(LocalDateTime expected, LocalDateTime result, Encoding enc) {
991  if (expected.equals(result)) return ok;
992 
993  LocalDateTime okish = result.minus(1, ChronoUnit.NANOS);
994  okish = enc.clear(okish);
995 
996  if (expected.equals(okish)) return Fuzzy.okish;
997 
998  okish = result.plus(1, ChronoUnit.NANOS);
999  okish = enc.clear(okish);
1000 
1001  if (expected.equals(okish)) return Fuzzy.okish;
1002 
1003  return failed;
1004  }
1005 
1006  static Fuzzy compare(long expected, long result) {
1007  if (expected == result) return ok;
1008 
1009  long okish = result - 1;
1010 
1011  if (expected == okish) return Fuzzy.okish;
1012 
1013  okish = result + 1;
1014 
1015  if (expected == okish) return Fuzzy.okish;
1016 
1017  if ((result == 59 && expected == 0) || (result == 0 && expected == 59)) {
1018  // for minutes and seconds
1019  return Fuzzy.okish;
1020  }
1021 
1022  if ((result == 23 && expected == 0) || (result == 0 && expected == 23)) {
1023  // for hours
1024  return Fuzzy.okish;
1025  }
1026 
1027  return failed;
1028  }
1029 
1031  LocalDateTime expected, LocalDateTime result, Encoding enc) {
1032  if (expected.equals(result)) return ok;
1033 
1034  LocalDateTime okish = result.minus(1, ChronoUnit.NANOS);
1035  okish = enc.clearForDateAddResult(okish);
1036 
1037  if (expected.equals(okish)) return Fuzzy.okish;
1038 
1039  okish = result.plus(1, ChronoUnit.NANOS);
1040  okish = enc.clearForDateAddResult(okish);
1041 
1042  if (expected.equals(okish)) return Fuzzy.okish;
1043 
1044  return failed;
1045  }
1046  }
1047 
1048  public static void createTestTable(MapdTestClient client) throws Exception {
1049  client.runSql("DROP TABLE IF EXISTS DateTimeTest;");
1050  String sqlCreate = "CREATE TABLE DateTimeTest(id int";
1051  String sqlInsert = "INSERT INTO DateTimeTest VALUES(0";
1052  for (Encoding e : Encoding.values()) {
1053  sqlCreate += ", " + e.toSqlColumn("a", null) + " " + e.sqlType;
1054  sqlCreate += ", " + e.toSqlColumn("b", null) + " " + e.sqlType;
1055  sqlInsert += ", null, null";
1056  }
1057 
1058  sqlCreate += ");";
1059  sqlInsert += ");";
1060 
1061  client.runSql(sqlCreate);
1062  client.runSql(sqlInsert);
1063 
1064  System.out.println("CREATE: " + sqlCreate);
1065  System.out.println("INSERT: " + sqlInsert);
1066  }
1067 
1068  public static void main(String[] args) throws Exception {
1069  long seed;
1070 
1071  // to reproduce a previous run, use the same seed
1072  if (0 < args.length) {
1073  seed = Long.parseLong(args[0], 10);
1074  } else {
1075  seed = System.currentTimeMillis();
1076  }
1077 
1078  System.out.println("Seed: " + seed);
1079  Random r = new Random(seed);
1080 
1081  MapdTestClient su = MapdTestClient.getClient(
1082  "localhost", 6274, "omnisci", "admin", "HyperInteractive");
1083  LocalDateTime d0 = createRandomDateTime(r);
1084  LocalDateTime d1 = createRandomDateTime(r);
1085 
1086  createTestTable(su);
1087 
1088  // don't dump OK results
1089  resultsToDump = EnumSet.of(Fuzzy.failed, Fuzzy.okish);
1090  boolean testTrunc = true;
1091  boolean testExtract = true;
1092  boolean testDiff = true;
1093  boolean testAdd = true;
1094 
1095  if (testTrunc) {
1096  for (Encoding enc0 : Encoding.values()) {
1097  for (DateTruncUnit f : DateTruncUnit.values()) {
1098  LocalDateTime e = testDateTrunc(d0, f, su, enc0);
1099  e = e.minus(1, ChronoUnit.NANOS);
1100  testDateTrunc(e, f, su, enc0);
1101  e = testDateTrunc(d1, f, su, enc0);
1102  e = e.minus(1, ChronoUnit.NANOS);
1103  testDateTrunc(e, f, su, enc0);
1104  }
1105  }
1106  }
1107 
1108  if (testExtract) {
1109  for (Encoding enc0 : Encoding.values()) {
1110  for (DateExtractUnit f : DateExtractUnit.values()) {
1111  testDateExtract(d0, f, su, enc0);
1112  testDateExtract(d0.minusNanos(1), f, su, enc0);
1113  testDateExtract(d0.plusNanos(1), f, su, enc0);
1114  testDateExtract(d1, f, su, enc0);
1115  testDateExtract(d1.minusNanos(1), f, su, enc0);
1116  testDateExtract(d1.plusNanos(1), f, su, enc0);
1117  }
1118  }
1119  }
1120 
1121  if (testDiff) {
1122  for (Encoding enc0 : Encoding.values()) {
1123  for (Encoding enc1 : Encoding.values()) {
1124  for (DateDiffUnit f : DateDiffUnit.values()) {
1125  for (String fn : Arrays.asList("TIMESTAMPDIFF" /* , "DATEDIFF" */)) {
1126  testDiff(fn, d0, d1, f, su, enc0, enc1);
1127  testDiff(fn, d1, d0, f, su, enc0, enc1);
1128  testDiff(fn, d0, d0, f, su, enc0, enc1);
1129  testDiff(fn, d1, d1, f, su, enc0, enc1);
1130  }
1131  }
1132  }
1133  }
1134  }
1135 
1136  if (testAdd) {
1137  for (DateAddUnit f : DateAddUnit.values()) {
1138  long units = r.nextLong() % f.max;
1139  if (r.nextBoolean()) {
1140  units *= -1L;
1141  }
1142  for (Encoding enc0 : Encoding.values()) {
1143  for (String fn : Arrays.asList("TIMESTAMPADD", "DATEADD")) {
1144  testDateAdd(fn, d0, f, units, su, enc0);
1145  testDateAdd(fn, d1, f, units, su, enc0);
1146  }
1147  testAdd(d0, f, units, su, enc0);
1148  testSub(d0, f, units, su, enc0);
1149  testAdd(d1, f, units, su, enc0);
1150  testSub(d1, f, units, su, enc0);
1151  }
1152  }
1153  }
1154  }
1155 }
static LocalDateTime createRandomDateTime(Random r)
DateTruncUnit(String token, Function< LocalDateTime, LocalDateTime > trunc)
static void testDiffTable(String fn, LocalDateTime d0, LocalDateTime d1, DateDiffUnit f, MapdTestClient client, Encoding enc0, Encoding enc1)
String toSqlColumn(String prefx, LocalDateTime val)
static void testDateExtract(LocalDateTime d, DateExtractUnit f, MapdTestClient client, Encoding enc)
DateAddUnit(String token, long max, Function< Pair< LocalDateTime, Long >, LocalDateTime > f)
static void updateValues(MapdTestClient client, LocalDateTime a, Encoding aEnc)
static Fuzzy compare(LocalDateTime expected, LocalDateTime result, Encoding enc)
static void testDateAddTable(String fn, LocalDateTime d, DateAddUnit f, long units, MapdTestClient client, Encoding enc)
static void testDateExtractTable(LocalDateTime d, DateExtractUnit f, MapdTestClient client, Encoding enc)
static void testDiff(String fn, LocalDateTime d0, LocalDateTime d1, DateDiffUnit f, MapdTestClient client, Encoding enc0, Encoding enc1)
static Fuzzy compare(long expected, long result)
static Fuzzy compareDateAdd(LocalDateTime expected, LocalDateTime result, Encoding enc)
Definition: DateAdd.h:47
Function< LocalDateTime, LocalDateTime > trunc
DateExtractUnit(String token, Function< LocalDateTime, Long > f)
static void updateValues(MapdTestClient client, LocalDateTime a, Encoding aEnc, LocalDateTime b, Encoding bEnc)
Definition: DateAdd.h:43
Function< Pair< LocalDateTime, LocalDateTime >, Long > diff
Encoding(String sqlType, String pattern, ChronoUnit unit, LocalDateTime min, LocalDateTime max)
Definition: DateAdd.h:56
static void testDateAdd(String fn, LocalDateTime d, DateAddUnit f, long units, MapdTestClient client, Encoding enc)
static void main(String[] args)
DateDiffUnit(String token, Function< Pair< LocalDateTime, LocalDateTime >, Long > diff)
static void testAdd(LocalDateTime d, DateAddUnit f, long units, MapdTestClient client, Encoding enc)
Function< Pair< LocalDateTime, Long >, LocalDateTime > add
Function< LocalDateTime, Long > extract
static LocalDateTime getDateTimeFromQuery(MapdTestClient client, String sql)
static LocalDateTime testDateTrunc(LocalDateTime d, DateTruncUnit f, MapdTestClient client, Encoding enc)
LocalDateTime clearForDateAddResult(LocalDateTime d)
Definition: DateAdd.h:46
static void createTestTable(MapdTestClient client)
static long getLongFromQuery(MapdTestClient client, String sql)
string name
Definition: setup.py:35
LocalDateTime clear(LocalDateTime d)
boolean isValid(LocalDateTime t)
static void testSub(LocalDateTime d, DateAddUnit f, long units, MapdTestClient client, Encoding enc)
static LocalDateTime testDateTruncTable(LocalDateTime d, DateTruncUnit f, MapdTestClient client, Encoding enc)