Base64-Kodierung in SQL: Ein vollständiger Leitfaden
Von Zeit zu Zeit muss die Datenbank mit der Außenwelt reden, und die Außenwelt spricht nicht immer Bytes. Eine API will Ihr Logo in einem JSON-String. Ein Config-Export will ein Geheimnis, das auf eine Zeile von YAML passt, ohne Anführungszeichen und ohne Backslashes. Ein Wartungsskript will eine Datei über ein System schicken, das nur Text trägt. Das ist der Moment, in dem Ihre Daten ein Kostüm aus Buchstaben anziehen, und der Name dieses Kostüms ist base64.
Das Format selbst wird auf der Startseite bereits abgedeckt (64 druckbare Zeichen, alle vier von ihnen stehen für drei Bytes Eingabe, bis zu zwei =-Zeichen Padding in der letzten Gruppe), also überspringt dieser Artikel diese Vorlesung und geht direkt zur Maschinenarbeit. Zwei Dinge, die Sie festhalten sollten: Kodieren ist die Richtung, in der Daten größer werden, also spüren Spaltenbreiten und Paket-Limits jedes einzelne Byte davon, und die Kodierer in dieser SQL-Familie streiten sich über die beiden Dinge, die sich später am schwersten rückgängig machen lassen: Welche Bytes sie lesen, wenn Ihre Spalte Text hält, und wo sie die Zeilenumbrüche in dem, was sie schreiben, hinsetzen.
Die Kodierer-Schummelkarte
Wer im Dienst ist, was sie fressen und wo sie ihre Ausgabe brechen. Die letzten beiden Spalten sind die, die beißen, denn ein String voller ungebetener Zeilenumbrüche und ein String mit einem anderen Alphabet sind beide völlig gültige base64-Strings, die Ihr Konsument trotzdem ablehnen wird:
| Dialekt | Der Aufruf | Eingabe-Typ | Umbruch bei 76? | URL-sichere Option | Seit wann |
|---|---|---|---|---|---|
| MySQL 8.x / MariaDB 10.x | TO_BASE64(str) |
String (Zeichensatz gilt) | ja | keine | MySQL 5.6 (2013) |
| PostgreSQL | encode(bytea, 'base64') |
bytea |
ja, nur LF | keine | 7.2 (2002) |
| SQLite (CLI 3.41+) | base64(blob) |
BLOB |
ja, bei 72 | keine | 3.41.0 (2023) |
| DuckDB | to_base64(blob) |
BLOB |
nein | keine | aktuelle Releases |
| ClickHouse 18.16+ | base64Encode(x) |
alles, cast zu String | nein | base64URLEncode() |
18.16 (2018) |
| SQL Server 2025+ | BASE64_ENCODE(bin [, url_safe]) |
varbinary |
nein | zweites Argument | 2025 |
| Oracle | UTL_ENCODE.BASE64_ENCODE(raw) |
RAW |
nein | keine | 9i-Ära |
| Snowflake | BASE64_ENCODE(binary) |
BINARY |
nein | keine | aktuelle Releases |
Lesen Sie die Tabelle von links nach rechts, und die Arbeit fällt in zwei Entscheidungen. Erstens, wie Ihre Bytes dorthin kommen: Die Eingabe-Typ-Spalte ist der Ort, an dem Zeichensatz-Überraschungen geboren werden, denn "derselbe Text" sind unter verschiedenen Collations andere Bytes. Zweitens, was auf der anderen Seite herauskommt: Die Umbruch-Spalte entscheidet, ob Ihr Ergebnis eine einzige flache Zeile ist oder ein Gedicht mit einem Zeilenumbruch alle 76 Zeichen, und die URL-sichere Spalte entscheidet, ob Sie das Ergebnis überhaupt in einen Link setzen können.
Zuerst: Welche Bytes meinen Sie?
Ein Kodierer packt Bytes, aber Ihre Spalte hält normalerweise Buchstaben, und Buchstaben sind nur dann Bytes, wenn Sie sagen, welches Alphabet von Bytes gemeint ist. MySQLs TO_BASE64() liest sein Argument im Verbindungs-Zeichensatz, was eine Bequemlichkeit ist, bis sie es nicht mehr ist: dasselbe 'héllo' reist als anderes base64, je nachdem, ob ein latin1-Client oder ein utf8mb4-Client es schickt. Wenn Sie die exakten gespeicherten Bytes meinen, frieren Sie sie zuerst mit einem binären Cast ein:
SELECT TO_BASE64('hello') AS from_text;
SELECT TO_BASE64(CAST('héllo' AS BINARY)) AS utf8_bytes;
Die zweite Zeile kommt zurück als aMOpbGxv, die beiden hex-Bytes C3 A9 in der Mitte sind UTF-8s Art, é zu buchstabieren. PostgreSQL ist von Anfang an strenger: encode() weigert sich, auf irgendetwas zu schauen, das kein bytea ist, also muss ein Textwert erst seine Kodierung benennen, während rohe Bytes als hex-Literal ankommen können:
SELECT encode(convert_to('héllo', 'UTF8'), 'base64') AS text_as_utf8;
SELECT encode('\x68656c6c6f'::bytea, 'base64') AS raw_bytes;
Jeder andere Dialekt hat seine eigene Eingangstür zur selben Idee, und sie alle reduzieren sich auf "Hole die Bytes, dann packe sie":
| Dialekt | Text zu Bytes | Der Kodierer-Aufruf |
|---|---|---|
| T-SQL | CAST('héllo' AS VARBINARY(8000)) über die Collation der Spalte |
BASE64_ENCODE(bin) |
| Snowflake | TO_BINARY('héllo', 'UTF-8') |
BASE64_ENCODE(binary) |
| Oracle | UTL_RAW.CAST_TO_RAW('héllo') |
UTL_ENCODE.BASE64_ENCODE(raw) |
| DuckDB | encode('héllo') ergibt einen BLOB |
to_base64(blob) |
| SQLite CLI | ein BLOB-Literal wie X'68656C6C6F' |
base64(blob) |
Die praktische Regel ist dieselbe wie auf der Dekodierungsseite: Entscheiden Sie den Zeichensatz, bevor Sie kodieren, schreiben Sie ihn als Literal in die Abfrage und lassen Sie eine akzentuierte Payload durch die ganze Pipeline laufen, bevor Sie der Spalte vertrauen. Ein einziges héllo fängt jede falsche Collation, und es kostet nichts.
Dann: Schauen Sie, was herauskommt
Sind die Bytes erst gepackt, trennen sich die Kodierer bei den Zeilenumbrüchen. Drei von ihnen brechen die Ausgabe um: MySQL und PostgreSQL bei 76 Zeichen, die E-Mail-Gewohnheit, und die SQLite-CLI bei 72; der Rest gibt eine einzige flache Zeile zurück, egal wie lang sie wird. Der Unterschied ist leicht zu übersehen und teuer zu finden, denn ein base64-Feld mit versteckten Zeilenumbrüchen ist ein Feld, das einen JSON-Parser in der Mitte bricht:
SELECT LENGTH(TO_BASE64(REPEAT('x', 300))) AS wrapped,
LENGTH(REPLACE(TO_BASE64(REPEAT('x', 300)), '\n', '')) AS flat;
Dreihundert Eingabe-Bytes kommen zurück als 400 base64-Zeichen, und derselbe Aufruf misst 405, denn fünf Zeilenumbrüche sind mitgefahren. Die Arithmetik dahinter ist klein genug, um sie im Kopf zu behalten: Die flache Länge ist die Eingabelänge geteilt durch drei, aufgerundet, mal vier. Wenn Ihr Kodierer umbricht, kommen Zeilenumbrüche zwischen 76-Zeichen-Zeilen dazu, das ist die flache Länge geteilt durch 76, aufgerundet, minus eins. Dreihundert Bytes: 400 flach, 405 umgebrochen. Einhundertelf Bytes: 148 flach, 149 umgebrochen. Ein Zeilenumbruch mehr, als Sie eingeplant haben, ist der Weg, auf dem eine VARCHAR(500)-Spalte anfängt, eine VARCHAR(480)-Payload still abzuschneiden.
Zwei Konsequenzen, die sich aufzuschreiben lohnen. Dimensionieren Sie Text-Spalten für die flache Länge plus etwas Puffer, wenn der Schreiber umbrechen könnte, oder verbieten Sie den Umbruch beim Schreiber und dimensionieren Sie für flach. Und denken Sie daran, dass das Limit, gegen das Ihr Ergebnis kämpft, das Limit des Strings ist, nicht der Bytes: In MySQL zählt der umgebrochene Text gegen max_allowed_packet (64 MB Default in MySQL 8), also passt ein 50-Megabyte-Foto, kodiert auf grob 67 Megabyte Buchstaben, nicht in das Standard-Paket, obwohl die rohe Datei hineinpassen würde.
URL-sicheres base64: Das reisende Alphabet
Abschnitt 5 von RFC 4648 definierte ein zweites Alphabet für base64, weil das ursprüngliche zwei Zeichen hat, die in der URL-Syntax Jobs haben. Das Plus-Zeichen fügt Query-Parameter hinzu, der Schrägstrich trennt Pfadsegmente, und das Padding-Gleichheitszeichen wird prozent-kodiert, in dem Moment, in dem es auf einen Query-String trifft. Die URL-sichere Variante tauscht + gegen - und / gegen _ aus, und die JWT-Spezifikation streicht darüber hinaus das Padding komplett, sodass ein Token in einem Link, einem Pfadsegment oder einem Dateinamen sitzen kann, ohne ein einziges Prozentzeichen.
Nur ein Dialekt in dieser Familie liefert den Schalter nativ mit. SQL Servers BASE64_ENCODE() aus 2025 nimmt ein optionales zweites Argument an, und mit ihm an, benutzt das Ergebnis - und _ und überspringt das Padding:
SELECT BASE64_ENCODE(0xCAFECAFE) AS standard;
SELECT BASE64_ENCODE(0xCAFECAFE, TRUE) AS url_safe;
Dieselben vier Bytes kommen zurück als yv7K/g== und yv7K_g. ClickHouse hält die Varianten als separate Funktionen, und seine URL-sichere Form streicht auch das Padding:
SELECT base64URLEncode('https://clickhouse.com') AS url_safe;
das ankommt als aHR0cHM6Ly9jbGlja2hvdXNlLmNvbQ, die beiden Padding-Zeichen der Standard-Form weggeschnitten. Überall ist das Rezept zwei Zeichen-Übersetzungen und ein Trim, und es lohnt sich, es einmal als Datenbank-Funktion zu schreiben, denn jede Token-Pipeline braucht es. In PostgreSQL liest es sich so:
SELECT rtrim(replace(replace(
encode(convert_to('https://clickhouse.com', 'UTF8'), 'base64'),
'+', '-'),
'/', '_'),
'=') AS url_safe;
Übersetzen Sie + zu -, / zu _, schneiden Sie das am Ende sitzende Padding ab, fertig. Eine Warnung für die SQL-Server-Menge: Die url_safe-Ausgabe ist nicht das, was die eigenen XML- und JSON-base64-Dekodierer des Servers erwarten, also wird eine Spalte, die für die Außenwelt in URL-sicherer Form gepackt wurde, in der Datenbank mit den eingebauten Funktionen nicht ausgepackt. Halten Sie das Publikum im Kopf, bevor Sie das Alphabet wählen.
JWTs: Tokens aus der Datenbank prägen
Das interessanteste, was Sie mit dem Kodierer bauen können, ist ein JSON Web Token, denn ein JWT ist nichts als drei base64-Stücke in einer Reihe: ein Header und eine Payload, beide JSON-Objekte, URL-sicher ohne Padding gepackt, und eine Signatur, die über die ersten beiden berechnet wird. Wenn ein Batch-Job Tokens prägen muss (eine Testumgebung befüllen, abgelaufene API-Credentials neu erzeugen, einen Audit-Feed bauen), passt die ganze Zeremonie in eine PostgreSQL-Abfrage, wenn Sie pgcrypto für den HMAC akzeptieren (einmalig aktivieren mit CREATE EXTENSION IF NOT EXISTS pgcrypto;):
WITH head AS (
SELECT encode(convert_to('{"alg":"HS256","typ":"JWT"}', 'UTF8'), 'base64') AS h
),
body AS (
SELECT encode(convert_to('{"sub":"1234567890","name":"Dev User"}', 'UTF8'), 'base64') AS p
),
joined AS (
SELECT rtrim(replace(replace(h, '+', '-'), '/', '_'), '=') AS h64u,
rtrim(replace(replace(p, '+', '-'), '/', '_'), '=') AS p64u
FROM head, body
)
SELECT h64u || '.' || p64u || '.' ||
rtrim(replace(replace(
encode(hmac((h64u || '.' || p64u)::bytea, 'sql-secret-key'::bytea, 'sha256'), 'base64'),
'+', '-'),
'/', '_'),
'=') AS token
FROM joined;
Jeder Schritt ist einer der Züge, die dieser Artikel bereits gezeigt hat: Das JSON als base64 packen, es in das URL-sichere Alphabet ohne Padding umformen, dann die ersten beiden Stücke signieren und die Signatur auf dieselbe Art umformen. Für das JSON oben und das Geheimnis sql-secret-key ist das Ergebnis eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldiBVc2VyIn0.7_3VdmM8vH0L2bRBNqXXQXzZIR1l8T4_S4QxPPNBEFM, ein Token, das jeder HS256-Prüfer akzeptiert. Die Einschränkungen verdienen ebenso viel Sendezeit wie der Trick: Es deckt nur HMAC-Algorithmen ab (HS256, HS384, HS512), legt ein gemeinsames Geheimnis in eine Datenbank-Anweisung und ist gebaut für Batch- und Audit-Arbeit, nicht für einen Produktions-Token-Dienst. Die Verifikationsseite, wo Sie das Token gegen sein Geheimnis beweisen, ist ein Job für die Anwendungsebene oder für den Signatur-Check des Dekodierungs-Artikels.
Bilder und Dateien in einer Text-Spalte
Der häufigste Grund, in SQL zu kodieren, ist eine Datei, die als Text reisen muss: eine API, die das Bild inline einbettet statt es zu referenzieren, ein Export für ein System, das kein Binärformat trägt, ein Seed-Skript, das eine Datenbank auf einem neuen Server neu erzeugt. DuckDB macht die Rundreise beinahe trivial, denn es liest Dateien über eine Tabellenfunktion, die Glob-Muster akzeptiert, in BLOBs, und der Kodierer glättet alles, was ankommt:
SELECT filename, to_base64(content) AS b64
FROM read_blob('/data/pics/*.png');
Eine Zeile pro Datei, ein flacher base64-String pro Zeile, kein Umbruch zum Entfernen, auch wenn die üblichen ein oder zwei Padding-Zeichen am Ende mitfahren. Schreiben Sie das Ergebnis in eine Text-Spalte, und die Bilder sind über jeden Kanal portabel, der Text bewegt. Dann führen Sie das Kosten-Gespräch ehrlich: Ein 1-Megabyte-Foto kommt an als grob 1,33 Megabyte Buchstaben, und ab dann zahlt jeder Scan, jedes Sortieren und jeder Index-Eintrag diesen Preis. Wenn Sie das Schema kontrollieren, ist das bessere Design eine BLOB-Spalte plus ein Kodieren an der API-Grenze, wo nur die Bytes, die tatsächlich das Gebäude verlassen, angekleidet werden.
HTTP, JSON und API-Verkehr
Header und Payloads sind der Ort, an dem base64 seine stille Alltagsarbeit macht. Ein Basic-Auth-Header ist das wörtliche Präfix Basic gefolgt vom base64 von username:password, und einen davon in SQL zu bauen ist eine Konkatenation plus ein encode:
SELECT 'Basic ' || encode(convert_to('alice' || ':' || 's3cret', 'UTF8'), 'base64') AS header;
das Basic YWxpY2U6czNjcmV0 baut, den exakten Header, den ein Client senden würde. Benutzen Sie es, um die Fixtures zu generieren, mit denen Ihre Integrationstests vergleichen, oder um eine Spalte gespeicherter Header zu normalisieren, bevor Sie sie auditieren. Auf der JSON-Seite kann MySQL ein Feld packen und in ein Dokument einbetten in einem einzigen Ausdruck, kein Anwendungscode im Spiel:
SELECT JSON_OBJECT('img', TO_BASE64(CAST('hello file' AS BINARY))) AS doc;
Das Ergebnis ist {"img": "aGVsbG8gZmlsZQ=="}, eine versandbereite Payload. Dasselbe Format funktioniert für Zertifikate, öffentliche Schlüssel und jede andere Datei, die Ihre API inline haben wollte, und es ist die Richtung, die zählt, wenn Sie diejenige sind, die den Verkehr produziert, und nicht die, die den von jemand anderem dekodiert.
Config-Dateien, Geheimnisse und Umgebungsvariablen
Eine Export-Angewohnheit verdient einen eigenen Absatz, weil sie überall ist: Das Geheimnis, gespeichert als base64 in einer Config-Tabelle. Kubernetes hat die Angewohnheit am Leben gehalten, wo Geheimniswerte im Ruhezustand base64 sind, damit sie auf eine Zeile von YAML passen ohne Anführungszeichen, ohne Zeilenumbrüche und ohne Backslashes, und jedes Inhouse-Config-System, das je auf eine Kubernetes-Pipeline traf, hat sie übernommen. Die Pack-Richtung ist ein encode pro Wert, wobei der binäre Cast die Zeichensatz-Arbeit macht, damit der exportierte Text exakt die gespeicherten Bytes sind:
SELECT name, TO_BASE64(CAST(value AS BINARY)) AS for_config
FROM app_config
WHERE name LIKE '%_secret%';
Jeder Wert bis zu 57 Bytes kommt als flacher, einsetzbarer String heraus; alles Längere braucht ein REPLACE(), um die Umbruch-Zeilen zu entfernen, bevor es in YAML geht, und die neue Umgebung dekodiert es auf der anderen Seite zurück. Behandeln Sie das Ergebnis mit der Sorgfalt, die es verdient: Sie haben soeben eine Spalte gespeicherter Geheimnisse in eine Spalte gespeicherter Geheimnisse verwandelt, die jeder Mensch in etwa zehn Sekunden lesen kann, und die base64-in-config-Angewohnheit bekommt einen zweiten Blick, in dem Moment, in dem Sie so dicht am Klartext stehen. Base64 ist ein Transport, kein Tresor. Wenn die Umgebung einen echten Secret-Store hat, ist die base64-Spalte eine Migration von ihr fort.
E-Mail und die 76-Zeichen-Gewohnheit
Der 76-Zeichen-Umbruch ist älter als jede Datenbank auf dieser Seite. MIME, der Satz von Standards, der E-Mails binäre Anhänge tragen lässt (RFC 2045, Abschnitt 6.8, 1996), bricht base64-Ausgaben bei 76 Zeichen um und beendet jede Zeile mit Wagenrücklauf und Zeilenvorschub, weil man dem alten E-Mail-Netzwerk keine längeren Zeilen zumuten konnte. Drei Kodierer hier haben den Umbruch als ihr Default geerbt (MySQL, PostgreSQL, die SQLite-CLI), was ein Geschenk ist für alles, was in eine E-Mail kam, und eine Falle für alles, was nicht. Und sie haben ihn halb fertig geerbt: PostgreSQL beendet seine Zeilen mit einem einzelnen Zeilenumbruch, nicht mit dem Wagenrücklauf und Zeilenumbruch, den der MIME-Standard vorsieht, also braucht Ausgabe, die in einen echten E-Mail-Anhang gepackt werden sollte, einen weiteren Durchlauf:
WITH t AS (
SELECT replace(encode(attachment::bytea, 'base64'), chr(10), '') AS s
FROM email_outbox
)
SELECT regexp_replace(s, '(.{1,76})', '\1' || chr(13) || chr(10), 'g') AS mime_ready
FROM t;
Entfernen Sie die Zeilenumbrüche, die PostgreSQL bereits hinzugefügt hat, und brechen Sie dann bei 76 mit vollem CRLF nach jeder Zeile neu um, und der String ist MIME-korrekt in einem einzigen Ausdruck. Lassen Sie dreihundert Bytes dadurch laufen, und die 400 Zeichen, die Sie gepackt haben, werden zu 412: sechs umgebrochene Zeilen, sechs CRLF-Paare, zwölf Zeichen Transport-Zeremonie. Dasselbe Problem-Format zeigt sich bei PEM-Blöcken, die bei 64 statt 76 umbrechen, und bei den APIs, die gar keinen Umbruch wollen, weil ihr JSON-Parser keinen Zeilenumbruch in der Mitte eines Feldes treffen wird. Die Regel für all diese Fälle: Finden Sie heraus, welchen Vertrag der Konsument unterschrieben hat, bevor Sie kodieren, denn eine Spalte gespeicherten base64 neu umzubrechen ist eine Migration, keine Abfrage.
Fallstricke: Wo Kodierer Sie anlügen
Jede Falle auf dieser Liste ist eine, die ein bestimmter Dialekt stellt, nicht eine, die base64 stellt, und jede von ihnen hat mindestens eine Codebase, die sie in der Produktion gefunden hat:
- Der ungebetene Umbruch. MySQL und PostgreSQL brechen ihre Ausgabe standardmäßig bei 76 um, die SQLite-CLI bei 72, und niemand in Ihrer Abfrage hat danach gefragt. Das base64-Feld in Ihrem JSON enthält jetzt Zeilenumbrüche, und der Konsument, der das Format in der Spezifikation akzeptiert, lehnt es in der Wildnis ab. Die flache Form ist ein
REPLACE()über das Zeilenumbruch-Zeichen, angewendet auf der Schreiberseite, damit die Spalte speichert, was der Leser will. - Der Zeichensatz-Ausrutscher.
TO_BASE64('héllo')ohne den binären Cast kodiert, was der Verbindungs-Zeichensatz für die Buchstaben hält, und einlatin1-Client und einutf8mb4-Client halten Verschiedenes. Derselbe Abfrage-Text, zwei verschiedene base64-Ergebnisse, und das falsche dekodiert zu Mojibake, das niemand auf den Kodierer zurückführt. Der binäre Cast oder ein explizitesconvert_to()ist die einzige ehrliche Version der Abfrage. - Die BLOB-Tür. DuckDBs
to_base64()will einenBLOB: Geben Sie ihm Text, und er castet implizit, also kann einevarchar-Spalte mit einer nicht-UTF-8-Kodierung still die falschen Bytes kodieren. Der ehrliche Weg istto_base64(encode(...)), weshalb die Beispiele auf dieser Seite das Paar für Texteingabe immer zeigen. - Die 26.7-Leerzeichen-Änderung. ClickHouses
base64Decode()undbase64URLDecode()waren jahrelang streng bei der Eingabe, aber ab 26.7 ignorieren sie Leerzeichen (space, tab, line feed, carriage return, form feed) statt sie abzulehnen, also hat ein Skript, das früher bei einer umgebrochenen Spalte einen Fehler lieferte, jetzt stillen Erfolg, was eine Regression seiner eigenen Art ist. Prüfen Sie die Serverversion, bevor Sie dem Dekodieren vertrauen. - Die 6000-Byte-Grenze. SQL Servers
BASE64_ENCODE()gibtvarchar(8000)zurück, wenn die Eingabe einvarbinary(n)mit n von 6000 oder weniger ist, undvarchar(max)darüber; die Zuordnung richtet sich nach der deklarierten Größe, nicht nach dem Wert, also gibt einevarbinary(8000)-Spalte selbst bei drei Bytesvarchar(max)zurück. Dieurl_safe-Ausgabe derselben Funktion ist derweil nicht lesbar für die eigenen XML- und JSON-base64-Dekodierer des Servers, die das Standard-Alphabet mit Padding erwarten. Wählen Sie die Variante für das Publikum, das sie lesen wird. - Das 2000-Byte-RAW. In Oracle ist ein
RAW-Wert in einer reinen SQL-Anweisung auf 2000 Bytes gedeckelt. Da der KodiererRAWannimmt undRAWzurückgibt, kann ein Ein-Anweisung-Kodieren nur etwa 1500 Bytes Eingabe annehmen (seine 2000 Zeichen Ausgabe würden passen, mehr nicht), und ein Ein-Anweisung-Dekodieren kann nur 2000 Zeichen base64 annehmen. Größere Payloads wandern nach PL/SQL, wo eineRAW-Variable 32767 Bytes hält und ein einzelner Aufruf die meisten davon mitnimmt, und nur Payloads, deren base64-Ausgabe diese Obergrenze überschreiten würde, brauchen die Chunk-Schleife, die aus dem Limit der 1990er stammt, das nie umgezogen ist. - Die Paket-Steuer. MySQL rechnet den kodierten String gegen
max_allowed_packetan, nicht die rohen Bytes. Ein Foto, das in die Tabelle haushoch passt, kann das Paket überlaufen, sobald es 33 Prozent größer und umgebrochen ist, und der Fehlermodus ist ein abgeschnittener Wert oder einNULL, das wie Datenkorruption aussieht. Prüfen Sie das Limit in dem gleichen Atemzug wie die Spaltenbreite. - Der angehängte Zeilenumbruch. Die
base64()-Funktion der SQLite-CLI beendet ihre letzte Zeile mit einem Zeilenumbruch, die Zeilenende-Gewohnheit, angewendet auch auf die finale Zeile. Fügen Sie die Shell-Ausgabe in ein JSON-Feld ein, und Sie haben einen base64-String mit einem Zeilenumbruch darin verschickt, der ungebetene Umbruch in einem anderen Hut. - Die Alphabet-Annahme. Ein Konsument, gebaut für das Standard-Alphabet, trifft auf Ihre URL-sichere Ausgabe (oder umgekehrt) und sieht Zeichen, die er nicht kennt. Die meisten Dekodierer scheitern laut auf dem Unterstrich; ein paar scheitern still, indem sie ihn überspringen. Dokumentieren Sie das Alphabet jeder base64-Spalte im Schema-Kommentar, denn der nächste Entwickler wird nicht mehr wissen, welche Token-Pipeline die Zeile geschrieben hat.
Wenn Größe wirklich zählt
Die Größenrechnung ist die flache Länge plus alles an Umbruch, was Ihr Kodierer dazu gibt, und die Startseite macht die vollständige Herleitung des Verhältnisses. Was hier lohnenswert ist, ist der Gang durch die Orte, an denen die Zahl aufhört, eine Kuriosität zu sein. Eine VARCHAR-Spalte, dimensioniert auf die Byte-Anzahl der Eingabe, schneidet die Ausgabe das erste Mal still ab, wenn die Payload lang genug ist, um zusätzlichen Puffer zu brauchen, denn drei Bytes Eingabe kosten vier Zeichen. Ein Index über einer base64-Text-Spalte zahlt die Steuer doppelt: einmal in der Speicherung und nochmal in jedem Vergleich, denn die Index-Einträge sind die umgebrochenen Buchstaben, nicht die Bytes. MySQLs max_allowed_packet und PostgreSQLs 1-GB-bytea-Obergrenze sind die zwei Wände, die die meisten zuerst treffen, und beide werden gegen den Text geprüft, der die größere Seite des Tauschs ist. Die Design-Antwort dreht sich selten darum, einen anderen Kodierer zu wählen (es gibt nur ein base64); sie dreht sich darum, zu wählen, wo die Kodierung passiert. BLOB-Spalte, Hash-Spalte für Lookups, Kodieren an der Grenze: Das base64 existiert nur im Verkehr, wo es hingehört.
Sicherheit: Was base64 nicht ist
Base64 ist keine Verschlüsselung, und die eine Angewohnheit, die laut ausgesprochen werden muss, ist die Config-Tabelle von eben: Ein Geheimnis, gespeichert als base64, ist ein Geheimnis, gespeichert in einer anderen Schriftart. Die Transformation ist eine Bijektion ohne Schlüssel, rückwandelbar von jeder Programmiersprache der Welt in einem Funktionsaufruf, und ihr einziger echter Effekt ist, den Wert auf einer Zeile von YAML zu halten. Wenn das Bedrohungsmodell einen anderen Benutzer dieser Datenbank enthält, einen anderen Dienst, der den Export liest, oder ein Log, das die Zeile erfasst hat, bringt base64 genau null zur Verteidigung bei. Es verschleiert den Wert vor dem menschlichen Auge für ein paar Sekunden, weshalb es in einer Code-Review wie Schutz wirkt und weshalb es in einem Vorfall scheitert. Verschlüsseln Sie, was geheim sein muss, verschlüsseln Sie es mit einem Schlüssel, den jemand tatsächlich geheim halten kann, und lassen Sie base64 den Job machen, den es gut kann: Bytes durch einen Kanal zu bewegen, der nur Text trägt.
Wann jeder Dialekt das Umbrechen lernte
Die Release-Notes erzählen dieselbe Geschichte wie die Dekodierungsseite, nur mit den Buchstaben in die andere Richtung, und der Zeitplan sagt etwas über jede Engine:
2002. PostgreSQL 7.2 listet base64 als gleichberechtigtes Format von encode() und decode() - zeitgleich mit Oracles UTL_ENCODE in der 9i-Ära, und die älteste base64-Maschinerie dieser Familie mit knapper Marge. Eine Datenbank mit einem echten Binär-Typ und einem Format-Argument kam früh an, weil die Antwort einen enum-Wert entfernt war.
Anfang 2000er. Oracles UTL_ENCODE-Paket erscheint in der 9i-Ära mit BASE64_ENCODE() neben seinen MIME-Header-, quoted-printable- und uuecode-Geschwistern. RAW hinein, RAW hinaus, und ein Vierteljahrhundert später hat das Paket seine Meinung nicht geändert.
2013. MySQL 5.6 fügt TO_BASE64() und FROM_BASE64() als abgestimmtes Paar hinzu, und MariaDB 10.0 erbt beide. Der Vertrag des Paares hat sich seitdem nicht bewegt: 76-Zeichen-Zeilen auf dem Weg hinaus, Whitespace-Toleranz auf dem Weg hinein.
2018. ClickHouse 18.16 (Dezember 2018) liefert base64Encode() und base64Decode() zusammen mit dem MySQL-artigen Alias, weil die spaltenorientierte Welt Workloads importierte, deren Log-Schemas bereits base64 in sich trugen.
2023. SQLite 3.41.0 fügt base64() der Kommandozeilen-Shell als anwendung-definierte Funktion hinzu. Die Kernbibliothek bekommt nichts, wie es ihre Art ist; die Shell, wo Menschen tatsächlich an SQLite-Dateien herumstochern, bekommt das Werkzeug.
2025. SQL Server 2025, der im November 2025 allgemein verfügbar wurde, liefert endlich BASE64_ENCODE() und BASE64_DECODE(), 36 Jahre nach dem Produktstart und eine Generation nachdem seine Nutzer den XML-Workaround auswendig gelernt hatten.
Das Muster ist dasselbe, mit dem der Dekodierungs-Artikel endet, gespiegelt: Die Engines mit einem echten Binär-Typ und einem Format-Argument bekamen base64 an dem Tag, an dem der Bedarf offensichtlich war, und die Engines, wo alles ein String ist, haben es auf später verschoben.
Merkwürdigkeiten, die sich zu kennen lohnen
- Die
base64()-Funktion der SQLite-CLI ist der Verwandlungskünstler der Familie, und in der Kodier-Richtung zeigt er den Trick am besten: Geben Sie ihm einenBLOB, und er gibt umgebrochenen Text mit angehängtem Zeilenumbruch zurück, geben Sie ihm Text, und er gibt einenBLOBzurück. Ein Name, zwei Jobs, gewählt nach dem Typ des Arguments, und kein anderer Kodierer in dieser Familie macht das. - ClickHouses
base64Decode()-Familie wurde in 26.7 nachsichtig: Leerzeichen in der Eingabe werden jetzt ignoriert statt abgelehnt, also scheitert dieselbe Abfrage auf einer umgebrochenen Spalte auf dem alten Server und gibt auf dem neuen still einen Wert zurück. Der Dekodierer ist nicht kaputtgegangen; er ist entspannter geworden, was aus irgendeinem Grund schwerer zu debuggen ist. - PostgreSQL bricht bei 76 Zeichen um, genau wie der MIME-Standard von 1996, nur beendet es die Zeilen mit einem einzelnen Zeilenumbruch statt mit dem Wagenrücklauf und Zeilenumbruch des Standards. Über zwanzig Jahre nach der Spezifikation, ein Zeichen weniger pro Zeile, und die Rebellion ist unsichtbar, es sei denn, Sie diffen die Bytes.
- Im
mysql-Client geben die Bytes, die Sie kodieren, als base64-Text ganz normal aus, aber in dem Moment, in dem Sie mitCAST(... AS BINARY)auf die rohe Spalte schauen, wechselt der Client in die hex-Ansicht (binary-as-hex), und ein einwandfreieshellokommt auf dem Bildschirm an als0x68656C6C6F. Die Einstellung hat Tausende von Entwicklern davon überzeugt, ihr Kodierer sei kaputt. - Snowflake zeigt
BINARY-Werte als hex in jedem Ergebnis-Satz an, also liest sich eineTO_BINARY()-Eingabespalte in Ihrer Kodier-Abfrage wie eine Prüfsumme, selbst wenn alles funktioniert hat. Zwei Dialekte, zwei hex-Anzeigen, ein identisches Gefühl der Unruhe. - Oracles SQL-Ebenen-
RAWist auf 2000 Bytes gedeckelt, also kann ein 3-Kilobyte-Zertifikat überhaupt nicht alsRAW-Literal in eine SQL-Anweisung kopiert werden. Das Kodieren muss in PL/SQL passieren, wo eineRAW-Variable 32767 Bytes hält, also ist das 3-Kilobyte-Zertifikat ein einzelner Aufruf, und nur Payloads, deren base64-Ausgabe 32 Kilobytes überschreiten würde, brauchen die Chunk-Schleife, die aus den 1990ern stammt. - Eine Zeile MIME-base64 ist 76 Zeichen, das sind 57 rohe Bytes, denn vier Zeichen tragen drei. Die Zahl 76, die in den Defaults von drei Kodierern auftaucht, ist weniger ein Limit als eine Packungsdichte: Jede umgebrochene Zeile, die Sie in einem alten E-Mail-Anhang sehen, trug exakt 57 Bytes Ihrer Daten.
Die andere Richtung
Dieser Artikel hat sich darum gedreht, das Kostüm anzuziehen: zu entscheiden, welche Bytes Sie meinen, zu schauen, was herauskommt, das Alphabet für das Publikum zu wählen und die Größenrechnung zu machen, bevor die Spalte abschneidet. Das Kostüm auszuziehen ist ein völlig anderes Temperament, mit stillen NULLs, wo ein Dialekt die Achseln zuckt, harten Fehlern, wo ein anderer die Stimme erhebt, und einem URL-sicheren Alphabet, das die Hälfte der Familie überhaupt nicht kennt. All das, von FROM_BASE64() über decode() bis BASE64_DECODE(), wird in dem verwandten Base64-Dekodierungs-Artikel für SQL in der Tiefe abgedeckt, der direkt unten verlinkt ist. Kodieren Sie hier, dekodieren Sie dort, und die ganze Rundreise passt in einen Nachmittag.
Zuletzt aktualisiert: 2026-09-08
Verwandter Artikel: Base64-Dekodierung in SQL: Ein vollständiger Leitfaden