From e52ca00348ba609ed2b23190bc06d223d238f830 Mon Sep 17 00:00:00 2001 From: Brian Fraser Date: Wed, 22 Aug 2012 16:19:43 -0300 Subject: [PATCH 1/3] Fix for 1038276: ChangeHandler doesn't quote varchar columns with hex-looking values --- lib/ChangeHandler.pm | 17 ++++++++++++---- lib/Quoter.pm | 5 +++-- t/lib/ChangeHandler.t | 46 +++++++++++++++++++++++++++++++++++++++++-- t/lib/Quoter.t | 7 +++++-- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/lib/ChangeHandler.pm b/lib/ChangeHandler.pm index da0516ff..d72cb4ae 100644 --- a/lib/ChangeHandler.pm +++ b/lib/ChangeHandler.pm @@ -323,10 +323,13 @@ sub make_UPDATE { else { @cols = $self->sort_cols($row); } + my $types = $self->{tbl_struct}->{type_for}; return "UPDATE $self->{dst_db_tbl} SET " . join(', ', map { + my $is_char = ($types->{$_} || '') =~ m/char|text/i; $self->{Quoter}->quote($_) - . '=' . $self->{Quoter}->quote_val($row->{$_}) + . '=' . $self->{Quoter}->quote_val($row->{$_}, + is_char => $is_char); } grep { !$in_where{$_} } @cols) . " WHERE $where LIMIT 1"; } @@ -391,11 +394,15 @@ sub make_row { else { @cols = $self->sort_cols($row); } - my $q = $self->{Quoter}; + my $q = $self->{Quoter}; + my $type_for = $self->{tbl_struct}->{type_for}; return "$verb INTO $self->{dst_db_tbl}(" . join(', ', map { $q->quote($_) } @cols) . ') VALUES (' - . join(', ', map { $q->quote_val($_) } @{$row}{@cols} ) + . join(', ', map { + my $is_char = ($type_for->{$_} || '') =~ m/char|text/i; + $q->quote_val($row->{$_}, + is_char => $is_char) } @cols ) . ')'; } @@ -413,7 +420,9 @@ sub make_where_clause { my @clauses = map { my $val = $row->{$_}; my $sep = defined $val ? '=' : ' IS '; - $self->{Quoter}->quote($_) . $sep . $self->{Quoter}->quote_val($val); + my $is_char = ($self->{tbl_struct}->{type_for}->{$_} || '') =~ m/char|text/i; + $self->{Quoter}->quote($_) . $sep . $self->{Quoter}->quote_val($val, + is_char => $is_char); } @$cols; return join(' AND ', @clauses); } diff --git a/lib/Quoter.pm b/lib/Quoter.pm index 659d420f..a9916d7f 100644 --- a/lib/Quoter.pm +++ b/lib/Quoter.pm @@ -65,11 +65,12 @@ sub quote { # Returns: # Quoted value sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true # Quote and return non-numeric vals. $val =~ s/(['\\])/\\$1/g; diff --git a/t/lib/ChangeHandler.t b/t/lib/ChangeHandler.t index 835fdd31..2b1ba22d 100644 --- a/t/lib/ChangeHandler.t +++ b/t/lib/ChangeHandler.t @@ -9,7 +9,7 @@ BEGIN { use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); -use Test::More tests => 33; +use Test::More; use ChangeHandler; use Quoter; @@ -468,10 +468,52 @@ is_deeply( "process_rows() appends trace msg to SQL statements" ); +# ############################################################################# +# ChangeHandler doesn't quote varchar columns with hex-looking values +# https://bugs.launchpad.net/percona-toolkit/+bug/1038276 +# ############################################################################# +SKIP: { + skip 'Cannot connect to sandbox master', 1 unless $master_dbh; + $sb->load_file('master', "t/lib/samples/bug_1038276.sql"); + + @rows = (); + $tbl_struct = { + cols => [qw(id b)], + col_posn => {id=>0, b=>1}, + type_for => {id=>'int', b=>'varchar'}, + }; + $ch = new ChangeHandler( + Quoter => $q, + left_db => 'bug_1038276', + left_tbl => 'lt', + right_db => 'bug_1038276', + right_tbl => 'rt', + actions => [ sub { push @rows, $_[0]; } ], + replace => 0, + queue => 0, + tbl_struct => $tbl_struct, + ); + $ch->fetch_back($master_dbh); + + $ch->change('UPDATE', {id=>1}, [qw(id)] ); + $ch->change('INSERT', {id=>1}, [qw(id)] ); + + is_deeply( + \@rows, + [ + "UPDATE `bug_1038276`.`rt` SET `b`='0x89504E470D0A1A0A0000000D4948445200000079000000750802000000E55AD965000000097048597300000EC300000EC301C76FA8640000200049444154789C4CBB7794246779FFBBF78F7B7EBE466177677772CE3D9D667AA67BA62776CE39545557CE3974EE9EB049AB9556392210414258083' WHERE `id`='1' LIMIT 1", + "INSERT INTO `bug_1038276`.`rt`(`id`, `b`) VALUES ('1', '0x89504E470D0A1A0A0000000D4948445200000079000000750802000000E55AD965000000097048597300000EC300000EC301C76FA8640000200049444154789C4CBB7794246779FFBBF78F7B7EBE466177677772CE3D9D667AA67BA62776CE39545557CE3974EE9EB049AB9556392210414258083')", + ], + "UPDATE and INSERT quote data regardless of how it looks if tbl_struct->quote_val is true" + ); +} + # ############################################################################# # Done. # ############################################################################# $sb->wipe_clean($master_dbh); $sb->wipe_clean($slave1_dbh); ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); -exit; + +done_testing; + \ No newline at end of file diff --git a/t/lib/Quoter.t b/t/lib/Quoter.t index a843ecb9..6e3aaaae 100644 --- a/t/lib/Quoter.t +++ b/t/lib/Quoter.t @@ -9,7 +9,7 @@ BEGIN { use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); -use Test::More tests => 55; +use Test::More; use Quoter; use PerconaTest; @@ -59,6 +59,8 @@ is( $q->quote_val('\\\''), "'\\\\\\\''", 'embedded backslash'); is( $q->quote_val('123-abc'), "'123-abc'", 'looks numeric but is string'); is( $q->quote_val('123abc'), "'123abc'", 'looks numeric but is string'); is( $q->quote_val('0x89504E470'), '0x89504E470', 'hex string'); +is( $q->quote_val('0x89504E470', is_char => 0), '0x89504E470', 'hex string, with is_char => 0'); +is( $q->quote_val('0x89504E470', is_char => 1), "'0x89504E470'", 'hex string, with is_char => 1'); is( $q->quote_val('0x89504I470'), "'0x89504I470'", 'looks like hex string'); is( $q->quote_val('eastside0x3'), "'eastside0x3'", 'looks like hex str (issue 1110'); @@ -219,4 +221,5 @@ SKIP: { # Done. # ########################################################################### ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); -exit; + +done_testing; From f8fa5cd3e3bc8f4e162c0cc428ac17ca66c57b2a Mon Sep 17 00:00:00 2001 From: Brian Fraser Date: Wed, 22 Aug 2012 16:21:35 -0300 Subject: [PATCH 2/3] Updated Quoter and ChangeHandler in all the modules --- bin/pt-archiver | 5 +++-- bin/pt-deadlock-logger | 5 +++-- bin/pt-duplicate-key-checker | 5 +++-- bin/pt-find | 5 +++-- bin/pt-fk-error-logger | 5 +++-- bin/pt-heartbeat | 5 +++-- bin/pt-index-usage | 5 +++-- bin/pt-kill | 5 +++-- bin/pt-online-schema-change | 5 +++-- bin/pt-query-advisor | 5 +++-- bin/pt-query-digest | 5 +++-- bin/pt-slave-restart | 5 +++-- bin/pt-table-checksum | 5 +++-- bin/pt-table-sync | 22 ++++++++++++++++------ bin/pt-table-usage | 5 +++-- bin/pt-upgrade | 22 ++++++++++++++++------ 16 files changed, 74 insertions(+), 40 deletions(-) diff --git a/bin/pt-archiver b/bin/pt-archiver index 70355b73..2fae8664 100755 --- a/bin/pt-archiver +++ b/bin/pt-archiver @@ -2521,11 +2521,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-deadlock-logger b/bin/pt-deadlock-logger index 3e385cd4..3223d9d9 100755 --- a/bin/pt-deadlock-logger +++ b/bin/pt-deadlock-logger @@ -1706,11 +1706,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-duplicate-key-checker b/bin/pt-duplicate-key-checker index 64165559..8ba599e6 100755 --- a/bin/pt-duplicate-key-checker +++ b/bin/pt-duplicate-key-checker @@ -38,11 +38,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-find b/bin/pt-find index 6e35cbfe..2c66e2e3 100755 --- a/bin/pt-find +++ b/bin/pt-find @@ -1436,11 +1436,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-fk-error-logger b/bin/pt-fk-error-logger index 38763d54..38a0eb46 100755 --- a/bin/pt-fk-error-logger +++ b/bin/pt-fk-error-logger @@ -1063,11 +1063,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index edc02a36..21c3d6f5 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -2360,11 +2360,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-index-usage b/bin/pt-index-usage index 188a8539..eb6b282b 100755 --- a/bin/pt-index-usage +++ b/bin/pt-index-usage @@ -411,11 +411,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-kill b/bin/pt-kill index 06df0bcb..f0428386 100755 --- a/bin/pt-kill +++ b/bin/pt-kill @@ -4106,11 +4106,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index c03b7ce0..91f90f40 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -2270,11 +2270,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-query-advisor b/bin/pt-query-advisor index 2170103e..43295e5a 100755 --- a/bin/pt-query-advisor +++ b/bin/pt-query-advisor @@ -1436,11 +1436,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-query-digest b/bin/pt-query-digest index 5a899af3..fc78b4fe 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -411,11 +411,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-slave-restart b/bin/pt-slave-restart index f20ccb6f..57269e81 100755 --- a/bin/pt-slave-restart +++ b/bin/pt-slave-restart @@ -38,11 +38,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 30b21d52..620b6c43 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -2034,11 +2034,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-table-sync b/bin/pt-table-sync index 2207c55b..cccea956 100755 --- a/bin/pt-table-sync +++ b/bin/pt-table-sync @@ -1513,11 +1513,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; @@ -3412,10 +3413,13 @@ sub make_UPDATE { else { @cols = $self->sort_cols($row); } + my $types = $self->{tbl_struct}->{type_for}; return "UPDATE $self->{dst_db_tbl} SET " . join(', ', map { + my $is_char = ($types->{$_} || '') =~ m/char|text/i; $self->{Quoter}->quote($_) - . '=' . $self->{Quoter}->quote_val($row->{$_}) + . '=' . $self->{Quoter}->quote_val($row->{$_}, + is_char => $is_char); } grep { !$in_where{$_} } @cols) . " WHERE $where LIMIT 1"; } @@ -3449,11 +3453,15 @@ sub make_row { else { @cols = $self->sort_cols($row); } - my $q = $self->{Quoter}; + my $q = $self->{Quoter}; + my $type_for = $self->{tbl_struct}->{type_for}; return "$verb INTO $self->{dst_db_tbl}(" . join(', ', map { $q->quote($_) } @cols) . ') VALUES (' - . join(', ', map { $q->quote_val($_) } @{$row}{@cols} ) + . join(', ', map { + my $is_char = ($type_for->{$_} || '') =~ m/char|text/i; + $q->quote_val($row->{$_}, + is_char => $is_char) } @cols ) . ')'; } @@ -3462,7 +3470,9 @@ sub make_where_clause { my @clauses = map { my $val = $row->{$_}; my $sep = defined $val ? '=' : ' IS '; - $self->{Quoter}->quote($_) . $sep . $self->{Quoter}->quote_val($val); + my $is_char = ($self->{tbl_struct}->{type_for}->{$_} || '') =~ m/char|text/i; + $self->{Quoter}->quote($_) . $sep . $self->{Quoter}->quote_val($val, + is_char => $is_char); } @$cols; return join(' AND ', @clauses); } diff --git a/bin/pt-table-usage b/bin/pt-table-usage index 97b88f4c..ca75c6a1 100755 --- a/bin/pt-table-usage +++ b/bin/pt-table-usage @@ -5487,11 +5487,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; diff --git a/bin/pt-upgrade b/bin/pt-upgrade index daa72ddc..3169148f 100755 --- a/bin/pt-upgrade +++ b/bin/pt-upgrade @@ -852,11 +852,12 @@ sub quote { } sub quote_val { - my ( $self, $val ) = @_; + my ( $self, $val, %args ) = @_; return 'NULL' unless defined $val; # undef = NULL return "''" if $val eq ''; # blank string = '' - return $val if $val =~ m/^0x[0-9a-fA-F]+$/; # hex data + return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data + && !$args{is_char}; # unless is_char is true $val =~ s/(['\\])/\\$1/g; return "'$val'"; @@ -4646,10 +4647,13 @@ sub make_UPDATE { else { @cols = $self->sort_cols($row); } + my $types = $self->{tbl_struct}->{type_for}; return "UPDATE $self->{dst_db_tbl} SET " . join(', ', map { + my $is_char = ($types->{$_} || '') =~ m/char|text/i; $self->{Quoter}->quote($_) - . '=' . $self->{Quoter}->quote_val($row->{$_}) + . '=' . $self->{Quoter}->quote_val($row->{$_}, + is_char => $is_char); } grep { !$in_where{$_} } @cols) . " WHERE $where LIMIT 1"; } @@ -4683,11 +4687,15 @@ sub make_row { else { @cols = $self->sort_cols($row); } - my $q = $self->{Quoter}; + my $q = $self->{Quoter}; + my $type_for = $self->{tbl_struct}->{type_for}; return "$verb INTO $self->{dst_db_tbl}(" . join(', ', map { $q->quote($_) } @cols) . ') VALUES (' - . join(', ', map { $q->quote_val($_) } @{$row}{@cols} ) + . join(', ', map { + my $is_char = ($type_for->{$_} || '') =~ m/char|text/i; + $q->quote_val($row->{$_}, + is_char => $is_char) } @cols ) . ')'; } @@ -4696,7 +4704,9 @@ sub make_where_clause { my @clauses = map { my $val = $row->{$_}; my $sep = defined $val ? '=' : ' IS '; - $self->{Quoter}->quote($_) . $sep . $self->{Quoter}->quote_val($val); + my $is_char = ($self->{tbl_struct}->{type_for}->{$_} || '') =~ m/char|text/i; + $self->{Quoter}->quote($_) . $sep . $self->{Quoter}->quote_val($val, + is_char => $is_char); } @$cols; return join(' AND ', @clauses); } From ea62bf87f70d2c58e7c095023f322e4c141d434c Mon Sep 17 00:00:00 2001 From: Brian Fraser Date: Fri, 24 Aug 2012 20:12:41 -0300 Subject: [PATCH 3/3] Added missing .sql file --- t/lib/samples/bug_1038276.sql | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 t/lib/samples/bug_1038276.sql diff --git a/t/lib/samples/bug_1038276.sql b/t/lib/samples/bug_1038276.sql new file mode 100644 index 00000000..be577804 --- /dev/null +++ b/t/lib/samples/bug_1038276.sql @@ -0,0 +1,12 @@ +DROP DATABASE IF EXISTS bug_1038276; +CREATE DATABASE bug_1038276; +USE bug_1038276; +CREATE TABLE lt ( + id int not null auto_increment primary key, + b varchar(300) +) ENGINE=InnoDB; +CREATE TABLE rt ( + id int not null auto_increment primary key, + b varchar(300) +) ENGINE=InnoDB; +INSERT INTO lt VALUES (null, "0x89504E470D0A1A0A0000000D4948445200000079000000750802000000E55AD965000000097048597300000EC300000EC301C76FA8640000200049444154789C4CBB7794246779FFBBF78F7B7EBE466177677772CE3D9D667AA67BA62776CE39545557CE3974EE9EB049AB9556392210414258083");