SQL में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड
कभी-कभी डेटाबेस को बाहर की दुनिया से बात करनी पड़ती है, और बाहर की दुनिया हमेशा बाइट्स की भाषा नहीं बोलती। एक API आपके लोगो को JSON स्ट्रिंग के अंदर चाहता है। एक कॉन्फ़िग एक्सपोर्ट चाहता है एक सीक्रेट, जो YAML की एक ही लाइन में बिना कोट्स और बिना बैकस्लैश के बैठ जाए। एक मेंटेनेंस स्क्रिप्ट चाहता है कि फ़ाइल को उस सिस्टम के पार भेजा जाए जो सिर्फ़ टेक्स्ट धारण करता है। वही पल है जब आपका डेटा अक्षरों का कपड़ा पहनता है, और उस कपड़े का नाम base64 है।
फ़ॉर्मेट खुद होम पेज पर पहले से समझा दिया जा चुका है (64 प्रिंट होने योग्य अक्षर, हर चार अक्षरों का समूह तीन इनपुट बाइट्स का प्रतिनिधित्व करता है, और आख़िरी समूह की पैडिंग के लिए ज़्यादा से ज़्यादा दो = निशान), इसलिए यह लेख वह व्याख्यान छोड़कर सीधे मशीनरी काम पर आता है। दो बातें साथ रखिए: एन्कोडिंग वह दिशा है जिसमें डेटा बड़ा होता जाता है, इसलिए कॉलम चौड़ाई और पैकेट लीमिट्स उसका हर एक बाइट महसूस करती हैं, और इस SQL तालीम के एन्कोडर दो ऐसी चीज़ों पर आपस में मतभेद रखते हैं जो बाद में वापस उलटाना सबसे मुश्किल होता है: जब आपका कॉलम टेक्स्ट धारण करता है तो वे कौन-से बाइट्स पढ़ते हैं, और जो वे लिखते हैं उसमें लाइन ब्रेक कहाँ लगाते हैं।
एन्कोडर चीट शीट
कौन ड्यूटी पर है, वह क्या खाता है, और वह अपना आउटपुट कहाँ तोड़ता है। आख़िरी दो कॉलम वही हैं जो काटते हैं, क्योंकि बिना-मंगे लाइन ब्रेक्स वाली स्ट्रिंग और दूसरी वर्णमाला वाली स्ट्रिंग दोनों बिल्कुल वैध base64 स्ट्रिंग्स हैं, फिर भी आपका कन्ज़्यूमर उन्हें मंज़ूर नहीं करेगा:
| डायलैक्ट | कॉल | इनपुट टाइप | 76 पर रैप करता है? | URL-safe विकल्प | कब से |
|---|---|---|---|---|---|
| MySQL 8.x / MariaDB 10.x | TO_BASE64(str) |
स्ट्रिंग (कैरेक्टर सेट लागू होता है) | हाँ | कोई नहीं | MySQL 5.6 (2013) |
| PostgreSQL | encode(bytea, 'base64') |
bytea |
हाँ, सिर्फ़ LF | कोई नहीं | 7.2 (2002) |
| SQLite (CLI 3.41+) | base64(blob) |
BLOB |
हाँ, 72 पर | कोई नहीं | 3.41.0 (2023) |
| DuckDB | to_base64(blob) |
BLOB |
नहीं | कोई नहीं | मॉडर्न रिलीज़ |
| ClickHouse 18.16+ | base64Encode(x) |
कोई भी, String में cast | नहीं | base64URLEncode() |
18.16 (2018) |
| SQL Server 2025+ | BASE64_ENCODE(bin [, url_safe]) |
varbinary |
नहीं | दूसरा आर्ग्यूमेंट | 2025 |
| Oracle | UTL_ENCODE.BASE64_ENCODE(raw) |
RAW |
नहीं | कोई नहीं | 9i दौर |
| Snowflake | BASE64_ENCODE(binary) |
BINARY |
नहीं | कोई नहीं | मौजूदा रिलीज़ |
टेबल को बाएँ से दाएँ पढ़िए और काम दो फ़ैसलों में गिर जाता है। पहला, आपके बाइट्स वहाँ कैसे पहुँचते हैं: इनपुट टाइप कॉलम वही जगह है जहाँ कैरेक्टर-सेट की चौंकाहटें पैदा होती हैं, क्योंकि "वही टेक्स्ट" अलग-अलग कॉलेशन में अलग-अलग बाइट्स है। दूसरा, दूसरी तरफ़ क्या निकलता है: रैप कॉलम फ़ैसला करती है कि आपका रिज़ल्ट एक सपाट लाइन है या हर 76 अक्षरों पर लाइन ब्रेक वाली कविता, और URL-safe कॉलम फ़ैसला करती है कि आप उस रिज़ल्ट को लिंक में डाल ही सकते हैं या नहीं।
पहले, तय कीजिए कि आप कौन-से बाइट्स की बात कर रहे हैं
एन्कोडर बाइट्स को पैक करता है, पर आपका कॉलम आमतौर पर अक्षरों को धारण करता है, और अक्षर तभी बाइट्स बनते हैं जब आप बोलें कि कौन-सी बाइट्स वर्णमाला की। MySQL का TO_BASE64() अपना आर्ग्यूमेंट कनेक्शन कैरेक्टर सेट में पढ़ता है, जो एक सुविधा है - जब तक वह सुविधा न बन जाए: वही 'héllo' latin1 क्लाइंट और utf8mb4 क्लाइंट के तहत अलग-अलग base64 के रूप में निकलता है। जब आप उन सटीक बाइट्स की बात कर रहे हैं जैसे वे स्टोर हैं, तो पहले उन्हें बाइनरी cast से फ़्रीज़ कीजिए:
SELECT TO_BASE64('hello') AS from_text;
SELECT TO_BASE64(CAST('héllo' AS BINARY)) AS utf8_bytes;
दूसरी रो वापस aMOpbGxv के रूप में आती है, बीच के दो हेक्स बाइट्स C3 A9 UTF-8 का é लिखने का तरीका हैं। PostgreSQL आगे से ही सख़्त है: encode() bytea न हो तो उसकी तरफ़ देखना ही नहीं चाहता, इसलिए टेक्स्ट वैल्यू को पहले अपनी एन्कोडिंग का नाम लेना पड़ता है, जबकि कच्चे बाइट्स हेक्स लीटरल के रूप में आ सकते हैं:
SELECT encode(convert_to('héllo', 'UTF8'), 'base64') AS text_as_utf8;
SELECT encode('\x68656c6c6f'::bytea, 'base64') AS raw_bytes;
बाकी हर डायलैक्ट के पास उसी विचार का अपना-अपना आगे का दरवाज़ा है, और सब मिलकर एक ही बात पर आकर ख़त्म होते हैं: बाइट्स लीजिए, फिर उन्हें पैक कीजिए:
| डायलैक्ट | टेक्स्ट से बाइट्स | एन्कोडर कॉल |
|---|---|---|
| T-SQL | CAST('héllo' AS VARBINARY(8000)) कॉलम कॉलेशन के ज़रिए |
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') से BLOB मिलता है |
to_base64(blob) |
| SQLite CLI | BLOB लीटरल, जैसे X'68656C6C6F' |
base64(blob) |
अमली नियम डिकोडिंग तरफ़ वाला वही है: एन्कोड करने से पहले कैरेक्टर सेट तय कीजिए, उसे लीटरल के रूप में क्वेरी में लिखिए, और कॉलम पर भरोसा करने से पहले एक एक्सेंटेड पेलोड को पूरे पाइपलाइन से गुज़ारिए। एक héllo हर ग़लत कॉलेशन को पकड़ लेता है, और इसकी कोई कीमत नहीं है।
फिर, देखिए कि बाहर क्या निकलता है
जैसे ही बाइट्स पैक हो जाते हैं, एन्कोडर लाइन ब्रेक पर आपस में बिछड़ जाते हैं। तीन रैप करते हैं: MySQL और PostgreSQL 76 अक्षरों पर - ईमेल की आदत - और SQLite CLI 72 पर; बाकी सब एक सपाट लाइन वापस देते हैं, चाहे वह कितनी भी लंबी हो जाए। यह अंतर छुपाना आसान है और खोजना महँगा, क्योंकि छिपी लाइन ब्रेक्स वाली base64 फ़ील्ड वही फ़ील्ड है जो JSON पार्सर को आधे रास्ते तोड़ देती है:
SELECT LENGTH(TO_BASE64(REPEAT('x', 300))) AS wrapped,
LENGTH(REPLACE(TO_BASE64(REPEAT('x', 300)), '\n', '')) AS flat;
तीन सौ इनपुट बाइट्स वापस 400 base64 अक्षरों के रूप में आते हैं, और वही कॉल 405 नापती है क्योंकि पाँच लाइन ब्रेक्स सफ़र में साथ चढ़ गए थे। इसके पीछे की गणना इतनी छोटी है कि उसे सिर में रखा जा सकता है: सपाट लंबाई = इनपुट लंबाई को तीन से भाग दो, ऊपर गोल करो, चार से गुणा करो। अगर आपका एन्कोडर रैप करता है, तो 76-अक्षर वाली लाइनों के बीच एक लाइन ब्रेक जोड़ो, जो सपाट लंबाई को 76 से भाग देने पर ऊपर गोल करके एक घटाना है। तीन सौ बाइट्स: 400 सपाट, 405 रैप्ड। एक सौ ग्यारह बाइट्स: 148 सपाट, 149 रैप्ड। बजट से एक न्यूलाइन ज़्यादा - वही बात है जो VARCHAR(500) कॉलम को VARCHAR(480) पेलोड को चुपचाप ट्रंकेट करने लग जाती है।
दो परिणाम जो लिखकर रखने लायक़ हैं। अगर राइटर रैप कर सकता है, तो टेक्स्ट कॉलम की साइज़ सपाट लंबाई और थोड़े लचीलापन के साथ कीजिए, या राइटर में रैप ही मना कर दो और सपाट के हिसाब से साइज़ कीजिए। और याद रखिए कि जो लीमिट आपके रिज़ल्ट से लड़ती है, वह स्ट्रिंग की लीमिट है, बाइट्स की नहीं: MySQL में रैप्ड टेक्स्ट max_allowed_packet (MySQL 8 में डिफ़ॉल्ट 64 MB) के ख़िलाफ़ गिना जाता है, इसलिए 50-मेगाबाइट की फ़ोटो जो अक्षरों में लगभग 67-मेगाबाइट बन जाए, डिफ़ॉल्ट पैकेट में बैठती ही नहीं - भले ही कच्ची फ़ाइल बैठ जाती।
URL-safe Base64: वह वर्णमाला जो सफ़र करती है
RFC 4648 की सेक्शन 5 ने base64 के लिए दूसरी वर्णमाला परिभाषित की, क्योंकि मूल वर्णमाला में दो ऐसे अक्षर हैं जिनके URL सिंटैक्स में अपने काम हैं। प्लस निशान क्वेरी पैरामीटर्स जोड़ने का काम करता है, स्लैश पैथ सेगमेंट्स अलग करने का, और पैडिंग का बराबर निशान क्वेरी स्ट्रिंग से मिलते ही पर्सेंट-एन्कोडेड हो जाता है। URL-safe वैरिएंट + की जगह - और / की जगह _ रखता है, और JWT स्पेसिफिकेशन उस पर पैडिंग बिल्कुल ही हटाने देता है, ताकि टोकन एक पर्सेंट निशान के बिना लिंक, पैथ सेगमेंट या फ़ाइल-नेम में बैठ सके।
इस तालीम में सिर्फ़ एक ही डायलैक्ट यह स्विच नेटिव रूप में साथ लाता है। SQL Server 2025 का BASE64_ENCODE() एक वैकल्पिक दूसरा आर्ग्यूमेंट लेता है, और उसे चालू करने पर रिज़ल्ट - और _ इस्तेमाल करता है और पैडिंग छोड़ देता है:
SELECT BASE64_ENCODE(0xCAFECAFE) AS standard;
SELECT BASE64_ENCODE(0xCAFECAFE, TRUE) AS url_safe;
वही चार बाइट्स yv7K/g== और yv7K_g के रूप में वापस आते हैं। ClickHouse वैरिएंट्स को अलग-अलग फ़ंक्शनों के रूप में रखता है, और उसकी URL-safe शक्ल भी पैडिंग हटा देती है:
SELECT base64URLEncode('https://clickhouse.com') AS url_safe;
जो aHR0cHM6Ly9jbGlja2hvdXNlLmNvbQ के रूप में आता है, स्टैंडर्ड शक्ल के दो पैडिंग निशान कटकर। बाकी हर जगह रेसिपी दो अक्षर-अनुवाद और एक त्रिम है, और इसे एक बार डेटाबेस फ़ंक्शन के रूप में लिखने की औकात है क्योंकि हर टोकन पाइपलाइन को यह चाहिए। PostgreSQL में यह ऐसे पढ़ा जाता है:
SELECT rtrim(replace(replace(
encode(convert_to('https://clickhouse.com', 'UTF8'), 'base64'),
'+', '-'),
'/', '_'),
'=') AS url_safe;
+ को - में बदलो, / को _ में बदलो, आख़िरी पैडिंग त्रिम करो, ख़त्म। SQL Server वालों के लिए एक चेतावनी: url_safe आउटपुट वह नहीं है जो सर्वर के अपने XML और JSON base64 डिकोडर की उम्मीद है, इसलिए बाहर की दुनिया के लिए URL-safe शक्ल में पैक की गई कॉलम बिल्ट-इन से डेटाबेस के अंदर अनपैक नहीं होगी। वर्णमाला चुनने से पहले अपना पाठक ध्यान में रखिए।
JWTs: डेटाबेस से टोकन स्टांप करना
एन्कोडर से बनाने की सबसे दिलचस्प चीज़ JSON Web Token है, क्योंकि JWT बस तीन base64 टुकड़ों की क़तार है: एक हेडर और एक पेलोड - दोनों URL-safe, बिना पैडिंग के पैक किए गए JSON ऑब्जेक्ट - और एक सिग्नेचर जो पहले दोनों पर गढ़ा गया हो। जब बैच जॉब को टोकन छापने हों (टेस्ट एनवायरनमेंट सीड करना, ख़त्म हुए API क्रेडेंशियल्स रीजनरेट करना, ऑडिट फ़ीड बनाना), तो pgcrypto को HMAC के लिए मंज़ूर करने पर पूरा समारोह एक ही PostgreSQL क्वेरी में बस जाता है (एक बार इसे 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;
हर स्टेप वह चाल है जो यह लेख पहले ही दिखा चुका है: JSON को base64 में पैक करो, उसे URL-safe बिना-पैडिंग वर्णमाला में दोबारा गढ़ो, फिर पहले दोनों टुकड़ों पर सिग्नेचर बनाओ और सिग्नेचर को भी वही शक्ल दो। ऊपर वाले JSON और सीक्रेट sql-secret-key के लिए रिज़ल्ट eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldiBVc2VyIn0.7_3VdmM8vH0L2bRBNqXXQXzZIR1l8T4_S4QxPPNBEFM है - एक ऐसा टोकन जो कोई भी HS256 इंस्पेक्टर मंज़ूर कर लेगा। चौकसें भी उस ट릭 जितनी ही जगह माँगती हैं: यह सिर्फ़ HMAC एल्गोरिदम्स (HS256, HS384, HS512) तक सीमित है, एक शेयर्ड सीक्रेट को डेटाबेस स्टेटमेंट के अंदर रखता है, और बैच और ऑडिट काम के लिए बना है, प्रोडक्शन टोकन सर्विस के लिए नहीं। वेरिफ़िकेशन वाली तरफ़, जहाँ आप वह टोकन उसके सीक्रेट के ख़िलाफ़ साबित करते हैं, वह एप्लिकेशन लेयर का काम है या डिकोडिंग लेख की सिग्नेचर चेक का।
टेक्स्ट कॉलम में इमेजेज़ और फ़ाइलें
SQL में एन्कोड करने का सबसे आम कारण वही फ़ाइल है जो टेक्स्ट की शक्ल में सफ़र करनी पड़े: API जो इमेज को रिफरेंस करने के बजाय इनलाइन कर दे, बिना बाइनरी के चलने वाले सिस्टम के लिए एक्सपोर्ट, या सीड स्क्रिप्ट जो नए सर्वर पर डेटाबेस दोबारा गढ़े। DuckDB को राउंड ट्रिप लगभग आसान बना देता है, क्योंकि वह ग्लोब पैटर्न्स मंज़ूर करने वाले टेबल फ़ंक्शन के ज़रिए फ़ाइलें BLOBs में पढ़ता है, और एन्कोडर जो कुछ भी आए उसे सपाट कर देता है:
SELECT filename, to_base64(content) AS b64
FROM read_blob('/data/pics/*.png');
हर फ़ाइल की एक रो, हर रो में एक सपाट base64 स्ट्रिंग, उतारने के लिए कोई रैपिंग नहीं, भले ही आख़िर में आमतौर पर एक या दो पैडिंग निशान साथ चढ़ें। रिज़ल्ट को टेक्स्ट कॉलम में लिख दो और इमेजेज़ अब उस किसी भी चैनल से पोर्टेबल हैं जो टेक्स्ट हिलाता है। फिर ख़र्च की बात ईमानदारी से कीजिए: 1-मेगाबाइट की फ़ोटो लगभग 1.33-मेगाबाइट अक्षरों के रूप में आती है, और उससे आगे हर स्कैन, हर सॉर्ट और हर इंडेक्स एंट्री वह कीमत चुकाता है। अगर स्कीमा आपकी पकड़ में है, तो बेहतर डिज़ाइन BLOB कॉलम, और API बाउंड्री पर एन्कोडिंग - जहाँ सिर्फ़ वही बाइट्स सजाए जाते हैं जो असल में इमारत से बाहर निकलते हैं।
HTTP, JSON और API ट्रैफ़िक
हेडर्स और पेलोड्स वही जगह है जहाँ base64 अपना चुपचाप रोज़मर्रा का काम करता है। Basic ऑथ हेडर लीटरल प्रीफ़िक्स Basic है, जिसके बाद username:password की base64 आती है, और SQL में एक बनाना कन्कटेनेशन है और एक एन्कोड जोड़कर:
SELECT 'Basic ' || encode(convert_to('alice' || ':' || 's3cret', 'UTF8'), 'base64') AS header;
जो Basic YWxpY2U6czNjcmV0 बनाता है - वही ठीक-ठाक हेडर जो क्लाइंट भेजता। इससे फ़िक्चर्स बनाइए जो आपकी इंटिग्रेशन टेस्ट्स तुलना के लिए इस्तेमाल करती हैं, या ऑडिट करने से पहले स्टोर्ड हेडर्स के कॉलम को नॉर्मलाइज़ करने के लिए। JSON की तरफ़, MySQL एक ही एक्सप्रेशन में फ़ील्ड को पैक करके उसे डॉक्यूमेंट के अंदर एम्बेड कर सकता है - एप्लिकेशन कोड बिना:
SELECT JSON_OBJECT('img', TO_BASE64(CAST('hello file' AS BINARY))) AS doc;
रिज़ल्ट {"img": "aGVsbG8gZmlsZQ=="} है - भेजने के लिए तैयार पेलोड। वही शक्ल सर्टिफ़िकेट्स, पब्लिक कीज़ और किसी भी दूसरी फ़ाइल के लिए चलती है जिसे आपका API इनलाइन करने का फ़ैसला करे, और यह वही दिशा है जो तब मायने रखती है जब ट्रैफ़िक आप ही प्रोड्यूस कर रहे हों, किसी और के को डिकोड नहीं।
कॉन्फ़िग फ़ाइलें, सीक्रेट्स और एनवायरनमेंट वैरिएबल्स
एक एक्सपोर्ट आदत का अपना अलग पैराग्राफ़ माँगता है क्योंकि वह हर जगह है: कॉन्फ़िग टेबल में base64 के रूप में स्टोर किया हुआ सीक्रेट। Kubernetes ने यह आदत ज़िंदा रखी, जहाँ सीक्रेट वैल्यूज़ rest की स्थिति में base64 होती हैं ताकि वे YAML की एक लाइन में बिना कोट्स, बिना न्यूलाइन और बिना बैकस्लैश के बैठ जाएँ, और हर इन-हाउस कॉन्फ़िग सिस्टम ने इसे उठा लिया जो किसी न किसी Kubernetes पाइपलाइन से मिला। पैक करने की दिशा है हर वैल्यू के लिए एक एन्कोड, बाइनरी cast कैरेक्टर-सेट का काम करता है ताकि एक्सपोर्ट हुआ टेक्स्ट बिल्कुल वही हो स्टोर किए हुए बाइट्स:
SELECT name, TO_BASE64(CAST(value AS BINARY)) AS for_config
FROM app_config
WHERE name LIKE '%_secret%';
हर वैल्यू 57 बाइट्स तक सपाट, पेस्ट-रेडी स्ट्रिंग के रूप में निकलती है; उससे लंबी के लिए एक REPLACE() चाहिए जो YAML में जाने से पहले रैप लाइनों को हटा दे, और नया एनवायरनमेंट दूसरी तरफ़ इसे वापस डिकोड कर लेता है। रिज़ल्ट के साथ उतनी ही सावधानी बरतिए जितनी वह माँगता है: आपने बस स्टोर्ड सीक्रेट्स के कॉलम को स्टोर्ड सीक्रेट्स के उस कॉलम में बदल दिया जो कोई भी इंसान करीब दस सेकंड में पढ़ ले, और कॉन्फ़िग में base64 की आदत एक और दृष्टि ले लेती है उसी पल जब आप प्लेनटेक्स्ट इतने करीब खड़े हों। Base64 ट्रांसपोर्ट है, ख़ज़ाना नहीं। अगर एनवायरनमेंट में असली सीक्रेट स्टोर है, तो base64 कॉलम उससे दूर जाने का मिग्रेशन है।
ईमेल और 76-अक्षरों की आदत
76-अक्षरों का रैप इस पेज पर हर डेटाबेस से पुराना है। MIME, वह स्टैंडर्ड्स की टोली जो ईमेल को बाइनरी एटैचमेंट धारण करने देती है (RFC 2045, सेक्शन 6.8, 1996), base64 आउटपुट को 76 अक्षरों पर रैप करती है और हर लाइन को एक कैरेज रिटर्न और एक लाइन फ़ीड से ख़त्म करती है, क्योंकि पुराने ईमेल नेटवर्क को उससे लंबी लाइनों पर भरोसा नहीं किया जा सकता था। यहाँ के तीन एन्कोडरों ने यह रैप डिफ़ॉल्ट के रूप में उठाया (MySQL, PostgreSQL, SQLite CLI), जो किसी भी चीज़ के लिए दान है जो ईमेल में जा पहुँची और उस चीज़ के लिए जाल जो नहीं गई। और यह आदत उन्हें अधूरी-अधूरी में मिली: PostgreSQL अपनी लाइनों को अकेले न्यूलाइन से ख़त्म करता है, MIME स्पेसिफिकेशन के कैरेज रिटर्न और न्यूलाइन की जगह, इसलिए वह आउटपुट जो असली ईमेल एटैचमेंट में पेस्ट होना चाहिए, उसे एक और चक्कर चाहिए:
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;
वह न्यूलाइन हटाइए जो PostgreSQL ने पहले से जोड़ दिए हैं, फिर 76 पर दोबारा रैप कीजिए हर लाइन के बाद पूरे CRLF के साथ, और स्ट्रिंग एक ही एक्सप्रेशन में MIME-सही हो जाती है। तीन सौ बाइट्स इसमें से गुज़ाइए और 400 अक्षर जो आपने पैक किए थे 412 बन जाते हैं: छह रैप्ड लाइनें, छह CRLF जोड़े, ट्रांसपोर्ट समारोह के बारह अक्षर। वही शक्ल की समस्या PEM ब्लॉक्स के साथ भी दिखती है, जो 76 की बजाय 64 पर रैप होते हैं, और उन API के साथ जिनको रैप बिल्कुल नहीं चाहिए क्योंकि उनका JSON पार्सर फ़ील्ड के बीच में न्यूलाइन से मुलाक़ात करने को तैयार नहीं है। सभी के लिए नियम: एन्कोड करने से पहले पता कीजिए कि कन्ज़्यूमर ने कौन-सा करार साइन किया, क्योंकि स्टोर्ड base64 के कॉलम को दोबारा रैप करना मिग्रेशन है, क्वेरी नहीं।
जाल: जहाँ एन्कोडर आपसे झूठ बोलते हैं
इस सूची में हर जाल वह है जो कोई न कोई ख़ास डायलैक्ट लगाता है, base64 नहीं, और हर एक के पीछे कम से कम एक कोडबेस है जिसे यह प्रोडक्शन में मिला:
- बिना-मँगा रैप। MySQL और PostgreSQL डिफ़ॉल्ट रूप से अपना आउटपुट 76 पर रैप करते हैं, SQLite CLI 72 पर, और आपकी क्वेरी में किसी ने इसके लिए नहीं कहा। आपके JSON में base64 फ़ील्ड में अब लाइन ब्रेक्स हैं, और कन्ज़्यूमर जो स्पेसिफिकेशन में फ़ॉर्मेट मंज़ूर करता है उसे बाहर दुनिया में ठुकरा देता है। सपाट शक्ल है न्यूलाइन कैरेक्टर पर एक
REPLACE(), जो राइटर तरफ़ लगाया जाता है ताकि कॉलम वही स्टोर करे जो पाठक चाहता है। - कैरेक्टर-सेट की फिसलन। बिना बाइनरी cast के
TO_BASE64('héllo')वह एन्कोड करता है जो कनेक्शन कैरेक्टर सेट अक्षरों को मानता है, औरlatin1क्लाइंट औरutf8mb4क्लाइंट अलग-अलग चीज़ें मानते हैं। वही क्वेरी टेक्स्ट, दो अलग base64 रिज़ल्ट्स, और ग़लत वाला मोज़ीबेक में डिकोड होता है जिसे कोई एन्कोडर तक वापस न खोजे। बाइनरी cast, या एक्सप्लिसिटconvert_to(), ही उस क्वेरी की ईमानदार शक्ल है। - BLOB का दरवाज़ा। DuckDB का
to_base64()BLOBचाहता है: आप टेक्स्ट दे दो तो वह इम्प्लिसिटली cast कर देता है, इसलिए non-UTF-8 एन्कोडिंग वालाvarcharकॉलम चुपचाप ग़लत बाइट्स एन्कोड कर सकता है। ईमानदार रास्ता हैto_base64(encode(...)), इसलिए इस पेज के उदाहरण टेक्स्ट इनपुट के लिए हमेशा जोड़ी दिखाते हैं। - 26.7 की व्हाइटस्पेस बदलाव। ClickHouse के
base64Decode()औरbase64URLDecode()सालों तक इनपुट के सख़्त थे, पर 26.7 से वे व्हाइटस्पेस (स्पेस, टैब, लाइन फ़ीड, कैरेज रिटर्न, फ़ॉर्म फ़ीड) को ठुकराने की बजाय अनदेखा करते हैं, इसलिए वह स्क्रिप्ट जो रैप्ड कॉलम पर एरर करता था अब चुपचाप सफल हो जाता है, जो खुद के लिए एक अलग रिग्रेशन है। डिकोड पर भरोसा करने से पहले सर्वर का वर्ज़न-चेक कीजिए। - 6000-बाइट की सीमा। SQL Server का
BASE64_ENCODE()तबvarchar(8000)लौटाता है जब इनपुटvarbinary(n)हो n 6000 या कम, और उससे ऊपरvarchar(max); मैपिंग डिक्लेयर्ड साइज़ पर चली जाती है, वैल्यू पर नहीं, इसलिएvarbinary(8000)कॉलम तीन बाइट्स पर भीvarchar(max)लौटाता है। वही फ़ंक्शन काurl_safeआउटपुट, इसी दौरान, सर्वर के अपने XML और JSON base64 डिकोडर्स द्वारा नहीं पढ़ा जा सकता, जो पैडिंग के साथ स्टैंडर्ड वर्णमाला की उम्मीद करते हैं। वैरिएंट उस पाठक के लिए चुनिए जो उसे पढ़ेगा। - 2000-बाइट RAW। Oracle में साधारण SQL स्टेटमेंट में
RAWवैल्यू 2000 बाइट्स पर रुक जाती है। चूँकि एन्कोडरRAWलेता है औरRAWलौटाता है, एक-स्टेटमेंट एन्कोड सिर्फ़ करीब 1500 बाइट्स इनपुट मान सकता है (उसके 2000 अक्षरों का आउटपुट बैठ जाएगा, उससे ज़्यादा नहीं), और एक-स्टेटमेंट डिकोड सिर्फ़ 2000 अक्षर base64 मान सकता है। बड़े पेलोड्स PL/SQL में जाते हैं, जहाँRAWवैरिएबल 32767 बाइट्स धारण करता है और एक ही कॉल उनमें से ज़्यादातर उठा लेती है, और सिर्फ़ वे पेलोड्स जिनका base64 आउटपुट उस सीमा से ऊपर जाएगा, को चंक लूप चाहिए - जो 1990s की उस लीमिट से जुड़ी है जो कभी नहीं हटी। - पैकेट कर। MySQL एन्कोडेड स्ट्रिंग
max_allowed_packetके ख़िलाफ़ गिनता है, कच्चे बाइट्स नहीं। फ़ोटो जो टेबल में गद्दी-बगद्दी से बैठती है, 33 पर्सेंट बड़ी होकर रैप होने पर पैकेट में ओवरफ़्लो कर सकती है, और फ़ेलियर मोड है ट्रंकेटेड वैल्यू या ऐसाNULLजो डेटा कअरप्शन जैसा दिखे। लीमिट की जाँच कॉलम चौड़ाई के उसी साँस में कीजिए। - आख़िरी न्यूलाइन। SQLite CLI की
base64()अपनी आख़िरी लाइन को न्यूलाइन से ख़त्म करती है, लाइन-एंडिंग की आदत आख़िरी लाइन पर भी लागू। शेल आउटपुट को JSON फ़ील्ड में पेस्ट कीजिए और आपने न्यूलाइन के साथ base64 स्ट्रिंग भेज दी - बिना-मँगा रैप दूसरी टोपी में। - वर्णमाला की धारणा। स्टैंडर्ड वर्णमाला के लिए बना कन्ज़्यूमर आपके URL-safe आउटपुट से मिलता है (या उल्टा) और ऐसे अक्षर देखता है जो उसे नहीं पते। ज़्यादातर डिकोडर अंडरस्कोर पर ज़ोर से गिरते हैं; कुछ चुपचाप उसे स्किप करके गिरते हैं। स्कीमा कमेंट में हर base64 कॉलम की वर्णमाला लिख दीजिए, क्योंकि अगला डेवलपर याद नहीं रखेगा कि कौन-सी टोकन पाइपलाइन ने वह रो लिखी।
जब साइज़ असल में मायने रखती है
साइज़ की गणना है सपाट लंबाई, और जो भी रैपिंग जोड़ता है आपका एन्कोडर, और होम पेज अनुपात की पूरी तर्क-शृंखला करता है। यहाँ जो करना लायक़ है, यह देखना है कि आँकड़ा कहाँ रुचि-वस्तु बंद बनता है। इनपुट के बाइट-गिनती के हिसाब से साइज़ किया गया VARCHAR कॉलम पहली बार ही आउटपुट चुपचाप ट्रंकेट कर देता है जब पेलोड काफ़ी लंबा होता है, क्योंकि तीन बाइट्स इनपुट चार अक्षरों की कीमत के होते हैं। base64 टेक्स्ट कॉलम पर इंडेक्स वह कर दो बार चुकाता है: एक बार स्टोरेज में, दूसरी बार हर तुलना में, क्योंकि इंडेक्स एंट्रियाँ रैप्ड अक्षर हैं, बाइट्स नहीं। MySQL की max_allowed_packet और PostgreSQL की 1-GB bytea सीमा वही दो दीवारें हैं जो ज़्यादातर लोग सबसे पहले टोकते हैं, और दोनों टेक्स्ट के ख़िलाफ़ जाँची जाती हैं, जो इस मुबादले की बड़ी तरफ़ है। डिज़ाइन जवाब ज़्यादातरी किसी दूसरे एन्कोडर चुनने का नहीं (base64 तो सिर्फ़ एक है); वह यह चुनने का है कि एन्कोडिंग कहाँ हो। BLOB कॉलम, लुकअप्स के लिए हैश कॉलम, बाउंड्री पर एन्कोड: base64 सिर्फ़ ट्राफ़िक में मौजूद रहता है, जहाँ उसे रहना चाहिए।
सुरक्षा: base64 क्या नहीं है
Base64 एन्क्रिप्शन नहीं है, और वही एक आदत जो ज़ोर से बोलकर कहने ज़रूरी है वह है ऊपर वाली कॉन्फ़िग-टेबल वाली: base64 में स्टोर किया हुआ सीक्रेट वही सीक्रेट है जो दूसरी फ़ॉन्ट में स्टोर किया गया हो। यह परिवर्तन बिना की वाला बाइजेक्शन है, हर प्रोग्रामिंग लैंग्वेज इसको एक ही फ़ंक्शन कॉल में उलट सकती है, और इसका असली असर बस यही है कि वैल्यू YAML की एक लाइन पर रहे। अगर थ्रेट मॉडल में इसी डेटाबेस का कोई और यूज़र हो, कोई और सर्विस जो एक्सपोर्ट पढ़े, या कोई लॉग जिसने वह रो पकड़ी हो, तो base64 रक्षा में बिल्कुल शून्य लाता है। यह वैल्यू को इंसानी नज़र से कुछ सेकंड के लिए छुपाता है, इसलिए कोड रिव्यू में यह प्रोटेक्शन जैसा लगता है और इसलिए ही इन्सिडेंट में यह टूटता है। जो सीक्रेट होना चाहिए उसे एन्क्रिप्ट कीजिए, ऐसे की से जो किसी ने असल में सीक्रेट रख सके, और base64 को वह काम करने दीजिए जिसमें वह महारत रखता है: बाइट्स को उस चैनल से हिलाना जो सिर्फ़ टेक्स्ट धारण करता है।
जब हर डायलैक्ट रैप करना सीखा
रिलीज़ नोट्स वही कहानी बताने हैं जो डिकोडिंग तरफ़ ने बताई, बस अक्षर उल्टी दिशा में जाते हैं, और स्केजूल हर इंजन के बारे में कुछ कहता है:
2002। PostgreSQL 7.2 में base64 encode() और decode() का पहली-श्रेणी फ़ॉर्मेट है - Oracle के 9i दौर के UTL_ENCODE से समकालीन, और इस तालीम में बारीक अंतर से सबसे पुराना base64 मशीनरी। एक डेटाबेस जिसके पास असली बाइनरी टाइप और फ़ॉर्मेट आर्ग्यूमेंट था, वह जल्दी पहुँच गया, क्योंकि जवाब एक इनिम वैल्यू दूर था।
2000s की शुरुआत। Oracle का UTL_ENCODE पैकेज 9i दौर में दिखा, BASE64_ENCODE() को उसके MIME हेडर, quoted-printable और uuecode भाइयों के बग़ल में लेकर। RAW अंदर, RAW बाहर - और एक चतुर्थांश सदी बाद भी पैकेज ने मन नहीं बदला।
2013। MySQL 5.6 ने TO_BASE64() और FROM_BASE64() जोड़े, और MariaDB 10.0 ने दोनों को विरासत में ले लिया। जोड़ी 76-अक्षर लाइनों से एन्कोड करती है और व्हाइटस्पेस सहनशीलता के साथ डिकोड करती है, एक मेल खाता सेट जो बदला नहीं।
2018। ClickHouse 18.16 (दिसंबर 2018) ने base64Encode() और base64Decode() जारी किए, MySQL स्टाइल एलियास के साथ, क्योंकि कॉलमर दुनिया वर्कलोड्स इम्पोर्ट कर रही थीं जिनके लॉग स्कीमाज़ में पहले से base64 थी।
2023। SQLite 3.41.0 ने base64() कमांड-लाइन शेल में एप्लिकेशन-डिफाइंड फ़ंक्शन के रूप में जोड़ा। कोर लाइब्रेरी, अपने किरदार के हिसाब से, कुछ नहीं पाती; शेल, जहाँ इंसान असल में SQLite फ़ाइलों को छूते हैं, वहाँ टूल मिलता है।
2025। SQL Server 2025, नवंबर 2025 में जनरली एवेलेबल, ने अंत में BASE64_ENCODE() और BASE64_DECODE() जोड़े, प्रोडक्ट के लॉन्च के 36 साल बाद, और उन यूज़र्स से एक पीढ़ी दूर जिन्होंने XML वर्कअराउंड रट ले चुका था।
पैटर्न वही है जो डिकोडिंग लेख के अंत में है, उल्टी दिशा में: असली बाइनरी टाइप और फ़ॉर्मेट आर्ग्यूमेंट वाले इंजनों को base64 उसी दिन मिला जब ज़रूरत साफ़ दिखी, और उन इंजनों ने जहाँ सब कुछ स्ट्रिंग है, उसने उसे बाद के लिए स्केजूल कर दिया।
ज़ाने लायक़ विचित्रियाँ
- SQLite CLI की
base64()इस तालीम की शक्ल-बदल है, और एन्कोडिंग की दिशा में वह यह ट्राइक सबसे अच्छी दिखाती है:BLOBदीजिए तो रैप्ड टेक्स्ट वापस मिलता है आख़िरी न्यूलाइन के साथ, टेक्स्ट दीजिए तोBLOBमिलता है। एक नाम, दो काम, आर्ग्यूमेंट के टाइप से चुना गया, और इस तालीम का कोई दूसरा एन्कोडर ऐसा नहीं करेगा। - ClickHouse का
base64Decode()फैमिली 26.7 में ढीला गया: इनपुट का व्हाइटस्पेस अब ठुकराने की बजाय अनदेखा किया जाता है, इसलिए वही क्वेरी रैप्ड कॉलम पर पुराने सर्वर पर फेल होती है और नए सर्वर पर चुपचाप वैल्यू लौटाती है। डिकोडर टूटा नहीं; वह ढीला गया, जो किसी न किसी तरह डिबग करने से ज़्यादा मुश्किल है। - PostgreSQL बिल्कुल 1996 MIME स्पेसिफिकेशन की तरह 76 अक्षरों पर रैप करता है, सिवाय इसके कि वह लाइनों को अकेले न्यूलाइन से ख़त्म करता है, स्पेसिफिकेशन के कैरेज रिटर्न और न्यूलाइन की जगह। स्पेसिफिकेशन के बीस से ज़्यादा साल बाद, हर लाइन में एक अक्षर कम, और यह बगावत तब तक अदृश्य है जब तक आप बाइट्स का diff न लें।
mysqlक्लाइंट में, जो बाइट्स आप एन्कोड करते हैं वे base64 टेक्स्ट के रूप में बख़ुबी प्रिंट होती हैं, पर उसी पल जब आपCAST(... AS BINARY)से कच्चे कॉलम को देखते हैं, क्लाइंट हेक्स डिस्प्ले (binary-as-hex) पर चला जाता है, और बिल्कुल सहीhelloस्क्रीन पर0x68656C6C6Fके रूप में आता है। यह सेटिंग हज़ारों डेवलपर्स को यकीन दिला चुकी है कि उनका एन्कोडर ख़राब है।- Snowflake हर रिज़ल्ट सेट में
BINARYवैल्यूज़ को हेक्स में दिखाता है, इसलिए आपकी एन्कोड क्वेरी मेंTO_BINARY()इनपुट कॉलम चेकसम जैसा पढ़ा जाता है भले ही सब कुछ काम करता हो। दो डायलैक्ट्स, दो हेक्स डिस्प्ले, एक एक जैसा बेचैन होने का अहसास। - Oracle की SQL-level
RAW2000 बाइट्स पर बँधी है, इसलिए 3-किलोबाइट का सर्टिफ़िकेट SQL स्टेटमेंट मेंRAWलीटरल के रूप में पेस्ट ही नहीं किया जा सकता। एन्कोड PL/SQL में होना चाहिए, जहाँRAWवैरिएबल 32767 बाइट्स धारण करता है, इसलिए 3-किलोबाइट का सर्टिफ़िकेट एक ही कॉल है, और सिर्फ़ वे पेलोड्स जिनका base64 आउटपुट 32 किलोबाइट से ऊपर जाएगा, को चंक लूप चाहिए - जो 1990s की है। - MIME base64 की एक लाइन 76 अक्षरों की है, जो 57 कच्चे बाइट्स है, क्योंकि चार अक्षर तीन उठाते हैं। वह आँकड़ा 76 जो तीन एन्कोडरों के डिफ़ॉल्ट में दिखता है, लीमिट से ज़्यादा एक पैकिंग घनत्व है: पुराने ईमेल एटैचमेंट में आप जो हर रैप्ड लाइन देखें, उसने आपके डेटा के बिल्कुल 57 बाइट्स उठाए थे।
उल्टी दिशा
यह लेख उस कपड़े को पहनाने के बारे में रहा: तय करना कि आप कौन-से बाइट्स की बात कर रहे हैं, देखना कि बाहर क्या निकलता है, पाठक के लिए वर्णमाला चुनना, और कॉलम ट्रंकेट करने से पहले साइज़ की गणना करना। कपड़ा उतारना बिल्कुल अलग निसन का काम है - एक डायलैक्ट जो कंधे उचला देता है वहाँ चुप NULL्स, दूसरा जो ज़ोर बढ़ा देता है वहाँ कठोर एरर, और URL-safe वर्णमाला जो तालीम के आधे सदस्यों को बिल्कुल नहीं मालूम। सब कुछ, FROM_BASE64() से लेकर decode() तक BASE64_DECODE() तक, SQL की जुड़ी हुई Base64 डिकोडिंग आर्टिकल में विस्तार से покры है, जो ठीक नीचे लिंक है। यहाँ एन्कोड कीजिए, वहाँ डिकोड कीजिए, और पूरा राउंड ट्रिप एक दोपहर में समा जाता है।
अंतिम अपडेट: 2026-09-08
संबंधित लेख: SQL में Base64 डिकोडिंग: एक सम्पूर्ण गाइड