mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-2.1' into trunk
Conflicts: pylib/cqlshlib/cql3handling.py
This commit is contained in:
commit
3d11ec5dd3
|
|
@ -62,6 +62,7 @@
|
|||
|
||||
|
||||
2.1.4
|
||||
* Add SimpleDate (cql date) and Time (cql time) types (CASSANDRA-7523)
|
||||
* Use long for key count in cfstats (CASSANDRA-8913)
|
||||
* Make SSTableRewriter.abort() more robust to failure (CASSANDRA-8832)
|
||||
* Remove cold_reads_to_omit from STCS (CASSANDRA-8860)
|
||||
|
|
|
|||
5
NEWS.txt
5
NEWS.txt
|
|
@ -85,6 +85,11 @@ Upgrading
|
|||
removed - it is almost always better to use date tiered compaction for
|
||||
workloads that have cold data.
|
||||
|
||||
New features
|
||||
------------
|
||||
- New `SimpleDateType` (cql date). 4-byte unsigned integer w/out timestamp
|
||||
- New `TimeType` (cql time). 8-byte long nano-second resolution timestamp
|
||||
|
||||
2.1.3
|
||||
=====
|
||||
|
||||
|
|
|
|||
47
bin/cqlsh
47
bin/cqlsh
|
|
@ -122,6 +122,10 @@ from cqlshlib.displaying import (RED, BLUE, CYAN, ANSI_RESET, COLUMN_NAME_COLORS
|
|||
FormattedValue, colorme)
|
||||
from cqlshlib.formatting import format_by_type, formatter_for, format_value_utype
|
||||
from cqlshlib.util import trim_if_present, get_file_encoding_bomsize
|
||||
from cqlshlib.formatting import DateTimeFormat
|
||||
from cqlshlib.formatting import DEFAULT_TIMESTAMP_FORMAT
|
||||
from cqlshlib.formatting import DEFAULT_DATE_FORMAT
|
||||
from cqlshlib.formatting import DEFAULT_NANOTIME_FORMAT
|
||||
from cqlshlib.tracing import print_trace_session, print_trace
|
||||
|
||||
DEFAULT_HOST = '127.0.0.1'
|
||||
|
|
@ -129,7 +133,6 @@ DEFAULT_PORT = 9042
|
|||
DEFAULT_CQLVER = '3.2.0'
|
||||
DEFAULT_PROTOCOL_VERSION = 3
|
||||
|
||||
DEFAULT_TIME_FORMAT = '%Y-%m-%d %H:%M:%S%z'
|
||||
DEFAULT_FLOAT_PRECISION = 5
|
||||
DEFAULT_MAX_TRACE_WAIT = 10
|
||||
|
||||
|
|
@ -431,7 +434,7 @@ def full_cql_version(ver):
|
|||
vertuple = tuple(map(int, ver_parts[0].split('.')) + [ver_parts[1]])
|
||||
return ver, vertuple
|
||||
|
||||
def format_value(val, output_encoding, addcolor=False, time_format=None,
|
||||
def format_value(val, output_encoding, addcolor=False, date_time_format=None,
|
||||
float_precision=None, colormap=None, nullval=None):
|
||||
if isinstance(val, DecodeError):
|
||||
if addcolor:
|
||||
|
|
@ -439,7 +442,7 @@ def format_value(val, output_encoding, addcolor=False, time_format=None,
|
|||
else:
|
||||
return FormattedValue(repr(val.thebytes))
|
||||
return format_by_type(type(val), val, output_encoding, colormap=colormap,
|
||||
addcolor=addcolor, nullval=nullval, time_format=time_format,
|
||||
addcolor=addcolor, nullval=nullval, date_time_format=date_time_format,
|
||||
float_precision=float_precision)
|
||||
|
||||
def show_warning_without_quoting_line(message, category, filename, lineno, file=None, line=None):
|
||||
|
|
@ -529,7 +532,9 @@ class Shell(cmd.Cmd):
|
|||
completekey=DEFAULT_COMPLETEKEY, use_conn=None,
|
||||
cqlver=DEFAULT_CQLVER, keyspace=None,
|
||||
tracing_enabled=False, expand_enabled=False,
|
||||
display_time_format=DEFAULT_TIME_FORMAT,
|
||||
display_nanotime_format=DEFAULT_NANOTIME_FORMAT,
|
||||
display_timestamp_format=DEFAULT_TIMESTAMP_FORMAT,
|
||||
display_date_format=DEFAULT_DATE_FORMAT,
|
||||
display_float_precision=DEFAULT_FLOAT_PRECISION,
|
||||
max_trace_wait=DEFAULT_MAX_TRACE_WAIT,
|
||||
ssl=False,
|
||||
|
|
@ -564,7 +569,11 @@ class Shell(cmd.Cmd):
|
|||
self.session = self.conn.connect()
|
||||
|
||||
self.color = color
|
||||
self.display_time_format = display_time_format
|
||||
|
||||
self.display_nanotime_format = display_nanotime_format
|
||||
self.display_timestamp_format = display_timestamp_format
|
||||
self.display_date_format = display_date_format
|
||||
|
||||
self.display_float_precision = display_float_precision
|
||||
|
||||
# Workaround for CASSANDRA-8521 until PYTHON-205 is resolved.
|
||||
|
|
@ -588,6 +597,10 @@ class Shell(cmd.Cmd):
|
|||
|
||||
self.current_keyspace = keyspace
|
||||
|
||||
self.display_timestamp_format = display_timestamp_format
|
||||
self.display_nanotime_format = display_nanotime_format
|
||||
self.display_date_format = display_date_format
|
||||
|
||||
self.max_trace_wait = max_trace_wait
|
||||
self.session.max_trace_wait = max_trace_wait
|
||||
if encoding is None:
|
||||
|
|
@ -634,8 +647,10 @@ class Shell(cmd.Cmd):
|
|||
if isinstance(val, DecodeError):
|
||||
self.decoding_errors.append(val)
|
||||
try:
|
||||
dtformats = DateTimeFormat(timestamp_format=self.display_timestamp_format,
|
||||
date_format=self.display_date_format, nanotime_format=self.display_nanotime_format)
|
||||
return format_value(val, self.output_codec.name,
|
||||
addcolor=self.color, time_format=self.display_time_format,
|
||||
addcolor=self.color, date_time_format=dtformats,
|
||||
float_precision=self.display_float_precision, **kwargs)
|
||||
except Exception, e:
|
||||
err = FormatError(val, e)
|
||||
|
|
@ -1480,7 +1495,7 @@ class Shell(cmd.Cmd):
|
|||
cqltype = table_meta.columns[name].typestring
|
||||
|
||||
if value != nullval:
|
||||
if cqltype in ('ascii', 'text', 'timestamp', 'inet'):
|
||||
if cqltype in ('ascii', 'text', 'timestamp', 'date', 'time', 'inet'):
|
||||
rowmap[name] = protect_value(value)
|
||||
else:
|
||||
rowmap[name] = value
|
||||
|
|
@ -1542,7 +1557,7 @@ class Shell(cmd.Cmd):
|
|||
return 0
|
||||
wmeter = meter.Meter()
|
||||
try:
|
||||
|
||||
dtformats = DateTimeFormat(self.display_timestamp_format, self.display_date_format, self.display_nanotime_format)
|
||||
dump = self.prep_export_dump(ks, cf, columns)
|
||||
writer = csv.writer(csvdest, **dialect_options)
|
||||
if header:
|
||||
|
|
@ -1550,7 +1565,7 @@ class Shell(cmd.Cmd):
|
|||
for row in dump:
|
||||
fmt = lambda v: \
|
||||
format_value(v, output_encoding=encoding, nullval=nullval,
|
||||
time_format=self.display_time_format,
|
||||
date_time_format=dtformats,
|
||||
float_precision=self.display_float_precision).strval
|
||||
writer.writerow(map(fmt, row.values()))
|
||||
wmeter.mark_written()
|
||||
|
|
@ -1632,7 +1647,9 @@ class Shell(cmd.Cmd):
|
|||
subshell = Shell(self.hostname, self.port,
|
||||
color=self.color, encoding=self.encoding, stdin=f,
|
||||
tty=False, use_conn=self.conn, cqlver=self.cql_version,
|
||||
display_time_format=self.display_time_format,
|
||||
display_timestamp_format=self.display_timestamp_format,
|
||||
display_date_format=self.display_date_format,
|
||||
display_nanotime_format=self.display_nanotime_format,
|
||||
display_float_precision=self.display_float_precision,
|
||||
max_trace_wait=self.max_trace_wait)
|
||||
subshell.cmdloop()
|
||||
|
|
@ -1940,7 +1957,11 @@ def read_options(cmdlineargs, environment):
|
|||
DEFAULT_COMPLETEKEY)
|
||||
optvalues.color = option_with_default(configs.getboolean, 'ui', 'color')
|
||||
optvalues.time_format = raw_option_with_default(configs, 'ui', 'time_format',
|
||||
DEFAULT_TIME_FORMAT)
|
||||
DEFAULT_TIMESTAMP_FORMAT)
|
||||
optvalues.nanotime_format = raw_option_with_default(configs, 'ui', 'nanotime_format',
|
||||
DEFAULT_NANOTIME_FORMAT)
|
||||
optvalues.date_format = raw_option_with_default(configs, 'ui', 'date_format',
|
||||
DEFAULT_DATE_FORMAT)
|
||||
optvalues.float_precision = option_with_default(configs.getint, 'ui', 'float_precision',
|
||||
DEFAULT_FLOAT_PRECISION)
|
||||
optvalues.max_trace_wait = option_with_default(configs.getfloat, 'tracing', 'max_trace_wait',
|
||||
|
|
@ -2057,7 +2078,9 @@ def main(options, hostname, port):
|
|||
completekey=options.completekey,
|
||||
cqlver=options.cqlversion,
|
||||
keyspace=options.keyspace,
|
||||
display_time_format=options.time_format,
|
||||
display_timestamp_format=options.time_format,
|
||||
display_nanotime_format=options.nanotime_format,
|
||||
display_date_format=options.date_format,
|
||||
display_float_precision=options.float_precision,
|
||||
max_trace_wait=options.max_trace_wait,
|
||||
ssl=options.ssl,
|
||||
|
|
|
|||
|
|
@ -1103,12 +1103,14 @@ bc(syntax)..
|
|||
| blob
|
||||
| boolean
|
||||
| counter
|
||||
| date
|
||||
| decimal
|
||||
| double
|
||||
| float
|
||||
| inet
|
||||
| int
|
||||
| text
|
||||
| time
|
||||
| timestamp
|
||||
| timeuuid
|
||||
| uuid
|
||||
|
|
@ -1129,13 +1131,15 @@ p. The following table gives additional informations on the native data types, a
|
|||
|@blob@ | blobs |Arbitrary bytes (no validation)|
|
||||
|@boolean@ | booleans |true or false|
|
||||
|@counter@ | integers |Counter column (64-bit signed value). See "Counters":#counters for details|
|
||||
|@date@ | integers, strings |A date (with no corresponding time value). See "Working with dates":#usingdates below for more information.|
|
||||
|@decimal@ | integers, floats |Variable-precision decimal|
|
||||
|@double@ | integers |64-bit IEEE-754 floating point|
|
||||
|@float@ | integers, floats |32-bit IEEE-754 floating point|
|
||||
|@inet@ | strings |An IP address. It can be either 4 bytes long (IPv4) or 16 bytes long (IPv6). There is no @inet@ constant, IP address should be inputed as strings|
|
||||
|@int@ | integers |32-bit signed int|
|
||||
|@text@ | strings |UTF8 encoded string|
|
||||
|@timestamp@| integers, strings |A timestamp. Strings constant are allow to input timestamps as dates, see "Working with dates":#usingdates below for more information.|
|
||||
|@time@ | integers, strings |A time with nanosecond precision. See "Working with time":#usingtime below for more information.|
|
||||
|@timestamp@| integers, strings |A timestamp. Strings constant are allow to input timestamps as dates, see "Working with timestamps":#usingtimestamps below for more information.|
|
||||
|@timeuuid@ | uuids |Type 1 UUID. This is generally used as a "conflict-free" timestamp. Also see the "functions on Timeuuid":#timeuuidFun|
|
||||
|@uuid@ | uuids |Type 1 or type 4 UUID|
|
||||
|@varchar@ | strings |UTF8 encoded string|
|
||||
|
|
@ -1143,7 +1147,7 @@ p. The following table gives additional informations on the native data types, a
|
|||
|
||||
For more information on how to use the collection types, see the "Working with collections":#collections section below.
|
||||
|
||||
h3(#usingdates). Working with dates
|
||||
h3(#usingtimestamps). Working with timestamps
|
||||
|
||||
Values of the @timestamp@ type are encoded as 64-bit signed integers representing a number of milliseconds since the standard base time known as "the epoch": January 1 1970 at 00:00:00 GMT.
|
||||
|
||||
|
|
@ -1177,6 +1181,31 @@ The time of day may also be omitted, if the date is the only piece that matters:
|
|||
In that case, the time of day will default to 00:00:00, in the specified or default time zone.
|
||||
|
||||
|
||||
h3(#usingdates). Working with dates
|
||||
|
||||
Values of the @date@ type are encoded as 32-bit unsigned integers representing a number of days with "the epoch" at the center of the range (2^31). Epoch is January 1st, 1970
|
||||
|
||||
A date can be input in CQL as an unsigned integer as defined above.
|
||||
|
||||
They can also be input as string literals in the following format:
|
||||
|
||||
* @2014-01-01@
|
||||
|
||||
|
||||
h3(#usingtime). Working with time
|
||||
|
||||
Values of the @time@ type are encoded as 64-bit signed integers representing the number of nanoseconds since midnight.
|
||||
|
||||
A time can be input in CQL as simple long integers, giving the number of nanoseconds since midnight.
|
||||
|
||||
They can also be input as string literals in any of the following formats:
|
||||
|
||||
* @08:12:54@
|
||||
* @08:12:54.123@
|
||||
* @08:12:54.123456@
|
||||
* @08:12:54.123456789@
|
||||
|
||||
|
||||
h3(#counters). Counters
|
||||
|
||||
The @counter@ type is used to define _counter columns_. A counter column is a column whose value is a 64-bit signed integer and on which 2 operations are supported: incrementation and decrementation (see "@UPDATE@":#updateStmt for syntax). Note the value of a counter cannot be set. A counter doesn't exist until first incremented/decremented, and the first incrementation/decrementation is made as if the previous value was 0. Deletion of counter columns is supported but have some limitations (see the "Cassandra Wiki":http://wiki.apache.org/cassandra/Counters for more information).
|
||||
|
|
@ -1341,7 +1370,7 @@ will never return any result by design, since the value returned by @now()@ is g
|
|||
|
||||
h4. @minTimeuuid@ and @maxTimeuuid@
|
||||
|
||||
The @minTimeuuid@ (resp. @maxTimeuuid@) function takes a @timestamp@ value @t@ (which can be "either a timestamp or a date string":#usingdates) and return a _fake_ @timeuuid@ corresponding to the _smallest_ (resp. _biggest_) possible @timeuuid@ having for timestamp @t@. So for instance:
|
||||
The @minTimeuuid@ (resp. @maxTimeuuid@) function takes a @timestamp@ value @t@ (which can be "either a timestamp or a date string":#usingtimestamps) and return a _fake_ @timeuuid@ corresponding to the _smallest_ (resp. _biggest_) possible @timeuuid@ having for timestamp @t@. So for instance:
|
||||
|
||||
bc(sample).
|
||||
SELECT * FROM myTable WHERE t > maxTimeuuid('2013-01-01 00:05+0000') AND t < minTimeuuid('2013-02-02 10:00+0000')
|
||||
|
|
@ -1554,6 +1583,8 @@ CQL distinguishes between _reserved_ and _non-reserved_ keywords. Reserved keywo
|
|||
| @WITH@ | yes |
|
||||
| @WRITETIME@ | no |
|
||||
| @DISTINCT@ | no |
|
||||
| @DATE@ | no |
|
||||
| @TIME@ | no |
|
||||
|
||||
h2(#appendixB). Appendix B: CQL Reserved Types
|
||||
|
||||
|
|
@ -1608,7 +1639,7 @@ h3. 3.1.4
|
|||
|
||||
h3. 3.1.3
|
||||
|
||||
* Millisecond precision formats have been added to the timestamp parser (see "working with dates":#usingdates).
|
||||
* Millisecond precision formats have been added to the timestamp parser (see "working with dates":#usingtimestamps).
|
||||
|
||||
h3. 3.1.2
|
||||
|
||||
|
|
@ -1648,7 +1679,7 @@ h3. 3.0.2
|
|||
|
||||
h3. 3.0.1
|
||||
|
||||
* "Date strings":#usingdates (and timestamps) are no longer accepted as valid @timeuuid@ values. Doing so was a bug in the sense that date string are not valid @timeuuid@, and it was thus resulting in "confusing behaviors":https://issues.apache.org/jira/browse/CASSANDRA-4936. However, the following new methods have been added to help working with @timeuuid@: @now@, @minTimeuuid@, @maxTimeuuid@ , @dateOf@ and @unixTimestampOf@. See the "section dedicated to these methods":#usingtimeuuid for more detail.
|
||||
* "Date strings":#usingtimestamps (and timestamps) are no longer accepted as valid @timeuuid@ values. Doing so was a bug in the sense that date string are not valid @timeuuid@, and it was thus resulting in "confusing behaviors":https://issues.apache.org/jira/browse/CASSANDRA-4936. However, the following new methods have been added to help working with @timeuuid@: @now@, @minTimeuuid@, @maxTimeuuid@ , @dateOf@ and @unixTimestampOf@. See the "section dedicated to these methods":#usingtimeuuid for more detail.
|
||||
* "Float constants"#constants now support the exponent notation. In other words, @4.2E10@ is now a valid floating point value.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -574,6 +574,8 @@ Table of Contents
|
|||
0x000E Varint
|
||||
0x000F Timeuuid
|
||||
0x0010 Inet
|
||||
0x0011 Date
|
||||
0x0012 Time
|
||||
0x0020 List: the value is an [option], representing the type
|
||||
of the elements of the list.
|
||||
0x0021 Map: the value is two [option], representing the types of the
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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.
|
||||
|
|
@ -19,8 +19,8 @@ from cassandra.metadata import maybe_escape_name
|
|||
from cassandra.metadata import escape_name
|
||||
|
||||
|
||||
simple_cql_types = set(('ascii', 'bigint', 'blob', 'boolean', 'counter', 'decimal', 'double', 'float', 'inet', 'int',
|
||||
'text', 'timestamp', 'timeuuid', 'uuid', 'varchar', 'varint'))
|
||||
simple_cql_types = set(('ascii', 'bigint', 'blob', 'boolean', 'counter', 'date', 'decimal', 'double', 'float', 'inet', 'int',
|
||||
'text', 'time', 'timestamp', 'timeuuid', 'uuid', 'varchar', 'varint'))
|
||||
simple_cql_types.difference_update(('set', 'map', 'list'))
|
||||
|
||||
from . import helptopics
|
||||
|
|
@ -42,7 +42,7 @@ class Cql3ParsingRuleSet(CqlParsingRuleSet):
|
|||
'limit', 'using', 'use', 'set',
|
||||
'begin', 'apply', 'batch', 'truncate', 'delete', 'in', 'create',
|
||||
'function', 'aggregate', 'keyspace', 'schema', 'columnfamily', 'table', 'index', 'on', 'drop',
|
||||
'primary', 'into', 'values', 'timestamp', 'ttl', 'alter', 'add', 'type',
|
||||
'primary', 'into', 'values', 'date', 'time', 'timestamp', 'ttl', 'alter', 'add', 'type',
|
||||
'compact', 'storage', 'order', 'by', 'asc', 'desc', 'clustering',
|
||||
'token', 'writetime', 'map', 'list', 'to', 'custom', 'if', 'not'
|
||||
))
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ DEFAULT_VALUE_COLORS = dict(
|
|||
error=RED,
|
||||
blob=DARK_MAGENTA,
|
||||
timestamp=GREEN,
|
||||
date=GREEN,
|
||||
time=GREEN,
|
||||
int=GREEN,
|
||||
float=GREEN,
|
||||
decimal=GREEN,
|
||||
|
|
|
|||
|
|
@ -14,13 +14,15 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import re
|
||||
import time
|
||||
import calendar
|
||||
import math
|
||||
import re
|
||||
import time
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from . import wcwidth
|
||||
from .displaying import colorme, FormattedValue, DEFAULT_VALUE_COLORS
|
||||
from datetime import datetime, timedelta
|
||||
from cassandra.cqltypes import EMPTY
|
||||
|
||||
unicode_controlchars_re = re.compile(r'[\x00-\x31\x7f-\xa0]')
|
||||
|
|
@ -45,13 +47,12 @@ def _make_turn_bits_red_f(color1, color2):
|
|||
return _turn_bits_red
|
||||
|
||||
default_null_placeholder = 'null'
|
||||
default_time_format = ''
|
||||
default_float_precision = 3
|
||||
default_colormap = DEFAULT_VALUE_COLORS
|
||||
empty_colormap = defaultdict(lambda: '')
|
||||
|
||||
def format_by_type(cqltype, val, encoding, colormap=None, addcolor=False,
|
||||
nullval=None, time_format=None, float_precision=None):
|
||||
nullval=None, date_time_format=None, float_precision=None):
|
||||
if nullval is None:
|
||||
nullval = default_null_placeholder
|
||||
if val is None:
|
||||
|
|
@ -60,12 +61,12 @@ def format_by_type(cqltype, val, encoding, colormap=None, addcolor=False,
|
|||
colormap = empty_colormap
|
||||
elif colormap is None:
|
||||
colormap = default_colormap
|
||||
if time_format is None:
|
||||
time_format = default_time_format
|
||||
if date_time_format is None:
|
||||
date_time_format = DateTimeFormat()
|
||||
if float_precision is None:
|
||||
float_precision = default_float_precision
|
||||
return format_value(cqltype, val, encoding=encoding, colormap=colormap,
|
||||
time_format=time_format, float_precision=float_precision,
|
||||
date_time_format=date_time_format, float_precision=float_precision,
|
||||
nullval=nullval)
|
||||
|
||||
def color_text(bval, colormap, displaywidth=None):
|
||||
|
|
@ -86,6 +87,16 @@ def color_text(bval, colormap, displaywidth=None):
|
|||
displaywidth -= bval.count(r'\\')
|
||||
return FormattedValue(bval, coloredval, displaywidth)
|
||||
|
||||
DEFAULT_NANOTIME_FORMAT = '%H:%M:%S.%N'
|
||||
DEFAULT_DATE_FORMAT = '%Y-%m-%d'
|
||||
DEFAULT_TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S%z'
|
||||
|
||||
class DateTimeFormat():
|
||||
def __init__(self, timestamp_format=DEFAULT_TIMESTAMP_FORMAT, date_format=DEFAULT_DATE_FORMAT, nanotime_format=DEFAULT_NANOTIME_FORMAT):
|
||||
self.timestamp_format=timestamp_format
|
||||
self.date_format=date_format
|
||||
self.nanotime_format=nanotime_format
|
||||
|
||||
def format_value_default(val, colormap, **_):
|
||||
val = str(val)
|
||||
escapedval = val.replace('\\', '\\\\')
|
||||
|
|
@ -157,15 +168,13 @@ def format_integer_type(val, colormap, **_):
|
|||
formatter_for('long')(format_integer_type)
|
||||
formatter_for('int')(format_integer_type)
|
||||
|
||||
@formatter_for('date')
|
||||
def format_value_timestamp(val, colormap, time_format, quote=False, **_):
|
||||
bval = strftime(time_format, calendar.timegm(val.utctimetuple()))
|
||||
@formatter_for('datetime')
|
||||
def format_value_timestamp(val, colormap, date_time_format, quote=False, **_):
|
||||
bval = strftime(date_time_format.timestamp_format, calendar.timegm(val.utctimetuple()))
|
||||
if quote:
|
||||
bval = "'%s'" % bval
|
||||
return colorme(bval, colormap, 'timestamp')
|
||||
|
||||
formatter_for('datetime')(format_value_timestamp)
|
||||
|
||||
def strftime(time_format, seconds):
|
||||
local = time.localtime(seconds)
|
||||
formatted = time.strftime(time_format, local)
|
||||
|
|
@ -183,6 +192,14 @@ def strftime(time_format, seconds):
|
|||
hours, minutes = divmod(abs(offset) / 60, 60)
|
||||
return formatted[:-5] + sign + '{0:0=2}{1:0=2}'.format(hours, minutes)
|
||||
|
||||
@formatter_for('date')
|
||||
def format_value_uuid(val, colormap, **_):
|
||||
return format_python_formatted_type(val, colormap, 'date')
|
||||
|
||||
@formatter_for('Time')
|
||||
def format_value_time(val, colormap, **_):
|
||||
return format_python_formatted_type(val, colormap, 'time')
|
||||
|
||||
@formatter_for('str')
|
||||
def format_value_text(val, encoding, colormap, quote=False, **_):
|
||||
escapedval = val.replace(u'\\', u'\\\\')
|
||||
|
|
@ -199,9 +216,9 @@ def format_value_text(val, encoding, colormap, quote=False, **_):
|
|||
formatter_for('unicode')(format_value_text)
|
||||
|
||||
def format_simple_collection(val, lbracket, rbracket, encoding,
|
||||
colormap, time_format, float_precision, nullval):
|
||||
colormap, date_time_format, float_precision, nullval):
|
||||
subs = [format_value(type(sval), sval, encoding=encoding, colormap=colormap,
|
||||
time_format=time_format, float_precision=float_precision,
|
||||
date_time_format=date_time_format, float_precision=float_precision,
|
||||
nullval=nullval, quote=True)
|
||||
for sval in val]
|
||||
bval = lbracket + ', '.join(sval.strval for sval in subs) + rbracket
|
||||
|
|
@ -212,28 +229,28 @@ def format_simple_collection(val, lbracket, rbracket, encoding,
|
|||
return FormattedValue(bval, coloredval, displaywidth)
|
||||
|
||||
@formatter_for('list')
|
||||
def format_value_list(val, encoding, colormap, time_format, float_precision, nullval, **_):
|
||||
def format_value_list(val, encoding, colormap, date_time_format, float_precision, nullval, **_):
|
||||
return format_simple_collection(val, '[', ']', encoding, colormap,
|
||||
time_format, float_precision, nullval)
|
||||
date_time_format, float_precision, nullval)
|
||||
|
||||
@formatter_for('tuple')
|
||||
def format_value_tuple(val, encoding, colormap, time_format, float_precision, nullval, **_):
|
||||
def format_value_tuple(val, encoding, colormap, date_time_format, float_precision, nullval, **_):
|
||||
return format_simple_collection(val, '(', ')', encoding, colormap,
|
||||
time_format, float_precision, nullval)
|
||||
date_time_format, float_precision, nullval)
|
||||
|
||||
@formatter_for('set')
|
||||
def format_value_set(val, encoding, colormap, time_format, float_precision, nullval, **_):
|
||||
def format_value_set(val, encoding, colormap, date_time_format, float_precision, nullval, **_):
|
||||
return format_simple_collection(sorted(val), '{', '}', encoding, colormap,
|
||||
time_format, float_precision, nullval)
|
||||
date_time_format, float_precision, nullval)
|
||||
formatter_for('frozenset')(format_value_set)
|
||||
formatter_for('sortedset')(format_value_set)
|
||||
|
||||
|
||||
@formatter_for('dict')
|
||||
def format_value_map(val, encoding, colormap, time_format, float_precision, nullval, **_):
|
||||
def format_value_map(val, encoding, colormap, date_time_format, float_precision, nullval, **_):
|
||||
def subformat(v):
|
||||
return format_value(type(v), v, encoding=encoding, colormap=colormap,
|
||||
time_format=time_format, float_precision=float_precision,
|
||||
date_time_format=date_time_format, float_precision=float_precision,
|
||||
nullval=nullval, quote=True)
|
||||
|
||||
subs = [(subformat(k), subformat(v)) for (k, v) in sorted(val.items())]
|
||||
|
|
@ -249,12 +266,12 @@ formatter_for('OrderedDict')(format_value_map)
|
|||
formatter_for('OrderedMap')(format_value_map)
|
||||
|
||||
|
||||
def format_value_utype(val, encoding, colormap, time_format, float_precision, nullval, **_):
|
||||
def format_value_utype(val, encoding, colormap, date_time_format, float_precision, nullval, **_):
|
||||
def format_field_value(v):
|
||||
if v is None:
|
||||
return colorme(nullval, colormap, 'error')
|
||||
return format_value(type(v), v, encoding=encoding, colormap=colormap,
|
||||
time_format=time_format, float_precision=float_precision,
|
||||
date_time_format=date_time_format, float_precision=float_precision,
|
||||
nullval=nullval, quote=True)
|
||||
|
||||
def format_field_name(name):
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ class CQLHelpTopics(object):
|
|||
one of the following topics:
|
||||
|
||||
HELP TIMESTAMP_INPUT
|
||||
HELP DATE_INPUT
|
||||
HELP TIME_INPUT
|
||||
HELP BLOB_INPUT
|
||||
HELP UUID_INPUT
|
||||
HELP BOOLEAN_INPUT
|
||||
|
|
@ -69,6 +71,27 @@ class CQLHelpTopics(object):
|
|||
server node will be used.
|
||||
"""
|
||||
|
||||
def help_date_input(self):
|
||||
print """
|
||||
Date input
|
||||
|
||||
CQL supports the following format for date specification:
|
||||
|
||||
yyyy-mm-dd
|
||||
"""
|
||||
|
||||
def help_time_input(self):
|
||||
print """
|
||||
Time input
|
||||
|
||||
CQL supports the following format for time specification:
|
||||
|
||||
HH:MM:SS
|
||||
HH:MM:SS.mmm
|
||||
HH:MM:SS.mmmuuu
|
||||
HH:MM:SS.mmmuuunnn
|
||||
"""
|
||||
|
||||
def help_blob_input(self):
|
||||
print """
|
||||
Blob input
|
||||
|
|
|
|||
|
|
@ -113,10 +113,11 @@ class TestCqlshOutput(BaseTestCase):
|
|||
self.assertTrue(6 <= len(output) <= 8,
|
||||
msg='output: %r' % '\n'.join(output))
|
||||
self.assertEqual(output[0], '')
|
||||
self.assertNicelyFormattedTableHeader(output[1])
|
||||
self.assertNicelyFormattedTableRule(output[2])
|
||||
self.assertNicelyFormattedTableData(output[3])
|
||||
self.assertEqual(output[4].strip(), '')
|
||||
self.assertEqual(output[1], 'Warning! Non-ISO 8601 dates detected (< 1-1-1 or > 9999-12-31). Returning raw days since epoch.');
|
||||
self.assertNicelyFormattedTableHeader(output[2])
|
||||
self.assertNicelyFormattedTableRule(output[3])
|
||||
self.assertNicelyFormattedTableData(output[4])
|
||||
self.assertEqual(output[5].strip(), '')
|
||||
|
||||
def test_color_output(self):
|
||||
for termname in ('xterm', 'unknown-garbage'):
|
||||
|
|
@ -274,9 +275,9 @@ class TestCqlshOutput(BaseTestCase):
|
|||
# same query should show up as empty in cql 3
|
||||
self.assertQueriesGiveColoredOutput((
|
||||
(q, """
|
||||
num | asciicol | bigintcol | blobcol | booleancol | decimalcol | doublecol | floatcol | intcol | textcol | timestampcol | uuidcol | varcharcol | varintcol
|
||||
RRR MMMMMMMM MMMMMMMMM MMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMM MMMMMMM MMMMMMMMMMMM MMMMMMM MMMMMMMMMM MMMMMMMMM
|
||||
-----+----------+-----------+---------+------------+------------+-----------+----------+--------+---------+--------------+---------+------------+-----------
|
||||
num | asciicol | bigintcol | blobcol | booleancol | datecol | decimalcol | doublecol | floatcol | intcol | textcol | timecol | timestampcol | uuidcol | varcharcol | varintcol
|
||||
RRR MMMMMMMM MMMMMMMMM MMMMMMM MMMMMMMMMM MMMMMMM MMMMMMMMMM MMMMMMMMM MMMMMMMM MMMMMM MMMMMMM MMMMMMM MMMMMMMMMMMM MMMMMMM MMMMMMMMMM MMMMMMMMM
|
||||
-----+----------+-----------+---------+------------+---------+------------+-----------+----------+--------+---------+---------+--------------+---------+------------+-----------
|
||||
|
||||
|
||||
(0 rows)
|
||||
|
|
@ -597,11 +598,13 @@ class TestCqlshOutput(BaseTestCase):
|
|||
bigintcol bigint,
|
||||
blobcol blob,
|
||||
booleancol boolean,
|
||||
datecol date,
|
||||
decimalcol decimal,
|
||||
doublecol double,
|
||||
floatcol float,
|
||||
intcol int,
|
||||
textcol text,
|
||||
timecol time,
|
||||
timestampcol timestamp,
|
||||
uuidcol uuid,
|
||||
varcharcol text,
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ CREATE TABLE has_all_types (
|
|||
bigintcol bigint,
|
||||
blobcol blob,
|
||||
booleancol boolean,
|
||||
datecol date,
|
||||
decimalcol decimal,
|
||||
doublecol double,
|
||||
floatcol float,
|
||||
textcol text,
|
||||
timecol time,
|
||||
timestampcol timestamp,
|
||||
uuidcol uuid,
|
||||
varcharcol varchar,
|
||||
|
|
@ -16,40 +18,41 @@ CREATE TABLE has_all_types (
|
|||
) WITH compression = {'sstable_compression':'LZ4Compressor'};
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (0, -12, 'abcdefg', 1234567890123456789, 0x000102030405fffefd, true,
|
||||
19952.11882, 1.0, -2.1, 'Voilá!', '2012-05-14 12:53:20+0000',
|
||||
bd1924e1-6af8-44ae-b5e1-f24131dbd460, '"', 10000000000000000000000000);
|
||||
'2001-07-13', 19952.11882, 1.0, -2.1, 'Voilá!',
|
||||
'23:12:15.889445123', '2012-05-14 12:53:20+0000', bd1924e1-6af8-44ae-b5e1-f24131dbd460, '"', 10000000000000000000000000);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (1, 2147483647, '__!''$#@!~"', 9223372036854775807, 0xffffffffffffffffff, true,
|
||||
0.00000000000001, 9999999.999, 99999.99, '∭Ƕ⑮ฑ➳❏''', '1900-01-01+0000',
|
||||
ffffffff-ffff-ffff-ffff-ffffffffffff, 'newline->
|
||||
'2012-11-30', 0.00000000000001, 9999999.999, 99999.99, '∭Ƕ⑮ฑ➳❏''',
|
||||
'00:01:59.998994', '1900-01-01+0000', ffffffff-ffff-ffff-ffff-ffffffffffff, 'newline->
|
||||
<-', 9);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (2, 0, '', 0, 0x, false,
|
||||
0.0, 0.0, 0.0, '', 0,
|
||||
00000000-0000-0000-0000-000000000000, '', 0);
|
||||
0, 0.0, 0.0, 0.0, '',
|
||||
'0:0:0.1', 0, 00000000-0000-0000-0000-000000000000, '', 0);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
datecol, decimalcol, doublecol, floatcol, textcol,
|
||||
timecol, timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (3, -2147483648, '''''''', -9223372036854775808, 0x80, false,
|
||||
10.0000000000000, -1004.10, 100000000.9, '龍馭鬱', '2038-01-19T03:14-1200',
|
||||
ffffffff-ffff-1fff-8fff-ffffffffffff, '''', -10000000000000000000000000);
|
||||
'9999-12-31', 10.0000000000000, -1004.10, 100000000.9, '龍馭鬱',
|
||||
'23:59:59.999999999', '2038-01-19T03:14-1200', ffffffff-ffff-1fff-8fff-ffffffffffff,
|
||||
'''', -10000000000000000000000000);
|
||||
|
||||
INSERT INTO has_all_types (num, intcol, asciicol, bigintcol, blobcol, booleancol,
|
||||
decimalcol, doublecol, floatcol, textcol,
|
||||
timestampcol, uuidcol, varcharcol, varintcol)
|
||||
VALUES (4, blobAsInt(0x), '', blobAsBigint(0x), 0x, blobAsBoolean(0x), blobAsDecimal(0x),
|
||||
blobAsDouble(0x), blobAsFloat(0x), '', blobAsTimestamp(0x), blobAsUuid(0x), '',
|
||||
blobAsVarint(0x));
|
||||
VALUES (4, blobAsInt(0x), '', blobAsBigint(0x), 0x, blobAsBoolean(0x),
|
||||
blobAsDecimal(0x), blobAsDouble(0x), blobAsFloat(0x), '',
|
||||
blobAsTimestamp(0x), blobAsUuid(0x), '', blobAsVarint(0x));
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,22 +38,24 @@ public interface CQL3Type
|
|||
|
||||
public enum Native implements CQL3Type
|
||||
{
|
||||
ASCII (AsciiType.instance),
|
||||
BIGINT (LongType.instance),
|
||||
BLOB (BytesType.instance),
|
||||
BOOLEAN (BooleanType.instance),
|
||||
COUNTER (CounterColumnType.instance),
|
||||
DECIMAL (DecimalType.instance),
|
||||
DOUBLE (DoubleType.instance),
|
||||
FLOAT (FloatType.instance),
|
||||
INET (InetAddressType.instance),
|
||||
INT (Int32Type.instance),
|
||||
TEXT (UTF8Type.instance),
|
||||
TIMESTAMP(TimestampType.instance),
|
||||
UUID (UUIDType.instance),
|
||||
VARCHAR (UTF8Type.instance),
|
||||
VARINT (IntegerType.instance),
|
||||
TIMEUUID (TimeUUIDType.instance);
|
||||
ASCII (AsciiType.instance),
|
||||
BIGINT (LongType.instance),
|
||||
BLOB (BytesType.instance),
|
||||
BOOLEAN (BooleanType.instance),
|
||||
COUNTER (CounterColumnType.instance),
|
||||
DECIMAL (DecimalType.instance),
|
||||
DOUBLE (DoubleType.instance),
|
||||
FLOAT (FloatType.instance),
|
||||
INET (InetAddressType.instance),
|
||||
INT (Int32Type.instance),
|
||||
TEXT (UTF8Type.instance),
|
||||
TIMESTAMP (TimestampType.instance),
|
||||
UUID (UUIDType.instance),
|
||||
VARCHAR (UTF8Type.instance),
|
||||
VARINT (IntegerType.instance),
|
||||
TIMEUUID (TimeUUIDType.instance),
|
||||
DATE (SimpleDateType.instance),
|
||||
TIME (TimeType.instance);
|
||||
|
||||
private final AbstractType<?> type;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public abstract class Constants
|
|||
|
||||
public enum Type
|
||||
{
|
||||
STRING, INTEGER, UUID, FLOAT, BOOLEAN, HEX;
|
||||
STRING, INTEGER, UUID, FLOAT, DATE, TIME, BOOLEAN, HEX;
|
||||
}
|
||||
|
||||
public static final Term.Raw NULL_LITERAL = new Term.Raw()
|
||||
|
|
@ -181,6 +181,8 @@ public abstract class Constants
|
|||
case TEXT:
|
||||
case INET:
|
||||
case VARCHAR:
|
||||
case DATE:
|
||||
case TIME:
|
||||
case TIMESTAMP:
|
||||
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
|
||||
}
|
||||
|
|
@ -190,6 +192,7 @@ public abstract class Constants
|
|||
{
|
||||
case BIGINT:
|
||||
case COUNTER:
|
||||
case DATE:
|
||||
case DECIMAL:
|
||||
case DOUBLE:
|
||||
case FLOAT:
|
||||
|
|
|
|||
|
|
@ -1390,6 +1390,8 @@ native_type returns [CQL3Type t]
|
|||
| K_VARCHAR { $t = CQL3Type.Native.VARCHAR; }
|
||||
| K_VARINT { $t = CQL3Type.Native.VARINT; }
|
||||
| K_TIMEUUID { $t = CQL3Type.Native.TIMEUUID; }
|
||||
| K_DATE { $t = CQL3Type.Native.DATE; }
|
||||
| K_TIME { $t = CQL3Type.Native.TIME; }
|
||||
;
|
||||
|
||||
collection_type returns [CQL3Type.Raw pt]
|
||||
|
|
@ -1576,6 +1578,8 @@ K_VARINT: V A R I N T;
|
|||
K_TIMEUUID: T I M E U U I D;
|
||||
K_TOKEN: T O K E N;
|
||||
K_WRITETIME: W R I T E T I M E;
|
||||
K_DATE: D A T E;
|
||||
K_TIME: T I M E;
|
||||
|
||||
K_NULL: N U L L;
|
||||
K_NOT: N O T;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ public final class IntegerType extends AbstractType<BigInteger>
|
|||
IntegerType() {/* singleton */}
|
||||
|
||||
public int compare(ByteBuffer lhs, ByteBuffer rhs)
|
||||
{
|
||||
return IntegerType.compareIntegers(lhs, rhs);
|
||||
}
|
||||
|
||||
public static int compareIntegers(ByteBuffer lhs, ByteBuffer rhs)
|
||||
{
|
||||
int lhsLen = lhs.remaining();
|
||||
int rhsLen = rhs.remaining();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.SimpleDateSerializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class SimpleDateType extends AbstractType<Integer>
|
||||
{
|
||||
public static final SimpleDateType instance = new SimpleDateType();
|
||||
|
||||
SimpleDateType() {} // singleton
|
||||
|
||||
public int compare(ByteBuffer o1, ByteBuffer o2)
|
||||
{
|
||||
// We add Integer.MIN_VALUE to overflow to allow unsigned comparison
|
||||
return ByteBufferUtil.compareUnsigned(o1, o2);
|
||||
}
|
||||
|
||||
public boolean isByteOrderComparable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public ByteBuffer fromString(String source) throws MarshalException
|
||||
{
|
||||
return ByteBufferUtil.bytes(SimpleDateSerializer.dateStringToDays(source));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompatibleWith(AbstractType<?> previous)
|
||||
{
|
||||
return super.isCompatibleWith(previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
|
||||
{
|
||||
return this == otherType || otherType == IntegerType.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.DATE;
|
||||
}
|
||||
|
||||
public TypeSerializer<Integer> getSerializer()
|
||||
{
|
||||
return SimpleDateSerializer.instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.serializers.TimeSerializer;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
/**
|
||||
* Nanosecond resolution time values
|
||||
*/
|
||||
public class TimeType extends AbstractType<Long>
|
||||
{
|
||||
public static final TimeType instance = new TimeType();
|
||||
private TimeType() {} // singleton
|
||||
|
||||
public int compare(ByteBuffer o1, ByteBuffer o2)
|
||||
{
|
||||
return ByteBufferUtil.compareUnsigned(o1, o2);
|
||||
}
|
||||
|
||||
public ByteBuffer fromString(String source) throws MarshalException
|
||||
{
|
||||
return decompose(TimeSerializer.timeStringToLong(source));
|
||||
}
|
||||
|
||||
public boolean isByteOrderComparable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompatibleWith(AbstractType<?> previous)
|
||||
{
|
||||
return super.isCompatibleWith(previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
|
||||
{
|
||||
return this == otherType || otherType == LongType.instance;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.TIME;
|
||||
}
|
||||
|
||||
public TypeSerializer<Long> getSerializer()
|
||||
{
|
||||
return TimeSerializer.instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.serializers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
// For byte-order comparability, we shift by Integer.MIN_VALUE and treat the data as an unsigned integer ranging from
|
||||
// min date to max date w/epoch sitting in the center @ 2^31
|
||||
public class SimpleDateSerializer implements TypeSerializer<Integer>
|
||||
{
|
||||
private static final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
|
||||
private static final long minSupportedDateMillis = TimeUnit.DAYS.toMillis(Integer.MIN_VALUE);
|
||||
private static final long maxSupportedDateMillis = TimeUnit.DAYS.toMillis(Integer.MAX_VALUE);
|
||||
private static final long maxSupportedDays = (long)Math.pow(2,32) - 1;
|
||||
private static final long byteOrderShift = (long)Math.pow(2,31) * 2;
|
||||
|
||||
private static final Pattern rawPattern = Pattern.compile("^-?\\d+$");
|
||||
public static final SimpleDateSerializer instance = new SimpleDateSerializer();
|
||||
|
||||
public Integer deserialize(ByteBuffer bytes)
|
||||
{
|
||||
return bytes.remaining() == 0 ? null : ByteBufferUtil.toInt(bytes);
|
||||
}
|
||||
|
||||
public ByteBuffer serialize(Integer value)
|
||||
{
|
||||
return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value);
|
||||
}
|
||||
|
||||
public static Integer dateStringToDays(String source) throws MarshalException
|
||||
{
|
||||
// Raw day value in unsigned int form, epoch @ 2^31
|
||||
if (rawPattern.matcher(source).matches())
|
||||
{
|
||||
try
|
||||
{
|
||||
Long result = Long.parseLong(source);
|
||||
|
||||
if (result < 0 || result > maxSupportedDays)
|
||||
throw new NumberFormatException("Input out of bounds: " + source);
|
||||
|
||||
// Shift > epoch days into negative portion of Integer result for byte order comparability
|
||||
if (result >= Integer.MAX_VALUE)
|
||||
result -= byteOrderShift;
|
||||
|
||||
return result.intValue();
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new MarshalException(String.format("Unable to make unsigned int (for date) from: '%s'", source), e);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to parse as date string
|
||||
try
|
||||
{
|
||||
DateTime parsed = formatter.parseDateTime(source);
|
||||
long millis = parsed.getMillis();
|
||||
if (millis < minSupportedDateMillis)
|
||||
throw new MarshalException(String.format("Input date %s is less than min supported date %s", source, new LocalDate(minSupportedDateMillis).toString()));
|
||||
if (millis > maxSupportedDateMillis)
|
||||
throw new MarshalException(String.format("Input date %s is greater than max supported date %s", source, new LocalDate(maxSupportedDateMillis).toString()));
|
||||
|
||||
Integer result = (int)TimeUnit.MILLISECONDS.toDays(millis);
|
||||
result -= Integer.MIN_VALUE;
|
||||
return result;
|
||||
}
|
||||
catch (IllegalArgumentException e1)
|
||||
{
|
||||
throw new MarshalException(String.format("Unable to coerce '%s' to a formatted date (long)", source), e1);
|
||||
}
|
||||
}
|
||||
|
||||
public void validate(ByteBuffer bytes) throws MarshalException
|
||||
{
|
||||
if (bytes.remaining() != 4)
|
||||
throw new MarshalException(String.format("Expected 4 byte long for date (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public String toString(Integer value)
|
||||
{
|
||||
if (value == null)
|
||||
return "";
|
||||
|
||||
return formatter.print(new LocalDate(TimeUnit.DAYS.toMillis(value - Integer.MIN_VALUE), DateTimeZone.UTC));
|
||||
}
|
||||
|
||||
public Class<Integer> getType()
|
||||
{
|
||||
return Integer.class;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.serializers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class TimeSerializer implements TypeSerializer<Long>
|
||||
{
|
||||
public static final Pattern timePattern = Pattern.compile("^-?\\d+$");
|
||||
public static final TimeSerializer instance = new TimeSerializer();
|
||||
|
||||
public Long deserialize(ByteBuffer bytes)
|
||||
{
|
||||
return bytes.remaining() == 0 ? null : ByteBufferUtil.toLong(bytes);
|
||||
}
|
||||
|
||||
public ByteBuffer serialize(Long value)
|
||||
{
|
||||
return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value);
|
||||
}
|
||||
|
||||
public static Long timeStringToLong(String source) throws MarshalException
|
||||
{
|
||||
// nano since start of day, raw
|
||||
if (timePattern.matcher(source).matches())
|
||||
{
|
||||
try
|
||||
{
|
||||
Long result = Long.parseLong(source);
|
||||
if (result < 0 || result > TimeUnit.DAYS.toNanos(1))
|
||||
throw new NumberFormatException("Input long out of bounds: " + source);
|
||||
return result;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new MarshalException(String.format("Unable to make long (for time) from: '%s'", source), e);
|
||||
}
|
||||
}
|
||||
|
||||
// Last chance, attempt to parse as time string
|
||||
try
|
||||
{
|
||||
return parseTimeStrictly(source);
|
||||
}
|
||||
catch (IllegalArgumentException e1)
|
||||
{
|
||||
throw new MarshalException(String.format("(TimeType) Unable to coerce '%s' to a formatted time (long)", source), e1);
|
||||
}
|
||||
}
|
||||
|
||||
public void validate(ByteBuffer bytes) throws MarshalException
|
||||
{
|
||||
if (bytes.remaining() != 8)
|
||||
throw new MarshalException(String.format("Expected 8 byte long for time (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public String toString(Long value)
|
||||
{
|
||||
if (value == null)
|
||||
return "null";
|
||||
|
||||
int nano = (int)(value % 1000);
|
||||
value -= nano;
|
||||
value /= 1000;
|
||||
int micro = (int)(value % 1000);
|
||||
value -= micro;
|
||||
value /= 1000;
|
||||
int milli = (int)(value % 1000);
|
||||
value -= milli;
|
||||
value /= 1000;
|
||||
int seconds = (int)(value % 60);
|
||||
value -= seconds;
|
||||
value /= 60;
|
||||
int minutes = (int)(value % 60);
|
||||
value -= minutes;
|
||||
value /= 60;
|
||||
int hours = (int)(value % 24);
|
||||
value -= hours;
|
||||
value /= 24;
|
||||
assert(value == 0);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
leftPadZeros(hours, 2, sb);
|
||||
sb.append(":");
|
||||
leftPadZeros(minutes, 2, sb);
|
||||
sb.append(":");
|
||||
leftPadZeros(seconds, 2, sb);
|
||||
sb.append(".");
|
||||
leftPadZeros(milli, 3, sb);
|
||||
leftPadZeros(micro, 3, sb);
|
||||
leftPadZeros(nano, 3, sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void leftPadZeros(int value, int digits, StringBuilder sb)
|
||||
{
|
||||
for (int i = 1; i < digits; ++i)
|
||||
{
|
||||
if (value < Math.pow(10, i))
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(value);
|
||||
}
|
||||
|
||||
public Class<Long> getType()
|
||||
{
|
||||
return Long.class;
|
||||
}
|
||||
|
||||
// Time specific parsing loosely based on java.sql.Timestamp
|
||||
private static Long parseTimeStrictly(String s) throws IllegalArgumentException
|
||||
{
|
||||
String nanos_s;
|
||||
|
||||
long hour;
|
||||
long minute;
|
||||
long second;
|
||||
long a_nanos = 0;
|
||||
|
||||
int firstColon = 0;
|
||||
int secondColon = 0;
|
||||
int period = 0;
|
||||
String formatError = "Timestamp format must be hh:mm:ss[.fffffffff]";
|
||||
String zeros = "000000000";
|
||||
|
||||
if (s == null)
|
||||
throw new java.lang.IllegalArgumentException(formatError);
|
||||
s = s.trim();
|
||||
|
||||
// Parse the time
|
||||
firstColon = s.indexOf(':');
|
||||
secondColon = s.indexOf(':', firstColon+1);
|
||||
period = s.indexOf('.', secondColon+1);
|
||||
|
||||
// Convert the time; default missing nanos
|
||||
if (firstColon > 0 && secondColon > 0 && secondColon < s.length() - 1)
|
||||
{
|
||||
hour = Integer.parseInt(s.substring(0, firstColon));
|
||||
if (hour < 0 || hour >= 24)
|
||||
throw new IllegalArgumentException("Hour out of bounds.");
|
||||
|
||||
minute = Integer.parseInt(s.substring(firstColon + 1, secondColon));
|
||||
if (minute < 0 || minute >= 60)
|
||||
throw new IllegalArgumentException("Minute out of bounds.");
|
||||
|
||||
if (period > 0 && period < s.length() - 1)
|
||||
{
|
||||
second = Integer.parseInt(s.substring(secondColon + 1, period));
|
||||
if (second < 0 || second >= 60)
|
||||
throw new IllegalArgumentException("Second out of bounds.");
|
||||
|
||||
nanos_s = s.substring(period + 1);
|
||||
if (nanos_s.length() > 9)
|
||||
throw new IllegalArgumentException(formatError);
|
||||
if (!Character.isDigit(nanos_s.charAt(0)))
|
||||
throw new IllegalArgumentException(formatError);
|
||||
nanos_s = nanos_s + zeros.substring(0, 9 - nanos_s.length());
|
||||
a_nanos = Integer.parseInt(nanos_s);
|
||||
}
|
||||
else if (period > 0)
|
||||
throw new IllegalArgumentException(formatError);
|
||||
else
|
||||
{
|
||||
second = Integer.parseInt(s.substring(secondColon + 1));
|
||||
if (second < 0 || second >= 60)
|
||||
throw new IllegalArgumentException("Second out of bounds.");
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException(formatError);
|
||||
|
||||
long rawTime = 0;
|
||||
rawTime += TimeUnit.HOURS.toNanos(hour);
|
||||
rawTime += TimeUnit.MINUTES.toNanos(minute);
|
||||
rawTime += TimeUnit.SECONDS.toNanos(second);
|
||||
rawTime += a_nanos;
|
||||
return rawTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -35,3 +35,4 @@ public interface TypeSerializer<T>
|
|||
|
||||
public Class<T> getType();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ public enum DataType implements OptionCodec.Codecable<DataType>
|
|||
VARINT (14, IntegerType.instance),
|
||||
TIMEUUID (15, TimeUUIDType.instance),
|
||||
INET (16, InetAddressType.instance),
|
||||
DATE (17, DateType.instance),
|
||||
TIME (18, TimeType.instance),
|
||||
LIST (32, null),
|
||||
MAP (33, null),
|
||||
SET (34, null),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.apache.cassandra.serializers.SimpleDateSerializer;
|
||||
|
||||
public class SimpleDateTypeTest
|
||||
{
|
||||
@Test public void TestComparison()
|
||||
{
|
||||
ByteBuffer d1 = SimpleDateType.instance.fromString("1970-01-05");
|
||||
ByteBuffer d2 = SimpleDateSerializer.instance.serialize(makeUnsigned(4));
|
||||
assert SimpleDateType.instance.compare(d1, d2) == 0 : "Failed == comparison";
|
||||
String.format("Failed == comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("1970-01-05");
|
||||
d2 = SimpleDateSerializer.instance.serialize(makeUnsigned(10));
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed comparison of %s and %s, expected <",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("1970-01-05"); // 4
|
||||
d2 = SimpleDateSerializer.instance.serialize(makeUnsigned(-10));
|
||||
assert SimpleDateType.instance.compare(d1, d2) > 0 :
|
||||
String.format("Failed comparison of %s and %s, expected > 0",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("1");
|
||||
d2 = SimpleDateType.instance.fromString("1000");
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed < comparison with string inputs %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
Integer intLimit = Integer.MAX_VALUE;
|
||||
d1 = SimpleDateType.instance.fromString("0");
|
||||
d2 = SimpleDateType.instance.fromString(intLimit.toString());
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed < comparison with string inputs at integer bounds %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
Long overLimit = (long)(Integer.MAX_VALUE);
|
||||
d1 = SimpleDateType.instance.fromString("0");
|
||||
d2 = SimpleDateType.instance.fromString(overLimit.toString());
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed < comparison with string inputs at integer bounds %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
Long i1 = 0L;
|
||||
Long i2 = (long)Math.pow(2,32) - 1;
|
||||
d1 = SimpleDateType.instance.fromString(i1.toString());
|
||||
d2 = SimpleDateType.instance.fromString(i2.toString());
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed limits comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("256");
|
||||
d2 = SimpleDateType.instance.fromString("512");
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateSerializer.instance.serialize(makeUnsigned(0));
|
||||
d2 = SimpleDateSerializer.instance.serialize(makeUnsigned(Integer.MAX_VALUE));
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed neg/pos comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("-10000-10-10");
|
||||
d2 = SimpleDateType.instance.fromString("10000-10-10");
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed neg/pos string comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("1969-12-31");
|
||||
d2 = SimpleDateType.instance.fromString("1970-1-1");
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed pre/post epoch comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("1970-1-1");
|
||||
d2 = SimpleDateType.instance.fromString("1970-1-1");
|
||||
assert SimpleDateType.instance.compare(d1, d2) == 0 :
|
||||
String.format("Failed == date from string comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
d1 = SimpleDateType.instance.fromString("1970-1-1");
|
||||
d2 = SimpleDateType.instance.fromString("1970-1-2");
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed post epoch string comparison with %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
int offset = (int)Math.pow(2,i);
|
||||
d1 = SimpleDateSerializer.instance.serialize(makeUnsigned(0 - offset));
|
||||
d2 = SimpleDateSerializer.instance.serialize(makeUnsigned(offset));
|
||||
assert SimpleDateType.instance.compare(d1, d2) < 0 :
|
||||
String.format("Failed < comparison of %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
int offset = (int)Math.pow(2,i);
|
||||
d1 = SimpleDateSerializer.instance.serialize(makeUnsigned(offset));
|
||||
d2 = SimpleDateSerializer.instance.serialize(makeUnsigned(0 - offset));
|
||||
assert SimpleDateType.instance.compare(d1, d2) > 0 :
|
||||
String.format("Failed > comparison of %s and %s",
|
||||
SimpleDateSerializer.instance.deserialize(d1),
|
||||
SimpleDateSerializer.instance.deserialize(d2));
|
||||
}
|
||||
}
|
||||
|
||||
private Integer makeUnsigned(int input)
|
||||
{
|
||||
return input - Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.apache.cassandra.serializers.TimeSerializer;
|
||||
|
||||
public class TimeTypeTest
|
||||
{
|
||||
@Test public void TestComparison()
|
||||
{
|
||||
Long t1 = TimeSerializer.timeStringToLong("01:00:00.123456789");
|
||||
Long t2 = new Long((1L * 60L * 60L * 1000L * 1000L * 1000L) + 123456789);
|
||||
ByteBuffer b1 = TimeSerializer.instance.serialize(t1);
|
||||
ByteBuffer b2 = TimeSerializer.instance.serialize(t2);
|
||||
assert TimeType.instance.compare(b1, b2) == 0 : "Failed == comparison";
|
||||
|
||||
b2 = TimeSerializer.instance.serialize(123456789L);
|
||||
assert TimeType.instance.compare(b1, b2) > 0 : "Failed > comparison";
|
||||
|
||||
t2 = new Long(2L * 60L * 60L * 1000L * 1000L * 1000L + 123456789);
|
||||
b2 = TimeSerializer.instance.serialize(t2);
|
||||
assert TimeType.instance.compare(b1, b2) < 0 : "Failed < comparison";
|
||||
|
||||
b1 = TimeSerializer.instance.serialize(0L);
|
||||
b2 = TimeSerializer.instance.serialize(0L);
|
||||
assert TimeType.instance.compare(b1, b2) == 0 : "Failed == comparison on 0";
|
||||
|
||||
b1 = TimeSerializer.instance.serialize(0L);
|
||||
b2 = TimeSerializer.instance.serialize(10000000L);
|
||||
assert TimeType.instance.compare(b1, b2) == -1 : "Failed < comparison on 0";
|
||||
|
||||
b1 = TimeSerializer.instance.serialize(0L);
|
||||
b2 = TimeSerializer.instance.serialize(TimeUnit.DAYS.toNanos(1));
|
||||
assert TimeType.instance.compare(b1, b2) == -1 : "Failed < comparison against max range.";
|
||||
|
||||
b1 = TimeSerializer.instance.serialize(TimeUnit.DAYS.toNanos(1));
|
||||
b2 = TimeSerializer.instance.serialize(0L);
|
||||
assert TimeType.instance.compare(b1, b2) == 1 : "Failed > comparison against max range.";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.serializers;
|
||||
|
||||
import org.apache.cassandra.db.marshal.SimpleDateType;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
public class SimpleDateSerializerTest
|
||||
{
|
||||
private static final long millisPerDay = 1000 * 60 * 60 * 24;
|
||||
|
||||
private String dates[] = new String[]
|
||||
{
|
||||
"1970-01-01",
|
||||
"1970-01-02",
|
||||
"1969-12-31",
|
||||
"-0001-01-02",
|
||||
"-5877521-01-02",
|
||||
"2014-01-01",
|
||||
"5881580-01-10",
|
||||
"1920-12-01",
|
||||
"1582-10-19"
|
||||
};
|
||||
|
||||
private static GregorianCalendar testCalendar = new GregorianCalendar();
|
||||
private static SimpleDateFormat dateFormatUTC = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
testCalendar.setGregorianChange(new Date(Long.MIN_VALUE));
|
||||
testCalendar.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
dateFormatUTC.setCalendar(testCalendar);
|
||||
dateFormatUTC.setLenient(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateStringToTimestamp()
|
||||
{
|
||||
List<String> unparsedDates = new ArrayList<>();
|
||||
List<String> badParseResults = new ArrayList<>();
|
||||
for (String date : dates)
|
||||
{
|
||||
try
|
||||
{
|
||||
Integer days = SimpleDateSerializer.dateStringToDays(date);
|
||||
ByteBuffer value = SimpleDateSerializer.instance.serialize(days);
|
||||
Integer deserialized = SimpleDateSerializer.instance.deserialize(value);
|
||||
|
||||
String toStringValue = SimpleDateSerializer.instance.toString(deserialized);
|
||||
if (!date.equals(toStringValue)) {
|
||||
badParseResults.add(String.format("Failed to parse date correctly. Expected %s, got %s\n", date, toStringValue));
|
||||
}
|
||||
}
|
||||
catch (MarshalException e)
|
||||
{
|
||||
System.err.println("Got an exception: " + e);
|
||||
unparsedDates.add(date);
|
||||
}
|
||||
}
|
||||
assert unparsedDates.isEmpty() : "Unable to parse: " + unparsedDates;
|
||||
assert badParseResults.isEmpty() : "Incorrect parse results: " + badParseResults;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDaysStringToInt()
|
||||
{
|
||||
Integer value = SimpleDateSerializer.dateStringToDays("12345");
|
||||
assert value.compareTo(12345) == 0 : String.format("Failed to parse integer based date. Expected %s, got %s",
|
||||
12345,
|
||||
value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProlepticRange()
|
||||
{
|
||||
for (int i = 1; i < 31; ++i)
|
||||
{
|
||||
String date = "1582-10-";
|
||||
if (i < 10) date += "0";
|
||||
date += i;
|
||||
|
||||
Integer days = SimpleDateSerializer.dateStringToDays(date);
|
||||
|
||||
ByteBuffer value = SimpleDateType.instance.fromString(days.toString());
|
||||
Integer deserialized = SimpleDateSerializer.instance.deserialize(value);
|
||||
|
||||
// Serialized values are unsigned int, unwrap bits w/overflow
|
||||
deserialized -= Integer.MIN_VALUE;
|
||||
|
||||
Timestamp ts = new Timestamp(deserialized * millisPerDay);
|
||||
testCalendar.setTime(ts);
|
||||
|
||||
Date newDate = testCalendar.getTime();
|
||||
assert (dateFormatUTC.format(newDate)).equals(date) :
|
||||
String.format("Expected [%s], got [%s]", date, dateFormatUTC.format(newDate).toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testOutOfBoundsLow()
|
||||
{
|
||||
Integer days = SimpleDateSerializer.dateStringToDays(new Date(Integer.MIN_VALUE * millisPerDay - millisPerDay).toString());
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testOutOfBoundsHigh()
|
||||
{
|
||||
Integer days = SimpleDateSerializer.dateStringToDays(new Date(Integer.MAX_VALUE * millisPerDay + millisPerDay).toString());
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadInput()
|
||||
{
|
||||
Integer days = SimpleDateSerializer.dateStringToDays("12A-01-01");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadMonth()
|
||||
{
|
||||
Integer days = SimpleDateSerializer.dateStringToDays("1000-13-01");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadDay()
|
||||
{
|
||||
Integer days = SimpleDateSerializer.dateStringToDays("1000-12-32");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadDayToMonth()
|
||||
{
|
||||
Integer days = SimpleDateSerializer.dateStringToDays("1000-09-31");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.cassandra.serializers;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class TimeSerializerTest
|
||||
{
|
||||
@Test
|
||||
public void testSerializerFromString()
|
||||
{
|
||||
// nano
|
||||
long expected = 5;
|
||||
Long time = TimeSerializer.timeStringToLong("00:00:00.000000005");
|
||||
assert time == expected : String.format("Failed nano conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// usec
|
||||
expected = TimeUnit.MICROSECONDS.toNanos(123);
|
||||
time = TimeSerializer.timeStringToLong("00:00:00.000123000");
|
||||
assert time == expected : String.format("Failed usec conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// milli
|
||||
expected = TimeUnit.MILLISECONDS.toNanos(123);
|
||||
time = TimeSerializer.timeStringToLong("00:00:00.123000");
|
||||
assert time == expected : String.format("Failed milli conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// sec
|
||||
expected = TimeUnit.SECONDS.toNanos(15);
|
||||
time = TimeSerializer.timeStringToLong("00:00:15.000");
|
||||
assert time == expected : String.format("Failed sec conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// min
|
||||
expected = TimeUnit.MINUTES.toNanos(13);
|
||||
time = TimeSerializer.timeStringToLong("00:13:00.000");
|
||||
assert time == expected : String.format("Failed min conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// hour
|
||||
expected = TimeUnit.HOURS.toNanos(2);
|
||||
time = TimeSerializer.timeStringToLong("02:0:00.000");
|
||||
assert time == expected : String.format("Failed min conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// complex
|
||||
expected = buildExpected(4, 31, 12, 123, 456, 789);
|
||||
time = TimeSerializer.timeStringToLong("4:31:12.123456789");
|
||||
assert time == expected : String.format("Failed complex conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// upper bound
|
||||
expected = buildExpected(23, 59, 59, 999, 999, 999);
|
||||
time = TimeSerializer.timeStringToLong("23:59:59.999999999");
|
||||
assert time == expected : String.format("Failed upper bounds conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// Test partial nano
|
||||
expected = buildExpected(12, 13, 14, 123, 654, 120);
|
||||
time = TimeSerializer.timeStringToLong("12:13:14.12365412");
|
||||
assert time == expected : String.format("Failed partial nano timestring. Expected %s, got %s", expected, time);
|
||||
|
||||
// Test raw long value
|
||||
expected = 10;
|
||||
time = TimeSerializer.timeStringToLong("10");
|
||||
assert time == expected : String.format("Failed long conversion. Expected %s, got %s", expected, time);
|
||||
|
||||
// Test 0 long
|
||||
expected = 0;
|
||||
time = TimeSerializer.timeStringToLong("0");
|
||||
assert time == expected : String.format("Failed long conversion. Expected %s, got %s", expected, time);
|
||||
}
|
||||
|
||||
private long buildExpected(int hour, int minute, int second, int milli, int micro, int nano)
|
||||
{
|
||||
return TimeUnit.HOURS.toNanos(hour) +
|
||||
TimeUnit.MINUTES.toNanos(minute) +
|
||||
TimeUnit.SECONDS.toNanos(second) +
|
||||
TimeUnit.MILLISECONDS.toNanos(milli) +
|
||||
TimeUnit.MICROSECONDS.toNanos(micro) +
|
||||
nano;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializerToString()
|
||||
{
|
||||
String source = "00:00:00.000000011";
|
||||
Long time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
source = "00:00:00.000012311";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
source = "00:00:00.123000000";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
source = "00:00:12.123450000";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
source = "00:34:12.123450000";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
source = "15:00:12.123450000";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
// boundaries
|
||||
source = "00:00:00.000000000";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
source = "23:59:59.999999999";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
assert(source.equals(TimeSerializer.instance.toString(time)));
|
||||
|
||||
// truncated
|
||||
source = "01:14:18.12";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
String result = TimeSerializer.instance.toString(time);
|
||||
assert(result.equals("01:14:18.120000000"));
|
||||
|
||||
source = "01:14:18.1201";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
result = TimeSerializer.instance.toString(time);
|
||||
assert(result.equals("01:14:18.120100000"));
|
||||
|
||||
source = "01:14:18.1201098";
|
||||
time = TimeSerializer.timeStringToLong(source);
|
||||
result = TimeSerializer.instance.toString(time);
|
||||
assert(result.equals("01:14:18.120109800"));
|
||||
}
|
||||
|
||||
@Test public void testSerialization()
|
||||
{
|
||||
String source = "01:01:01.123123123";
|
||||
Long nt = TimeSerializer.timeStringToLong(source);
|
||||
|
||||
ByteBuffer buf = TimeSerializer.instance.serialize(nt);
|
||||
TimeSerializer.instance.validate(buf);
|
||||
|
||||
Long result = TimeSerializer.instance.deserialize(buf);
|
||||
String strResult = TimeSerializer.instance.toString(result);
|
||||
|
||||
assert(strResult.equals(source));
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadHourLow()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("-1:0:0.123456789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadHourHigh()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("24:0:0.123456789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadMinuteLow()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:-1:0.123456789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadMinuteHigh()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:60:0.123456789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testEmpty()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadSecondLow()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:59:-1.123456789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadSecondHigh()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:59:60.123456789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadSecondHighNoMilli()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:59:60");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadNanoLow()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:59:59.-123456789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadNanoHigh()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:59:59.1234567899");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testBadNanoCharacter()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("23:59:59.12345A789");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testNegativeLongTime()
|
||||
{
|
||||
Long time = TimeSerializer.timeStringToLong("-10");
|
||||
}
|
||||
|
||||
@Test (expected=MarshalException.class)
|
||||
public void testRawLongOverflow()
|
||||
{
|
||||
Long input = TimeUnit.DAYS.toNanos(1) + 1;
|
||||
Long time = TimeSerializer.timeStringToLong(input.toString());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue