mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-18 04:12:19 +00:00
Merge pull request #24350 from MyroTk/tfs_extended_precision_data_types_testing
Testflows tests for Extended Precision Data Types: Int128, UInt128, Int256, UInt256, Decimal256
This commit is contained in:
commit
91f910a612
118
tests/testflows/extended_precision_data_types/common.py
Normal file
118
tests/testflows/extended_precision_data_types/common.py
Normal file
@ -0,0 +1,118 @@
|
||||
import uuid
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from testflows.core.name import basename, parentname
|
||||
from testflows._core.testtype import TestSubType
|
||||
from testflows.asserts import values, error, snapshot
|
||||
|
||||
from helpers.common import *
|
||||
|
||||
@contextmanager
|
||||
def allow_experimental_bigint(node):
|
||||
"""Enable experimental big int setting in Clickhouse.
|
||||
"""
|
||||
setting = ("allow_experimental_bigint_types", 1)
|
||||
default_query_settings = None
|
||||
|
||||
try:
|
||||
with Given("I add allow_experimental_bigint to the default query settings"):
|
||||
default_query_settings = getsattr(current().context, "default_query_settings", [])
|
||||
default_query_settings.append(setting)
|
||||
yield
|
||||
finally:
|
||||
with Finally("I remove allow_experimental_bigint from the default query settings"):
|
||||
if default_query_settings:
|
||||
try:
|
||||
default_query_settings.pop(default_query_settings.index(setting))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
@TestStep(Given)
|
||||
def allow_experimental_map_type(self):
|
||||
"""Set allow_experimental_map_type = 1
|
||||
"""
|
||||
setting = ("allow_experimental_map_type", 1)
|
||||
default_query_settings = None
|
||||
|
||||
try:
|
||||
with By("adding allow_experimental_map_type to the default query settings"):
|
||||
default_query_settings = getsattr(current().context, "default_query_settings", [])
|
||||
default_query_settings.append(setting)
|
||||
yield
|
||||
finally:
|
||||
with Finally("I remove allow_experimental_map_type from the default query settings"):
|
||||
if default_query_settings:
|
||||
try:
|
||||
default_query_settings.pop(default_query_settings.index(setting))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def execute_query(sql, expected=None, format="TabSeparatedWithNames", compare_func=None):
|
||||
"""Execute SQL query and compare the output to the snapshot.
|
||||
"""
|
||||
name = basename(current().name)
|
||||
|
||||
with When("I execute query", description=sql):
|
||||
r = current().context.node.query(sql + " FORMAT " + format)
|
||||
|
||||
if expected is not None:
|
||||
with Then("I check output against expected"):
|
||||
|
||||
if compare_func is None:
|
||||
assert r.output.strip() == expected, error()
|
||||
|
||||
else:
|
||||
assert compare_func(r.output.strip(), expected), error()
|
||||
|
||||
else:
|
||||
with Then("I check output against snapshot"):
|
||||
with values() as that:
|
||||
assert that(snapshot("\n" + r.output.strip() + "\n", "tests", name=name, encoder=str)), error()
|
||||
|
||||
@TestStep(Given)
|
||||
def table(self, data_type, name="table0"):
|
||||
"""Create a table.
|
||||
"""
|
||||
node = current().context.node
|
||||
|
||||
try:
|
||||
with By("creating table"):
|
||||
node.query(f"CREATE TABLE {name}(a {data_type}) ENGINE = Memory")
|
||||
yield
|
||||
|
||||
finally:
|
||||
with Finally("drop the table"):
|
||||
node.query(f"DROP TABLE IF EXISTS {name}")
|
||||
|
||||
def getuid():
|
||||
"""Create a unique variable name based on the test it is called from.
|
||||
"""
|
||||
if current().subtype == TestSubType.Example:
|
||||
testname = f"{basename(parentname(current().name)).replace(' ', '_').replace(',','')}"
|
||||
else:
|
||||
testname = f"{basename(current().name).replace(' ', '_').replace(',','')}"
|
||||
|
||||
for char in ['(', ')', '[', ']','\'']:
|
||||
testname = testname.replace(f'{char}', '')
|
||||
|
||||
return testname + "_" + str(uuid.uuid1()).replace('-', '_')
|
||||
|
||||
def to_data_type(data_type, value):
|
||||
"""Return a conversion statement based on the data type provided
|
||||
"""
|
||||
if data_type in ['Decimal256(0)']:
|
||||
return f'toDecimal256(\'{value}\',0)'
|
||||
|
||||
else:
|
||||
return f'to{data_type}(\'{value}\')'
|
||||
|
||||
|
||||
data_types = [
|
||||
('Int128', '-170141183460469231731687303715884105728', '170141183460469231731687303715884105727'),
|
||||
('Int256', '-57896044618658097711785492504343953926634992332820282019728792003956564819968', '57896044618658097711785492504343953926634992332820282019728792003956564819967'),
|
||||
('UInt128','0','340282366920938463463374607431768211455'),
|
||||
('UInt256', '0', '115792089237316195423570985008687907853269984665640564039457584007913129639935'),
|
||||
]
|
||||
|
||||
Decimal256_min_max = -1000000000000000000000000000000000000000000000000000000000000000000000000000,1000000000000000000000000000000000000000000000000000000000000000000000000000
|
@ -0,0 +1,6 @@
|
||||
<yandex>
|
||||
<timezone>Europe/Moscow</timezone>
|
||||
<listen_host replace="replace">::</listen_host>
|
||||
<path>/var/lib/clickhouse/</path>
|
||||
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
|
||||
</yandex>
|
@ -0,0 +1,17 @@
|
||||
<yandex>
|
||||
<shutdown_wait_unfinished>3</shutdown_wait_unfinished>
|
||||
<logger>
|
||||
<level>trace</level>
|
||||
<log>/var/log/clickhouse-server/log.log</log>
|
||||
<errorlog>/var/log/clickhouse-server/log.err.log</errorlog>
|
||||
<size>1000M</size>
|
||||
<count>10</count>
|
||||
<stderr>/var/log/clickhouse-server/stderr.log</stderr>
|
||||
<stdout>/var/log/clickhouse-server/stdout.log</stdout>
|
||||
</logger>
|
||||
<part_log>
|
||||
<database>system</database>
|
||||
<table>part_log</table>
|
||||
<flush_interval_milliseconds>500</flush_interval_milliseconds>
|
||||
</part_log>
|
||||
</yandex>
|
@ -0,0 +1,20 @@
|
||||
<yandex>
|
||||
|
||||
<storage_configuration>
|
||||
<disks>
|
||||
<default>
|
||||
<keep_free_space_bytes>1024</keep_free_space_bytes>
|
||||
</default>
|
||||
</disks>
|
||||
<policies>
|
||||
<default>
|
||||
<volumes>
|
||||
<default>
|
||||
<disk>default</disk>
|
||||
</default>
|
||||
</volumes>
|
||||
</default>
|
||||
</policies>
|
||||
</storage_configuration>
|
||||
|
||||
</yandex>
|
@ -0,0 +1,448 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
NOTE: User and query level settings are set up in "users.xml" file.
|
||||
-->
|
||||
<yandex>
|
||||
<logger>
|
||||
<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger.h#L105 -->
|
||||
<level>trace</level>
|
||||
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
|
||||
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
|
||||
<size>1000M</size>
|
||||
<count>10</count>
|
||||
<!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
|
||||
</logger>
|
||||
<!--display_name>production</display_name--> <!-- It is the name that will be shown in the client -->
|
||||
<http_port>8123</http_port>
|
||||
<tcp_port>9000</tcp_port>
|
||||
|
||||
<!-- For HTTPS and SSL over native protocol. -->
|
||||
<!--
|
||||
<https_port>8443</https_port>
|
||||
<tcp_port_secure>9440</tcp_port_secure>
|
||||
-->
|
||||
|
||||
<!-- Used with https_port and tcp_port_secure. Full ssl options list: https://github.com/ClickHouse-Extras/poco/blob/master/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h#L71 -->
|
||||
<openSSL>
|
||||
<server> <!-- Used for https server AND secure tcp port -->
|
||||
<!-- openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt -->
|
||||
<certificateFile>/etc/clickhouse-server/server.crt</certificateFile>
|
||||
<privateKeyFile>/etc/clickhouse-server/server.key</privateKeyFile>
|
||||
<!-- openssl dhparam -out /etc/clickhouse-server/dhparam.pem 4096 -->
|
||||
<dhParamsFile>/etc/clickhouse-server/dhparam.pem</dhParamsFile>
|
||||
<verificationMode>none</verificationMode>
|
||||
<loadDefaultCAFile>true</loadDefaultCAFile>
|
||||
<cacheSessions>true</cacheSessions>
|
||||
<disableProtocols>sslv2,sslv3</disableProtocols>
|
||||
<preferServerCiphers>true</preferServerCiphers>
|
||||
</server>
|
||||
|
||||
<client> <!-- Used for connecting to https dictionary source -->
|
||||
<loadDefaultCAFile>true</loadDefaultCAFile>
|
||||
<cacheSessions>true</cacheSessions>
|
||||
<disableProtocols>sslv2,sslv3</disableProtocols>
|
||||
<preferServerCiphers>true</preferServerCiphers>
|
||||
<!-- Use for self-signed: <verificationMode>none</verificationMode> -->
|
||||
<invalidCertificateHandler>
|
||||
<!-- Use for self-signed: <name>AcceptCertificateHandler</name> -->
|
||||
<name>RejectCertificateHandler</name>
|
||||
</invalidCertificateHandler>
|
||||
</client>
|
||||
</openSSL>
|
||||
|
||||
<!-- Default root page on http[s] server. For example load UI from https://tabix.io/ when opening http://localhost:8123 -->
|
||||
<!--
|
||||
<http_server_default_response><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></http_server_default_response>
|
||||
-->
|
||||
|
||||
<!-- Port for communication between replicas. Used for data exchange. -->
|
||||
<interserver_http_port>9009</interserver_http_port>
|
||||
|
||||
<!-- Hostname that is used by other replicas to request this server.
|
||||
If not specified, than it is determined analoguous to 'hostname -f' command.
|
||||
This setting could be used to switch replication to another network interface.
|
||||
-->
|
||||
<!--
|
||||
<interserver_http_host>example.yandex.ru</interserver_http_host>
|
||||
-->
|
||||
|
||||
<!-- Listen specified host. use :: (wildcard IPv6 address), if you want to accept connections both with IPv4 and IPv6 from everywhere. -->
|
||||
<!-- <listen_host>::</listen_host> -->
|
||||
<!-- Same for hosts with disabled ipv6: -->
|
||||
<listen_host>0.0.0.0</listen_host>
|
||||
|
||||
<!-- Default values - try listen localhost on ipv4 and ipv6: -->
|
||||
<!--
|
||||
<listen_host>::1</listen_host>
|
||||
<listen_host>127.0.0.1</listen_host>
|
||||
-->
|
||||
<!-- Don't exit if ipv6 or ipv4 unavailable, but listen_host with this protocol specified -->
|
||||
<!-- <listen_try>0</listen_try> -->
|
||||
|
||||
<!-- Allow listen on same address:port -->
|
||||
<!-- <listen_reuse_port>0</listen_reuse_port> -->
|
||||
|
||||
<!-- <listen_backlog>64</listen_backlog> -->
|
||||
|
||||
<max_connections>4096</max_connections>
|
||||
<keep_alive_timeout>3</keep_alive_timeout>
|
||||
|
||||
<!-- Maximum number of concurrent queries. -->
|
||||
<max_concurrent_queries>100</max_concurrent_queries>
|
||||
|
||||
<!-- Set limit on number of open files (default: maximum). This setting makes sense on Mac OS X because getrlimit() fails to retrieve
|
||||
correct maximum value. -->
|
||||
<!-- <max_open_files>262144</max_open_files> -->
|
||||
|
||||
<!-- Size of cache of uncompressed blocks of data, used in tables of MergeTree family.
|
||||
In bytes. Cache is single for server. Memory is allocated only on demand.
|
||||
Cache is used when 'use_uncompressed_cache' user setting turned on (off by default).
|
||||
Uncompressed cache is advantageous only for very short queries and in rare cases.
|
||||
-->
|
||||
<uncompressed_cache_size>8589934592</uncompressed_cache_size>
|
||||
|
||||
<!-- Approximate size of mark cache, used in tables of MergeTree family.
|
||||
In bytes. Cache is single for server. Memory is allocated only on demand.
|
||||
You should not lower this value.
|
||||
-->
|
||||
<mark_cache_size>5368709120</mark_cache_size>
|
||||
|
||||
|
||||
<!-- Path to data directory, with trailing slash. -->
|
||||
<path>/var/lib/clickhouse/</path>
|
||||
|
||||
<!-- Path to temporary data for processing hard queries. -->
|
||||
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
|
||||
|
||||
<!-- Directory with user provided files that are accessible by 'file' table function. -->
|
||||
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
|
||||
|
||||
<!-- Path to folder where users and roles created by SQL commands are stored. -->
|
||||
<access_control_path>/var/lib/clickhouse/access/</access_control_path>
|
||||
|
||||
<!-- Sources to read users, roles, access rights, profiles of settings, quotas. -->
|
||||
<user_directories>
|
||||
<users_xml>
|
||||
<!-- Path to configuration file with predefined users. -->
|
||||
<path>users.xml</path>
|
||||
</users_xml>
|
||||
<local_directory>
|
||||
<!-- Path to folder where users created by SQL commands are stored. -->
|
||||
<path>/var/lib/clickhouse/access/</path>
|
||||
</local_directory>
|
||||
</user_directories>
|
||||
|
||||
<!-- Path to configuration file with users, access rights, profiles of settings, quotas. -->
|
||||
<users_config>users.xml</users_config>
|
||||
|
||||
<!-- Default profile of settings. -->
|
||||
<default_profile>default</default_profile>
|
||||
|
||||
<!-- System profile of settings. This settings are used by internal processes (Buffer storage, Distibuted DDL worker and so on). -->
|
||||
<!-- <system_profile>default</system_profile> -->
|
||||
|
||||
<!-- Default database. -->
|
||||
<default_database>default</default_database>
|
||||
|
||||
<!-- Server time zone could be set here.
|
||||
|
||||
Time zone is used when converting between String and DateTime types,
|
||||
when printing DateTime in text formats and parsing DateTime from text,
|
||||
it is used in date and time related functions, if specific time zone was not passed as an argument.
|
||||
|
||||
Time zone is specified as identifier from IANA time zone database, like UTC or Africa/Abidjan.
|
||||
If not specified, system time zone at server startup is used.
|
||||
|
||||
Please note, that server could display time zone alias instead of specified name.
|
||||
Example: W-SU is an alias for Europe/Moscow and Zulu is an alias for UTC.
|
||||
-->
|
||||
<!-- <timezone>Europe/Moscow</timezone> -->
|
||||
|
||||
<!-- You can specify umask here (see "man umask"). Server will apply it on startup.
|
||||
Number is always parsed as octal. Default umask is 027 (other users cannot read logs, data files, etc; group can only read).
|
||||
-->
|
||||
<!-- <umask>022</umask> -->
|
||||
|
||||
<!-- Perform mlockall after startup to lower first queries latency
|
||||
and to prevent clickhouse executable from being paged out under high IO load.
|
||||
Enabling this option is recommended but will lead to increased startup time for up to a few seconds.
|
||||
-->
|
||||
<mlock_executable>false</mlock_executable>
|
||||
|
||||
<!-- Configuration of clusters that could be used in Distributed tables.
|
||||
https://clickhouse.yandex/docs/en/table_engines/distributed/
|
||||
-->
|
||||
<remote_servers incl="clickhouse_remote_servers" >
|
||||
<!-- Test only shard config for testing distributed storage -->
|
||||
<test_shard_localhost>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>localhost</host>
|
||||
<port>9000</port>
|
||||
</replica>
|
||||
</shard>
|
||||
</test_shard_localhost>
|
||||
<test_cluster_two_shards_localhost>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>localhost</host>
|
||||
<port>9000</port>
|
||||
</replica>
|
||||
</shard>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>localhost</host>
|
||||
<port>9000</port>
|
||||
</replica>
|
||||
</shard>
|
||||
</test_cluster_two_shards_localhost>
|
||||
<test_shard_localhost_secure>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>localhost</host>
|
||||
<port>9440</port>
|
||||
<secure>1</secure>
|
||||
</replica>
|
||||
</shard>
|
||||
</test_shard_localhost_secure>
|
||||
<test_unavailable_shard>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>localhost</host>
|
||||
<port>9000</port>
|
||||
</replica>
|
||||
</shard>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>localhost</host>
|
||||
<port>1</port>
|
||||
</replica>
|
||||
</shard>
|
||||
</test_unavailable_shard>
|
||||
</remote_servers>
|
||||
|
||||
|
||||
<!-- If element has 'incl' attribute, then for it's value will be used corresponding substitution from another file.
|
||||
By default, path to file with substitutions is /etc/metrika.xml. It could be changed in config in 'include_from' element.
|
||||
Values for substitutions are specified in /yandex/name_of_substitution elements in that file.
|
||||
-->
|
||||
|
||||
<!-- ZooKeeper is used to store metadata about replicas, when using Replicated tables.
|
||||
Optional. If you don't use replicated tables, you could omit that.
|
||||
|
||||
See https://clickhouse.yandex/docs/en/table_engines/replication/
|
||||
-->
|
||||
<zookeeper incl="zookeeper-servers" optional="true" />
|
||||
|
||||
<!-- Substitutions for parameters of replicated tables.
|
||||
Optional. If you don't use replicated tables, you could omit that.
|
||||
|
||||
See https://clickhouse.yandex/docs/en/table_engines/replication/#creating-replicated-tables
|
||||
-->
|
||||
<macros incl="macros" optional="true" />
|
||||
|
||||
|
||||
<!-- Reloading interval for embedded dictionaries, in seconds. Default: 3600. -->
|
||||
<builtin_dictionaries_reload_interval>3600</builtin_dictionaries_reload_interval>
|
||||
|
||||
|
||||
<!-- Maximum session timeout, in seconds. Default: 3600. -->
|
||||
<max_session_timeout>3600</max_session_timeout>
|
||||
|
||||
<!-- Default session timeout, in seconds. Default: 60. -->
|
||||
<default_session_timeout>60</default_session_timeout>
|
||||
|
||||
<!-- Sending data to Graphite for monitoring. Several sections can be defined. -->
|
||||
<!--
|
||||
interval - send every X second
|
||||
root_path - prefix for keys
|
||||
hostname_in_path - append hostname to root_path (default = true)
|
||||
metrics - send data from table system.metrics
|
||||
events - send data from table system.events
|
||||
asynchronous_metrics - send data from table system.asynchronous_metrics
|
||||
-->
|
||||
<!--
|
||||
<graphite>
|
||||
<host>localhost</host>
|
||||
<port>42000</port>
|
||||
<timeout>0.1</timeout>
|
||||
<interval>60</interval>
|
||||
<root_path>one_min</root_path>
|
||||
<hostname_in_path>true</hostname_in_path>
|
||||
|
||||
<metrics>true</metrics>
|
||||
<events>true</events>
|
||||
<asynchronous_metrics>true</asynchronous_metrics>
|
||||
</graphite>
|
||||
<graphite>
|
||||
<host>localhost</host>
|
||||
<port>42000</port>
|
||||
<timeout>0.1</timeout>
|
||||
<interval>1</interval>
|
||||
<root_path>one_sec</root_path>
|
||||
|
||||
<metrics>true</metrics>
|
||||
<events>true</events>
|
||||
<asynchronous_metrics>false</asynchronous_metrics>
|
||||
</graphite>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Query log. Used only for queries with setting log_queries = 1. -->
|
||||
<query_log>
|
||||
<!-- What table to insert data. If table is not exist, it will be created.
|
||||
When query log structure is changed after system update,
|
||||
then old table will be renamed and new table will be created automatically.
|
||||
-->
|
||||
<database>system</database>
|
||||
<table>query_log</table>
|
||||
<!--
|
||||
PARTITION BY expr https://clickhouse.yandex/docs/en/table_engines/custom_partitioning_key/
|
||||
Example:
|
||||
event_date
|
||||
toMonday(event_date)
|
||||
toYYYYMM(event_date)
|
||||
toStartOfHour(event_time)
|
||||
-->
|
||||
<partition_by>toYYYYMM(event_date)</partition_by>
|
||||
<!-- Interval of flushing data. -->
|
||||
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
|
||||
</query_log>
|
||||
|
||||
<!-- Trace log. Stores stack traces collected by query profilers.
|
||||
See query_profiler_real_time_period_ns and query_profiler_cpu_time_period_ns settings. -->
|
||||
<trace_log>
|
||||
<database>system</database>
|
||||
<table>trace_log</table>
|
||||
|
||||
<partition_by>toYYYYMM(event_date)</partition_by>
|
||||
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
|
||||
</trace_log>
|
||||
|
||||
<!-- Query thread log. Has information about all threads participated in query execution.
|
||||
Used only for queries with setting log_query_threads = 1. -->
|
||||
<query_thread_log>
|
||||
<database>system</database>
|
||||
<table>query_thread_log</table>
|
||||
<partition_by>toYYYYMM(event_date)</partition_by>
|
||||
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
|
||||
</query_thread_log>
|
||||
|
||||
<!-- Uncomment if use part log.
|
||||
Part log contains information about all actions with parts in MergeTree tables (creation, deletion, merges, downloads).
|
||||
<part_log>
|
||||
<database>system</database>
|
||||
<table>part_log</table>
|
||||
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
|
||||
</part_log>
|
||||
-->
|
||||
|
||||
<!-- Uncomment to write text log into table.
|
||||
Text log contains all information from usual server log but stores it in structured and efficient way.
|
||||
<text_log>
|
||||
<database>system</database>
|
||||
<table>text_log</table>
|
||||
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
|
||||
</text_log>
|
||||
-->
|
||||
|
||||
<!-- Parameters for embedded dictionaries, used in Yandex.Metrica.
|
||||
See https://clickhouse.yandex/docs/en/dicts/internal_dicts/
|
||||
-->
|
||||
|
||||
<!-- Path to file with region hierarchy. -->
|
||||
<!-- <path_to_regions_hierarchy_file>/opt/geo/regions_hierarchy.txt</path_to_regions_hierarchy_file> -->
|
||||
|
||||
<!-- Path to directory with files containing names of regions -->
|
||||
<!-- <path_to_regions_names_files>/opt/geo/</path_to_regions_names_files> -->
|
||||
|
||||
|
||||
<!-- Configuration of external dictionaries. See:
|
||||
https://clickhouse.yandex/docs/en/dicts/external_dicts/
|
||||
-->
|
||||
<dictionaries_config>*_dictionary.xml</dictionaries_config>
|
||||
|
||||
<!-- Uncomment if you want data to be compressed 30-100% better.
|
||||
Don't do that if you just started using ClickHouse.
|
||||
-->
|
||||
<compression incl="clickhouse_compression">
|
||||
<!--
|
||||
<!- - Set of variants. Checked in order. Last matching case wins. If nothing matches, lz4 will be used. - ->
|
||||
<case>
|
||||
|
||||
<!- - Conditions. All must be satisfied. Some conditions may be omitted. - ->
|
||||
<min_part_size>10000000000</min_part_size> <!- - Min part size in bytes. - ->
|
||||
<min_part_size_ratio>0.01</min_part_size_ratio> <!- - Min size of part relative to whole table size. - ->
|
||||
|
||||
<!- - What compression method to use. - ->
|
||||
<method>zstd</method>
|
||||
</case>
|
||||
-->
|
||||
</compression>
|
||||
|
||||
<!-- Allow to execute distributed DDL queries (CREATE, DROP, ALTER, RENAME) on cluster.
|
||||
Works only if ZooKeeper is enabled. Comment it if such functionality isn't required. -->
|
||||
<distributed_ddl>
|
||||
<!-- Path in ZooKeeper to queue with DDL queries -->
|
||||
<path>/clickhouse/task_queue/ddl</path>
|
||||
|
||||
<!-- Settings from this profile will be used to execute DDL queries -->
|
||||
<!-- <profile>default</profile> -->
|
||||
</distributed_ddl>
|
||||
|
||||
<!-- Settings to fine tune MergeTree tables. See documentation in source code, in MergeTreeSettings.h -->
|
||||
<!--
|
||||
<merge_tree>
|
||||
<max_suspicious_broken_parts>5</max_suspicious_broken_parts>
|
||||
</merge_tree>
|
||||
-->
|
||||
|
||||
<!-- Protection from accidental DROP.
|
||||
If size of a MergeTree table is greater than max_table_size_to_drop (in bytes) than table could not be dropped with any DROP query.
|
||||
If you want do delete one table and don't want to restart clickhouse-server, you could create special file <clickhouse-path>/flags/force_drop_table and make DROP once.
|
||||
By default max_table_size_to_drop is 50GB; max_table_size_to_drop=0 allows to DROP any tables.
|
||||
The same for max_partition_size_to_drop.
|
||||
Uncomment to disable protection.
|
||||
-->
|
||||
<!-- <max_table_size_to_drop>0</max_table_size_to_drop> -->
|
||||
<!-- <max_partition_size_to_drop>0</max_partition_size_to_drop> -->
|
||||
|
||||
<!-- Example of parameters for GraphiteMergeTree table engine -->
|
||||
<graphite_rollup_example>
|
||||
<pattern>
|
||||
<regexp>click_cost</regexp>
|
||||
<function>any</function>
|
||||
<retention>
|
||||
<age>0</age>
|
||||
<precision>3600</precision>
|
||||
</retention>
|
||||
<retention>
|
||||
<age>86400</age>
|
||||
<precision>60</precision>
|
||||
</retention>
|
||||
</pattern>
|
||||
<default>
|
||||
<function>max</function>
|
||||
<retention>
|
||||
<age>0</age>
|
||||
<precision>60</precision>
|
||||
</retention>
|
||||
<retention>
|
||||
<age>3600</age>
|
||||
<precision>300</precision>
|
||||
</retention>
|
||||
<retention>
|
||||
<age>86400</age>
|
||||
<precision>3600</precision>
|
||||
</retention>
|
||||
</default>
|
||||
</graphite_rollup_example>
|
||||
|
||||
<!-- Directory in <clickhouse-path> containing schema files for various input formats.
|
||||
The directory will be created if it doesn't exist.
|
||||
-->
|
||||
<format_schema_path>/var/lib/clickhouse/format_schemas/</format_schema_path>
|
||||
|
||||
<!-- Uncomment to disable ClickHouse internal DNS caching. -->
|
||||
<!-- <disable_internal_dns_cache>1</disable_internal_dns_cache> -->
|
||||
</yandex>
|
@ -0,0 +1,133 @@
|
||||
<?xml version="1.0"?>
|
||||
<yandex>
|
||||
<!-- Profiles of settings. -->
|
||||
<profiles>
|
||||
<!-- Default settings. -->
|
||||
<default>
|
||||
<!-- Maximum memory usage for processing single query, in bytes. -->
|
||||
<max_memory_usage>10000000000</max_memory_usage>
|
||||
|
||||
<!-- Use cache of uncompressed blocks of data. Meaningful only for processing many of very short queries. -->
|
||||
<use_uncompressed_cache>0</use_uncompressed_cache>
|
||||
|
||||
<!-- How to choose between replicas during distributed query processing.
|
||||
random - choose random replica from set of replicas with minimum number of errors
|
||||
nearest_hostname - from set of replicas with minimum number of errors, choose replica
|
||||
with minimum number of different symbols between replica's hostname and local hostname
|
||||
(Hamming distance).
|
||||
in_order - first live replica is chosen in specified order.
|
||||
first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
|
||||
-->
|
||||
<load_balancing>random</load_balancing>
|
||||
</default>
|
||||
|
||||
<!-- Profile that allows only read queries. -->
|
||||
<readonly>
|
||||
<readonly>1</readonly>
|
||||
</readonly>
|
||||
</profiles>
|
||||
|
||||
<!-- Users and ACL. -->
|
||||
<users>
|
||||
<!-- If user name was not specified, 'default' user is used. -->
|
||||
<default>
|
||||
<!-- Password could be specified in plaintext or in SHA256 (in hex format).
|
||||
|
||||
If you want to specify password in plaintext (not recommended), place it in 'password' element.
|
||||
Example: <password>qwerty</password>.
|
||||
Password could be empty.
|
||||
|
||||
If you want to specify SHA256, place it in 'password_sha256_hex' element.
|
||||
Example: <password_sha256_hex>65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5</password_sha256_hex>
|
||||
Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
|
||||
|
||||
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
|
||||
Example: <password_double_sha1_hex>e395796d6546b1b65db9d665cd43f0e858dd4303</password_double_sha1_hex>
|
||||
|
||||
How to generate decent password:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
|
||||
In first line will be password and in second - corresponding SHA256.
|
||||
|
||||
How to generate double SHA1:
|
||||
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | openssl dgst -sha1 -binary | openssl dgst -sha1
|
||||
In first line will be password and in second - corresponding double SHA1.
|
||||
-->
|
||||
<password></password>
|
||||
|
||||
<!-- List of networks with open access.
|
||||
|
||||
To open access from everywhere, specify:
|
||||
<ip>::/0</ip>
|
||||
|
||||
To open access only from localhost, specify:
|
||||
<ip>::1</ip>
|
||||
<ip>127.0.0.1</ip>
|
||||
|
||||
Each element of list has one of the following forms:
|
||||
<ip> IP-address or network mask. Examples: 213.180.204.3 or 10.0.0.1/8 or 10.0.0.1/255.255.255.0
|
||||
2a02:6b8::3 or 2a02:6b8::3/64 or 2a02:6b8::3/ffff:ffff:ffff:ffff::.
|
||||
<host> Hostname. Example: server01.yandex.ru.
|
||||
To check access, DNS query is performed, and all received addresses compared to peer address.
|
||||
<host_regexp> Regular expression for host names. Example, ^server\d\d-\d\d-\d\.yandex\.ru$
|
||||
To check access, DNS PTR query is performed for peer address and then regexp is applied.
|
||||
Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
|
||||
Strongly recommended that regexp is ends with $
|
||||
All results of DNS requests are cached till server restart.
|
||||
-->
|
||||
<networks incl="networks" replace="replace">
|
||||
<ip>::/0</ip>
|
||||
</networks>
|
||||
|
||||
<!-- Settings profile for user. -->
|
||||
<profile>default</profile>
|
||||
|
||||
<!-- Quota for user. -->
|
||||
<quota>default</quota>
|
||||
|
||||
<!-- Allow access management -->
|
||||
<access_management>1</access_management>
|
||||
|
||||
<!-- Example of row level security policy. -->
|
||||
<!-- <databases>
|
||||
<test>
|
||||
<filtered_table1>
|
||||
<filter>a = 1</filter>
|
||||
</filtered_table1>
|
||||
<filtered_table2>
|
||||
<filter>a + b < 1 or c - d > 5</filter>
|
||||
</filtered_table2>
|
||||
</test>
|
||||
</databases> -->
|
||||
</default>
|
||||
|
||||
<!-- Example of user with readonly access. -->
|
||||
<!-- <readonly>
|
||||
<password></password>
|
||||
<networks incl="networks" replace="replace">
|
||||
<ip>::1</ip>
|
||||
<ip>127.0.0.1</ip>
|
||||
</networks>
|
||||
<profile>readonly</profile>
|
||||
<quota>default</quota>
|
||||
</readonly> -->
|
||||
</users>
|
||||
|
||||
<!-- Quotas. -->
|
||||
<quotas>
|
||||
<!-- Name of quota. -->
|
||||
<default>
|
||||
<!-- Limits for time interval. You could specify many intervals with different limits. -->
|
||||
<interval>
|
||||
<!-- Length of interval. -->
|
||||
<duration>3600</duration>
|
||||
|
||||
<!-- No limits. Just calculate resource usage for time interval. -->
|
||||
<queries>0</queries>
|
||||
<errors>0</errors>
|
||||
<result_rows>0</result_rows>
|
||||
<read_rows>0</read_rows>
|
||||
<execution_time>0</execution_time>
|
||||
</interval>
|
||||
</default>
|
||||
</quotas>
|
||||
</yandex>
|
11
tests/testflows/extended_precision_data_types/errors.py
Normal file
11
tests/testflows/extended_precision_data_types/errors.py
Normal file
@ -0,0 +1,11 @@
|
||||
def not_implemented_bigints(name):
|
||||
return(48, f"Exception: {name} is not implemented for big integers")
|
||||
|
||||
def bigints_not_implements(name):
|
||||
return(48, f'Exception: {name} for big integers is not implemented')
|
||||
|
||||
def illegal_type():
|
||||
return(43, 'Exception: Illegal type')
|
||||
|
||||
def illegal_column():
|
||||
return(44, 'Exception: Illegal column')
|
@ -0,0 +1,27 @@
|
||||
version: '2.3'
|
||||
|
||||
services:
|
||||
clickhouse:
|
||||
image: yandex/clickhouse-integration-test
|
||||
expose:
|
||||
- "9000"
|
||||
- "9009"
|
||||
- "8123"
|
||||
volumes:
|
||||
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/config.d:/etc/clickhouse-server/config.d"
|
||||
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/users.d:/etc/clickhouse-server/users.d"
|
||||
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/config.xml:/etc/clickhouse-server/config.xml"
|
||||
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/users.xml:/etc/clickhouse-server/users.xml"
|
||||
- "${CLICKHOUSE_TESTS_SERVER_BIN_PATH:-/usr/bin/clickhouse}:/usr/bin/clickhouse"
|
||||
- "${CLICKHOUSE_TESTS_ODBC_BRIDGE_BIN_PATH:-/usr/bin/clickhouse-odbc-bridge}:/usr/bin/clickhouse-odbc-bridge"
|
||||
entrypoint: bash -c "clickhouse server --config-file=/etc/clickhouse-server/config.xml --log-file=/var/log/clickhouse-server/clickhouse-server.log --errorlog-file=/var/log/clickhouse-server/clickhouse-server.err.log"
|
||||
healthcheck:
|
||||
test: clickhouse client --query='select 1'
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 300s
|
||||
cap_add:
|
||||
- SYS_PTRACE
|
||||
security_opt:
|
||||
- label:disable
|
@ -0,0 +1,30 @@
|
||||
version: '2.3'
|
||||
|
||||
services:
|
||||
|
||||
mysql1:
|
||||
extends:
|
||||
file: mysql-service.yml
|
||||
service: mysql
|
||||
hostname: mysql1
|
||||
volumes:
|
||||
- "${CLICKHOUSE_TESTS_DIR}/_instances/mysql1/database:/var/lib/mysql"
|
||||
|
||||
clickhouse1:
|
||||
extends:
|
||||
file: clickhouse-service.yml
|
||||
service: clickhouse
|
||||
hostname: clickhouse1
|
||||
volumes:
|
||||
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/database/:/var/lib/clickhouse/"
|
||||
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/logs/:/var/log/clickhouse-server/"
|
||||
|
||||
# dummy service which does nothing, but allows to postpone
|
||||
# 'docker-compose up -d' till all dependecies will go healthy
|
||||
all_services_ready:
|
||||
image: hello-world
|
||||
depends_on:
|
||||
clickhouse1:
|
||||
condition: service_healthy
|
||||
mysql1:
|
||||
condition: service_healthy
|
@ -0,0 +1,19 @@
|
||||
version: '2.3'
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7.30
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_DATABASE: 'db'
|
||||
MYSQL_USER: 'user'
|
||||
MYSQL_PASSWORD: 'password'
|
||||
MYSQL_ROOT_PASSWORD: 'password'
|
||||
expose:
|
||||
- '3306'
|
||||
healthcheck:
|
||||
test: mysql -D db -u user --password=password -e "select 1;"
|
||||
interval: 3s
|
||||
timeout: 2s
|
||||
retries: 40
|
||||
start_period: 2s
|
52
tests/testflows/extended_precision_data_types/regression.py
Executable file
52
tests/testflows/extended_precision_data_types/regression.py
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
|
||||
from testflows.core import *
|
||||
|
||||
append_path(sys.path, "..")
|
||||
|
||||
from helpers.cluster import Cluster
|
||||
from helpers.argparser import argparser
|
||||
from extended_precision_data_types.requirements import *
|
||||
|
||||
xfails = {
|
||||
}
|
||||
|
||||
xflags = {
|
||||
}
|
||||
|
||||
@TestModule
|
||||
@ArgumentParser(argparser)
|
||||
@XFails(xfails)
|
||||
@XFlags(xflags)
|
||||
@Name("extended precision data types")
|
||||
@Specifications(
|
||||
QA_SRS020_ClickHouse_Extended_Precision_Data_Types
|
||||
)
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision("1.0"),
|
||||
)
|
||||
def regression(self, local, clickhouse_binary_path, stress=None, parallel=None):
|
||||
"""Extended precision data type regression.
|
||||
"""
|
||||
|
||||
top().terminating = False
|
||||
|
||||
nodes = {
|
||||
"clickhouse":
|
||||
("clickhouse1",)
|
||||
}
|
||||
with Cluster(local, clickhouse_binary_path, nodes=nodes,
|
||||
docker_compose_project_dir=os.path.join(current_dir(), "extended-precision-data-type_env")) as cluster:
|
||||
|
||||
self.context.cluster = cluster
|
||||
self.context.stress = stress
|
||||
|
||||
if parallel is not None:
|
||||
self.context.parallel = parallel
|
||||
|
||||
Feature(run=load("extended_precision_data_types.tests.feature", "feature"))
|
||||
|
||||
if main():
|
||||
regression()
|
@ -0,0 +1 @@
|
||||
from .requirements import *
|
@ -0,0 +1,565 @@
|
||||
# QA-SRS020 ClickHouse Extended Precision Data Types
|
||||
# Software Requirements Specification
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* 1 [Revision History](#revision-history)
|
||||
* 2 [Introduction](#introduction)
|
||||
* 3 [Terminology](#terminology)
|
||||
* 3.1 [Extended Precision Data Types](#extended-precision-data-types)
|
||||
* 4 [Requirements](#requirements)
|
||||
* 4.1 [RQ.SRS-020.ClickHouse.Extended.Precision](#rqsrs-020clickhouseextendedprecision)
|
||||
* 4.2 [Conversion](#conversion)
|
||||
* 4.2.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toInt128](#rqsrs-020clickhouseextendedprecisionconversiontoint128)
|
||||
* 4.2.2 [RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toUInt128](#rqsrs-020clickhouseextendedprecisionconversiontouint128)
|
||||
* 4.2.3 [RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toInt256](#rqsrs-020clickhouseextendedprecisionconversiontoint256)
|
||||
* 4.2.4 [RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toUInt256](#rqsrs-020clickhouseextendedprecisionconversiontouint256)
|
||||
* 4.2.5 [RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toDecimal256](#rqsrs-020clickhouseextendedprecisionconversiontodecimal256)
|
||||
* 4.2.6 [RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.FromMySQL](#rqsrs-020clickhouseextendedprecisionconversionfrommysql)
|
||||
* 4.2.7 [RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.ToMySQL](#rqsrs-020clickhouseextendedprecisionconversiontomysql)
|
||||
* 4.3 [Arithmetic](#arithmetic)
|
||||
* 4.3.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Arithmetic.Int.Supported](#rqsrs-020clickhouseextendedprecisionarithmeticintsupported)
|
||||
* 4.3.2 [RQ.SRS-020.ClickHouse.Extended.Precision.Arithmetic.Dec.Supported](#rqsrs-020clickhouseextendedprecisionarithmeticdecsupported)
|
||||
* 4.3.3 [RQ.SRS-020.ClickHouse.Extended.Precision.Arithmetic.Dec.NotSupported](#rqsrs-020clickhouseextendedprecisionarithmeticdecnotsupported)
|
||||
* 4.4 [Arrays](#arrays)
|
||||
* 4.4.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Int.Supported](#rqsrs-020clickhouseextendedprecisionarraysintsupported)
|
||||
* 4.4.2 [RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Int.NotSupported](#rqsrs-020clickhouseextendedprecisionarraysintnotsupported)
|
||||
* 4.4.3 [RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Dec.Supported](#rqsrs-020clickhouseextendedprecisionarraysdecsupported)
|
||||
* 4.4.4 [RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Dec.NotSupported](#rqsrs-020clickhouseextendedprecisionarraysdecnotsupported)
|
||||
* 4.5 [Comparison](#comparison)
|
||||
* 4.5.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Comparison](#rqsrs-020clickhouseextendedprecisioncomparison)
|
||||
* 4.6 [Logical Functions](#logical-functions)
|
||||
* 4.6.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Logical](#rqsrs-020clickhouseextendedprecisionlogical)
|
||||
* 4.7 [Mathematical Functions](#mathematical-functions)
|
||||
* 4.7.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Mathematical.Supported](#rqsrs-020clickhouseextendedprecisionmathematicalsupported)
|
||||
* 4.7.2 [RQ.SRS-020.ClickHouse.Extended.Precision.Mathematical.NotSupported](#rqsrs-020clickhouseextendedprecisionmathematicalnotsupported)
|
||||
* 4.8 [Rounding Functions](#rounding-functions)
|
||||
* 4.8.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Int.Supported](#rqsrs-020clickhouseextendedprecisionroundingintsupported)
|
||||
* 4.8.2 [RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Int.NotSupported](#rqsrs-020clickhouseextendedprecisionroundingintnotsupported)
|
||||
* 4.8.3 [RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Dec.Supported](#rqsrs-020clickhouseextendedprecisionroundingdecsupported)
|
||||
* 4.8.4 [RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Dec.NotSupported](#rqsrs-020clickhouseextendedprecisionroundingdecnotsupported)
|
||||
* 4.9 [Bit Functions](#bit-functions)
|
||||
* 4.9.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Bit.Int.Supported](#rqsrs-020clickhouseextendedprecisionbitintsupported)
|
||||
* 4.9.2 [RQ.SRS-020.ClickHouse.Extended.Precision.Bit.Int.NotSupported](#rqsrs-020clickhouseextendedprecisionbitintnotsupported)
|
||||
* 4.9.3 [RQ.SRS-020.ClickHouse.Extended.Precision.Bit.Dec.NotSupported](#rqsrs-020clickhouseextendedprecisionbitdecnotsupported)
|
||||
* 4.10 [Null Functions](#null-functions)
|
||||
* 4.10.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Null](#rqsrs-020clickhouseextendedprecisionnull)
|
||||
* 4.11 [Tuple Functions](#tuple-functions)
|
||||
* 4.11.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Tuple](#rqsrs-020clickhouseextendedprecisiontuple)
|
||||
* 4.12 [Map Functions](#map-functions)
|
||||
* 4.12.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Map.Supported](#rqsrs-020clickhouseextendedprecisionmapsupported)
|
||||
* 4.12.2 [RQ.SRS-020.ClickHouse.Extended.Precision.Map.NotSupported](#rqsrs-020clickhouseextendedprecisionmapnotsupported)
|
||||
* 4.13 [Create](#create)
|
||||
* 4.13.1 [RQ.SRS-020.ClickHouse.Extended.Precision.Create.Table](#rqsrs-020clickhouseextendedprecisioncreatetable)
|
||||
* 5 [References](#references)
|
||||
|
||||
## Revision History
|
||||
|
||||
This document is stored in an electronic form using [Git] source control management software
|
||||
hosted in a [GitHub Repository].
|
||||
All the updates are tracked using the [Revision History].
|
||||
|
||||
## Introduction
|
||||
|
||||
This software requirements specification covers requirements related to [ClickHouse]
|
||||
using extended precision data types.
|
||||
|
||||
## Terminology
|
||||
|
||||
### Extended Precision Data Types
|
||||
|
||||
Inclusive bounds:
|
||||
* Int128 - [-170141183460469231731687303715884105728 : 170141183460469231731687303715884105727]
|
||||
* UInt128 - [0 : 340282366920938463463374607431768211455]
|
||||
* Int256 - [-57896044618658097711785492504343953926634992332820282019728792003956564819968 : 57896044618658097711785492504343953926634992332820282019728792003956564819967]
|
||||
* UInt256 - [0 : 115792089237316195423570985008687907853269984665640564039457584007913129639935]
|
||||
|
||||
Exclusive bounds:
|
||||
* Decimal256 - (10^(76 - S): 10^(76 - S)), where S is the scale.
|
||||
|
||||
## Requirements
|
||||
|
||||
### RQ.SRS-020.ClickHouse.Extended.Precision
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using [Extended Precision Data Types].
|
||||
|
||||
### Conversion
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toInt128
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support converting values to `Int128` using the `toInt128` function.
|
||||
|
||||
For example,
|
||||
|
||||
```sql
|
||||
SELECT toInt128(1)
|
||||
```
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toUInt128
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support converting values to `UInt128` format using `toUInt128` function.
|
||||
|
||||
For example,
|
||||
|
||||
```sql
|
||||
SELECT toUInt128(1)
|
||||
```
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toInt256
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support converting values to `Int256` using `toInt256` function.
|
||||
|
||||
For example,
|
||||
|
||||
```sql
|
||||
SELECT toInt256(1)
|
||||
```
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toUInt256
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support converting values to `UInt256` format using `toUInt256` function.
|
||||
|
||||
For example,
|
||||
|
||||
```sql
|
||||
SELECT toUInt256(1)
|
||||
```
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.toDecimal256
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support converting values to `Decimal256` format using `toDecimal256` function.
|
||||
|
||||
For example,
|
||||
|
||||
```sql
|
||||
SELECT toDecimal256(1,2)
|
||||
```
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.FromMySQL
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support converting to [Extended Precision Data Types] from MySQL.
|
||||
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Conversion.ToMySQL
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support converting from [Extended Precision Data Types] to MySQL.
|
||||
|
||||
### Arithmetic
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Arithmetic.Int.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using [Arithmetic functions] with Int128, UInt128, Int256, and UInt256.
|
||||
|
||||
Arithmetic functions:
|
||||
* plus
|
||||
* minus
|
||||
* multiply
|
||||
* divide
|
||||
* intDiv
|
||||
* intDivOrZero
|
||||
* modulo
|
||||
* moduloOrZero
|
||||
* negate
|
||||
* abs
|
||||
* gcd
|
||||
* lcm
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Arithmetic.Dec.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Arithmetic functions] with Decimal256:
|
||||
|
||||
* plus
|
||||
* minus
|
||||
* multiply
|
||||
* divide
|
||||
* intDiv
|
||||
* intDivOrZero
|
||||
* negate
|
||||
* abs
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Arithmetic.Dec.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Arithmetic functions] with Decimal256:
|
||||
|
||||
* modulo
|
||||
* moduloOrZero
|
||||
* gcd
|
||||
* lcm
|
||||
|
||||
### Arrays
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Int.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Array functions] with Int128, UInt128, Int256, and UInt256.
|
||||
|
||||
* empty
|
||||
* notEmpty
|
||||
* length
|
||||
* arrayCount
|
||||
* arrayPopBack
|
||||
* arrayPopFront
|
||||
* arraySort
|
||||
* arrayReverseSort
|
||||
* arrayUniq
|
||||
* arrayJoin
|
||||
* arrayDistinct
|
||||
* arrayEnumerate
|
||||
* arrayEnumerateDense
|
||||
* arrayEnumerateUniq
|
||||
* arrayReverse
|
||||
* reverse
|
||||
* arrayFlatten
|
||||
* arrayCompact
|
||||
* arrayExists
|
||||
* arrayAll
|
||||
* arrayMin
|
||||
* arrayMax
|
||||
* arraySum
|
||||
* arrayAvg
|
||||
* arrayReduce
|
||||
* arrayReduceInRanges
|
||||
* arrayZip
|
||||
* arrayMap
|
||||
* arrayFilter
|
||||
* arrayFill
|
||||
* arrayReverseFill
|
||||
* arraySplit
|
||||
* arrayFirst
|
||||
* arrayFirstIndex
|
||||
* arrayConcat
|
||||
* hasAll
|
||||
* hasAny
|
||||
* hasSubstr
|
||||
* arrayElement
|
||||
* has
|
||||
* indexOf
|
||||
* countEqual
|
||||
* arrayPushBack
|
||||
* arrayPushFront
|
||||
* arrayResize
|
||||
* arraySlice
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Int.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Array functions] with Int128, UInt128, Int256, and UInt256:
|
||||
|
||||
* arrayDifference
|
||||
* arrayCumSum
|
||||
* arrayCumSumNonNegative
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Dec.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Array functions] with Decimal256:
|
||||
|
||||
* empty
|
||||
* notEmpty
|
||||
* length
|
||||
* arrayCount
|
||||
* arrayPopBack
|
||||
* arrayPopFront
|
||||
* arraySort
|
||||
* arrayReverseSort
|
||||
* arrayUniq
|
||||
* arrayJoin
|
||||
* arrayDistinct
|
||||
* arrayEnumerate
|
||||
* arrayEnumerateDense
|
||||
* arrayEnumerateUniq
|
||||
* arrayReverse
|
||||
* reverse
|
||||
* arrayFlatten
|
||||
* arrayCompact
|
||||
* arrayExists
|
||||
* arrayAll
|
||||
* arrayReduce
|
||||
* arrayReduceInRanges
|
||||
* arrayZip
|
||||
* arrayMap
|
||||
* arrayFilter
|
||||
* arrayFill
|
||||
* arrayReverseFill
|
||||
* arraySplit
|
||||
* arrayFirst
|
||||
* arrayFirstIndex
|
||||
* arrayConcat
|
||||
* hasAll
|
||||
* hasAny
|
||||
* hasSubstr
|
||||
* arrayElement
|
||||
* has
|
||||
* indexOf
|
||||
* countEqual
|
||||
* arrayPushBack
|
||||
* arrayPushFront
|
||||
* arrayResize
|
||||
* arraySlice
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Arrays.Dec.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Array functions] with Decimal256:
|
||||
|
||||
* arrayMin
|
||||
* arrayMax
|
||||
* arraaySum
|
||||
* arrayAvg
|
||||
* arrayDifference
|
||||
* arrayCumSum
|
||||
* arrayCumSumNonNegative
|
||||
|
||||
### Comparison
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Comparison
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using [Comparison functions] with [Extended Precision Data Types].
|
||||
|
||||
Comparison functions:
|
||||
* equals
|
||||
* notEquals
|
||||
* less
|
||||
* greater
|
||||
* lessOrEquals
|
||||
* greaterOrEquals
|
||||
|
||||
### Logical Functions
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Logical
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using [Logical functions] with [Extended Precision Data Types].
|
||||
|
||||
Logical functions:
|
||||
* and
|
||||
* or
|
||||
* not
|
||||
* xor
|
||||
|
||||
### Mathematical Functions
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Mathematical.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Mathematical functions] with [Extended Precision Data Types]:
|
||||
|
||||
* exp
|
||||
* log, ln
|
||||
* exp2
|
||||
* log2
|
||||
* exp10
|
||||
* log10
|
||||
* sqrt
|
||||
* cbrt
|
||||
* erf
|
||||
* erfc
|
||||
* lgamma
|
||||
* tgamma
|
||||
* sin
|
||||
* cos
|
||||
* tan
|
||||
* asin
|
||||
* acos
|
||||
* atan
|
||||
* cosh
|
||||
* acosh
|
||||
* sinh
|
||||
* asinh
|
||||
* tanh
|
||||
* atanh
|
||||
* log1p
|
||||
* sign
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Mathematical.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Mathematical functions] with [Extended Precision Data Types]:
|
||||
|
||||
* pow, power
|
||||
* intExp2
|
||||
* intExp10
|
||||
* atan2
|
||||
* hypot
|
||||
|
||||
### Rounding Functions
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Int.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Rounding functions] with Int128, UInt128, Int256, and UInt256:
|
||||
|
||||
* floor
|
||||
* ceil
|
||||
* trunc
|
||||
* round
|
||||
* roundBankers
|
||||
* roundDuration
|
||||
* roundAge
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Int.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Rounding functions] with Int128, UInt128, Int256, and UInt256:
|
||||
|
||||
* roundDown
|
||||
* roundToExp2
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Dec.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Rounding functions] with Decimal256:
|
||||
|
||||
* floor
|
||||
* ceil
|
||||
* trunc
|
||||
* round
|
||||
* roundBankers
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Rounding.Dec.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Rounding functions] with Decimal256:
|
||||
|
||||
* roundDuration
|
||||
* roundAge
|
||||
* roundDown
|
||||
* roundToExp2
|
||||
|
||||
### Bit Functions
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Bit.Int.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Bit functions] with Int128, UInt128, Int256, and UInt256:
|
||||
|
||||
* bitAnd
|
||||
* bitOr
|
||||
* bitXor
|
||||
* bitNot
|
||||
* bitShiftLeft
|
||||
* bitShiftRight
|
||||
* bitCount
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Bit.Int.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Bit functions] with Int128, UInt128, Int256, and UInt256:
|
||||
|
||||
* bitRotateLeft
|
||||
* bitRotateRight
|
||||
* bitTest
|
||||
* bitTestAll
|
||||
* bitTestAny
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Bit.Dec.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using [Bit functions] with Decimal256.
|
||||
|
||||
Bit functions:
|
||||
* bitAnd
|
||||
* bitOr
|
||||
* bitXor
|
||||
* bitNot
|
||||
* bitShiftLeft
|
||||
* bitShiftRight
|
||||
* bitCount
|
||||
* bitRotateLeft
|
||||
* bitRotateRight
|
||||
* bitTest
|
||||
* bitTestAll
|
||||
* bitTestAny
|
||||
|
||||
### Null Functions
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Null
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using [Null functions] with [Extended Precision Data Types].
|
||||
|
||||
Null functions:
|
||||
* isNull
|
||||
* isNotNull
|
||||
* coalesce
|
||||
* ifNull
|
||||
* nullIf
|
||||
* assumeNotNull
|
||||
* toNullable
|
||||
|
||||
### Tuple Functions
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Tuple
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using [Tuple functions] with [Extended Precision Data Types].
|
||||
|
||||
Tuple functions:
|
||||
* tuple
|
||||
* tupleElement
|
||||
* untuple
|
||||
|
||||
### Map Functions
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Map.Supported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support using the following [Map functions] with [Extended Precision Data Types]:
|
||||
|
||||
* map
|
||||
* mapContains
|
||||
* mapKeys
|
||||
* mapValues
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Map.NotSupported
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] MAY not support using the following [Map functions] with [Extended Precision Data Types]:
|
||||
|
||||
* mapAdd
|
||||
* mapSubtract
|
||||
* mapPopulateSeries
|
||||
|
||||
### Create
|
||||
|
||||
#### RQ.SRS-020.ClickHouse.Extended.Precision.Create.Table
|
||||
version: 1.0
|
||||
|
||||
[ClickHouse] SHALL support creating table with columns that use [Extended Precision Data Types].
|
||||
|
||||
## References
|
||||
|
||||
* **ClickHouse:** https://clickhouse.tech
|
||||
* **GitHub Repository**: https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/extended_precision_data_types/requirements/requirements.md
|
||||
* **Revision History**: https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/extended_precision_data_types/requirements/requirements.md
|
||||
* **Git:** https://git-scm.com/
|
||||
|
||||
[Extended Precision Data Types]: #extended-precision-data-types
|
||||
[Arithmetic functions]: https://clickhouse.tech/docs/en/sql-reference/functions/arithmetic-functions/
|
||||
[Array functions]: https://clickhouse.tech/docs/en/sql-reference/functions/array-functions/
|
||||
[Comparison functions]: https://clickhouse.tech/docs/en/sql-reference/functions/comparison-functions/
|
||||
[Logical Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/logical-functions/
|
||||
[Mathematical Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/math-functions/
|
||||
[Rounding Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/rounding-functions/
|
||||
[Bit Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/bit-functions/
|
||||
[Null Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/functions-for-nulls/
|
||||
[Tuple Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/tuple-functions/
|
||||
[Map Functions]: https://clickhouse.tech/docs/en/sql-reference/functions/tuple-map-functions/
|
||||
[SRS]: #srs
|
||||
[ClickHouse]: https://clickhouse.tech
|
||||
[GitHub Repository]: https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/extended_precision_data_types/requirements/requirements.md
|
||||
[Revision History]: https://github.com/ClickHouse/ClickHouse/blob/master/tests/testflows/extended_precision_data_types/requirements/requirements.md
|
||||
[Git]: https://git-scm.com/
|
||||
[GitHub]: https://github.com
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,217 @@
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
funcs = [
|
||||
('plus', '2'),
|
||||
('minus', '0'),
|
||||
('multiply', '1'),
|
||||
('divide', '1'),
|
||||
('intDiv', '1'),
|
||||
('intDivOrZero', '1'),
|
||||
('modulo', '0'),
|
||||
('moduloOrZero', '0'),
|
||||
('negate', '-1'),
|
||||
('abs', '1'),
|
||||
('gcd', '1'),
|
||||
('lcm', '1'),
|
||||
]
|
||||
|
||||
Examples_list = [tuple(list(func)+list(data_type)+[Name(f'{func[0]} - {data_type[0]}')]) for func in funcs for data_type in data_types]
|
||||
Examples_dec_list = [tuple(list(func)+[Name(f'{func[0]} - Decimal256')]) for func in funcs]
|
||||
|
||||
@TestOutline
|
||||
@Examples('arithmetic_func expected_result int_type min max', Examples_list)
|
||||
def inline_check(self, arithmetic_func, expected_result, int_type, min, max, node=None):
|
||||
"""Check that arithmetic functions work using inline tests with Int128, UInt128, Int256, and UInt256.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if arithmetic_func in ['negate','abs']:
|
||||
|
||||
with When(f"I check {arithmetic_func} with {int_type}"):
|
||||
output = node.query(f"SELECT {arithmetic_func}(to{int_type}(1))").output
|
||||
assert output == expected_result, error()
|
||||
|
||||
with When(f"I check {arithmetic_func} with {int_type} max and min value"):
|
||||
execute_query(f"""
|
||||
SELECT {arithmetic_func}(to{int_type}(\'{max}\')), {arithmetic_func}(to{int_type}(\'{min}\'))
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {arithmetic_func} with {int_type}"):
|
||||
output = node.query(f"SELECT {arithmetic_func}(to{int_type}(1), to{int_type}(1))").output
|
||||
assert output == expected_result, error()
|
||||
|
||||
if arithmetic_func in ['gcd','lcm']:
|
||||
|
||||
if int_type in ['UInt128','UInt256']:
|
||||
exitcode=153
|
||||
else:
|
||||
exitcode=151
|
||||
|
||||
with When(f"I check {arithmetic_func} with {int_type} max and min value"):
|
||||
node.query(f"SELECT {arithmetic_func}(to{int_type}(\'{max}\'), to{int_type}(1)), {arithmetic_func}(to{int_type}(\'{min}\'), to{int_type}(1))",
|
||||
exitcode = exitcode, message = 'Exception:')
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {arithmetic_func} with {int_type} max and min value"):
|
||||
execute_query(f"""
|
||||
SELECT {arithmetic_func}(to{int_type}(\'{max}\'), to{int_type}(1)), {arithmetic_func}(to{int_type}(\'{min}\'), to{int_type}(1))
|
||||
""")
|
||||
|
||||
@TestOutline
|
||||
@Examples('arithmetic_func expected_result int_type min max', Examples_list)
|
||||
def table_check(self, arithmetic_func, expected_result, int_type, min, max, node=None):
|
||||
"""Check that arithmetic functions work using tables with Int128, UInt128, Int256, and UInt256.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = int_type)
|
||||
|
||||
if arithmetic_func in ['negate','abs']:
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert {arithmetic_func} with {int_type} {value} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(to{int_type}(\'{value}\'))")
|
||||
|
||||
with Then(f"I check the table output of {arithmetic_func} with {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I insert {arithmetic_func} with {int_type} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(to{int_type}(1), to{int_type}(1))")
|
||||
|
||||
with Then("I check that the output matches the expected value"):
|
||||
output = node.query(f"SELECT * FROM {table_name}").output
|
||||
assert output == expected_result, error()
|
||||
|
||||
if arithmetic_func in ['gcd', 'lcm']:
|
||||
|
||||
if int_type in ['UInt128', 'UInt256']:
|
||||
|
||||
with When(f"I insert {arithmetic_func} with {int_type} {min} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(to{int_type}(\'{min}\'), to{int_type}(1))",
|
||||
exitcode = 153, message = 'Exception:')
|
||||
|
||||
with And(f"I insert {arithmetic_func} with {int_type} {max} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(to{int_type}(\'{max}\'), to{int_type}(1))")
|
||||
|
||||
else:
|
||||
|
||||
for value in [min, max]:
|
||||
|
||||
with When(f"I insert {arithmetic_func} with {int_type} {value} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(to{int_type}(\'{value}\'), to{int_type}(1))",
|
||||
exitcode = 151, message = 'Exception:')
|
||||
|
||||
else:
|
||||
|
||||
for value in [min, max]:
|
||||
|
||||
with When(f"I insert {arithmetic_func} with {int_type} {value} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(to{int_type}(\'{value}\'), to{int_type}(1))")
|
||||
|
||||
with Then(f"I check the table output of {arithmetic_func} with {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestOutline
|
||||
@Examples('arithmetic_func expected_result', Examples_dec_list)
|
||||
def inline_check_dec(self, arithmetic_func, expected_result, node=None):
|
||||
"""Check that arithmetic functions work using inline with Decimal256.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if arithmetic_func is 'negate' or arithmetic_func is 'abs':
|
||||
|
||||
with When(f"I check {arithmetic_func} with toDecimal256"):
|
||||
output = node.query(f"SELECT {arithmetic_func}(toDecimal256(1,0))").output
|
||||
assert output == expected_result, error()
|
||||
|
||||
elif arithmetic_func in ['modulo', 'moduloOrZero', 'gcd', 'lcm']:
|
||||
|
||||
with When(f"I check {arithmetic_func} with toDecimal256"):
|
||||
node.query(f"SELECT {arithmetic_func}(toDecimal256(1,0), toDecimal256(1,0))",
|
||||
exitcode=43, message = 'Exception:')
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {arithmetic_func} with toDecimal256"):
|
||||
output = node.query(f"SELECT {arithmetic_func}(toDecimal256(1,0), toDecimal256(1,0))").output
|
||||
assert output == expected_result, error()
|
||||
|
||||
@TestOutline
|
||||
@Examples('arithmetic_func expected_result', Examples_dec_list)
|
||||
def table_check_dec(self, arithmetic_func, expected_result, node=None):
|
||||
"""Check that arithmetic functions work using tables with Decimal256.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = 'Decimal256(0)')
|
||||
|
||||
if arithmetic_func in ['negate','abs']:
|
||||
|
||||
with When(f"I insert {arithmetic_func} with toDecimal256 into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(toDecimal256(1,0))")
|
||||
|
||||
with Then(f"I check the table for output of {arithmetic_func} with Decimal256"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
elif arithmetic_func in ['modulo', 'moduloOrZero', 'gcd', 'lcm']:
|
||||
|
||||
with When(f"I check {arithmetic_func} with toDecimal256"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(toDecimal256(1,0), toDecimal256(1,0))",
|
||||
exitcode=43, message = 'Exception:')
|
||||
|
||||
else:
|
||||
with When(f"I insert {arithmetic_func} with toDecimal256 into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {arithmetic_func}(toDecimal256(1,0), toDecimal256(1,0))")
|
||||
|
||||
with Then("I check that the output matches the expected value"):
|
||||
output = node.query(f"SELECT * FROM {table_name}").output
|
||||
assert output == expected_result, error()
|
||||
|
||||
@TestFeature
|
||||
@Name("arithmetic")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Arithmetic_Int_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Arithmetic_Dec_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Arithmetic_Dec_NotSupported("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that arithmetic functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run = inline_check)
|
||||
Scenario(run = table_check)
|
||||
Scenario(run = inline_check_dec)
|
||||
Scenario(run = table_check_dec)
|
@ -0,0 +1,484 @@
|
||||
import uuid
|
||||
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
def get_table_name():
|
||||
return "table" + "_" + str(uuid.uuid1()).replace('-', '_')
|
||||
|
||||
@TestOutline(Suite)
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Arrays_Int_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Arrays_Int_NotSupported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Arrays_Dec_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Arrays_Dec_NotSupported("1.0"),
|
||||
)
|
||||
def array_func(self, data_type, node=None):
|
||||
"""Check array functions with extended precision data types.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
for func in ['arrayPopBack(',
|
||||
'arrayPopFront(',
|
||||
'arraySort(',
|
||||
'arrayReverseSort(',
|
||||
'arrayDistinct(',
|
||||
'arrayEnumerate(',
|
||||
'arrayEnumerateDense(',
|
||||
'arrayEnumerateUniq(',
|
||||
'arrayReverse(',
|
||||
'reverse(',
|
||||
'arrayFlatten(',
|
||||
'arrayCompact(',
|
||||
'arrayReduceInRanges(\'sum\', [(1, 5)],',
|
||||
'arrayMap(x -> (x + 2),',
|
||||
'arrayFill(x -> x=3,',
|
||||
'arrayReverseFill(x -> x=3,',
|
||||
f'arrayConcat([{to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}],',
|
||||
'arrayFilter(x -> x == 1, ']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
execute_query(f"""
|
||||
SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Array({data_type})')
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in ['arraySplit((x, y) -> x=y, [0, 0, 0],']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
execute_query(f"""
|
||||
SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Array(Array({data_type}))')
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in [f'arrayZip([{to_data_type(data_type,1)}],']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
execute_query(f"""
|
||||
SELECT {func}array({to_data_type(data_type,3)}))
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Array(Tuple({data_type}, {data_type}))')
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}array({to_data_type(data_type,1)}))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in ['empty(',
|
||||
'notEmpty(',
|
||||
'length(',
|
||||
'arrayCount(x -> x == 1, ',
|
||||
'arrayUniq(',
|
||||
'arrayJoin(',
|
||||
'arrayExists(x -> x==1,',
|
||||
'arrayAll(x -> x==1,',
|
||||
'arrayMin(',
|
||||
'arrayMax(',
|
||||
'arraySum(',
|
||||
'arrayAvg(',
|
||||
'arrayReduce(\'max\', ',
|
||||
'arrayFirst(x -> x==3,',
|
||||
'arrayFirstIndex(x -> x==3,',
|
||||
f'hasAll([{to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}], ',
|
||||
f'hasAny([{to_data_type(data_type,2)}, {to_data_type(data_type,1)}], ',
|
||||
f'hasSubstr([{to_data_type(data_type,2)}, {to_data_type(data_type,1)}], ']:
|
||||
|
||||
if func in ['arrayMin(','arrayMax(','arraySum(', 'arrayAvg('] and data_type in ['Decimal256(0)']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
node.query(f"SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))",
|
||||
exitcode = 44, message = 'Exception:')
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))",
|
||||
exitcode = 44, message = 'Exception:')
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
|
||||
execute_query(f"""
|
||||
SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in ['arrayDifference(',
|
||||
'arrayCumSum(',
|
||||
'arrayCumSumNonNegative(']:
|
||||
|
||||
if data_type in ['Decimal256(0)']:
|
||||
exitcode = 44
|
||||
else:
|
||||
exitcode = 43
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
node.query(f"SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))",
|
||||
exitcode = exitcode, message = 'Exception:')
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}))",
|
||||
exitcode = exitcode, message = 'Exception:')
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in ['arrayElement']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
|
||||
execute_query(f"""
|
||||
SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), 1)
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), 1)")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in ['arrayPushBack',
|
||||
'arrayPushFront']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
|
||||
execute_query(f"""
|
||||
SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), {to_data_type(data_type,1)})
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Array({data_type})')
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), {to_data_type(data_type,1)})")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in ['arrayResize',
|
||||
'arraySlice']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
|
||||
execute_query(f"""
|
||||
SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), 1)
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Array({data_type})')
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), 1)")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
for func in ['has',
|
||||
'indexOf',
|
||||
'countEqual']:
|
||||
|
||||
with Scenario(f"Inline - {data_type} - {func}"):
|
||||
execute_query(f"""
|
||||
SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), NULL)
|
||||
""")
|
||||
|
||||
with Scenario(f"Table - {data_type} - {func}"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(array({to_data_type(data_type,3)}, {to_data_type(data_type,2)}, {to_data_type(data_type,1)}), NULL)")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestOutline(Suite)
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Tuple("1.0"),
|
||||
)
|
||||
def tuple_func(self, data_type, node=None):
|
||||
"""Check tuple functions with extended precision data types.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with Scenario(f"Creating a tuple with {data_type}"):
|
||||
node.query(f"SELECT tuple({to_data_type(data_type,1)}, {to_data_type(data_type,1)}, {to_data_type(data_type,1)})")
|
||||
|
||||
with Scenario(f"Creating a tuple with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Tuple({data_type}, {data_type}, {data_type})')
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT tuple({to_data_type(data_type,1)}, {to_data_type(data_type,1)}, {to_data_type(data_type,1)})")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"tupleElement with {data_type}"):
|
||||
node.query(f"SELECT tupleElement(({to_data_type(data_type,1)}, {to_data_type(data_type,1)}), 1)")
|
||||
|
||||
with Scenario(f"tupleElement with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT tupleElement(({to_data_type(data_type,1)}, {to_data_type(data_type,1)}), 1)")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"untuple with {data_type}"):
|
||||
node.query(f"SELECT untuple(({to_data_type(data_type,1)},))")
|
||||
|
||||
with Scenario(f"untuple with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT untuple(({to_data_type(data_type,1)},))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"tupleHammingDistance with {data_type}"):
|
||||
node.query(f"SELECT tupleHammingDistance(({to_data_type(data_type,1)}, {to_data_type(data_type,1)}), ({to_data_type(data_type,2)}, {to_data_type(data_type,2)}))")
|
||||
|
||||
with Scenario(f"tupleHammingDistance with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT tupleHammingDistance(({to_data_type(data_type,1)}, {to_data_type(data_type,1)}), ({to_data_type(data_type,2)}, {to_data_type(data_type,2)}))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestOutline(Suite)
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Map_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Map_NotSupported("1.0"),
|
||||
)
|
||||
def map_func(self, data_type, node=None):
|
||||
"""Check Map functions with extended precision data types.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with Scenario(f"Creating a map with {data_type}"):
|
||||
node.query(f"SELECT map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)})")
|
||||
|
||||
with Scenario(f"Creating a map with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Map(String, {data_type})')
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)})")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name}
|
||||
""")
|
||||
|
||||
with Scenario(f"mapAdd with {data_type}"):
|
||||
node.query(f"SELECT mapAdd(([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]), ([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]))",
|
||||
exitcode = 44, message='Exception:')
|
||||
|
||||
with Scenario(f"mapAdd with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Tuple(Array({data_type}), Array({data_type}))')
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT mapAdd(([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]), ([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]))",
|
||||
exitcode = 44, message='Exception:')
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"mapSubtract with {data_type}"):
|
||||
node.query(f"SELECT mapSubtract(([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]), ([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]))",
|
||||
exitcode = 44, message='Exception:')
|
||||
|
||||
with Scenario(f"mapSubtract with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Tuple(Array({data_type}), Array({data_type}))')
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT mapSubtract(([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]), ([{to_data_type(data_type,1)}, {to_data_type(data_type,2)}], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}]))",
|
||||
exitcode = 44, message='Exception:')
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"mapPopulateSeries with {data_type}"):
|
||||
node.query(f"SELECT mapPopulateSeries([1,2,3], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}, {to_data_type(data_type,3)}], 5)",
|
||||
exitcode = 44, message='Exception:')
|
||||
|
||||
with Scenario(f"mapPopulateSeries with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Tuple(Array({data_type}), Array({data_type}))')
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT mapPopulateSeries([1,2,3], [{to_data_type(data_type,1)}, {to_data_type(data_type,2)}, {to_data_type(data_type,3)}], 5)",
|
||||
exitcode = 44, message='Exception:')
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"mapContains with {data_type}"):
|
||||
node.query(f"SELECT mapContains( map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)}), 'key1')")
|
||||
|
||||
with Scenario(f"mapContains with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = data_type)
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT mapContains( map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)}), 'key1')")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"mapKeys with {data_type}"):
|
||||
node.query(f"SELECT mapKeys( map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)}))")
|
||||
|
||||
with Scenario(f"mapKeys with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = 'Array(String)')
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT mapKeys( map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)}))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
with Scenario(f"mapValues with {data_type}"):
|
||||
node.query(f"SELECT mapValues( map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)}))")
|
||||
|
||||
with Scenario(f"mapValues with {data_type} on a table"):
|
||||
table_name = get_table_name()
|
||||
|
||||
table(name = table_name, data_type = f'Array({data_type})')
|
||||
|
||||
with When("I insert the output into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT mapValues( map('key1', {to_data_type(data_type,1)}, 'key2', {to_data_type(data_type,2)}))")
|
||||
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestFeature
|
||||
@Name("array, tuple, map")
|
||||
@Examples("data_type",[
|
||||
('Int128',),
|
||||
('Int256',),
|
||||
('UInt128',),
|
||||
('UInt256',),
|
||||
('Decimal256(0)',),
|
||||
])
|
||||
def feature(self, node="clickhouse1", stress=None, parallel=None):
|
||||
"""Check that array, tuple, and map functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
for example in self.examples:
|
||||
data_type, = example
|
||||
|
||||
with Feature(data_type):
|
||||
|
||||
Suite(test=array_func)(data_type=data_type)
|
||||
Suite(test=tuple_func)(data_type=data_type)
|
||||
|
||||
with Given("I allow experimental map type"):
|
||||
allow_experimental_map_type()
|
||||
|
||||
Suite(test=map_func)(data_type=data_type)
|
179
tests/testflows/extended_precision_data_types/tests/bit.py
Normal file
179
tests/testflows/extended_precision_data_types/tests/bit.py
Normal file
@ -0,0 +1,179 @@
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
from extended_precision_data_types.errors import *
|
||||
|
||||
funcs = [
|
||||
('bitAnd', True, None),
|
||||
('bitOr', True, None),
|
||||
('bitXor', True, None),
|
||||
('bitShiftLeft', True, None),
|
||||
('bitShiftRight', True, None),
|
||||
('bitRotateLeft', False, not_implemented_bigints('Bit rotate')),
|
||||
('bitRotateRight', False, not_implemented_bigints('Bit rotate')),
|
||||
('bitTest', False, not_implemented_bigints('bitTest')),
|
||||
('bitTestAll', False, illegal_column()),
|
||||
('bitTestAny', False, illegal_column()),
|
||||
('bitNot', True, None),
|
||||
('bitCount', True, None)
|
||||
]
|
||||
|
||||
Examples_list = [tuple(list(func)+list(data_type)+[Name(f'{func[0]} - {data_type[0]}')]) for func in funcs for data_type in data_types]
|
||||
Examples_dec_list = [tuple(list(func)+[Name(f'{func[0]} - Decimal256')]) for func in funcs]
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func supported error int_type min max', Examples_list)
|
||||
def bit_int_inline(self, func, supported, error, int_type, min, max, node=None):
|
||||
""" Check bit functions with Int128, UInt128, Int256, and UInt256 using inline tests.
|
||||
"""
|
||||
|
||||
if error is not None:
|
||||
exitcode,message = error
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if func in ["bitNot", "bitCount"]:
|
||||
|
||||
with When(f"Check {func} with {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT {func}(to{int_type}(1)), {func}(to{int_type}(\'{max}\')), {func}(to{int_type}(\'{min}\'))
|
||||
""")
|
||||
|
||||
elif supported:
|
||||
|
||||
with When(f"I check {func} with {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT {func}(to{int_type}(1), 1), {func}(to{int_type}(\'{max}\'), 1), {func}(to{int_type}(\'{min}\'), 1)
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {func} with {int_type}"):
|
||||
node.query(f"SELECT {func}(to{int_type}(1), 1), {func}(to{int_type}(\'{max}\'), 1), {func}(to{int_type}(\'{min}\'), 1)",
|
||||
exitcode=exitcode, message = message)
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func supported error int_type min max', Examples_list)
|
||||
def bit_int_table(self, func, supported, error, int_type, min, max, node=None):
|
||||
""" Check bit functions with Int128, UInt128, Int256, and UInt256 using table tests.
|
||||
"""
|
||||
|
||||
table_name = f"table_{getuid()}"
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if error is not None:
|
||||
exitcode,message = error
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = int_type)
|
||||
|
||||
if func in ["bitNot", "bitCount"]:
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert the output of {func} with {int_type} and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(to{int_type}(\'{value}\'))")
|
||||
|
||||
with Then(f"I check the table with values of {func} and {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
elif supported:
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert the output of {func} with {int_type} and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(to{int_type}(\'{value}\'), 1)")
|
||||
|
||||
with Then(f"I check the table with values of {func} and {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert the output of {func} with {int_type} and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(to{int_type}(\'{value}\'), 1)",
|
||||
exitcode=exitcode, message=message)
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func supported error', Examples_dec_list)
|
||||
def bit_dec_inline(self, func, supported, error, node=None):
|
||||
""" Check bit functions with Decimal256 using inline tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
exitcode, message = illegal_type()
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if func in ["bitNot", "bitCount"]:
|
||||
|
||||
with When(f"Check {func} with Decimal256"):
|
||||
node.query(f"SELECT {func}(toDecimal256(1,0)), {func}(toDecimal256(\'{max}\',0)), {func}(toDecimal256(\'{min}\',0))",
|
||||
exitcode=exitcode, message = message)
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {func} with Decimal256"):
|
||||
node.query(f"SELECT {func}(toDecimal256(1,0), 1), {func}(toDecimal256(\'{max}\',0), 1), {func}(toDecimal256(\'{min}\',0), 1)",
|
||||
exitcode=exitcode, message = message)
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func supported error', Examples_dec_list)
|
||||
def bit_dec_table(self, func, supported, error, node=None):
|
||||
""" Check bit functions with Decimal256 using table tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
table_name = f"table_{getuid()}"
|
||||
exitcode, message = illegal_type()
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = 'Decimal256(0)')
|
||||
|
||||
if func in ["bitNot", "bitCount"]:
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert the output of {func} with Decimal256 and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(toDecimal256(\'{value}\',0))",
|
||||
exitcode=exitcode, message = message)
|
||||
|
||||
else:
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert the output of {func} with Decimal256 and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(toDecimal256(\'{value}\',0), 1)",
|
||||
exitcode=exitcode, message=message)
|
||||
|
||||
@TestFeature
|
||||
@Name("bit")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Bit_Int_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Bit_Int_NotSupported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Bit_Dec_NotSupported("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that bit functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run=bit_int_inline)
|
||||
Scenario(run=bit_int_table)
|
||||
Scenario(run=bit_dec_inline)
|
||||
Scenario(run=bit_dec_table)
|
@ -0,0 +1,110 @@
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
funcs = [
|
||||
('equals',),
|
||||
('notEquals',),
|
||||
('less',),
|
||||
('greater',),
|
||||
('lessOrEquals',),
|
||||
('greaterOrEquals',)
|
||||
]
|
||||
|
||||
Examples_list = [tuple(list(func)+list(data_type)+[Name(f'{func[0]} - {data_type[0]}')]) for func in funcs for data_type in data_types]
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func int_type min max', Examples_list)
|
||||
def comp_int_inline(self, func, int_type, min, max, node=None):
|
||||
"""Check comparison functions with Int128, UInt128, Int256, and UInt256 using inline tests.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with When(f"I check {func} with {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT {func}(to{int_type}(1), to{int_type}(1)), {func}(to{int_type}(\'{max}\'), to{int_type}(\'{min}\'))
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func int_type min max', Examples_list)
|
||||
def comp_int_table(self, func, int_type, min, max, node=None):
|
||||
"""Check comparison functions with Int128, UInt128, Int256, and UInt256 using table tests.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = int_type)
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I insert into a table the output {func} with {int_type} and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(to{int_type}(\'{value}\'), to{int_type}(1))")
|
||||
|
||||
with Then(f"I check the table for the output of {func} with {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func', funcs)
|
||||
def comp_dec_inline(self, func, node=None):
|
||||
"""Check comparison functions with Decimal256 using inline tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with When(f"I check {func} with Decimal256"):
|
||||
execute_query(f"""
|
||||
SELECT {func}(toDecimal256(1,0), toDecimal256(1,0)), {func}(toDecimal256(\'{max}\',0), toDecimal256(\'{min}\',0))
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func', funcs)
|
||||
def comp_dec_table(self, func, node=None):
|
||||
"""Check comparison functions with Decimal256 using table tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = 'Decimal256(0)')
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I insert into a table the output {func} with Decimal256 and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(toDecimal256(\'{value}\',0), toDecimal256(1,0))")
|
||||
|
||||
with Then(f"I check the table for the output of {func} with Decimal256"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestFeature
|
||||
@Name("comparison")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Comparison("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that comparison functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run=comp_int_inline)
|
||||
Scenario(run=comp_int_table)
|
||||
Scenario(run=comp_dec_inline)
|
||||
Scenario(run=comp_dec_table)
|
@ -0,0 +1,275 @@
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
@contextmanager
|
||||
def dictionary(name, node, mysql_node):
|
||||
"""Create a table in MySQL and use it a source for a dictionary.
|
||||
"""
|
||||
try:
|
||||
with Given("table in MySQL"):
|
||||
sql = f"""
|
||||
CREATE TABLE {name}(
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
int128 BIGINT,
|
||||
uint128 BIGINT,
|
||||
int256 BIGINT,
|
||||
uint256 BIGINT,
|
||||
dec256 DECIMAL,
|
||||
PRIMARY KEY ( id )
|
||||
);
|
||||
"""
|
||||
with When("I drop the table if exists"):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user -e \"DROP TABLE IF EXISTS {name};\"", exitcode=0)
|
||||
with And("I create a table"):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user <<'EOF'{textwrap.dedent(sql)}\nEOF", exitcode=0)
|
||||
|
||||
with And("dictionary that uses MySQL table as the external source"):
|
||||
with When("I drop the dictionary if exists"):
|
||||
node.query(f"DROP DICTIONARY IF EXISTS dict_{name}")
|
||||
with And("I create the dictionary"):
|
||||
sql = f"""
|
||||
CREATE DICTIONARY dict_{name}
|
||||
(
|
||||
id UInt8,
|
||||
int128 Int128,
|
||||
uint128 UInt128,
|
||||
int256 Int256,
|
||||
uint256 UInt256,
|
||||
dec256 Decimal256(0)
|
||||
)
|
||||
PRIMARY KEY id
|
||||
SOURCE(MYSQL(
|
||||
USER 'user'
|
||||
PASSWORD 'password'
|
||||
DB 'db'
|
||||
TABLE '{name}'
|
||||
REPLICA(PRIORITY 1 HOST '{mysql_node.name}' PORT 3306)
|
||||
))
|
||||
LAYOUT(HASHED())
|
||||
LIFETIME(0)
|
||||
"""
|
||||
node.query(textwrap.dedent(sql))
|
||||
|
||||
yield f"dict_{name}"
|
||||
|
||||
finally:
|
||||
with Finally("I drop the dictionary", flags=TE):
|
||||
node.query(f"DROP DICTIONARY IF EXISTS dict_{name}")
|
||||
|
||||
with And("I drop a table in MySQL", flags=TE):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user -e \"DROP TABLE IF EXISTS {name};\"", exitcode=0)
|
||||
|
||||
@contextmanager
|
||||
def table(name, node, mysql_node):
|
||||
"""Create a table in MySQL and use it a source for a table in ClickHouse.
|
||||
"""
|
||||
try:
|
||||
with Given("table in MySQL"):
|
||||
sql = f"""
|
||||
CREATE TABLE {name}(
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
int128 BIGINT,
|
||||
uint128 BIGINT,
|
||||
int256 BIGINT,
|
||||
uint256 BIGINT,
|
||||
dec256 DECIMAL,
|
||||
PRIMARY KEY ( id )
|
||||
);
|
||||
"""
|
||||
with When("I drop the table if exists"):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user -e \"DROP TABLE IF EXISTS {name};\"", exitcode=0)
|
||||
|
||||
with And("I create a table"):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user <<'EOF'{textwrap.dedent(sql)}\nEOF", exitcode=0)
|
||||
|
||||
with And("table that uses MySQL table as the external source"):
|
||||
|
||||
with When("I drop the table if exists"):
|
||||
node.query(f"DROP TABLE IF EXISTS {name}")
|
||||
with And("I create the table"):
|
||||
sql = f"""
|
||||
CREATE TABLE {name}
|
||||
(
|
||||
id UInt8,
|
||||
int128 Int128,
|
||||
uint128 UInt128,
|
||||
int256 Int256,
|
||||
uint256 UInt256,
|
||||
dec256 Decimal256(0)
|
||||
)
|
||||
ENGINE = MySQL('{mysql_node.name}:3306', 'default', '{name}', 'default', 'password')
|
||||
"""
|
||||
node.query(textwrap.dedent(sql))
|
||||
|
||||
yield f"table_{name}"
|
||||
|
||||
finally:
|
||||
with Finally("I drop the table", flags=TE):
|
||||
node.query(f"DROP TABLE IF EXISTS {name}")
|
||||
|
||||
with And("I drop a table in MySQL", flags=TE):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user -e \"DROP TABLE IF EXISTS {name};\"", exitcode=0)
|
||||
|
||||
@contextmanager
|
||||
def table_func(name, node, mysql_node):
|
||||
"""Create a table in MySQL and use it a source for a table using mysql table function.
|
||||
"""
|
||||
try:
|
||||
with Given("table in MySQL"):
|
||||
sql = f"""
|
||||
CREATE TABLE {name}(
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
int128 BIGINT,
|
||||
uint128 BIGINT,
|
||||
int256 BIGINT,
|
||||
uint256 BIGINT,
|
||||
dec256 DECIMAL,
|
||||
PRIMARY KEY ( id )
|
||||
);
|
||||
"""
|
||||
with When("I drop the table if exists"):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user -e \"DROP TABLE IF EXISTS {name};\"", exitcode=0)
|
||||
with And("I create a table"):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user <<'EOF'{textwrap.dedent(sql)}\nEOF", exitcode=0)
|
||||
|
||||
yield f"mysql('{mysql_node.name}:3306', 'db', '{name}', 'user', 'password')"
|
||||
|
||||
finally:
|
||||
|
||||
with Finally("I drop the table", flags=TE):
|
||||
node.query(f"DROP TABLE IF EXISTS {name}")
|
||||
|
||||
with And("I drop a table in MySQL", flags=TE):
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user -e \"DROP TABLE IF EXISTS {name};\"", exitcode=0)
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('int_type min max',[
|
||||
('Int128', '-170141183460469231731687303715884105728', '170141183460469231731687303715884105727', Requirements(RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_toInt128("1.0")), Name('Int128')),
|
||||
('Int256', '-57896044618658097711785492504343953926634992332820282019728792003956564819968', '57896044618658097711785492504343953926634992332820282019728792003956564819967', Requirements(RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_toInt256("1.0")), Name('Int256')),
|
||||
('UInt128','0','340282366920938463463374607431768211455', Requirements(RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_toUInt128("1.0")), Name('UInt128')),
|
||||
('UInt256', '0', '115792089237316195423570985008687907853269984665640564039457584007913129639935', Requirements(RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_toUInt256("1.0")), Name('UInt256')),
|
||||
])
|
||||
def int_conversion(self, int_type, min, max, node=None):
|
||||
"""Check that ClickHouse converts values to Int128.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with When(f"I convert {min}, {max}, 1 to {int_type}"):
|
||||
output = node.query(f"SELECT to{int_type}(\'{min}\'), to{int_type}(\'{max}\'), to{int_type}(1) format TabSeparatedRaw").output
|
||||
assert output == f'{min}\t{max}\t1', error()
|
||||
|
||||
@TestScenario
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_toDecimal256("1.0"),
|
||||
)
|
||||
def to_decimal256(self, node=None):
|
||||
"""Check that ClickHouse converts values to Int128.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
for value in [1,min,max]:
|
||||
output = node.query(f"SELECT toDecimal256(\'{value}\',0)").output
|
||||
assert output == str(value), error()
|
||||
|
||||
@TestScenario
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_ToMySQL("1.0"),
|
||||
)
|
||||
def MySQL_table(self, node=None):
|
||||
"""Check that ClickHouse converts MySQL values from MySQL table into ClickHouse table.
|
||||
"""
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
node = self.context.node
|
||||
mysql_node = self.context.mysql_node
|
||||
|
||||
with table(table_name, node, mysql_node):
|
||||
|
||||
with When("I insert parameters values in MySQL"):
|
||||
sql = f"""
|
||||
INSERT INTO {table_name}(int128, uint128, int256, uint256, dec256) VALUES (1,1,1,1,1);
|
||||
"""
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user <<'EOF'{textwrap.dedent(sql)}\nEOF", exitcode=0)
|
||||
|
||||
with Then("I select from the table on top of the mysql table"):
|
||||
node.query(f"SELECT * FROM {table_name}",
|
||||
exitcode=50, message='Exception:')
|
||||
|
||||
@TestScenario
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_FromMySQL("1.0"),
|
||||
)
|
||||
def MySQL_func(self, node=None):
|
||||
"""Check that ClickHouse converts MySQL values into a ClickHouse table using the MySQL table function.
|
||||
"""
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
node = self.context.node
|
||||
mysql_node = self.context.mysql_node
|
||||
|
||||
with table_func(table_name, node, mysql_node) as table_function:
|
||||
|
||||
with When("I insert parameters values in MySQL"):
|
||||
sql = f"""
|
||||
INSERT INTO {table_name}(int128, uint128, int256, uint256, dec256) VALUES (1,1,1,1,1);
|
||||
"""
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user <<'EOF'{textwrap.dedent(sql)}\nEOF", exitcode=0)
|
||||
|
||||
with And("I make sure the table doesn't exist"):
|
||||
node.query(f"DROP TABLE IF EXISTS {table_name}")
|
||||
|
||||
with And("I create the table"):
|
||||
node.query(f"CREATE TABLE {table_name} (id UInt8, int128 Int128, uint128 UInt128, int256 Int256, uint256 UInt256, dec256 Decimal256(0)) Engine = Memory")
|
||||
|
||||
with And("I insert into the clickhouse table from the mysql table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT * FROM {table_function}")
|
||||
|
||||
with Then("I select from the clickhouse table"):
|
||||
output = node.query(f"SELECT * FROM {table_name}").output
|
||||
assert output == '1\t1\t1\t1\t1\t1', error()
|
||||
|
||||
@TestScenario
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Conversion_ToMySQL("1.0"),
|
||||
)
|
||||
def MySQL_dict(self, node=None):
|
||||
"""Check that ClickHouse converts MySQL values from MySQL table into ClickHouse dictionary.
|
||||
"""
|
||||
|
||||
node = self.context.node
|
||||
mysql_node = self.context.mysql_node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with dictionary(table_name, node, mysql_node):
|
||||
|
||||
with When("I insert parameters values in MySQL"):
|
||||
sql = f"""
|
||||
INSERT INTO {table_name}(int128, uint128, int256, uint256, dec256) VALUES (1,1,1,1,1);
|
||||
"""
|
||||
mysql_node.command(f"MYSQL_PWD=password mysql -D db -u user <<'EOF'{textwrap.dedent(sql)}\nEOF", exitcode=0)
|
||||
|
||||
with Then("I select from the table on top of the mysql table"):
|
||||
node.query(f"SELECT * FROM dict_{table_name}",
|
||||
exitcode=50, message='Exception:')
|
||||
|
||||
@TestFeature
|
||||
@Name("conversion")
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check the conversion of extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
for scenario in loads(current_module(), Scenario):
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run=scenario)
|
@ -0,0 +1,19 @@
|
||||
from testflows.core import *
|
||||
from testflows.core.name import basename, parentname
|
||||
from testflows._core.testtype import TestSubType
|
||||
|
||||
@TestFeature
|
||||
@Name("tests")
|
||||
def feature(self):
|
||||
"""Check functions with Int128, Int256, UInt256, and Decimal256.
|
||||
"""
|
||||
Feature(run=load("extended_precision_data_types.tests.conversion", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.arithmetic", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.array_tuple_map", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.comparison", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.logical", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.mathematical", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.rounding", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.bit", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.null", "feature"))
|
||||
Feature(run=load("extended_precision_data_types.tests.table", "feature"))
|
@ -0,0 +1,99 @@
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
funcs = [
|
||||
('and',),
|
||||
('or',),
|
||||
('not',),
|
||||
('xor',),
|
||||
]
|
||||
|
||||
Examples_list = [tuple(list(func)+list(data_type)+[Name(f'{func[0]} - {data_type[0]}')]) for func in funcs for data_type in data_types]
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func int_type min max', Examples_list)
|
||||
def log_int_inline(self, func, int_type, min, max, node=None):
|
||||
"""Check logical functions with Int128, Int256, and UInt256 using inline tests.
|
||||
"""
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with When(f"Check {func} with {int_type}"):
|
||||
node.query(f"SELECT {func}(to{int_type}(1), to{int_type}(1)), {func}(to{int_type}(\'{max}\'), to{int_type}(1)), {func}(to{int_type}(\'{min}\'), to{int_type}(1))",
|
||||
exitcode=43, message = 'Exception: Illegal type ')
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func int_type min max', Examples_list)
|
||||
def log_int_table(self, func, int_type, min, max, node=None):
|
||||
"""Check logical functions with Int128, Int256, and UInt256 using table tests.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = int_type)
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"Check {func} with {int_type} and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(to{int_type}(\'{value}\'), to{int_type}(\'{value}\'))",
|
||||
exitcode=43, message = 'Exception: Illegal type')
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func', funcs)
|
||||
def log_dec_inline(self, func, node=None):
|
||||
"""Check logical functions with Decimal256 using inline tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with When(f"Check {func} with Decimal256"):
|
||||
node.query(f"SELECT {func}(toDecimal256(1,0), toDecimal256(1,0)), {func}(toDecimal256(\'{max}\',0), toDecimal256(1)), {func}(toDecimal256(\'{min}\',0), toDecimal256(1))",
|
||||
exitcode=43, message = 'Exception: Illegal type ')
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func', funcs)
|
||||
def log_dec_table(self, func, node=None):
|
||||
"""Check logical functions with Decimal256 using table tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = 'Decimal256(0)')
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"Check {func} with Decimal256 and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(toDecimal256(\'{value}\',0), toDecimal256(\'{value}\',0))",
|
||||
exitcode=43, message = 'Exception: Illegal type ')
|
||||
|
||||
@TestFeature
|
||||
@Name("logical")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Logical("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that comparison functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run=log_int_inline)
|
||||
Scenario(run=log_int_table)
|
||||
Scenario(run=log_dec_inline)
|
||||
Scenario(run=log_dec_table)
|
@ -0,0 +1,187 @@
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
funcs = [
|
||||
('exp(', 3, 0),
|
||||
('log(', 0, 0),
|
||||
('ln(', 0, 0),
|
||||
('exp2(', 2, 0),
|
||||
('log2(', 0, 0),
|
||||
('exp10(', 10, 0),
|
||||
('log10(', 0, 0),
|
||||
('sqrt(', 1, 0),
|
||||
('cbrt(', 1, 0),
|
||||
('erf(', 1, 0),
|
||||
('erfc(', 0, 0),
|
||||
('lgamma(', 0, 0),
|
||||
('tgamma(', 1, 0),
|
||||
('sin(', 1, 0),
|
||||
('cos(', 1, 0),
|
||||
('tan(', 2, 0),
|
||||
('asin(', 2, 0),
|
||||
('acos(', 0, 0),
|
||||
('atan(', 1, 0),
|
||||
('intExp2(', 2, 48),
|
||||
('intExp10(', 10, 48),
|
||||
('cosh(', 2, 0),
|
||||
('acosh(', 0, 0),
|
||||
('sinh(', 1, 0),
|
||||
('asinh(', 1, 0),
|
||||
('tanh(', 1, 0),
|
||||
('atanh(', 'inf', 0),
|
||||
('log1p(', 1, 0),
|
||||
('sign(', 1, 0),
|
||||
('pow(1,', 1, 43),
|
||||
('power(1,', 1, 43),
|
||||
('atan2(1,', 1, 43),
|
||||
('hypot(1,', 1, 43),
|
||||
]
|
||||
|
||||
Examples_list = [tuple(list(func)+list(data_type)+[Name(f'{func[0]} - {data_type[0]}')]) for func in funcs for data_type in data_types]
|
||||
Examples_dec_list = [tuple(list(func)+[Name(f'{func[0]} - Decimal256')]) for func in funcs]
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result exitcode int_type min max', Examples_list)
|
||||
def math_int_inline(self, func, expected_result, exitcode, int_type, min, max, node=None):
|
||||
"""Check mathematical functions with Int128, UInt128, Int256, and UInt256 using inline tests.
|
||||
"""
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if func in ['intExp2(', 'intExp10(', 'pow(1,', 'power(1,', 'atan2(1,', 'hypot(1,']:
|
||||
|
||||
with When(f"I check {func} with {int_type} using 1, max, and min"):
|
||||
node.query(f"SELECT {func} to{int_type}(1)), {func} to{int_type}(\'{max}\')), {func} to{int_type}(\'{min}\'))",
|
||||
exitcode=exitcode, message = 'Exception:')
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {func} with {int_type} using 1"):
|
||||
output = node.query(f"SELECT {func} to{int_type}(1))").output
|
||||
if output == 'inf':
|
||||
pass
|
||||
else:
|
||||
assert round(float(output)) == expected_result, error()
|
||||
|
||||
with And(f"I check {func} with {int_type} using max and min"):
|
||||
execute_query(f"""
|
||||
SELECT {func} to{int_type}(\'{max}\')), {func} to{int_type}(\'{min}\'))
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result exitcode int_type min max', Examples_list)
|
||||
def math_int_table(self, func, expected_result, exitcode, int_type, min, max, node=None):
|
||||
"""Check mathematical functions with Int128, UInt128, Int256, and UInt256 using table tests.
|
||||
"""
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = f'Nullable({int_type})')
|
||||
|
||||
if func in ['intExp2(', 'intExp10(', 'pow(1,', 'power(1,', 'atan2(1,', 'hypot(1,']:
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I insert the output of {func} with {int_type} using {value} into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func} to{int_type}(\'{value}\'))",
|
||||
exitcode=exitcode, message = 'Exception:')
|
||||
|
||||
else:
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with And(f"I insert the output of {func} with {int_type} using {value} into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT to{int_type}OrZero( toString({func} to{int_type}(\'{value}\'))))")
|
||||
|
||||
with Then(f"I check the outputs of {func} with {int_type}"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result exitcode', Examples_dec_list)
|
||||
def math_dec_inline(self, func, expected_result, exitcode, node=None):
|
||||
"""Check mathematical functions with Decimal256 using inline tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if func in ['intExp2(', 'intExp10(', 'pow(1,', 'power(1,', 'atan2(1,', 'hypot(1,']:
|
||||
|
||||
with When(f"I check {func} with Decimal256 using 1, max, and min"):
|
||||
node.query(f"SELECT {func} toDecimal256(1,0)), {func} toDecimal256(\'{max}\',0)), {func} toDecimal256(\'{min}\',0))",
|
||||
exitcode=43, message = 'Exception: Illegal type ')
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {func} with Decimal256 using 1"):
|
||||
output = node.query(f"SELECT {func} toDecimal256(1,0))").output
|
||||
if output == 'inf':
|
||||
pass
|
||||
else:
|
||||
assert round(float(output)) == expected_result, error()
|
||||
|
||||
with And(f"I check {func} with Decimal256 using max and min"):
|
||||
execute_query(f"""
|
||||
SELECT {func} toDecimal256(\'{max}\',0)), {func} toDecimal256(\'{min}\',0))
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result exitcode', Examples_dec_list)
|
||||
def math_dec_table(self, func, expected_result, exitcode, node=None):
|
||||
"""Check mathematical functions with Decimal256 using table tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
table_name = f'table_{getuid()}'
|
||||
|
||||
with Given(f"I have a table"):
|
||||
table(name = table_name, data_type = 'Decimal256(0)')
|
||||
|
||||
if func in ['intExp2(', 'intExp10(', 'pow(1,', 'power(1,', 'atan2(1,', 'hypot(1,']:
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I insert the output of {func} with Decimal256 using {value} into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func} toDecimal256(\'{value}\',0))",
|
||||
exitcode=43, message = 'Exception: Illegal type ')
|
||||
|
||||
else:
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I insert the output of {func} with Decimal256 using {value} into a table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT toDecimal256OrZero( toString({func} toDecimal256(\'{value}\',0))),0)")
|
||||
|
||||
with Then(f"I check the outputs of {func} with Decimal256"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestFeature
|
||||
@Name("mathematical")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Mathematical_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Mathematical_NotSupported("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that mathematical functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run=math_int_inline)
|
||||
Scenario(run=math_int_table)
|
||||
Scenario(run=math_dec_inline)
|
||||
Scenario(run=math_dec_table)
|
119
tests/testflows/extended_precision_data_types/tests/null.py
Normal file
119
tests/testflows/extended_precision_data_types/tests/null.py
Normal file
@ -0,0 +1,119 @@
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
funcs = [
|
||||
('isNull(', 0),
|
||||
('isNotNull(', 1),
|
||||
('coalesce(', 1),
|
||||
('assumeNotNull(', 1),
|
||||
('toNullable(', 1),
|
||||
('ifNull(1,', 1),
|
||||
('nullIf(1,', '\\N'),
|
||||
]
|
||||
|
||||
Examples_list = [tuple(list(func)+list(data_type)+[Name(f'{func[0]} - {data_type[0]}')]) for func in funcs for data_type in data_types]
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result int_type min max', Examples_list)
|
||||
def null_int_inline(self, func, expected_result, int_type, min, max, node=None):
|
||||
"""Check null function with Int128, UInt128, Int256, and UInt256 using inline tests.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with When(f"I check {func} with {int_type}"):
|
||||
output = node.query(f"SELECT {func} to{int_type}(1))").output
|
||||
assert output == str(expected_result), error()
|
||||
|
||||
with And(f"I check {func} with {int_type} using min and max"):
|
||||
execute_query(f"""
|
||||
SELECT {func} to{int_type}(\'{min}\')), {func} to{int_type}(\'{max}\'))
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result int_type min max', Examples_list)
|
||||
def null_int_table(self, func, expected_result, int_type, min, max, node=None):
|
||||
"""Check null function with Int128, UInt128, Int256, and UInt256 using table tests.
|
||||
"""
|
||||
|
||||
table_name = f"table_{getuid()}"
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with Given("I have a table"):
|
||||
table(name = table_name, data_type = f'Nullable({int_type})')
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert the output of {func} with {int_type} and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func} to{int_type}(\'{value}\'))")
|
||||
|
||||
with Then(f"I check {func} with {int_type} on the table"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result', funcs)
|
||||
def null_dec_inline(self, func, expected_result, node=None):
|
||||
"""Check null function with Decimal256 using inline tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with When(f"I check {func} with Decimal256"):
|
||||
output = node.query(f"SELECT {func} toDecimal256(1,0))").output
|
||||
assert output == str(expected_result), error()
|
||||
|
||||
with And(f"I check {func} with Decimal256 using min and max"):
|
||||
execute_query(f"""
|
||||
SELECT {func} toDecimal256(\'{min}\',0)), {func} toDecimal256(\'{max}\',0))
|
||||
""")
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result', funcs)
|
||||
def null_dec_table(self, func, expected_result, node=None):
|
||||
"""Check null function with Decimal256 using table tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
table_name = f"table_{getuid()}"
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with Given("I have a table"):
|
||||
table(name = table_name, data_type = 'Nullable(Decimal256(0))')
|
||||
|
||||
for value in [1, min, max]:
|
||||
|
||||
with When(f"I insert the output of {func} with Decimal256 and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func} toDecimal256(\'{value}\',0))")
|
||||
|
||||
with Then(f"I check {func} with Decimal256 on the table"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
@TestFeature
|
||||
@Name("null")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Null("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that null functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run=null_int_inline)
|
||||
Scenario(run=null_int_table)
|
||||
Scenario(run=null_dec_inline)
|
||||
Scenario(run=null_dec_table)
|
191
tests/testflows/extended_precision_data_types/tests/rounding.py
Normal file
191
tests/testflows/extended_precision_data_types/tests/rounding.py
Normal file
@ -0,0 +1,191 @@
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
funcs = [
|
||||
('ceil', 1, True),
|
||||
('floor', 1, True),
|
||||
('trunc', 1, True),
|
||||
('round', 1, True),
|
||||
('roundBankers', 1, True),
|
||||
('roundToExp2', 1, False),
|
||||
('roundDuration', 1, True),
|
||||
('roundAge', 17, True),
|
||||
('roundDown', 1, False)
|
||||
]
|
||||
|
||||
Examples_list = [tuple(list(func)+list(data_type)+[Name(f'{func[0]} - {data_type[0]}')]) for func in funcs for data_type in data_types]
|
||||
Examples_dec_list = [tuple(list(func)+[Name(f'{func[0]} - Decimal256')]) for func in funcs]
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result supported int_type min max', Examples_list)
|
||||
def round_int_inline(self, func, expected_result, supported, int_type, min, max, node=None):
|
||||
"""Check rounding functions with Int128, UInt128, Int256, and UInt256 using inline tests.
|
||||
"""
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if func is 'roundDown':
|
||||
|
||||
with When(f"I check roundDown with {int_type}"):
|
||||
node.query(f"SELECT roundDown(to{int_type}(1), [0,2]), roundDown(to{int_type}(\'{max}\'), [0,2]), roundDown(to{int_type}(\'{min}\'), [0,2])",
|
||||
exitcode=44, message=f'Exception: Illegal column {int_type} of first argument of function roundDown')
|
||||
|
||||
elif supported:
|
||||
|
||||
with When(f"I check {func} with {int_type}"):
|
||||
output = node.query(f"SELECT {func}(to{int_type}(1))").output
|
||||
assert output == str(expected_result), error()
|
||||
|
||||
with And(f'I check {func} with {int_type} using min and max values'):
|
||||
execute_query(f"""
|
||||
SELECT {func}(to{int_type}(\'{min}\')), {func}(to{int_type}(\'{max}\'))
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {func} with {int_type}"):
|
||||
node.query(f"SELECT {func}(to{int_type}(1)), {func}(to{int_type}(\'{max}\')), {func}(to{int_type}(\'{min}\'))",
|
||||
exitcode=48, message=f'Exception: {func}() for big integers is not implemented:')
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result supported int_type min max', Examples_list)
|
||||
def round_int_table(self, func, expected_result, supported, int_type, min, max, node=None):
|
||||
"""Check rounding functions with Int128, UInt128, Int256, and UInt256 using table tests.
|
||||
"""
|
||||
|
||||
table_name = f"table_{getuid()}"
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with Given("I have a table"):
|
||||
table(name = table_name, data_type = int_type)
|
||||
|
||||
if func is 'roundDown':
|
||||
|
||||
for value in [1,max,min]:
|
||||
|
||||
with When(f"I check roundDown with {int_type} and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT roundDown(to{int_type}(\'{value}\'), [0,2])",
|
||||
exitcode=44, message=f'Exception: Illegal column {int_type} of first argument of function roundDown')
|
||||
|
||||
elif supported:
|
||||
|
||||
for value in [1,max,min]:
|
||||
|
||||
with When(f"I insert the output of {func} with {int_type} and {value} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(to{int_type}(\'{value}\'))")
|
||||
|
||||
with Then(f"I select the output of {func} with {int_type} from the table"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
for value in [1,max,min]:
|
||||
|
||||
with When(f"I insert the output of {func} with {int_type} and {value} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(to{int_type}(1))",
|
||||
exitcode=48, message=f'Exception: {func}() for big integers is not implemented:')
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result supported', Examples_dec_list)
|
||||
def round_dec_inline(self, func, expected_result, supported, node=None):
|
||||
"""Check rounding functions with Decimal256 using inline tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
if func is 'roundDown':
|
||||
|
||||
with When(f"I check roundDown with Decimal256"):
|
||||
node.query(f"""SELECT roundDown(toDecimal256(1,0), [toDecimal256(0,0),toDecimal256(2,0)]),
|
||||
roundDown(toDecimal256(\'{max}\',0), [toDecimal256(0,0),toDecimal256(2,0)]),
|
||||
roundDown(toDecimal256(\'{min}\',0), [toDecimal256(0,0),toDecimal256(2,0)])""",
|
||||
exitcode=44, message=f'Exception: Illegal column Decimal256 of first argument of function roundDown')
|
||||
|
||||
elif func not in ['roundDuration', 'roundAge', 'roundToExp2']:
|
||||
|
||||
with When(f"I check {func} with Decimal256"):
|
||||
output = node.query(f"SELECT {func}(toDecimal256(1,0))").output
|
||||
assert output == str(expected_result), error()
|
||||
|
||||
with And(f'I check {func} with Decimal256 using min and max values'):
|
||||
execute_query(f"""
|
||||
SELECT {func}(toDecimal256(\'{min}\',0)), {func}(toDecimal256(\'{max}\',0))
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
with When(f"I check {func} with Decimal256"):
|
||||
node.query(f"SELECT {func}(toDecimal256(1,0)), {func}(toDecimal256(\'{max}\',0)), {func}(toDecimal256(\'{min}\',0))",
|
||||
exitcode=43, message=f'Exception: Illegal type Decimal(76, 0)')
|
||||
|
||||
@TestOutline(Scenario)
|
||||
@Examples('func expected_result supported', Examples_dec_list)
|
||||
def round_dec_table(self, func, expected_result, supported, node=None):
|
||||
"""Check rounding functions with Decimal256 using table tests.
|
||||
"""
|
||||
min = Decimal256_min_max[0]
|
||||
max = Decimal256_min_max[1]
|
||||
|
||||
table_name = f"table_{getuid()}"
|
||||
|
||||
if node is None:
|
||||
node = self.context.node
|
||||
|
||||
with Given("I have a table"):
|
||||
table(name = table_name, data_type = 'Decimal256(0)')
|
||||
|
||||
if func is 'roundDown':
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I check roundDown with Decimal256 and {value}"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT roundDown(toDecimal256(\'{value}\',0), [toDecimal256(0,0),toDecimal256(2,0)])",
|
||||
exitcode=44, message=f'Exception: Illegal column Decimal256 of first argument of function roundDown')
|
||||
|
||||
elif func not in ['roundDuration', 'roundAge', 'roundToExp2']:
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I insert the output of {func} with Decimal256 and {value} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(toDecimal256(\'{value}\',0))")
|
||||
|
||||
with Then(f"I select the output of {func} with Decimal256 from the table"):
|
||||
execute_query(f"""
|
||||
SELECT * FROM {table_name} ORDER BY a ASC
|
||||
""")
|
||||
|
||||
else:
|
||||
|
||||
for value in [1, max, min]:
|
||||
|
||||
with When(f"I insert the output of {func} with Decimal256 and {value} into the table"):
|
||||
node.query(f"INSERT INTO {table_name} SELECT {func}(toDecimal256(\'{value}\',0))",
|
||||
exitcode=43, message=f'Exception: Illegal type Decimal(76, 0)')
|
||||
|
||||
@TestFeature
|
||||
@Name("rounding")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Rounding_Int_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Rounding_Int_NotSupported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Rounding_Dec_Supported("1.0"),
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Rounding_Dec_NotSupported("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that rounding functions work with extended precision data types.
|
||||
"""
|
||||
self.context.node = self.context.cluster.node(node)
|
||||
self.context.mysql_node = self.context.cluster.node(mysql_node)
|
||||
|
||||
with allow_experimental_bigint(self.context.node):
|
||||
Scenario(run=round_int_inline)
|
||||
Scenario(run=round_int_table)
|
||||
Scenario(run=round_dec_inline)
|
||||
Scenario(run=round_dec_table)
|
35
tests/testflows/extended_precision_data_types/tests/table.py
Normal file
35
tests/testflows/extended_precision_data_types/tests/table.py
Normal file
@ -0,0 +1,35 @@
|
||||
from testflows.core import *
|
||||
from testflows.asserts import error
|
||||
from contextlib import contextmanager
|
||||
|
||||
from extended_precision_data_types.requirements import *
|
||||
from extended_precision_data_types.common import *
|
||||
|
||||
@TestFeature
|
||||
@Name("table")
|
||||
@Requirements(
|
||||
RQ_SRS_020_ClickHouse_Extended_Precision_Create_Table("1.0"),
|
||||
)
|
||||
def feature(self, node="clickhouse1", mysql_node="mysql1", stress=None, parallel=None):
|
||||
"""Check that clickhouse is able to create a table with extended precision data types.
|
||||
"""
|
||||
node = self.context.cluster.node(node)
|
||||
|
||||
table_name = f"table_{getuid()}"
|
||||
|
||||
with allow_experimental_bigint(node):
|
||||
|
||||
try:
|
||||
with When("I create a table with Int128, UInt128, Int256, UInt256, Decimal256"):
|
||||
node.query(f"CREATE TABLE {table_name}(a Int128, b UInt128, c Int256, d UInt256, e Decimal256(0)) ENGINE = Memory")
|
||||
|
||||
with And("I insert values into the table"):
|
||||
node.query(f"INSERT INTO {table_name} VALUES (toInt128(1), toUInt128(1), toInt256(1), toUInt256(1), toDecimal256(1,0))")
|
||||
|
||||
with Then("I select from the table"):
|
||||
output = node.query(f"SELECT * FROM {table_name}").output
|
||||
assert output == '1\t1\t1\t1\t1', error()
|
||||
|
||||
finally:
|
||||
with Finally("I drop the table"):
|
||||
node.query(f"DROP TABLE IF EXISTS {table_name}")
|
@ -30,6 +30,7 @@ def regression(self, local, clickhouse_binary_path, stress=None, parallel=None):
|
||||
run_scenario(pool, tasks, Feature(test=load("window_functions.regression", "regression")), args)
|
||||
run_scenario(pool, tasks, Feature(test=load("datetime64_extended_range.regression", "regression")), args)
|
||||
#run_scenario(pool, tasks, Feature(test=load("kerberos.regression", "regression")), args)
|
||||
run_scenario(pool, tasks, Feature(test=load("extended_precision_data_types.regression", "regression")), args)
|
||||
finally:
|
||||
join(tasks)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user