<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Data Bene - Tag: 'Qrcode'</title>
  <subtitle>Relational database, open-source and scalable.</subtitle>
  <link href="https://www.data-bene.io/en/blog/tags/qrcode.xml" rel="self" type="application/atom+xml" />
  <updated>2025-04-01T00:00:00Z</updated>
  <id>https://www.data-bene.io/en/blog/tags/qrcode.xml</id>
    <entry>
      <title>Once Upon a Time in a Confined Database - PostgreSQL, QRCodes, and the Art of Backup Without a Network</title>
      <link href="https://www.data-bene.io/en/blog/backup-without-a-network/" />
      <updated>2025-04-01T00:00:00Z</updated>
      <id>https://www.data-bene.io/en/blog/backup-without-a-network/</id>
     <content type="html"><![CDATA[ <h2 id="📦-the-fort-knox-of-databases"><a class="heading-anchor" href="#📦-the-fort-knox-of-databases">📦 The Fort Knox of Databases</a></h2>
<p>Once upon a time, in a faraway server room encased in heavy glass and reinforced concrete, lived a PostgreSQL database so confined, so secluded, it could only dream of the cloud.</p>
<p>No network.</p>
<p>No USB.</p>
<p>No writable external storage device.</p>
<p>Just a keyboard, a monitor, and the hum of industrial-grade air filters.</p>
<p>This wasn’t your average air-gapped setup. This was a zero-exfiltration zone, with operational security so tight you’d think it was guarding state secrets—or worse, legacy banking software.</p>
<p>And yet, in this digital oubliette, one innocent challenge remained:<br>
<strong>How do you back up a PostgreSQL database without ever extracting a file?</strong></p>
<hr>
<h2 id="🎥-when-screens-are-your-network"><a class="heading-anchor" href="#🎥-when-screens-are-your-network">🎥 When Screens Are Your Network</a></h2>
<p>Our customer didn’t just want backups—they <em>needed</em> them. The fear wasn’t theft, it was <strong>total failure</strong>: a motherboard dying quietly in its glass sarcophagus, taking the data with it. And if it came to that, chiseling through reinforced architecture wasn’t a viable disaster recovery plan.</p>
<p>We brainstormed everything:</p>
<ul class="list">
<li>OCR of scrolling SQL dumps? Too lossy.</li>
<li>Filming the <code>psql</code> output? Way too verbose.</li>
<li>Printing out hex? Please, we’re not monsters.</li>
</ul>
<p>And then came the epiphany: <strong>QR codes</strong>.</p>
<p>What if we could <code>pg_dump</code> the database…</p>
<p>into QR codes…</p>
<p>on the screen…</p>
<p>captured by a high-speed camera…</p>
<p>then reassembled frame by frame outside the vault?</p>
<p>It was so absurd, it just might work.</p>
<hr>
<h2 id="🧠-hacking-pg_dump-now-with-more-pixels"><a class="heading-anchor" href="#🧠-hacking-pg_dump-now-with-more-pixels">🧠 Hacking <code>pg_dump</code>: Now with More Pixels</a></h2>
<p>PostgreSQL’s beloved <code>pg_dump</code> tool is modular. So we extended it with a custom archiver: <code>--format=qrcode</code>.</p>
<p>Here’s how it works:</p>
<ol class="list">
<li>
<p><strong>QR encoding</strong>: Each chunk of SQL output is encoded into a PNG QR code.</p>
</li>
<li>
<p><strong>Streaming</strong>: Instead of saving to disk, we push the stream of PNGs directly to <code>stdout</code>.</p>
</li>
<li>
<p><strong>Framing</strong>: Our UI lays out multiple QR codes on a single screen using high-DPI output. (We’re talking 2000+ pixels here—room for a whole grid of codes.)</p>
</li>
<li>
<p><strong>Playback</strong>: A dedicated machine with a 1280Hz high-speed camera films the screen, capturing the sequence as a video.</p>
</li>
</ol>
<p>No keyboard macros. No sneaky uploads. Just photons and frames.</p>
<hr>
<h2 id="🔍-reassembly-outside-the-glass"><a class="heading-anchor" href="#🔍-reassembly-outside-the-glass">🔍 Reassembly Outside the Glass</a></h2>
<p>Once the video is extracted from the glass box:</p>
<ul class="list">
<li>
<p>Our parser watches the footage, frame by frame.</p>
</li>
<li>
<p>QR codes are detected and decoded in parallel.</p>
</li>
<li>
<p>Each chunk is sequence-tagged for ordering.</p>
</li>
<li>
<p>The resulting text is reassembled into a proper <code>pg_dump.sql</code>.</p>
</li>
</ul>
<p>And just like that: the database lives again—<strong>fully exported with no digital transfer</strong>.<br>
Only light and lenses.</p>
<hr>
<h2 id="🧩-notes-on-performance-and-fidelity"><a class="heading-anchor" href="#🧩-notes-on-performance-and-fidelity">🧩 Notes on Performance &amp; Fidelity</a></h2>
<ul class="list">
<li>
<p><strong>QR Version</strong>: We used Version 40 QR codes (max capacity) with optimized binary mode for high density.</p>
</li>
<li>
<p><strong>Error Correction</strong>: Level Q for resilience under compression/artifacts.</p>
</li>
<li>
<p><strong>Screen Real Estate</strong>: 25×16 grid of codes per frame on a 1920×1080 pixel monitor—350 chunks per screen, around 1,016KB per frame.</p>
</li>
<li>
<p><strong>Playback Rate</strong>: We achieved ~60 screens/sec = 21,000 chunks/sec, nearly 60MB/sec!.</p>
</li>
<li>
<p><strong>Total Export Time</strong>: A full logical backup under 6GB was exported in less than 100 minutes!</p>
</li>
</ul>
<hr>
<h2 id="🛡️-why-this-matters"><a class="heading-anchor" href="#🛡️-why-this-matters">🛡️ Why This Matters</a></h2>
<p>This isn’t just a quirky story—it’s a reminder that <strong>PostgreSQL’s flexibility extends even into the absurd</strong>. Air-gapped systems aren’t rare in defense, finance, or critical infrastructure. And when normal tooling fails, PostgreSQL’s pluggable architecture gives you room to innovate, even in the tightest constraints.</p>
<p>We at <strong>Data Bene</strong> live for this kind of challenge. Whether it’s optimizing query plans or designing data exfiltration methods that look like spycraft, we’re here to help you make PostgreSQL dance—even when it’s stuck in a cage.</p>
<hr>
<p><em>Want to try it yourself? Drop us a line—we love weird backups.</em></p>
<p><em>And if you’re thinking of streaming <code>pg_restore</code> into a laser light show, call us. We’re intrigued.</em></p>
 ]]></content>
			<author>
				<name>Cédric Villemain</name>
			</author>
    </entry>
</feed>
