Конвертация MariaDB в Oracle
Перетащите дамп из mariadb-dump, mysqldump, phpMyAdmin или Adminer в формате .sql или .sql.gz и скачайте скрипт Oracle с теми же таблицами, ключами, индексами и данными. Каждое значение, которое Oracle не может хранить как есть, и каждый объект, который он не переносит, указаны в отчете.
18 строк конвертировано, 4 исправления, ни одна не отклонена
Таблицы в shop_2024_mariadb.sqlДамп MariaDB 11.8.9-MariaDB-ubu2404 · создан программой mariadb-dump · utf8mb4
customersзаписана как CUSTOMERS8 строк2
8 столбцов ID NUMBER(10) not null NAME VARCHAR2(100 CHAR) not null EMAIL VARCHAR2(150 CHAR) not null COUNTRY VARCHAR2(2 CHAR) not null IS_ACTIVE NUMBER(1) not null SIGNED_UP DATE CREATED_AT TIMESTAMP(0) WITH TIME ZONE not null LAST_IP VARCHAR2(39 CHAR) ordersзаписана как ORDERS10 строк2
12 столбцов ID NUMBER(10) not null CUSTOMER_ID NUMBER(10) not null STATUS VARCHAR2(9 CHAR) TOTAL NUMBER(10,2) not null ITEMS NUMBER(5) not null ORDERED_AT TIMESTAMP(0) not null SHIPPED_AT TIMESTAMP(0) NOTE VARCHAR2(255 CHAR) ORDER_REF VARCHAR2(36 CHAR) not null INVOICE NUMBER(10) not null DETAILS CLOB UPDATED_AT TIMESTAMP(0) WITH TIME ZONE not null
-- Written by IntoSQL from a MySQL dump. Load it with: NLS_LANG=.AL32UTF8 sqlplus -S -L <user>/<password>@<database> @<file>
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
SET DEFINE OFF;
SET SQLBLANKLINES ON;
SET FEEDBACK OFF;
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION "INTOSQL_CLOB" (p SYS.ODCIVARCHAR2LIST) RETURN CLOB IS
r CLOB;
BEGIN
DBMS_LOB.CREATETEMPORARY(r, TRUE);
FOR i IN 1 .. p.COUNT LOOP
IF p(i) IS NOT NULL THEN
DBMS_LOB.WRITEAPPEND(r, LENGTH2(p(i)), p(i));
END IF;
END LOOP;
RETURN r;
END;
/
CREATE OR REPLACE FUNCTION "INTOSQL_BLOB" (p SYS.ODCIVARCHAR2LIST) RETURN BLOB IS
r BLOB;
piece RAW(2000);
BEGIN
DBMS_LOB.CREATETEMPORARY(r, TRUE);
FOR i IN 1 .. p.COUNT LOOP
piece := HEXTORAW(p(i));
DBMS_LOB.WRITEAPPEND(r, UTL_RAW.LENGTH(piece), piece);
END LOOP;
RETURN r;
END;
/
CREATE SEQUENCE "INVOICE_NUMBERS" START WITH 2000 INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775806;
CREATE TABLE "CUSTOMERS" (
"ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1001),
"NAME" VARCHAR2(100 CHAR) NOT NULL,
"EMAIL" VARCHAR2(150 CHAR) NOT NULL,
"COUNTRY" VARCHAR2(2 CHAR) DEFAULT 'US' NOT NULL,
"IS_ACTIVE" NUMBER(1) DEFAULT 1 NOT NULL,
"SIGNED_UP" DATE,
"CREATED_AT" TIMESTAMP(0) WITH TIME ZONE DEFAULT SYSTIMESTAMP NOT NULL,
"LAST_IP" VARCHAR2(39 CHAR),
CONSTRAINT "CK_CUSTOMERS_ID" CHECK ("ID" >= 0),
CONSTRAINT "CK_CUSTOMERS_IS_ACTIVE" CHECK ("IS_ACTIVE" IN (0, 1))
);
CREATE TABLE "ORDERS" (
"ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 5001),
"CUSTOMER_ID" NUMBER(10) NOT NULL,
"STATUS" VARCHAR2(9 CHAR) DEFAULT 'pending',
"TOTAL" NUMBER(10,2) NOT NULL,
"ITEMS" NUMBER(5) DEFAULT 1 NOT NULL,
"ORDERED_AT" TIMESTAMP(0) NOT NULL,
"SHIPPED_AT" TIMESTAMP(0),
"NOTE" VARCHAR2(255 CHAR),
"ORDER_REF" VARCHAR2(36 CHAR) NOT NULL,
"INVOICE" NUMBER(10) DEFAULT ("INVOICE_NUMBERS".NEXTVAL) NOT NULL,
"DETAILS" CLOB,
"UPDATED_AT" TIMESTAMP(0) WITH TIME ZONE DEFAULT SYSTIMESTAMP NOT NULL,
CONSTRAINT "CK_ORDERS_ID" CHECK ("ID" >= 0),
CONSTRAINT "CK_ORDERS_CUSTOMER_ID" CHECK ("CUSTOMER_ID" >= 0),
CONSTRAINT "CK_ORDERS_STATUS" CHECK ("STATUS" IN ('pending', 'paid', 'shipped', 'cancelled')),
CONSTRAINT "CK_ORDERS_ITEMS" CHECK ("ITEMS" >= 0)
);
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
1,
'Ana Martínez',
'ana@example.com',
'MX',
1,
DATE '2023-01-15',
TIMESTAMP '2023-01-15 10:24:00 +00:00',
'::ffff:203.0.113.7'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
2,
'Zoë Müller',
'zoe@example.de',
'DE',
1,
DATE '2023-02-03',
TIMESTAMP '2023-02-03 08:11:42 +00:00',
'2001:db8::1'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
3,
'José Peña',
'jose@example.es',
'ES',
0,
DATE '2023-03-21',
TIMESTAMP '2023-03-21 19:05:17 +00:00',
NULL
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
4,
'李雷',
'lilei@example.cn',
'CN',
1,
DATE '2023-05-09',
TIMESTAMP '2023-05-09 02:40:00 +00:00',
'::ffff:198.51.100.23'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
5,
'Noah O''Brien',
'noah@example.ie',
'IE',
1,
NULL,
TIMESTAMP '2023-06-30 14:00:00 +00:00',
NULL
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
6,
'Amélie Laurent',
'amelie@example.fr',
'FR',
1,
DATE '2024-01-02',
TIMESTAMP '2024-01-02 09:30:00 +00:00',
'2001:db8:85a3::8a2e:370:7334'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
7,
'Ravi Patel',
'ravi@example.in',
'IN',
0,
DATE '2024-02-29',
TIMESTAMP '2024-02-29 23:59:59 +00:00',
'::ffff:192.0.2.200'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT",
"LAST_IP"
) VALUES (
8,
'Sofia Rossi 🌻',
'sofia@example.it',
'IT',
1,
DATE '2024-04-12',
TIMESTAMP '2024-04-12 12:12:12 +00:00',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
1,
1,
'shipped',
129.90,
3,
TIMESTAMP '2024-03-01 10:00:00',
TIMESTAMP '2024-03-02 16:30:00',
NULL,
'0b7a4c2e-3f1d-4e8a-9c55-1a2b3c4d5e6f',
1000,
'{"gift": false}',
TIMESTAMP '2024-03-02 16:30:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
2,
2,
'paid',
54.00,
1,
TIMESTAMP '2024-03-02 11:15:00',
NULL,
'Gift wrap 🎁',
'1c8b5d3f-4a2e-4f9b-8d66-2b3c4d5e6f70',
1001,
'{"gift": true, "wrap": "red"}',
TIMESTAMP '2024-03-02 11:20:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
3,
1,
'cancelled',
12.50,
1,
TIMESTAMP '2024-03-03 09:45:00',
NULL,
'Customer changed their mind',
'2d9c6e4a-5b3f-4a0c-9e77-3c4d5e6f7081',
1002,
NULL,
TIMESTAMP '2024-03-03 10:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
4,
4,
'shipped',
980.00,
12,
TIMESTAMP '2024-03-05 02:10:00',
TIMESTAMP '2024-03-07 08:00:00',
'请小心轻放',
'3e0d7f5b-6c4a-4b1d-8f88-4d5e6f708192',
1003,
'{"fragile": true}',
TIMESTAMP '2024-03-07 08:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
5,
5,
'pending',
45.75,
2,
TIMESTAMP '2024-03-08 17:20:00',
NULL,
'Leave at the door; ring twice',
'4f1e806c-7d5b-4c2e-9a99-5e6f708192a3',
1004,
NULL,
TIMESTAMP '2024-03-08 17:20:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
6,
6,
'shipped',
310.40,
5,
TIMESTAMP '2024-03-10 13:00:00',
TIMESTAMP '2024-03-11 09:00:00',
'Fragile: "glass"',
'50f2917d-8e6c-4d3f-8baa-6f708192a3b4',
1005,
'{"fragile": true}',
TIMESTAMP '2024-03-11 09:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
7,
8,
'paid',
76.20,
2,
TIMESTAMP '2024-03-11 18:45:00',
NULL,
NULL,
'6103a28e-9f7d-4e40-9cbb-708192a3b4c5',
1006,
NULL,
TIMESTAMP '2024-03-11 18:46:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
8,
2,
NULL,
19.99,
1,
TIMESTAMP '2024-03-12 08:00:00',
NULL,
'Status lost in an old import',
'7214b39f-a08e-4f51-8dcc-8192a3b4c5d6',
1007,
NULL,
TIMESTAMP '2024-03-12 08:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
9,
3,
'shipped',
64.00,
2,
TIMESTAMP '2024-03-14 15:30:00',
NULL,
'Shipping date never recorded',
'8325c4a0-b19f-4062-9edd-92a3b4c5d6e7',
1008,
'{"parcels": [1, 2]}',
TIMESTAMP '2024-03-15 10:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"ORDER_REF",
"INVOICE",
"DETAILS",
"UPDATED_AT"
) VALUES (
10,
7,
'paid',
1499.00,
1,
TIMESTAMP '2024-03-15 21:05:00',
NULL,
'C:\Users\ravi\invoice.pdf',
'9436d5b1-c2a0-4173-8fee-a3b4c5d6e7f8',
1009,
NULL,
TIMESTAMP '2024-03-15 21:05:00 +00:00'
);
COMMIT;
END;
/
-- Keys, indexes, foreign keys, counters and triggers, after the rows.
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "PK_CUSTOMERS" PRIMARY KEY ("ID");
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "UQ_CUSTOMERS_UQ_EMAIL" UNIQUE ("EMAIL");
ALTER TABLE "ORDERS" ADD CONSTRAINT "PK_ORDERS" PRIMARY KEY ("ID");
CREATE INDEX "IX_ORDERS_IDX_CUSTOMER" ON "ORDERS" ("CUSTOMER_ID");
CREATE INDEX "IX_ORDERS_IDX_STATUS_DATE" ON "ORDERS" ("STATUS", "ORDERED_AT");
ALTER TABLE "ORDERS" ADD CONSTRAINT "FK_ORDERS_CUSTOMER" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "CUSTOMERS" ("ID") ENABLE NOVALIDATE;
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" ENABLE VALIDATE CONSTRAINT "FK_ORDERS_CUSTOMER"';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Foreign key ' || '"FK_ORDERS_CUSTOMER"' || ' has rows without a parent: it stays unvalidated, and new rows are checked.');
END;
/
DECLARE
next_id NUMBER;
BEGIN
SELECT NVL(MAX("ID"), 0) + 1 INTO next_id FROM "CUSTOMERS";
IF next_id < 1001 THEN
next_id := 1001;
END IF;
EXECUTE IMMEDIATE 'ALTER TABLE "CUSTOMERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
COMMENT ON TABLE "CUSTOMERS" IS 'People who bought at least once';
DECLARE
next_id NUMBER;
BEGIN
SELECT NVL(MAX("ID"), 0) + 1 INTO next_id FROM "ORDERS";
IF next_id < 5001 THEN
next_id := 5001;
END IF;
EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
CREATE OR REPLACE TRIGGER "TR_ORDERS_UPDATED_AT" BEFORE UPDATE ON "ORDERS" FOR EACH ROW
BEGIN
IF NOT UPDATING('UPDATED_AT') THEN
:NEW."UPDATED_AT" := SYSTIMESTAMP;
END IF;
END;
/
DROP FUNCTION "INTOSQL_CLOB";
DROP FUNCTION "INTOSQL_BLOB";
COMMIT;
EXIT;
Исправления
- Столбец "signed_up" таблицы customers теперь допускает NULL: часть его значений нельзя было сохранить, и они записаны как NULL.
- Значение по умолчанию столбца "signed_up" таблицы customers, 0000‑00‑00, не является датой, которую принимает Oracle, поэтому у столбца его нет.
- Столбец "status" таблицы orders теперь допускает NULL: часть его значений нельзя было сохранить, и они записаны как NULL.
- Столбец "updated_at" таблицы orders получает текущее время при каждом обновлении; в Oracle это делает триггер.
Требует проверки
- В "signed_up" таблицы customers 1 значение - нулевая или невозможная дата, например 0000‑00‑00; Oracle не может их хранить, поэтому записан NULL. Если эти даты что-то значат, замените их в источнике настоящими до создания дампа.
- В "shipped_at" таблицы orders 1 значение - нулевая или невозможная дата, например 0000‑00‑00 00:00:00; Oracle не может их хранить, поэтому записан NULL. Если эти даты что-то значат, замените их в источнике настоящими до создания дампа.
- В "status" таблицы orders 1 пустое значение стало NULL; Oracle хранит пустую строку как NULL. Где запросы сравнивают этот столбец с ', сравнивайте с IS NULL.
Файл конвертируется на этом компьютере и никуда не загружается.
Другие примеры:
Что меняется при переходе с MariaDB на Oracle
Каждая строка - это правило, которое применяет конвертер, и строка отчета, которую он пишет, когда правило что-то меняет в ваших данных.
TINYINT(1), BOOL
NUMBER(1) с CHECK на 0 и 1, если каждое значение 0 или 1, иначе NUMBER(3)
BOOL в MySQL - это TINYINT(1), который может хранить любое число от -128 до 127. В Oracle до 23ai нет логического столбца, поэтому столбец из 0 и 1 становится NUMBER(1) с проверкой; столбец с 2 или -1 сохраняет свои числа.
Строка отчета: bool_kept_numeric
UNSIGNED integers
NUMBER достаточной ширины для диапазона, с CHECK на неотрицательность
NUMBER в Oracle вмещает любое целое тех размеров, что есть в MySQL; проверка не пропускает отрицательные значения, как в MySQL.
ZEROFILL and display widths
удаляется
Дополнение нулями - это способ показа числа, а не его часть. Числа сохраняются; если дополнение важно, форматируйте их при чтении.
Строка отчета: zerofill_dropped
FLOAT(M,D)
BINARY_FLOAT или BINARY_DOUBLE, без масштаба
У двоичных чисел с плавающей точкой в Oracle нет фиксированного масштаба. Записанные значения копируются как есть.
Строка отчета: float_scale_dropped
DECIMAL(p,s)
NUMBER(p,s) до 38 цифр; дальше VARCHAR2
NUMBER в Oracle вмещает 38 цифр. Более широкие десятичные числа хранятся как текст, чтобы каждая цифра осталась точной.
Строка отчета: decimal_as_text
BIT(1), BIT(n)
NUMBER(1), NUMBER(19) до 63 бит, NUMBER(20) для BIT(64)
Битовые поля хранятся как число, которое составляют их биты.
zero, partial or impossible dates (0000-00-00, 2024-02-30)
NULL
Oracle хранит только настоящие календарные даты. MySQL сохраняет нулевые и невозможные даты, если это позволяет режим SQL; они становятся NULL, а отчет их подсчитывает.
Строка отчета: invalid_date_null
NOT NULL columns with values that become NULL
NOT NULL снимается
Столбец, значения которого пришлось заменить на NULL, включая пустые строки, не может сохранить NOT NULL, иначе загрузка остановится.
Строка отчета: not_null_relaxed
empty strings and empty binary values
NULL
Oracle хранит пустую строку как NULL, поэтому значение ' читается обратно как NULL. Отчет подсчитывает их по столбцам.
Строка отчета: empty_string_null
DEFAULT '0000-00-00'
без значения по умолчанию
Значение по умолчанию, которое Oracle не может хранить, опускается, а не заменяется выдуманной датой.
Строка отчета: zero_date_default
TIME
INTERVAL DAY TO SECOND, который вмещает длительности
В Oracle нет типа для времени суток, а TIME в MySQL - это длительность от -838:59:59 до 838:59:59; интервал вмещает любое значение.
YEAR
NUMBER(4) с CHECK диапазона
В Oracle нет типа для года; проверка допускает те же значения, что и MySQL.
CHAR(n), VARCHAR(n)
VARCHAR2(n CHAR), длина в символах
Длина считается в символах, как в MySQL, а MySQL возвращает значения CHAR без пробелов в конце, и VARCHAR2 хранит их так же.
VARCHAR(n) and TEXT longer than 4000 bytes
CLOB
VARCHAR2 по умолчанию вмещает 4000 байт, поэтому более длинный текст становится CLOB; столбец, все значения которого помещаются, остается VARCHAR2.
Строка отчета: text_as_lob
DATETIME
TIMESTAMP
DATETIME - это показание часов без часового пояса, как TIMESTAMP. DATE становится DATE в Oracle, который хранит и время суток, оно остается полночью.
TIMESTAMP
TIMESTAMP WITH TIME ZONE в поясе, указанном в дампе, или UTC, если он не указан
TIMESTAMP - это момент времени. Дампы указывают пояс, в котором он записан (mysqldump пишет UTC); без этого значения читаются как UTC, и отчет это отмечает.
Строка отчета: timestamp_zone_assumed
ENUM
VARCHAR2 с CHECK значений
Текст с проверкой хранит те же значения.
ENUM holding '' (MySQL's error value)
NULL
MySQL записывает пустую строку, когда недопустимое значение попадает в ENUM в нестрогом режиме SQL. Oracle хранит ее как NULL, что проверка допускает, а отчет учитывает ее вместе с другими пустыми значениями.
ENUM holding values outside its list
без CHECK
Значения, которых нет в списке, не прошли бы проверку, поэтому она не создается.
Строка отчета: enum_check_skipped
SET
VARCHAR2 в записи MySQL ('a,b')
В Oracle нет типа множества; текст тот же, что возвращает MySQL.
JSON
CLOB
Функции JSON в Oracle читают JSON из текста во всех версиях, а CLOB вмещает значения любого размера.
NUL bytes in text
сохраняется
VARCHAR2 и CLOB могут содержать символ NUL, поэтому значение копируется как есть.
text that isn't valid in its character set
неверные байты заменяются символом замены
Текст нужно прочитать как символы, чтобы записать его как VARCHAR2.
Строка отчета: invalid_utf8_replaced
text decoded twice (ñ)
копируется как есть
Дамп содержит именно эти символы, поэтому они копируются; отчет на них указывает.
Строка отчета: mojibake_suspected
AUTO_INCREMENT
GENERATED BY DEFAULT ON NULL AS IDENTITY, перезапуск после скопированных id
Скопированные id загружаются как есть, а счетчик продолжается после наибольшего из них или после AUTO_INCREMENT дампа, смотря что больше.
MyISAM AUTO_INCREMENT on the second column of a key
один счетчик на таблицу
MyISAM считает отдельно для каждой группы первого столбца ключа; в Oracle один счетчик на таблицу.
Строка отчета: myisam_group_autoincrement
ON UPDATE CURRENT_TIMESTAMP
триггер BEFORE UPDATE
Триггер записывает в столбец текущее время, когда обновление его не задает.
Строка отчета: on_update_trigger
generated columns
виртуальные столбцы
Oracle вычисляет генерируемые столбцы только при чтении; столбцы STORED становятся виртуальными с теми же значениями.
Строка отчета: stored_as_virtual
generated columns with functions Oracle lacks
обычный столбец
Формула, которую нельзя записать для Oracle, оставляет обычный столбец и строку в отчете.
Строка отчета: generated_not_translated
INVISIBLE columns
столбцы INVISIBLE
Oracle скрывает невидимые столбцы от SELECT *, как MySQL.
CHECK constraints
переводится, внутри CREATE TABLE
Встроенные проверки выполняются при загрузке каждой строки.
CHECK constraints with functions Oracle lacks
не создается
Проверка, которую нельзя записать для Oracle, опускается и попадает в отчет.
Строка отчета: check_skipped
CHECK ... NOT ENFORCED
не создается
MySQL хранит эти проверки, но не применяет их, поэтому строки могут их нарушать.
Строка отчета: check_not_enforced
defaults with functions Oracle lacks
без значения по умолчанию
Значение по умолчанию, которое нельзя записать для Oracle, опускается и попадает в отчет.
Строка отчета: default_not_translated
keys and indexes on a prefix, c(20)
индекс по SUBSTR столбца
Функциональный индекс по тому же началу столбца различает те же строки и индексирует столбцы CLOB, которые Oracle не индексирует целиком.
Строка отчета: prefix_unique
FULLTEXT indexes
не создается
Oracle Text строит полнотекстовый поиск со своим типом индекса и запросами.
Строка отчета: fulltext_not_created
SPATIAL indexes
не создается
Геометрии хранятся как байты WKB, которые пространственный индекс прочитать не может.
Строка отчета: spatial_index_not_created
functional indexes, and indexes on whole CLOB or BLOB columns
не создается
Oracle не индексирует большой объект целиком, а у некоторых функций MySQL нет аналога в Oracle.
Строка отчета: index_skipped
foreign keys
после данных ENABLE NOVALIDATE, затем валидация с предупреждением о строках без родителя
Дампы загружаются с FOREIGN_KEY_CHECKS=0, а MyISAM ничего не проверяет, поэтому строки без родительской записи встречаются часто. Ключ сразу проверяет новые строки, а валидация идет последней; при строках без родителя он остается без валидации с предупреждением, и загрузка не останавливается.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT
удаляется
Внешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL.
Строка отчета: foreign_key_action_unsupported
foreign keys to columns without a unique key
не создается
Oracle требует первичный ключ или ограничение уникальности на столбцах, на которые ссылается внешний ключ; InnoDB - нет.
Строка отчета: foreign_key_skipped
table and column names
верхний регистр для простых имен, иначе как в источнике
Oracle хранит имена, записанные без кавычек, в верхнем регистре, поэтому простые имена переводятся в верхний регистр и запросы могут обходиться без кавычек; остальные имена сохраняют регистр и требуют кавычек.
Строка отчета: identifier_renamed
names over 128 bytes
сокращается
Имена в Oracle 12.2 и новее вмещают 128 байт.
Строка отчета: name_shortened
GEOMETRY, POINT, POLYGON...
BLOB с WKB
WKB - стандартный формат, который читает любая пространственная библиотека; SDO_GEOMETRY нужны метаданные Oracle Spatial.
Строка отчета: geometry_as_blob
INET4, INET6, UUID (MariaDB)
VARCHAR2(39), VARCHAR2(36)
В Oracle нет ни одного из этих типов; текст тот же, что возвращает MariaDB.
BINARY, VARBINARY, BLOB
RAW до 2000 байт, иначе BLOB
Байты остаются байтами.
PARTITION BY
одна таблица
Строки те же; при необходимости секционируйте таблицу заново в Oracle.
Строка отчета: partitions_dropped
WITH SYSTEM VERSIONING (MariaDB)
таблица с текущими строками
Дамп содержит только текущие строки.
Строка отчета: system_versioning_dropped
MyISAM, MEMORY and other engines
обычная таблица
В Oracle один движок таблиц.
Строка отчета: engine_dropped
views, triggers, procedures, functions and events
перечисляются в отчете
Их код написан на языке MySQL, поэтому они перечислены, чтобы вы создали их заново.
Строка отчета: not_converted_objects
dumps without CREATE TABLE
типы определяются по значениям
Дамп, созданный с --no-create-info, содержит только строки, поэтому типы берутся из значений.
Строка отчета: no_schema
geometries in a dump without CREATE TABLE
BLOB с WKB
Формат геометрии MySQL распознается по значениям и сохраняется как стандартный WKB.
Строка отчета: geometry_inferred
_ci collations
точное сравнение
Oracle сравнивает текст точно, если не указано иное.
Строка отчета: case_insensitive_collation
SET NAMES utf8 from utf8mb4 tables
конвертируется с предупреждением
mysqldump из MySQL 5.x по умолчанию пишет 3-байтовую utf8 и заменяет каждый эмодзи вопросительным знаком еще до того, как файл увидит какой-либо конвертер.
Строка отчета: dump_lost_four_byte_chars
dumps without SET NAMES whose text isn't UTF-8
читается как Latin-1 (Windows-1252)
latin1 в MySQL - это Windows-1252, обычная кодировка таких дампов.
Строка отчета: charset_guessed
sjis, cp932, gbk, big5 dumps
читается как UTF-8, с предупреждением
Эти кодировки пока не декодируются.
Строка отчета: unsupported_charset
UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows
вычисляются
Некоторые программы дампа записывают значения как такие вызовы; они читаются как значения, которые возвращают, а в географическом WKT долгота ставится первой.
other expressions in rows
NULL
Конвертер, который не запускает базу данных, не может их вычислить.
Строка отчета: expression_value
DEFAULT in VALUES
значение столбца по умолчанию
Литеральное значение по умолчанию копируется в строку.
Строка отчета: default_keyword_filled
DEFAULT in VALUES without a literal default
NULL
Копировать нечего.
Строка отчета: default_keyword_null
REPLACE and INSERT IGNORE
обычные строки
В дампе одна строка на ключ, поэтому строки те же.
Строка отчета: replace_as_insert
types IntoSQL doesn't know
CLOB
Тип text вмещает любое значение; измените тип после загрузки.
Строка отчета: unknown_type
values that don't fit their column
NULL
Поврежденный или написанный вручную дамп может содержать значения, которые столбец не вмещает; они становятся NULL, чтобы остальное загрузилось.
Строка отчета: invalid_value_null
unreadable geometries
NULL
Байты, которые не являются геометрией, нельзя сохранить как геометрию.
Строка отчета: bad_geometry
dumps of several databases
одна схема, имя каждой таблицы начинается с имени ее базы
Скрипт загружается в схему пользователя, который его запускает, поэтому таблицы из разных баз данных получают в начале имя своей базы.
Строка отчета: databases_merged
CREATE SEQUENCE (MariaDB)
CREATE SEQUENCE с достигнутым значением
Последовательности в Oracle работают так же.
VECTOR(n) (MariaDB 11.7+)
CLOB с числами float в виде массива JSON
Векторный тип есть только в Oracle 23ai; массив JSON сохраняет каждое число float в любой версии.
Строка отчета: type_replaced
| В MariaDB | В Oracle | Строка отчета |
|---|---|---|
| TINYINT(1), BOOL | NUMBER(1) с CHECK на 0 и 1, если каждое значение 0 или 1, иначе NUMBER(3)BOOL в MySQL - это TINYINT(1), который может хранить любое число от -128 до 127. В Oracle до 23ai нет логического столбца, поэтому столбец из 0 и 1 становится NUMBER(1) с проверкой; столбец с 2 или -1 сохраняет свои числа. | bool_kept_numeric |
| UNSIGNED integers | NUMBER достаточной ширины для диапазона, с CHECK на неотрицательностьNUMBER в Oracle вмещает любое целое тех размеров, что есть в MySQL; проверка не пропускает отрицательные значения, как в MySQL. | |
| ZEROFILL and display widths | удаляетсяДополнение нулями - это способ показа числа, а не его часть. Числа сохраняются; если дополнение важно, форматируйте их при чтении. | zerofill_dropped |
| FLOAT(M,D) | BINARY_FLOAT или BINARY_DOUBLE, без масштабаУ двоичных чисел с плавающей точкой в Oracle нет фиксированного масштаба. Записанные значения копируются как есть. | float_scale_dropped |
| DECIMAL(p,s) | NUMBER(p,s) до 38 цифр; дальше VARCHAR2NUMBER в Oracle вмещает 38 цифр. Более широкие десятичные числа хранятся как текст, чтобы каждая цифра осталась точной. | decimal_as_text |
| BIT(1), BIT(n) | NUMBER(1), NUMBER(19) до 63 бит, NUMBER(20) для BIT(64)Битовые поля хранятся как число, которое составляют их биты. | |
| zero, partial or impossible dates (0000-00-00, 2024-02-30) | NULLOracle хранит только настоящие календарные даты. MySQL сохраняет нулевые и невозможные даты, если это позволяет режим SQL; они становятся NULL, а отчет их подсчитывает. | invalid_date_null |
| NOT NULL columns with values that become NULL | NOT NULL снимаетсяСтолбец, значения которого пришлось заменить на NULL, включая пустые строки, не может сохранить NOT NULL, иначе загрузка остановится. | not_null_relaxed |
| empty strings and empty binary values | NULLOracle хранит пустую строку как NULL, поэтому значение ' читается обратно как NULL. Отчет подсчитывает их по столбцам. | empty_string_null |
| DEFAULT '0000-00-00' | без значения по умолчаниюЗначение по умолчанию, которое Oracle не может хранить, опускается, а не заменяется выдуманной датой. | zero_date_default |
| TIME | INTERVAL DAY TO SECOND, который вмещает длительностиВ Oracle нет типа для времени суток, а TIME в MySQL - это длительность от -838:59:59 до 838:59:59; интервал вмещает любое значение. | |
| YEAR | NUMBER(4) с CHECK диапазонаВ Oracle нет типа для года; проверка допускает те же значения, что и MySQL. | |
| CHAR(n), VARCHAR(n) | VARCHAR2(n CHAR), длина в символахДлина считается в символах, как в MySQL, а MySQL возвращает значения CHAR без пробелов в конце, и VARCHAR2 хранит их так же. | |
| VARCHAR(n) and TEXT longer than 4000 bytes | CLOBVARCHAR2 по умолчанию вмещает 4000 байт, поэтому более длинный текст становится CLOB; столбец, все значения которого помещаются, остается VARCHAR2. | text_as_lob |
| DATETIME | TIMESTAMPDATETIME - это показание часов без часового пояса, как TIMESTAMP. DATE становится DATE в Oracle, который хранит и время суток, оно остается полночью. | |
| TIMESTAMP | TIMESTAMP WITH TIME ZONE в поясе, указанном в дампе, или UTC, если он не указанTIMESTAMP - это момент времени. Дампы указывают пояс, в котором он записан (mysqldump пишет UTC); без этого значения читаются как UTC, и отчет это отмечает. | timestamp_zone_assumed |
| ENUM | VARCHAR2 с CHECK значенийТекст с проверкой хранит те же значения. | |
| ENUM holding '' (MySQL's error value) | NULLMySQL записывает пустую строку, когда недопустимое значение попадает в ENUM в нестрогом режиме SQL. Oracle хранит ее как NULL, что проверка допускает, а отчет учитывает ее вместе с другими пустыми значениями. | |
| ENUM holding values outside its list | без CHECKЗначения, которых нет в списке, не прошли бы проверку, поэтому она не создается. | enum_check_skipped |
| SET | VARCHAR2 в записи MySQL ('a,b')В Oracle нет типа множества; текст тот же, что возвращает MySQL. | |
| JSON | CLOBФункции JSON в Oracle читают JSON из текста во всех версиях, а CLOB вмещает значения любого размера. | |
| NUL bytes in text | сохраняетсяVARCHAR2 и CLOB могут содержать символ NUL, поэтому значение копируется как есть. | |
| text that isn't valid in its character set | неверные байты заменяются символом заменыТекст нужно прочитать как символы, чтобы записать его как VARCHAR2. | invalid_utf8_replaced |
| text decoded twice (ñ) | копируется как естьДамп содержит именно эти символы, поэтому они копируются; отчет на них указывает. | mojibake_suspected |
| AUTO_INCREMENT | GENERATED BY DEFAULT ON NULL AS IDENTITY, перезапуск после скопированных idСкопированные id загружаются как есть, а счетчик продолжается после наибольшего из них или после AUTO_INCREMENT дампа, смотря что больше. | |
| MyISAM AUTO_INCREMENT on the second column of a key | один счетчик на таблицуMyISAM считает отдельно для каждой группы первого столбца ключа; в Oracle один счетчик на таблицу. | myisam_group_autoincrement |
| ON UPDATE CURRENT_TIMESTAMP | триггер BEFORE UPDATEТриггер записывает в столбец текущее время, когда обновление его не задает. | on_update_trigger |
| generated columns | виртуальные столбцыOracle вычисляет генерируемые столбцы только при чтении; столбцы STORED становятся виртуальными с теми же значениями. | stored_as_virtual |
| generated columns with functions Oracle lacks | обычный столбецФормула, которую нельзя записать для Oracle, оставляет обычный столбец и строку в отчете. | generated_not_translated |
| INVISIBLE columns | столбцы INVISIBLEOracle скрывает невидимые столбцы от SELECT *, как MySQL. | |
| CHECK constraints | переводится, внутри CREATE TABLEВстроенные проверки выполняются при загрузке каждой строки. | |
| CHECK constraints with functions Oracle lacks | не создаетсяПроверка, которую нельзя записать для Oracle, опускается и попадает в отчет. | check_skipped |
| CHECK ... NOT ENFORCED | не создаетсяMySQL хранит эти проверки, но не применяет их, поэтому строки могут их нарушать. | check_not_enforced |
| defaults with functions Oracle lacks | без значения по умолчаниюЗначение по умолчанию, которое нельзя записать для Oracle, опускается и попадает в отчет. | default_not_translated |
| keys and indexes on a prefix, c(20) | индекс по SUBSTR столбцаФункциональный индекс по тому же началу столбца различает те же строки и индексирует столбцы CLOB, которые Oracle не индексирует целиком. | prefix_unique |
| FULLTEXT indexes | не создаетсяOracle Text строит полнотекстовый поиск со своим типом индекса и запросами. | fulltext_not_created |
| SPATIAL indexes | не создаетсяГеометрии хранятся как байты WKB, которые пространственный индекс прочитать не может. | spatial_index_not_created |
| functional indexes, and indexes on whole CLOB or BLOB columns | не создаетсяOracle не индексирует большой объект целиком, а у некоторых функций MySQL нет аналога в Oracle. | index_skipped |
| foreign keys | после данных ENABLE NOVALIDATE, затем валидация с предупреждением о строках без родителяДампы загружаются с FOREIGN_KEY_CHECKS=0, а MyISAM ничего не проверяет, поэтому строки без родительской записи встречаются часто. Ключ сразу проверяет новые строки, а валидация идет последней; при строках без родителя он остается без валидации с предупреждением, и загрузка не останавливается. | |
| ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT | удаляетсяВнешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL. | foreign_key_action_unsupported |
| foreign keys to columns without a unique key | не создаетсяOracle требует первичный ключ или ограничение уникальности на столбцах, на которые ссылается внешний ключ; InnoDB - нет. | foreign_key_skipped |
| table and column names | верхний регистр для простых имен, иначе как в источникеOracle хранит имена, записанные без кавычек, в верхнем регистре, поэтому простые имена переводятся в верхний регистр и запросы могут обходиться без кавычек; остальные имена сохраняют регистр и требуют кавычек. | identifier_renamed |
| names over 128 bytes | сокращаетсяИмена в Oracle 12.2 и новее вмещают 128 байт. | name_shortened |
| GEOMETRY, POINT, POLYGON... | BLOB с WKBWKB - стандартный формат, который читает любая пространственная библиотека; SDO_GEOMETRY нужны метаданные Oracle Spatial. | geometry_as_blob |
| INET4, INET6, UUID (MariaDB) | VARCHAR2(39), VARCHAR2(36)В Oracle нет ни одного из этих типов; текст тот же, что возвращает MariaDB. | |
| BINARY, VARBINARY, BLOB | RAW до 2000 байт, иначе BLOBБайты остаются байтами. | |
| PARTITION BY | одна таблицаСтроки те же; при необходимости секционируйте таблицу заново в Oracle. | partitions_dropped |
| WITH SYSTEM VERSIONING (MariaDB) | таблица с текущими строкамиДамп содержит только текущие строки. | system_versioning_dropped |
| MyISAM, MEMORY and other engines | обычная таблицаВ Oracle один движок таблиц. | engine_dropped |
| views, triggers, procedures, functions and events | перечисляются в отчетеИх код написан на языке MySQL, поэтому они перечислены, чтобы вы создали их заново. | not_converted_objects |
| dumps without CREATE TABLE | типы определяются по значениямДамп, созданный с --no-create-info, содержит только строки, поэтому типы берутся из значений. | no_schema |
| geometries in a dump without CREATE TABLE | BLOB с WKBФормат геометрии MySQL распознается по значениям и сохраняется как стандартный WKB. | geometry_inferred |
| _ci collations | точное сравнениеOracle сравнивает текст точно, если не указано иное. | case_insensitive_collation |
| SET NAMES utf8 from utf8mb4 tables | конвертируется с предупреждениемmysqldump из MySQL 5.x по умолчанию пишет 3-байтовую utf8 и заменяет каждый эмодзи вопросительным знаком еще до того, как файл увидит какой-либо конвертер. | dump_lost_four_byte_chars |
| dumps without SET NAMES whose text isn't UTF-8 | читается как Latin-1 (Windows-1252)latin1 в MySQL - это Windows-1252, обычная кодировка таких дампов. | charset_guessed |
| sjis, cp932, gbk, big5 dumps | читается как UTF-8, с предупреждениемЭти кодировки пока не декодируются. | unsupported_charset |
| UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows | вычисляютсяНекоторые программы дампа записывают значения как такие вызовы; они читаются как значения, которые возвращают, а в географическом WKT долгота ставится первой. | |
| other expressions in rows | NULLКонвертер, который не запускает базу данных, не может их вычислить. | expression_value |
| DEFAULT in VALUES | значение столбца по умолчаниюЛитеральное значение по умолчанию копируется в строку. | default_keyword_filled |
| DEFAULT in VALUES without a literal default | NULLКопировать нечего. | default_keyword_null |
| REPLACE and INSERT IGNORE | обычные строкиВ дампе одна строка на ключ, поэтому строки те же. | replace_as_insert |
| types IntoSQL doesn't know | CLOBТип text вмещает любое значение; измените тип после загрузки. | unknown_type |
| values that don't fit their column | NULLПоврежденный или написанный вручную дамп может содержать значения, которые столбец не вмещает; они становятся NULL, чтобы остальное загрузилось. | invalid_value_null |
| unreadable geometries | NULLБайты, которые не являются геометрией, нельзя сохранить как геометрию. | bad_geometry |
| dumps of several databases | одна схема, имя каждой таблицы начинается с имени ее базыСкрипт загружается в схему пользователя, который его запускает, поэтому таблицы из разных баз данных получают в начале имя своей базы. | databases_merged |
| CREATE SEQUENCE (MariaDB) | CREATE SEQUENCE с достигнутым значениемПоследовательности в Oracle работают так же. | |
| VECTOR(n) (MariaDB 11.7+) | CLOB с числами float в виде массива JSONВекторный тип есть только в Oracle 23ai; массив JSON сохраняет каждое число float в любой версии. | type_replaced |
Загрузите скрипт в Oracle
Скрипт создает таблицы, копирует строки, затем добавляет ключи, индексы и внешние ключи, поэтому загрузка идет быстро и останавливается на первой ошибке.
NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @mariadb.oracle.sqlВнешние ключи добавляются ENABLE NOVALIDATE, поэтому новые строки проверяются сразу, а затем выполняется валидация. Если старая строка ссылается на несуществующую строку, скрипт сообщает, какое это ограничение, и оставляет его без валидации, а не прерывается на полпути.
Для большого дампа запускайте SQL*Plus на той же машине, где работает база данных. Скрипт фиксирует каждые 100 строк. Пользователю, который его запускает, нужны CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER и CREATE PROCEDURE, а также квота в его табличном пространстве.
Как создать дамп MariaDB для лучшего результата
Конвертер читает то, что есть в дампе. Эти параметры сохраняют в нем больше ваших данных:
- --default-character-set=utf8mb4 сохраняет эмодзи и другие 4-байтовые символы, которые дамп в utf8mb3 теряет еще до конвертера.
- --hex-blob записывает двоичные столбцы и значения VECTOR в шестнадцатеричном виде, который не портится при копировании между системами.
- --routines --triggers --events добавляют эти объекты в дамп, чтобы отчет мог их перечислить.
Что не конвертируется
Представления, триггеры, хранимые процедуры, функции и события написаны на собственном языке MariaDB. Они перечислены в отчете по имени и никогда не удаляются молча, чтобы вы могли переписать их для Oracle.
Вопросы о MariaDB в Oracle
Нет ответа на ваш вопрос? Напишите нам через страницу контактов, и вам ответит человек. Страница контактов
Мой дамп загружается на сервер?
Нет. Конвертер работает в вашем браузере и читает дамп с диска по частям, поэтому он никогда не покидает ваш компьютер. Приложение для компьютера и командная строка тоже конвертируют на вашем компьютере.
Насколько большим может быть дамп?
Конвертер никогда не держит весь дамп в памяти: он читает файл дважды, по диапазонам, и пишет скрипт по ходу чтения. Дампы в несколько гигабайт конвертируются в браузере, в приложении для компьютера и в командной строке.
Из каких версий MariaDB может быть дамп?
Дампы из mariadb-dump и mysqldump на MariaDB с 10.3 по 12, с одним INSERT на таблицу или одним на строку. Каждый тестовый дамп создан в MariaDB 10.11, 11.4 и 11.8 и сверен с источником ячейка за ячейкой.
Сохраняются ли столбцы UUID, INET6, JSON и VECTOR?
Столбцы UUID и INET становятся VARCHAR2, JSON - CLOB, а VECTOR - массивом JSON из его чисел float. Нулевые даты становятся NULL, как и пустые строки, так их хранит Oracle.
Сохраняются ли значения AUTO_INCREMENT и последовательности?
Да. Каждый столбец AUTO_INCREMENT становится столбцом identity, который продолжается после наибольшего id. Последовательности становятся последовательностями Oracle, а значения по умолчанию, которые берутся из них, продолжают из них браться.
А хранимые процедуры и триггеры?
Они перечислены в отчете по имени и не конвертируются, потому что каждая база данных пишет их на своем языке.
На каких версиях Oracle загружается скрипт?
Oracle 19c и новее. Каждый тестовый дамп загружается на 21c и 23ai и останавливается на первой ошибке, если что-то пойдет не так.