-
Notifications
You must be signed in to change notification settings - Fork 10
/
Type.hpp
510 lines (465 loc) · 18.5 KB
/
Type.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#ifndef QUICKSTEP_TYPES_TYPE_HPP_
#define QUICKSTEP_TYPES_TYPE_HPP_
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <string>
#include "types/Type.pb.h"
#include "types/TypeID.hpp"
#include "types/TypedValue.hpp"
#include "utility/Macros.hpp"
#include "glog/logging.h"
namespace quickstep {
struct DateLit;
struct DatetimeIntervalLit;
struct DatetimeLit;
struct YearMonthIntervalLit;
/** \addtogroup Types
* @{
*/
// TODO(chasseur) Adding a new Type and wiring it up in all the right places is
// a complicated process, as evidenced by the steps outlined below. A
// boilerplate template system to automate some of the process would be
// very desirable.
/**
* @brief A type in Quickstep's type system. Each exact concrete Type is a
* singleton.
*
* @note The following is a brief (and not very detailed) guide to adding a new
* Type to Quickstep:
* 1. Add a new TypeID and name for the Type in TypeID.hpp.
* 2. Add a new TypeID to Type.proto, and if necessary define any
* extensions needed to serialize/deserialize the Type.
* 3. Write a new subclass of Type to represent the Type. Concrete
* Types are Meyers-style singletons. See DatetimeType for a simple
* example of a Type that doesn't have any extra parameters, and
* see CharType for an example that has different instances for
* different lengths.
* 4. Modify TypeFactory so that it can instantiate and deserialize
* your Type.
* 5. Modify the SQL lexer (parser/SqlLexer.lpp) to add a token for
* your Type's name, and modify the SQL parser
* (parser/SqlParser.ypp) to add a case for your Type in the
* 'data_type' node.
* 6. Modify the SQL parser to parse literal values of your class as
* a ParseLiteralValue (there is WIP on string-parsing that will
* eliminate this requirement soon).
* 7. (OPTIONAL) If your new Type is fixed-length and values are 8
* bytes or less, you may want to modify TypedValue to store it
* inline. This is purely a performance optimization and is not
* necessary for correctness.
* 8. (OPTIONAL) If you want to be able to use existing operations from
* types/operations on your Type (e.g. if your type is "number-like"
* and you want to do arithmetic on it), modify the operations in
* question to take the new Type into account.
* 8.a. If you wish your new Type to be sortable or compressable, you
* should modify LessComparison (or the BasicComparison base
* class) to deal with it.
* 8.b. If you wish your new Type to be usable as a key in a HashTable,
* you should modify EqualComparison (or the BasicComparison base
* class) to deal with it. Note that the default hash function
* assumes that two values that have (some) differing bytes are
* never considered equal. If this is not the case, you must also
* modify TypedValue::getHash() to deal with your Type as a
* special case.
**/
class Type {
public:
/**
* @brief Categories of intermediate supertypes.
**/
enum SuperTypeID {
kNumeric = 0, // Fixed-length numeric types (Int, Long, Float, Double)
kAsciiString, // ASCII strings (Char, VarChar)
kOther // Others (Date, Datetime, DatetimeInterval, YearMonthInterval)
};
/**
* @brief Virtual destructor.
**/
virtual ~Type() {
}
/**
* @brief Generate a serialized Protocol Buffer representation of this Type.
*
* @return The serialized Protocol Buffer representation of this Type.
**/
virtual serialization::Type getProto() const;
/**
* @brief Determine what supertype this type belongs to.
*
* @return The ID of the supertype this type belongs to.
**/
inline SuperTypeID getSuperTypeID() const {
return super_type_id_;
}
/**
* @brief Determine the TypeID of this object.
*
* @return The ID of this type.
**/
inline TypeID getTypeID() const {
return type_id_;
}
/**
* @brief Determine whether this Type allows NULL values.
*
* @return Whether this Type allows NULLs.
**/
inline bool isNullable() const {
return nullable_;
}
/**
* @brief Get this Type's signature.
*
* @note The signature does not necessarily uniquely identify this Type. It
* merely provides some basic information for debugging that can be
* passed to TypedValue::isPlausibleInstanceOf().
*
* @return This Type's signature.
**/
inline TypeSignature getSignature() const {
TypeSignature sig;
sig.id = type_id_;
sig.nullable = nullable_;
switch (type_id_) {
case kChar:
sig.length = maximum_byte_length_;
break;
case kVarChar:
sig.length = maximum_byte_length_ - 1;
break;
default:
sig.length = 0;
}
return sig;
}
/**
* @brief Get a nullable (but otherwise identical) version of this type.
*
* @return This Type's nullable counterpart (or this Type itself if already
* nullable).
**/
virtual const Type& getNullableVersion() const = 0;
/**
* @brief Get a non-nullable (but otherwise identical) version of this type.
*
* @return This Type's non-nullable counterpart (or this Type itself if
* already non-nullable).
**/
virtual const Type& getNonNullableVersion() const = 0;
/**
* @brief Determine whether data items of this type have variable
* byte-length.
*
* @return Whether this is a variable-length type.
**/
inline bool isVariableLength() const {
return minimum_byte_length_ != maximum_byte_length_;
}
/**
* @brief Determine the minimum number of bytes used by data items of this
* type.
* @note If isVariableLength() is false, this is equivalent to
* maximumByteLength().
*
* @return The minimum number of bytes used by any data item of this type.
**/
inline std::size_t minimumByteLength() const {
return minimum_byte_length_;
}
/**
* @brief Determine the maximum number of bytes used by data items of this
* type.
* @note If isVariableLength() is false, this is equivalent to
* minimumByteLength().
*
* @return The maximum number of bytes used by any data item of this type.
**/
inline std::size_t maximumByteLength() const {
return maximum_byte_length_;
}
/**
* @brief Estimate the average number of bytes used by data items of this
* type. These estimates may be used in query planning and determining
* StorageBlock layout.
* @note If isVariableLength() is false, this is the same as
* minimumByteLength() and maximumByteLength().
*
* @return An estimate of the average number of bytes used by data items of
* this type.
**/
virtual std::size_t estimateAverageByteLength() const = 0;
/**
* @brief Determine whether this Type is exactly the same as another.
* @note Because all exact types are singletons, a simple pointer
* equality-check is usable here, but this method should be used in
* case this behavior might change in the future.
*
* @param other The Type to check for equality.
* @return Whether this Type and other are the same.
**/
bool equals(const Type &other) const {
return (this == &other);
}
/**
* @brief Determine whether data items of another Type can be converted to
* this type.
* @note This method only determines whether coercion is possible (truncation
* or loss of precision may still occur). To determine if coercion is
* possible without loss of precision, use isSafelyCoercibleFrom()
* instead.
* @note It is NOT possible to coerce a nullable type to a non-nullable type,
* even if coercion would otherwise be possible.
*
* @param original_type The original Type for coercion to this Type.
* @return true if coercion is supported, false otherwise.
**/
virtual bool isCoercibleFrom(const Type &original_type) const = 0;
/**
* @brief Determine whether data items of another type can be coerced (used
* as or converted to) this Type without truncation or loss of
* precision.
* @note It is NOT possible to coerce a nullable type to a non-nullable type,
* even if coercion would otherwise be possible.
* @note Integer types are safely coercible to other integer or
* floating-poin types of equal or greater length.
* @note Floating-point types are safely coercible to other floating-point
* types of equal or greater precision.
* @note ASCII string types are safely coercible to other ASCII string types
* of equal or greater maximum length.
* @warning Integer types are considered safely coercible to floating-point
* types of the same length, although for some large integer values
* this can lead to rounding off some of the lowest-magnitude binary
* digits.
*
* @param original_type The original Type for coercion to this Type.
* @return true if coercion is supported, false otherwise.
**/
virtual bool isSafelyCoercibleFrom(const Type &original_type) const = 0;
/**
* @brief Determine whether data items of this type are always guaranteed to
* be valid instances of another type WITHOUT coercion. For example,
* a non-nullable type is subsumed by a nullable type that is
* otherwise identical, and a shorter VARCHAR is subsumed by a longer
* VARCHAR.
* @note Because of issues of endianness, INT is not subsumed by LONG.
* Similarly, because a different number of bits are allocated to
* digits and mantissa in IEEE 754, FLOAT is not subsumed by DOUBLE.
*
* @param other The target Type to check whether this Type is strictly
* subsumed by.
* @return true if this Type is subsumed by other, false otherwise.
**/
virtual bool isSubsumedBy(const Type &other) const {
return equals(other) || getNullableVersion().equals(other);
}
/**
* @brief Get the name of this Type.
* @note Default version just returns the name from kTypeNames. Subclasses
* may override this to provided additional information, like lengths.
*
* @return The human-readable name of this Type (if the Type is nullable,
* this will include the NULL specifier).
**/
virtual std::string getName() const {
return std::string(kTypeNames[getTypeID()]).append(nullable_ ? " NULL" : "");
}
/**
* @brief Determine the maximum number of characters it takes to print a
* value of this Type.
*
* @note This counts only the characters needed to print non-NULL values of
* this type. NULL values are not directly printable by either
* Type::printValueToString() or Type::printValueToFile().
*
* @return The maximum number of characters used to print a value of this
* Type.
**/
virtual int getPrintWidth() const = 0;
/**
* @brief "Print" a value of this Type as a human-readable string.
* @warning It is an error to call this with a NULL value. This method prints
* non-NULL values only.
*
* @param value A value of this Type.
* @return The human-readable string representation of value.
**/
virtual std::string printValueToString(const TypedValue &value) const = 0;
/**
* @brief Print the human-readable string representation of a value of this
* type to a FILE stream.
* @warning It is an error to call this with a NULL value. This method prints
* non-NULL values only.
*
* @param value A value of this Type.
* @param file An open FILE stream to print to.
* @param padding If nonzero, left-pad the printed value with spaces up to
* this length. If padding is less than the number of characters
* needed to print the value, then more than padding characters will
* be printed (see getPrintWidth() for information about how long a
* printed string may be).
**/
virtual void printValueToFile(const TypedValue &value,
FILE *file,
const int padding = 0) const = 0;
/**
* @brief Make a TypedValue of this Type.
*
* @param value_ptr An untyped pointer to the data which will be represented
* as a TypedValue.
* @param value_size The size of the data at value_ptr in bytes. This may be
* omitted for numeric types, but must be explicitly specified for any
* other type. For Char and VarChar, this should include the
* terminating null character, if any.
* @return A TypedValue representing the data at value_ptr.
**/
inline TypedValue makeValue(const void* value_ptr,
const std::size_t value_size = 0) const {
DCHECK(value_ptr != nullptr);
switch (type_id_) {
case kInt:
return TypedValue(*static_cast<const int*>(value_ptr));
case kLong:
return TypedValue(*static_cast<const std::int64_t*>(value_ptr));
case kFloat:
return TypedValue(*static_cast<const float*>(value_ptr));
case kDouble:
return TypedValue(*static_cast<const double*>(value_ptr));
case kDate:
return TypedValue(*static_cast<const DateLit*>(value_ptr));
case kDatetime:
return TypedValue(*static_cast<const DatetimeLit*>(value_ptr));
case kDatetimeInterval:
return TypedValue(*static_cast<const DatetimeIntervalLit*>(value_ptr));
case kYearMonthInterval:
return TypedValue(*static_cast<const YearMonthIntervalLit*>(value_ptr));
case kNullType: {
LOG(FATAL) << "Calling makeValue() to make a non-null value for "
<< "NullType, which is impossible.";
}
default:
DCHECK_NE(value_size, 0u);
DCHECK_LE(value_size, maximum_byte_length_);
return TypedValue(type_id_, value_ptr, value_size);
}
}
/**
* @brief Make a NULL TypedValue of this Type.
*
* @return A NULL TypedValue of this Type.
**/
inline TypedValue makeNullValue() const {
DCHECK(nullable_);
return TypedValue(type_id_);
}
/**
* @brief Make a "zero" value of this Type.
* @note For arithmetic types that can be freely added, "zero" means the
* additive identity. For non-addable Types, there is no zero value and
* calling this method is an error.
*
* @return A zero value of this Type.
**/
virtual TypedValue makeZeroValue() const {
LOG(FATAL) << "Called makeZeroValue() on Type " << getName()
<< ", which does not have a defined zero value.";
}
/**
* @brief Parse a value of this type from its human-readable string
* representation.
*
* @param value_string The human-readable string representation of a value of
* this type.
* @param value Pointer to a TypedValue that will be overwritten with the
* parsed value.
* @return true if value_string was successfully parsed and value was
* written. false if value_string was not in the correct format.
**/
virtual bool parseValueFromString(const std::string &value_string,
TypedValue *value) const = 0;
/**
* @brief Coerce a value of another Type to this Type.
* @warning It is an error to call this method with an original_type that can
* not be coerced to this Type. If in doubt, check
* isCoercibleFrom().
* @note The base Type class provides a default implementation of this method
* that only allows coercing from the exact same Type or, if this Type
* is nullable, from the non-nullable version of a Type or the special
* NullType. Types that allow additional coercions should override this
* method.
*
* @param original_value The value to coerce to this Type.
* @param original_type The Type that original_value belongs to.
* @return A new TypedValue that represents original_value as an instance of
* this Type.
**/
virtual TypedValue coerceValue(const TypedValue &original_value,
const Type &original_type) const;
protected:
Type(const SuperTypeID super_type_id,
const TypeID type_id,
const bool nullable,
const std::size_t minimum_byte_length,
const std::size_t maximum_byte_length)
: super_type_id_(super_type_id),
type_id_(type_id),
nullable_(nullable),
minimum_byte_length_(minimum_byte_length),
maximum_byte_length_(maximum_byte_length) {
}
const SuperTypeID super_type_id_;
const TypeID type_id_;
const bool nullable_;
const std::size_t minimum_byte_length_;
const std::size_t maximum_byte_length_;
private:
DISALLOW_COPY_AND_ASSIGN(Type);
};
/**
* @brief A superclass for ASCII string types.
**/
class AsciiStringSuperType : public Type {
public:
bool isCoercibleFrom(const Type &original_type) const override;
/**
* @brief Get the character-length of this string type.
*
* @return The maximum length of a string of this type.
**/
inline std::size_t getStringLength() const {
return length_;
}
protected:
AsciiStringSuperType(const TypeID type_id,
const bool nullable,
const std::size_t minimum_byte_length,
const std::size_t maximum_byte_length,
const std::size_t string_length)
: Type(Type::kAsciiString, type_id, nullable, minimum_byte_length, maximum_byte_length),
length_(string_length) {
}
const std::size_t length_;
private:
DISALLOW_COPY_AND_ASSIGN(AsciiStringSuperType);
};
/** @} */
} // namespace quickstep
#endif // QUICKSTEP_TYPES_TYPE_HPP_