Skip to content

Commit

Permalink
Allow for very large Integers
Browse files Browse the repository at this point in the history
Values over 2^63 were not handled correctly. We could try uint64 or int128 for handling some larger values, but very very large values will still need to be treated as a string. Since the vast majority of integer values tend to be small, just treat anything outside int64 as a string.

Fixes #233
  • Loading branch information
rbt committed Nov 23, 2022
1 parent 9459a5e commit 8d30d3e
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 24 deletions.
12 changes: 11 additions & 1 deletion lib/DBDish/mysql/StatementHandle.rakumod
Expand Up @@ -116,7 +116,17 @@ method execute(*@params --> DBDish::StatementHandle) {
@Bufs[$k] = do {
when Blob { $st = MYSQL_TYPE_BLOB; $_ }
when Str { .encode }
when Int { $st = MYSQL_TYPE_LONGLONG; Blob[int64].new($_) }
when Int {
# Handle anything larger than int64 as a string. This has a small
# performance penalty but so does using int128 for everything or
# detecting a best fit range. Assume most numbers are small.
if $_ > -2**63 and $_ < 2**63 {
$st = MYSQL_TYPE_LONGLONG;
Blob[int64].new($_);
} else {
.Str.encode;
}
}
when DateTime {
# mysql knows nothing of timezones, all assumed local-time
# but in Windows the parser chokes with the offset,
Expand Down
81 changes: 58 additions & 23 deletions t/24-mysql-large-value.t
Expand Up @@ -8,40 +8,75 @@ my %con-parms = :database<dbdishtest>, :user<testuser>, :password<testpass>;

# Test buffer size scaling
my $dbh = DBIish::CommonTesting.connect-or-skip('mysql', |%con-parms);

ok $dbh, 'Connected';
lives-ok {
$dbh.execute(qq|

subtest 'Very large string' => {
lives-ok {
$dbh.execute(qq|
CREATE TEMPORARY TABLE test_long_string (
col1 varchar(16383)
)|)
}, 'Table created';
}, 'Table created';

my @string-lengths = 100, 8191, 8192, 8193, 10_000, 16383;
my @long-strings;
for @string-lengths -> $length {
@long-strings.push('x' x $length);
}
my @string-lengths = 100, 8191, 8192, 8193, 10_000, 16383;
my @long-strings;
for @string-lengths -> $length {
@long-strings.push('x' x $length);
}

my $sth = $dbh.prepare('INSERT INTO test_long_string (col1) VALUES(?)');
for @long-strings -> $string {
lives-ok {
$sth.execute($string);
}, 'Add value: %d chars'.sprintf($string.chars);
}
$sth.dispose;
my $sth = $dbh.prepare('INSERT INTO test_long_string (col1) VALUES(?)');
for @long-strings -> $string {
lives-ok {
$sth.execute($string);
}, 'Add value: %d chars'.sprintf($string.chars);
}
$sth.dispose;

$sth = $dbh.execute('SELECT col1 FROM test_long_string ORDER BY length(col1)');
$sth = $dbh.execute('SELECT col1 FROM test_long_string ORDER BY length(col1)');

is $sth.rows, @long-strings.elems, '%d row'.sprintf(@long-strings.elems);
is $sth.rows, @long-strings.elems, '%d row'.sprintf(@long-strings.elems);

# Compare both source and DB long strings in order by length.
for @long-strings -> $string {
my ($col1) = $sth.row;
# Compare both source and DB long strings in order by length.
for @long-strings -> $string {
my ($col1) = $sth.row;

isa-ok $col1, Str;
is $col1, $string, 'Value: %d chars'.sprintf($string.chars) ;
isa-ok $col1, Str;
is $col1, $string, 'Value: %d chars'.sprintf($string.chars);
}
}


# Very large integer test
subtest 'Very large integers' => {
lives-ok {
$dbh.execute(qq|
CREATE TEMPORARY TABLE test_long_number (
col1 numeric(64)
)|)
}, 'Table created';

my @values = 2**63 - 1, -2**63 + 1,
2**63, -2**63,
2**64 - 1, -2**64 + 1,
2**64, -2**64,
2**80, -2**80;
my $sth = $dbh.prepare('INSERT INTO test_long_number (col1) VALUES(?)');
for @values -> $num {
lives-ok {
$sth.execute($num);
}, 'Add value: %d digits'.sprintf($num.chars);
}
$sth.dispose;

$sth = $dbh.execute('SELECT col1 FROM test_long_number ORDER BY col1');

is $sth.rows, @values.elems, '%d row'.sprintf(@values.elems);

# Compare both source and DB long strings in order by length.
for @values.sort -> $num {
my ($col1) = $sth.row;

isa-ok $col1, Rat;
is $col1, $num, 'Value: %d digits'.sprintf($num.chars);
}
}

0 comments on commit 8d30d3e

Please sign in to comment.