Skip to content

Portabilitas database

Sistem: setiap instance INACT harus jalan di MySQL, PostgreSQL dan SQL Server dari satu code base. Itulah inti INA01, "Refactor INACT For Database Abstraction". Instance-instance memang berbeda: Medco dan Tomori menjalankan SQL Server, sisanya MySQL, dan QA master menjalankan ketiganya. SQL khusus MySQL rusak diam-diam di engine lain.

Cara halaman ini diverifikasi

Lapisan PDO, pemetaan driver dan helper legacy dibaca di master pada 2026-09-06. Fork mana yang masih punya helper legacy yang bekerja diperiksa di hari yang sama.

Lapisan-lapisannya

BagianApa itu
DB_CONNECTION di .envmysql, postgres atau mssql.
Konstanta DB_DRIVER, db_config.phpNama driver PDO: mysql, pgsql atau sqlsrv. Inilah yang menjadi cabang di kode.
InactPDO::connect(), libraries/InactPDO.phpMembangun DSN per driver dan membuka PDO biasa.
$pdo = new PDOLogActivity(), libraries/PDOLogActivity.phpHandle global. Pembungkus yang meneruskan setiap method PDO lewat __call() dan menambah ->log($text): $pdo->log("...")->exec($sql) menulis baris log aktivitas untuk insert, update dan delete. ->save() dan ->writeLog() adalah bagian di baliknya.
phinx, phinx.phpPengelolaan skema. Ia membaca .env yang sama, jadi migrasi ditulis sekali dalam DSL phinx dan berjalan di ketiga engine.

InactPDO::getLimit() dan InactPDO::getAggregatedColumnNames() adalah helper portabilitasnya.

Helper legacy sudah hilang

iw_mysql_query() di libraries/inweb.lib.php dinonaktifkan: baris pertamanya throw new Exception("Error Processing Request", 1). Pemanggilan mysqli_* dan $dbLink ikut mati. Itu berlaku di master, Jadestone, Medco dan Timas. JOTRE masih punya versi yang bekerja, itu sebabnya beberapa layar legacy berjalan di sana dan tidak di tempat lain.

Jadi sebuah fitur bisa terlihat ada dan mati. Sebelum berasumsi apa pun bekerja, periksa bahwa jalur aktifnya memakai $pdo. Halaman modul mencantumkan jalur mati per modul. Layar yang gagal dengan "Error Processing Request" mencapai helper legacy.

Pola yang bekerja di ketiga engine:

LakukanBukanKenapa
$pdo->query($sql), lalu $stmt->fetch(), while ($r = $stmt->fetch()), $stmt->rowCount(); $pdo->exec($sql) untuk penulisan; $pdo->prepare($sql)->execute([...]) untuk nilaiiw_mysql_query(), mysqli_fetch_array()helper legacy melempar exception
$pdo->quote($v)'$v' dengan mysqli_real_escape_string()quote() mengembalikan nilai dengan tanda kutipnya; jangan tambah sendiri
AND&&di PostgreSQL && adalah operator array-overlap: error, bukan warning
$limit = InactPDO::getLimit(1) setelah ORDER BYLIMIT 1SQL Server butuh OFFSET 0 ROWS FETCH NEXT n ROWS ONLY, dan mewajibkan ORDER BY
COALESCE()IFNULL()hanya MySQL
identifier polosbacktickhanya MySQL
ekspresi tanggal yang sadar driverNOW(), DATE_ADD(... INTERVAL ...), date(now())tidak portabel; kode bercabang pada DB_DRIVER untuk ini
kutip nilai yang dibandingkan dengan kolom varchar: rout_indicate IN ('11','15','16')IN (11,15,16)PostgreSQL menolak character varying = integer. INA01-751 memperbaiki tepat ini di aturan tutup sign-off.
GROUP BY eksplisit untuk setiap kolom yang dipilihGROUP BY longgar dengan SET sql_mode = ''trik sql_mode adalah artefak MySQL 5.7
if (DB_DRIVER == 'sqlsrv') { ... TOP n ... } else if (DB_DRIVER == 'pgsql') { ... CAST(...) ... }satu stringpola percabangan kode yang ada; tiru

Batasan engine yang perlu diingat:

EngineVersi produksiBatasan
MySQL5.7.44tanpa CTE (WITH), tanpa window function; sintaks LIMIT a,b hanya MySQL
PostgreSQL14.22pengetikan ketat; &&; pelipatan huruf identifier
SQL Server2019tanpa LIMIT; TOP n atau OFFSET ... FETCH; kolom ntext perlu perhatian; identity insert butuh SET IDENTITY_INSERT ... ON

Identity insert juga berbeda: SET IDENTITY_INSERT di SQL Server, OVERRIDING SYSTEM VALUE di PostgreSQL. Seed yang memasukkan id eksplisit harus menangani keduanya.

Mode fetch

$pdo->query() mengembalikan PDOStatement biasa; fetch() memberikan key numerik dan asosiatif kecuali kamu meneruskan PDO::FETCH_ASSOC. Kode yang dulu memakai mysqli_fetch_array() bergantung pada key ganda yang sama, itu sebabnya sebagian besar port mempertahankan default. Prepared statement di SQL Server kadang butuh PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL supaya rowCount() bermakna; handler Document Library menunjukkan polanya.

Memverifikasi perubahan di tiga engine

Menalar dialek bukan bukti. Database uji master inact-v3-eris ada di ketiga engine di host dev bersama (MySQL di port 3357, PostgreSQL di 54314, SQL Server di 1433). Tulis satu skrip PHP yang:

  1. terhubung ke setiap engine lewat PDO dengan aturan DSN yang sama seperti InactPDO::connect();
  2. mengisi baris yang sama ke inact-v3-eris di masing-masing;
  3. menjalankan query lama dan query baru dan mencetak keduanya;
  4. menghapus baris ujinya.

Itu menangkap perbedaan identity insert dan perbedaan ketatnya tipe sekaligus. Untuk bug yang bergantung pada data nyata, jalankan juga query baru di snapshot SQL Server Medco dan snapshot MySQL Jadestone; database master hampir kosong.

Hal yang perlu diwaspadai

  • quote() menyertakan tanda kutip. WHERE x = '" . $pdo->quote($v) . "' menghasilkan ''value''.
  • rowCount() setelah SELECT andal di MySQL, tidak andal di tempat lain. Hitung di SQL atau fetch lalu hitung.
  • lastInsertId() butuh nama sequence di PostgreSQL untuk beberapa tabel. Periksa cara kode tetangga melakukannya sebelum menyalin pemanggilan gaya MySQL.
  • Tanggal kembali sebagai string, dalam format engine-nya. Format saat keluar, jangan bandingkan mentah.
  • Pembungkus PDOLogActivity menyembunyikan nama method dari analisis statis. $pdo->log()->exec() nyata; IDE-mu mungkin tidak berpikir begitu.