Add a new transform function for byte-vector to hexadecimal string.

In some cases when migrating from MySQL we want to transform data from
binary representation to an hexadecimal number. One such case is going from
MySQL binary(16) to PostgreSQL UUID data type.

Fixes #904.
This commit is contained in:
Dimitri Fontaine 2019-03-18 14:21:33 +01:00
parent 4d005b5c9c
commit 957caa877e
4 changed files with 91 additions and 3 deletions

View File

@ -96,7 +96,8 @@
sql-server-bit-to-boolean
varbinary-to-string
base64-decode
hex-to-dec))
hex-to-dec
byte-vector-to-hexstring))
;;;
@ -413,6 +414,32 @@
((string= "((1))" bit-string-or-integer) "t")
(t nil)))))
(defun byte-vector-to-hexstring (vector)
"Transform binary input received as a vector of bytes into a string of
hexadecimal digits, as per the following example:
Input: #(136 194 152 47 66 138 70 183 183 27 33 6 24 174 22 88)
Output: 88C2982F428A46B7B71B210618AE1658"
(declare (type (or null string (simple-array (unsigned-byte 8) (*))) vector))
(etypecase vector
(null nil)
(string (if (string= "" vector)
nil
(error "byte-vector-to-bytea called on a string: ~s" vector)))
(simple-array
(let ((hex-digits "0123456789abcdef")
(bytea (make-array (* 2 (length vector))
:initial-element #\0
:element-type 'standard-char)))
(loop for pos from 0 by 2
for byte across vector
do (let ((high (ldb (byte 4 4) byte))
(low (ldb (byte 4 0) byte)))
(setf (aref bytea pos) (aref hex-digits high))
(setf (aref bytea (+ pos 1)) (aref hex-digits low)))
finally (return bytea))))))
(defun varbinary-to-string (string)
(let ((babel::*default-character-encoding*
(or qmynd::*mysql-encoding*

25
test/mysql/hex.sql vendored Normal file
View File

@ -0,0 +1,25 @@
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `encryption_key_canary` (
`encrypted_value` blob,
`nonce` tinyblob,
`uuid` binary(16) NOT NULL,
`salt` tinyblob,
PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `encryption_key_canary`
--
LOCK TABLES `encryption_key_canary` WRITE;
/*!40000 ALTER TABLE `encryption_key_canary` DISABLE KEYS */;
INSERT INTO `encryption_key_canary` VALUES (
0x1F36F183D7EE47C71453850B756945C16D9D711B2F0594E5D5E54D1EC94E081716AB8642AA60F84B50F69454D098122B7136A0DEB3AF200C2C5C7500BDFA0BD9689CCBF10A76972374882B304F7F15A227E815989FC87EEB72612396F569C662E72A2A7555E654605A3B83C1C753297832E52C5961E81EBC60DC43D929ABAB8CB14601DEFED121604CEB26210AB6D724,
0x044AA707DF17021E55E9A1E4,
0x88C2982F428A46B7B71B210618AE1658,
0xAE7F18028E7984FB5630F7D23FB77999C6CA7CF5355EF0194F3F16521EA7EC503F566229ED8DC5EFBBE9C12BA491BDDC939FE60FA31FB9AF123B2B4D5B7A61FE
);
/*!40000 ALTER TABLE `encryption_key_canary` ENABLE KEYS */;
UNLOCK TABLES;

View File

@ -11,6 +11,8 @@ load database
ALTER SCHEMA 'pgloader' RENAME TO 'mysql'
ALTER TABLE NAMES MATCHING ~/./ SET TABLESPACE 'pg_default'
INCLUDING ONLY TABLE NAMES MATCHING 'encryption_key_canary'
CAST column utilisateurs__Yvelines2013-06-28.sexe
to text drop not null using empty-string-to-null,
@ -31,6 +33,10 @@ load database
using zero-dates-to-null,
type timestamp with extra on update current timestamp
to "timestamp with time zone" drop extra
to "timestamp with time zone" drop extra,
BEFORE LOAD DO $$ create schema if not exists mysql; $$;
column encryption_key_canary.uuid
to uuid drop typemod using byte-vector-to-hexstring
BEFORE LOAD DO
$$ create schema if not exists mysql; $$;

30
test/mysql/my.sql vendored
View File

@ -118,6 +118,36 @@ CREATE TABLE `domain_filter` (
KEY `domain_filter` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii;
/*
* https://github.com/dimitri/pgloader/issues/904
*/
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `encryption_key_canary` (
`encrypted_value` blob,
`nonce` tinyblob,
`uuid` binary(16) NOT NULL,
`salt` tinyblob,
PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `encryption_key_canary`
--
LOCK TABLES `encryption_key_canary` WRITE;
/*!40000 ALTER TABLE `encryption_key_canary` DISABLE KEYS */;
INSERT INTO `encryption_key_canary` VALUES (
0x1F36F183D7EE47C71453850B756945C16D9D711B2F0594E5D5E54D1EC94E081716AB8642AA60F84B50F69454D098122B7136A0DEB3AF200C2C5C7500BDFA0BD9689CCBF10A76972374882B304F7F15A227E815989FC87EEB72612396F569C662E72A2A7555E654605A3B83C1C753297832E52C5961E81EBC60DC43D929ABAB8CB14601DEFED121604CEB26210AB6D724,
0x044AA707DF17021E55E9A1E4,
0x88C2982F428A46B7B71B210618AE1658,
0xAE7F18028E7984FB5630F7D23FB77999C6CA7CF5355EF0194F3F16521EA7EC503F566229ED8DC5EFBBE9C12BA491BDDC939FE60FA31FB9AF123B2B4D5B7A61FE
);
/*!40000 ALTER TABLE `encryption_key_canary` ENABLE KEYS */;
UNLOCK TABLES;
/*
* https://github.com/dimitri/pgloader/issues/703
*/