Codifica Base64 in SQL: una guida completa
Di tanto in tanto il database deve parlare con il mondo esterno, e il mondo esterno non sempre parla byte. Un'API vuole il tuo logo dentro una stringa JSON. Un export di configurazione vuole un segreto che stia su una riga di YAML senza virgolette o backslash. Uno script di manutenzione vuole spedire un file attraverso un sistema che trasporta solo testo. Quel momento è quello in cui i tuoi dati mettono un costume di lettere, e il nome di quel costume è base64.
Il formato in sé è già trattato nella pagina iniziale (64 caratteri stampabili, ogni quattro che stanno al posto di tre byte in input, fino a due segni = che fanno da padding all'ultimo gruppo), quindi questo articolo salta quella lezione e va dritto al lavoro pratico. Due cose da tenere a mente: la codifica è la direzione in cui i dati diventano più grandi, quindi le larghezze di colonna e i limiti di pacchetto sentono ogni byte di questo, e i codificatori di questa famiglia SQL non sono d'accordo sulle due cose più difficili da rimettere a posto in seguito: quali byte leggono quando la tua colonna contiene testo, e dove mettono gli a capo in ciò che scrivono.
La scheda riassuntiva dei codificatori
Chi è in servizio, cosa mangia, e dove spezza il suo output. Le ultime due colonne sono quelle che mordono, perché una stringa piena di a capo non invitati e una stringa con un alfabeto diverso sono entrambe stringhe base64 perfettamente valide che il tuo consumer rifiuterà lo stesso:
| Dialetto | La chiamata | Tipo di input | Avvolge a 76? | Opzione URL-safe | Da quando |
|---|---|---|---|---|---|
| MySQL 8.x / MariaDB 10.x | TO_BASE64(str) |
stringa (si applica il set di caratteri) | sì | nessuna | MySQL 5.6 (2013) |
| PostgreSQL | encode(bytea, 'base64') |
bytea |
sì, solo LF | nessuna | 7.2 (2002) |
| SQLite (CLI 3.41+) | base64(blob) |
BLOB |
sì, a 72 | nessuna | 3.41.0 (2023) |
| DuckDB | to_base64(blob) |
BLOB |
no | nessuna | release moderne |
| ClickHouse 18.16+ | base64Encode(x) |
qualsiasi cosa, cast a String | no | base64URLEncode() |
18.16 (2018) |
| SQL Server 2025+ | BASE64_ENCODE(bin [, url_safe]) |
varbinary |
no | secondo argomento | 2025 |
| Oracle | UTL_ENCODE.BASE64_ENCODE(raw) |
RAW |
no | nessuna | era 9i |
| Snowflake | BASE64_ENCODE(binary) |
BINARY |
no | nessuna | release correnti |
Leggi la tabella da sinistra a destra e il lavoro si riduce a due decisioni. Prima: come arrivano i tuoi byte: la colonna del tipo di input è il luogo dove nascono le sorprese dei set di caratteri, perché "lo stesso testo" sono byte diversi sotto collazioni diverse. Seconda: cosa esce dall'altra parte: la colonna dell'avvolgimento decide se il tuo risultato è una riga piatta o una poesia con un a capo ogni 76 caratteri, e la colonna URL-safe decide se puoi mettere il risultato in un link, e basta.
Prima, decidi quali byte intendi
Il codificatore impacchetta byte, ma la tua colonna di solito contiene lettere, e le lettere sono byte solo se dici quale alfabeto di byte. TO_BASE64() di MySQL legge il suo argomento nel set di caratteri della connessione, ed è una comodità finché non lo è: lo stesso 'héllo' viaggia come base64 diverso sotto un client latin1 e un client utf8mb4. Quando intendi i byte esatti come memorizzati, congiali prima con un cast binario:
SELECT TO_BASE64('hello') AS from_text;
SELECT TO_BASE64(CAST('héllo' AS BINARY)) AS utf8_bytes;
La seconda riga torna come aMOpbGxv, e i due byte hex C3 A9 in mezzo sono il modo in cui UTF-8 scrive é. PostgreSQL è più rigoroso in partenza: encode() rifiuta di guardare qualsiasi cosa che non sia bytea, quindi un valore di testo deve prima nominare la sua codifica, mentre i byte grezzi possono arrivare come letterale hex:
SELECT encode(convert_to('héllo', 'UTF8'), 'base64') AS text_as_utf8;
SELECT encode('\x68656c6c6f'::bytea, 'base64') AS raw_bytes;
Ogni altro dialetto ha la sua porta d'ingresso alla stessa idea, e tutti si riducono a "prendi i byte, poi impacchettali":
| Dialetto | Dal testo ai byte | La chiamata del codificatore |
|---|---|---|
| T-SQL | CAST('héllo' AS VARBINARY(8000)) tramite la collazione della colonna |
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') dà un BLOB |
to_base64(blob) |
| SQLite CLI | un letterale BLOB come X'68656C6C6F' |
base64(blob) |
La regola pratica è la stessa del lato decodifica: decidi il set di caratteri prima di codificare, scrivilo nella query come letterale, e fai passare un payload accentato per l'intero pipeline prima di fidarti della colonna. Un solo héllo rileva ogni collazione sbagliata, e non costa nulla.
Poi, osserva cosa esce fuori
Una volta che i byte sono impacchettati, i codificatori si dividono sugli a capo. Tre di essi avvolgono l'output: MySQL e PostgreSQL a 76 caratteri, l'abitudine email, e la CLI di SQLite a 72; gli altri restituiscono una riga piatta, no importa quanto diventa lunga. La differenza è facile da perdere e costosa da trovare, perché un campo base64 con a capo nascosti è un campo che rompe un parser JSON a metà strada:
SELECT LENGTH(TO_BASE64(REPEAT('x', 300))) AS wrapped,
LENGTH(REPLACE(TO_BASE64(REPEAT('x', 300)), '\n', '')) AS flat;
Trecento byte in input tornano come 400 caratteri base64, e la stessa chiamata misura 405 perché cinque a capo hanno viaggiato in omaggio. L'aritmetica dietro è piccola abbastanza da tenerla in testa: la lunghezza piatta è la lunghezza in input divisa per tre, arrotondata per eccesso, per quattro. Se il tuo codificatore avvolge, aggiungi un a capo tra righe di 76 caratteri, che è la lunghezza piatta divisa per 76 e arrotondata per eccesso, meno uno. Trecento byte: 400 piatto, 405 avvolto. Cento undici byte: 148 piatto, 149 avvolto. Un solo a capo in più di quello che avevi calcolato è il modo in cui una colonna VARCHAR(500) inizia a troncare in silenzio un payload VARCHAR(480).
Due conseguenze da mettere per iscritto. Dimensiona le colonne di testo per la lunghezza piatta più un po' di margine se chi scrive potrebbe avvolgere, oppure vieta l'avvolgimento a chi scrive e dimensiona per il piatto. E ricorda che il limite contro cui lotta il tuo risultato è il limite della stringa, non dei byte: in MySQL il testo avvolto conta contro max_allowed_packet (64 MB di default in MySQL 8), quindi una foto da 50 megabyte codificata in circa 67 megabyte di lettere non entra nel pacchetto di default anche se il file grezzo ci entrerebbe.
Base64 URL-safe: l'alfabeto in viaggio
La sezione 5 di RFC 4648 ha definito un secondo alfabeto per il base64, perché l'originale ha due caratteri con un ruolo nella sintassi URL. Il segno più aggiunge i parametri di query, la barra separa i segmenti di path, e il segno di uguale del padding viene codificato con percent-encoding nel momento in cui incontra una stringa di query. La variante URL-safe scambia + con - e / con _, e la specifica JWT per di più butta via il padding del tutto, così un token può stare in un link, un segmento di path o un nome di file senza un singolo segno di percentuale.
Solo un dialetto di questa famiglia offre l'interruttore in modo nativo. BASE64_ENCODE() di SQL Server 2025 accetta un secondo argomento opzionale, e con esso acceso il risultato usa - e _ e salta il padding:
SELECT BASE64_ENCODE(0xCAFECAFE) AS standard;
SELECT BASE64_ENCODE(0xCAFECAFE, TRUE) AS url_safe;
Gli stessi quattro byte tornano come yv7K/g== e yv7K_g. ClickHouse mantiene le varianti come funzioni separate, e la sua forma URL-safe butta via anche il padding:
SELECT base64URLEncode('https://clickhouse.com') AS url_safe;
che arriva come aHR0cHM6Ly9jbGlja2hvdXNlLmNvbQ, con i due segni di padding della forma standard tagliati via. Dovunque altrove la ricetta è due traduzioni di caratteri e un taglio, e vale la pena scriverla una volta come funzione di database perché ogni pipeline di token ne ha bisogno. In PostgreSQL si legge così:
SELECT rtrim(replace(replace(
encode(convert_to('https://clickhouse.com', 'UTF8'), 'base64'),
'+', '-'),
'/', '_'),
'=') AS url_safe;
Traduci + in -, traduci / in _, taglia il padding in coda, fatto. Un'avvertenza per la tribù di SQL Server: l'output url_safe non è ciò che i propri decodificatori base64 XML e JSON del server si aspettano, quindi una colonna impacchettata in forma URL-safe per il mondo esterno non si sgonfierà dentro il database con le funzioni built-in. Tieni a mente il pubblico prima di scegliere l'alfabeto.
JWT: stampare token dal database
La cosa più interessante che puoi costruire con il codificatore è un JSON Web Token, perché un JWT non è altro che tre pezzi base64 in fila: un header e un payload, entrambi oggetti JSON impacchettati URL-safe senza padding, e una firma calcolata sui primi due. Quando un lavoro in batch deve coniare token (popolare un ambiente di test, rigenerare credenziali API scadute, costruire un feed di auditing), tutta la cerimonia sta in una query PostgreSQL se accetti pgcrypto per l'HMAC (attivalo una volta con 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;
Ogni passo è una delle mosse che questo articolo ha già mostrato: impacchetta il JSON come base64, rimodellalo nell'alfabeto URL-safe senza padding, poi firma i primi due pezzi e rimodella la firma nello stesso modo. Per il JSON qui sopra e il segreto sql-secret-key, il risultato è eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldiBVc2VyIn0.7_3VdmM8vH0L2bRBNqXXQXzZIR1l8T4_S4QxPPNBEFM, un token che qualunque ispettore HS256 accetta. Le avvertenze meritano tanto spazio quanto il trucco: copre solo gli algoritmi HMAC (HS256, HS384, HS512), mette una chiave segreta condivisa dentro un'istruzione di database, ed è fatto per lavoro in batch e auditing, non per un servizio di token di produzione. Il lato verifica, dove dimostri quel token contro il suo segreto, è un lavoro del layer di applicazione o del controllo firma dell'articolo di decodifica.
Immagini e file in una colonna di testo
Il motivo più comune per codificare in SQL è un file che deve viaggiare come testo: un'API che incorpora l'immagine invece di riferirla, un export per un sistema che non trasporta binari, uno script di seed che ricrea un database su un server nuovo. DuckDB rende il viaggio di andata e ritorno quasi banale, perché legge i file in BLOB attraverso una funzione tabella che accetta pattern glob, e il codificatore appiattisce qualsiasi cosa arrivi:
SELECT filename, to_base64(content) AS b64
FROM read_blob('/data/pics/*.png');
Una riga per file, una stringa base64 piatta per riga, nessun avvolgimento da rimuovere, anche se i consueti uno o due segni di padding viaggiano in coda. Scrivi il risultato in una colonna di testo e le immagini sono portabili attraverso qualsiasi canale che sposti testo. Poi fai il discorso sui costi onestamente: una foto da 1 megabyte arriva come circa 1,33 megabyte di lettere, e da quel momento ogni scansione, ogni ordinamento e ogni voce di indice paga quel prezzo. Se controlli lo schema, il design migliore è una colonna BLOB più una codifica al confine dell'API, dove solo i byte che in effetti lasciano l'edificio si vestono a festa.
HTTP, JSON e traffico API
Gli header e i payload sono il luogo dove il base64 fa il suo tranquillo lavoro quotidiano. Un header di autenticazione Basic è il prefisso letterale Basic seguito dal base64 di username:password, e costruirne uno in SQL è una concatenazione più una codifica:
SELECT 'Basic ' || encode(convert_to('alice' || ':' || 's3cret', 'UTF8'), 'base64') AS header;
che costruisce Basic YWxpY2U6czNjcmV0, l'esatto header che un client manderebbe. Usalo per generare i fixture contro cui i tuoi test di integrazione confrontano, o per normalizzare una colonna di header salvati prima di farli auditare. Sul lato JSON, MySQL può impacchettare un campo e incorporarlo dentro un documento in una singola espressione, senza codice di applicazione in mezzo:
SELECT JSON_OBJECT('img', TO_BASE64(CAST('hello file' AS BINARY))) AS doc;
Il risultato è {"img": "aGVsbG8gZmlsZQ=="}, un payload pronto da spedire. La stessa forma funziona per certificati, chiavi pubbliche e qualsiasi altro file che la tua API ha deciso di incorporare, ed è la direzione che conta quando sei tu a produrre il traffico, non a decodificare quello degli altri.
File di configurazione, segreti e variabili d'ambiente
Un'abitudine di export merita il suo paragrafo perché è ovunque: il segreto salvato come base64 in una tabella di configurazione. Kubernetes ha mantenuto viva l'abitudine, dove i valori dei segreti sono base64 a riposo così da stare su una riga di YAML senza virgolette, senza a capo e senza backslash, e ogni sistema di configurazione interno che ha mai incontrato un pipeline Kubernetes l'ha adottata. La direzione di impacchettamento è una codifica per valore, con il cast binario che fa il lavoro del set di caratteri, così che il testo esportato sia esattamente i byte salvati:
SELECT name, TO_BASE64(CAST(value AS BINARY)) AS for_config
FROM app_config
WHERE name LIKE '%_secret%';
Ogni valore fino a 57 byte esce come una stringa piatta, pronta da incollare; qualsiasi cosa più lunga ha bisogno di un REPLACE() per rimuovere le righe di avvolgimento prima di andare in YAML, e il nuovo ambiente la decodifica di nuovo dall'altra parte. Tratta il risultato con la cura che merita: hai appena trasformato una colonna di segreti salvati in una colonna di segreti salvati che qualsiasi umano può leggere in circa dieci secondi, e l'abitudine base64-nelle-configurazioni riceve una seconda occhiata nel momento in cui ti trovi così vicino al testo in chiaro. Il base64 è un trasporto, non una cassaforte. Se l'ambiente ha un vero secret store, la colonna base64 è una migrazione di distanza da quello.
L'email e l'abitudine dei 76 caratteri
L'avvolgimento a 76 caratteri è più vecchio di ogni database di questa pagina. MIME, l'insieme di standard che permette all'email di portare allegati binari (RFC 2045, sezione 6.8, 1996), avvolge l'output base64 a 76 caratteri e termina ogni riga con un carriage return e un line feed, perché la vecchia rete email non poteva essere affidata a righe più lunghe. Tre codificatori qui hanno ereditato l'avvolgimento come default (MySQL, PostgreSQL, la CLI di SQLite), ed è un dono per qualsiasi cosa sia finita in un'email e una trappola per qualsiasi cosa non lo sia. E l'hanno ereditato a metà: PostgreSQL termina le sue righe con un solo a capo, non con il carriage return e a capo che lo standard MIME specifica, quindi l'output che dovrebbe essere incollato in un vero allegato email ha bisogno di un altro passaggio:
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;
Rimuovi gli a capo che PostgreSQL ha già aggiunto, poi riavvolgi a 76 con un CRLF completo dopo ogni riga, e la stringa è MIME-corretta in un'unica espressione. Fai passare trecento byte e i 400 caratteri che hai impacchettato diventano 412: sei righe avvolte, sei coppie CRLF, dodici caratteri di cerimonia di trasporto. La stessa forma di problema compare con i blocchi PEM, che avvolgono a 64 invece di 76, e con le API che non vogliono alcun avvolgimento perché il loro parser JSON non si aspetta un a capo a metà di un campo. La regola per tutti: scopri quale contratto ha firmato il consumer prima di codificare, perché riavvolgere una colonna di base64 salvato è una migrazione, non una query.
Insidie: dove i codificatori ti mentono
Ogni trappola di questa lista è una che mette un dialetto specifico, non una che mette il base64, e ognuna ha almeno un codebase che l'ha trovata in produzione:
- L'avvolgimento non chiesto. MySQL e PostgreSQL avvolgono il loro output a 76 di default, la CLI di SQLite a 72, e nessuno nella tua query l'ha chiesto. Il campo base64 nel tuo JSON ora contiene a capo, e il consumer che accetta il formato nella specifica lo rifiuta in natura. La forma piatta è un
REPLACE()sul carattere di a capo, applicato sul lato del writer così che la colonna conservi ciò che il reader vuole. - Lo slittamento del set di caratteri.
TO_BASE64('héllo')senza il cast binario codifica ciò che il set di caratteri della connessione crede che le lettere siano, e un clientlatin1e un clientutf8mb4credono cose diverse. Lo stesso testo di query, due risultati base64 diversi, e quello sbagliato si decodifica in caratteri corrotti (mojibake) che nessuno riconduce al codificatore. Il cast binario, o unconvert_to()esplicito, è l'unica versione onesta della query. - La porta BLOB.
to_base64()di DuckDB vuole unBLOB: dagli testo e fa il cast implicito, quindi una colonnavarcharcon una codifica non UTF-8 può codificare silenziosamente i byte sbagliati. La strada onesta èto_base64(encode(...)), ed è per questo che gli esempi di questa pagina mostrano sempre la coppia per l'input di testo. - La modifica degli spazi bianchi di 26.7.
base64Decode()ebase64URLDecode()di ClickHouse erano rigidi sull'input per anni, ma da 26.7 ignorano gli spazi bianchi (spazio, tab, line feed, carriage return, form feed) invece di rifiutarli, quindi uno script che prima dava errore su una colonna avvolta ora riesce in silenzio, il che è a sua volta una forma di regressione. Controlla la versione del server prima di fidarti della decodifica. - Il confine dei 6000 byte.
BASE64_ENCODE()di SQL Server restituiscevarchar(8000)quando l'input è unvarbinary(n)con n di 6000 o meno evarchar(max)sopra; la mappatura si aggancia alla dimensione dichiarata, non al valore, quindi una colonnavarbinary(8000)restituiscevarchar(max)anche a tre byte. L'outputurl_safedella stessa funzione, intanto, non è leggibile dai propri decodificatori base64 XML e JSON del server, che si aspettano l'alfabeto standard con padding. Scegli la variante per il pubblico che la leggerà. - Il RAW da 2000 byte. In Oracle, un valore
RAWin un'istruzione SQL pura arriva a un massimo di 2000 byte. Dato che il codificatore prendeRAWe restituisceRAW, una codifica in una singola istruzione può accettare solo circa 1500 byte di input (i suoi 2000 caratteri di output entrerebbero, di più no), e una decodifica in una singola istruzione può accettare solo 2000 caratteri di base64. I payload più grandi si spostano in PL/SQL, dove una variabileRAWcontiene 32767 byte e una singola chiamata porta la maggior parte di essi, e solo i payload il cui output base64 supererebbe quel tetto hanno bisogno del ciclo a blocchi, che risale al limite degli anni '90 che non si è mai mosso. - La tassa sul pacchetto. MySQL conta la stringa codificata contro
max_allowed_packet, non i byte grezzi. Una foto che entra nella tabella con ampio margine può far traboccare il pacchetto una volta diventata 33 percento più grande e avvolta, e il modo di fallire è un valore troncato o unaNULLche sembra corruzione dei dati. Controlla il limite nello stesso respiro della larghezza della colonna. - L'a capo in coda.
base64()della CLI di SQLite termina la sua ultima riga con un a capo, l'abitudine del termine di riga applicata anche alla riga finale. Incolla l'output della shell in un campo JSON e hai spedito una stringa base64 con un a capo dentro, l'avvolgimento non chiesto che indossa un cappello diverso. - L'assunzione sull'alfabeto. Un consumer costruito per l'alfabeto standard incontra il tuo output URL-safe (o viceversa) e vede caratteri che non conosce. La maggior parte dei decodificatori fallisce a gran voce sull'underscore; alcuni falliscono in silenzio saltandolo. Documenta l'alfabeto di ogni colonna base64 nel commento dello schema, perché il prossimo sviluppatore non ricorderà quale pipeline di token ha scritto la riga.
Quando la dimensione conta davvero
Il calcolo della dimensione è la lunghezza piatta più l'avvolgimento che il tuo codificatore aggiunge, e la pagina iniziale fa la derivazione completa del rapporto. Ciò che vale la pena fare qui è passare in rassegna il punto in cui il numero smette di essere una curiosità. Una colonna VARCHAR dimensionata sul numero di byte dell'input tronca in silenzio l'output la prima volta che il payload è abbastanza lungo da avere bisogno di margine in più, perché tre byte in input costano quattro caratteri. Un indice su una colonna di testo base64 paga la tassa due volte: una volta nello storage e di nuovo in ogni confronto, perché le voci dell'indice sono le lettere avvolte, non i byte. max_allowed_packet di MySQL e il tetto di 1 GB per bytea di PostgreSQL sono le due mura che la maggior parte delle persone colpisce per prima, e entrambi vengono controllati contro il testo, che è il lato più grande dello scambio. La risposta di design raramente riguarda la scelta di un codificatore diverso (c'è un solo base64); riguarda la scelta di dove avviene la codifica. Colonna BLOB, colonna hash per le ricerche, codifica al confine: il base64 esiste solo nel traffico, dove deve stare.
Sicurezza: ciò che il base64 non è
Il base64 non è cifratura, e l'abitudine che va detta ad alta voce è quella della tabella di configurazione vista prima: un segreto salvato come base64 è un segreto salvato in un carattere diverso. La trasformazione è una bijezione senza chiave, reversibile da ogni linguaggio di programmazione sulla terra in una chiamata di funzione, e il suo unico effetto reale è tenere il valore su una riga di YAML. Se il modello di minacce include un altro utente di questo database, un altro servizio che legge l'export, o un log che ha catturato la riga, il base64 contribuisce esattamente zero alla difesa. Oscura il valore agli occhi umani per qualche secondo, ed è per questo che sembra una protezione in una code review e per questo che fallisce in un incidente. Cifra ciò che deve essere segreto, cifralo con una chiave che qualcuno può davvero mantenere segreta, e lascia al base64 il lavoro che sa fare: spostare byte attraverso un canale che trasporta solo testo.
Quando ogni dialetto ha imparato ad avvolgere
Le note di rilascio raccontano la stessa storia del lato decodifica, solo con le lettere che vanno nella direzione opposta, e il piano dice qualcosa su ogni motore:
2002. PostgreSQL 7.2 elenca base64 come formato di prima classe di encode() e decode(), contemporaneo all'UTL_ENCODE di Oracle dell'era 9i, e il meccanismo base64 più antico di questa famiglia, di poco. Un database con un tipo binario vero e un argomento formato ci è arrivato presto, perché la risposta era a un valore enum di distanza.
Inizio anni 2000. Il pacchetto UTL_ENCODE di Oracle esce nell'era 9i con BASE64_ENCODE() accanto ai suoi fratelli per gli header MIME, il quoted-printable e l'uuecode. RAW in ingresso, RAW in uscita, e un quarto di secolo dopo il pacchetto non ha cambiato idea.
2013. MySQL 5.6 aggiunge TO_BASE64() e FROM_BASE64() come coppia fatta per sé, e MariaDB 10.0 eredita entrambi. Il contratto della coppia non si è mosso da allora: righe di 76 caratteri in uscita, tolleranza per gli spazi bianchi in ingresso.
2018. ClickHouse 18.16 (dicembre 2018) rilascia base64Encode() e base64Decode() insieme all'alias in stile MySQL, perché il mondo dei database a colonne importava carichi di lavoro i cui schema di log portavano già il base64 dentro.
2023. SQLite 3.41.0 aggiunge base64() alla shell da riga di comando come funzione definita dall'applicazione. La libreria core non riceve nulla, come da sua abitudine; la shell, dove gli umani effettivamente smanettano con i file SQLite, riceve lo strumento.
2025. SQL Server 2025, diventato disponibile in generale a novembre 2025, rilascia finalmente BASE64_ENCODE() e BASE64_DECODE(), trentasei anni dopo il lancio del prodotto e una generazione dopo che i suoi utenti avevano imparato a memoria il workaround XML.
Il pattern è lo stesso con cui l'articolo di decodifica finisce, specchiato: i motori con un tipo binario vero e un argomento formato hanno avuto il base64 il giorno in cui il bisogno è diventato ovvio, e i motori dove tutto è una stringa lo hanno programmato per dopo.
Particolari che vale la pena conoscere
base64()della CLI di SQLite è il camaleonte della famiglia, e nella direzione di codifica mostra il trucco al meglio: dagli unBLOBe restituisce testo avvolto con a capo in coda, dagli testo e restituisce unBLOB. Un nome, due lavori, scelti in base al tipo dell'argomento, e nessun altro codificatore di questa famiglia lo fa.- La famiglia di
base64Decode()di ClickHouse è diventata indulgente in 26.7: gli spazi bianchi nell'input ora vengono ignorati invece che rifiutati, quindi la stessa query su una colonna avvolta fallisce sul server vecchio e restituisce silenziosamente un valore su quello nuovo. Il decodificatore non si è rotto; si è rilassato, il che è in qualche modo più difficile da diagnosticare. - PostgreSQL avvolge a 76 caratteri esattamente come lo standard MIME del 1996, tranne per il fatto che termina le righe con un solo a capo invece del carriage return e a capo dello standard. Oltre venti anni dopo la specifica, un carattere in meno per riga, e la ribellione è invisibile a meno che non fai il diff dei byte.
- Nel client
mysql, i byte che codifichi si stampano bene come testo base64, ma nel momento in cui guardi la colonna grezza conCAST(... AS BINARY), il client passa alla visualizzazione hex (binary-as-hex), e un perfettohelloarriva sullo schermo come0x68656C6C6F. L'impostazione ha convinto migliaia di sviluppatori che il loro codificatore è rotto. - Snowflake mostra i valori
BINARYcome hex in ogni result set, quindi una colonna di inputTO_BINARY()nella tua query di codifica sembra un checksum anche quando tutto ha funzionato. Due dialetti, due visualizzazioni hex, un'identica sensazione di disagio. - Il
RAWa livello SQL di Oracle arriva a un massimo di 2000 byte, quindi un certificato da 3 kilobyte non può essere incollato in un'istruzione SQL come letteraleRAW, in quanto tale. La codifica deve succedere in PL/SQL, dove una variabileRAWcontiene 32767 byte, quindi il certificato da 3 kilobyte è una singola chiamata, e solo i payload il cui output base64 supererebbe 32 kilobyte hanno bisogno del ciclo a blocchi, che risale agli anni '90. - Una riga di base64 MIME fa 76 caratteri, che sono 57 byte grezzi, perché quattro caratteri portano tre. Il numero 76 che compare nei default di tre codificatori non è tanto un limite quanto una densità di impacchettamento: ogni riga avvolta che vedi in un vecchio allegato email portava esattamente 57 byte dei tuoi dati.
L'altra direzione
Questo articolo ha parlato di mettere il costume: decidere quali byte intendi, osservare cosa esce fuori, scegliere l'alfabeto per il pubblico, e fare il calcolo della dimensione prima che la colonna tronchi. Togliere il costume è un temperamento completamente diverso, con NULL silenziose dove un dialetto alza le spalle, errori duri dove un altro alza la voce, e un alfabeto URL-safe che metà della famiglia non conosce affatto. Tutto questo, da FROM_BASE64() a decode() a BASE64_DECODE(), è trattato in profondità nell'articolo correlato sulla decodifica Base64 per SQL, collegato qui sotto. Codifica qui, decodifica là, e l'intero viaggio di andata e ritorno sta dentro un solo pomeriggio.
Ultimo aggiornamento: 2026-09-08
Articolo correlato: Decodifica Base64 in SQL: una guida completa