क्या आपको Base64 फ़ॉर्मेट के साथ काम करना होता है? तो यह साइट आपके लिए एकदम सही है! अपने डेटा को एन्कोड या डिकोड करने के लिए, हमारे बेहद आसान ऑनलाइन टूल का इस्तेमाल करें।

SQL में Base64 डिकोडिंग: एक सम्पूर्ण गाइड

किसी भी प्रोडक्शन डेटाबेस में ज़रा लंबे समय तक रुकिए, और आपको वह नक़ाब ज़रूर मिलेगा। एक एवेटार, जो JSON एक्सपोर्ट के अंदर अक्षरों की दीवार बनकर आया हो। एक JWT, जो यूज़र आईडी के बग़ल में varchar कॉलम में पार्क हो। एक सर्टिफ़िकेट, जो किसी ने स्ट्रिंग के रूप में भेजने का फ़ैसला किया, क्योंकि ट्रांसफर फ़ॉर्मेट में बाइनरी की कोई जगह ही नहीं थी। टेबल के कहीं-न-कहीं आपका डेटा अक्षरों के कपड़े पहने बैठा है, और आपका काम है उन कपड़ों को उतार देना - बिना डेटाबेस से बाहर क़दम रखे।

SQL में इस काम का एक बहुत ही आरामदेह गुण है: एक बार जब आपको पता चल जाए कि आपका डायलैक्ट कौन-सा डिकोडर बोलता है, तो पूरा काम एक ही फ़ंक्शन कॉल तक सिकुड़ जाता है। फ़ॉर्मेट खुद होम पेज पर पहले से विस्तार से समझा दिया जा चुका है (64 प्रिंट होने योग्य अक्षर, हर चार अक्षरों का समूह तीन इनपुट बाइट्स का प्रतिनिधित्व करता है, और आख़िरी समूह की पैडिंग के लिए ज़्यादा से ज़्यादा दो = निशान), इसलिए यह लेख वह व्याख्यान छोड़कर आगे बढ़ता है। दो बातें साथ रखिए: base64 बाइट्स को टेक्स्ट के कपड़े पहनाने का तरीका है, कोई ताला नहीं, और डिकोडिंग वह दिशा है जिसमें डेटा छोटा होता जाता है (वापस अपने एन्कोडेड आकार के तीन-चौथाई पर), जो बिल्कुल उल्टी चीज़ है उससे जिसके लिए आपकी स्टोरेज कॉलम साइज़ की गई थी। असली कहानी यह है कि SQL डायलैक्ट्स की एक परिवार है, और उसके हर सदस्य अपने डिकोडर को एक अलग नाम से बुलाता है और ख़राब इनपुट के सामने बिल्कुल अलग स्वभाव दिखाता है। यह लेख उसी परिवार का दौरा है।

डिकोडर लाइन-अप

यहाँ देखिए कि ड्यूटी पर कौन-कौन है, और इनपुट कचरा हो तो हर एक का पहरा कैसा रहता है। "खराब कब" कॉलम मायने रखता है, क्योंकि स्टेजिंग में जोर-जोर से फेल होकर प्रोडक्शन में चुपचाप फेल होने वाला डिकोडर ही वह रास्ता है जिससे ग़ायब एवेटार फ़ील्ड में पहुँचते हैं:

डायलैक्ट कॉल क्या वापस आता है खराब कब कब से
MySQL 8.x / MariaDB 10.x FROM_BASE64(str) बाइनरी स्ट्रिंग चुपचाप NULL MySQL 5.6 (2013)
PostgreSQL decode(str, 'base64') bytea ज़ोर से ERROR, हिंट के साथ 7.2 (2002)
SQLite (CLI 3.41+) base64(str) BLOB जो पढ़ नहीं पाता उसे छोड़ देता है 3.41.0 (2023)
DuckDB from_base64(str) BLOB कन्वर्ज़न एरर आधुनिक रिलीज़
ClickHouse 18.16+ base64Decode(str) String एक्सेप्शन (INCORRECT_DATA) 18.16.0 (2018)
SQL Server 2025+ BASE64_DECODE(str) varbinary Msg 9803, तीन स्टेट्स 2025
Oracle UTL_ENCODE.BASE64_DECODE(raw) RAW PL/SQL एक्सेप्शन 9i दौर
Snowflake BASE64_DECODE_BINARY(str) BINARY एरर, या TRY_ वैरिएंट के साथ NULL मौजूदा रिलीज़

टेबल की शकल पर ध्यान दीजिए: फ़ंक्शन का नाम कभी भी मुश्किल हिस्सा नहीं होता। मुश्किल हिस्सा "खराब कब" कॉलम है, क्योंकि यही कॉलम तय करता है कि आपकी रिपोर्ट चुपचाप रोएँ खो दे, या आपका बैच जॉब रुककर मदद माँगे।

MySQL और MariaDB: वह डिकोडर जो कंधे उचला देता है

दोनों सर्वर जोड़ी TO_BASE64() / FROM_BASE64() साझा करते हैं। डिकोडर स्ट्रिंग लेता है और वापस बाइनरी स्ट्रिंग सौंपता है: बाइट्स की एक सिक्वेंस, जिससे कोई कैरेक्टर सेट जुड़ा नहीं होता। NULL अंदर जाए तो NULL बाहर आता है, और यहाँ पहली बात याद रखिए: असली base64 न हो, कुछ भी और भी NULL है, बिना किसी वार्निंग के। डिकोडर कंधे उचला देता है, और आपकी क्वेरी ख़ुशी-ख़ुशी आगे बढ़ती रहती है।

SELECT FROM_BASE64('aGVsbG8=') AS restored;
SELECT HEX(FROM_BASE64('aGVsbG8=')) AS as_hex;
SELECT CONVERT(FROM_BASE64('aGVsbG8gd29ybGQ=') USING utf8mb4) AS as_text;

बीच वाली पंक्ति के पास एक टिप्पणी का हक़ है, क्योंकि वह एक क्लासिक भ्रम के पल की बयानी है। mysql कमांड-लाइन क्लाइंट बाइनरी स्ट्रिंग्स को डिफ़ॉल्ट में हेक्सडेसिमल नोटेशन में प्रिंट करता है (एक सेटिंग, जिसका नाम binary-as-hex है), इसलिए बस SELECT FROM_BASE64('aGVsbG8=') hello की जगह 0x68656C6C6F दिखाता है। यह न कोई बग़ है और न डेटा का ख़राब होना; यह क्लाइंट की बाइनरी डेटा के लिए सावधानी है। अगर आपको अक्षर चाहिए, तो CONVERT(... USING utf8mb4) से कन्वर्ट करें या क्लाइंट --binary-as-hex=0 के साथ शुरू करें; बीच वाली पंक्ति का HEX() कॉल वही हेक्स है जो क्लाइंट डिफ़ॉल्ट में आपको दिखाता है, बस जानबूझकर किया हुआ।

अब देखिए वो नियम, जो यह चुप डिकोडर लागू करता है। व्हाइटस्पेस नज़रअंदाज़ करने के बाद, बचे हुए अक्षरों को चार का गुणज बनाना होगा, हर अक्षर स्टैंडर्ड वर्णमाला से होना चाहिए (अक्षर, अंक, +, /, और =), और पैडिंग केवल बिल्कुल आख़िर में आ सकती है:

SELECT FROM_BASE64('aGVsbG8gd29ybGQ=') AS ok;
SELECT FROM_BASE64('aGVsbG8gd29ybGQ') AS missing_padding;
SELECT FROM_BASE64('!!!') AS nonsense;

तीनों लाइनें बिना किसी शिकायत के चलती हैं, और दूसरी व तीसरी पंक्ति NULL लौटाती हैं। पैडिंग ग़ायब, लंबाई ग़लत, पराए अक्षर: वही कंधा उचलना। व्हाइटस्पेस एकमात्र छूट है; न्यूलाइन, कैरेज रिटर्न, टैब और स्पेस - सभी नज़रअंदाज़ हो जाते हैं, जो पहले ईमेल से गुज़री हर चीज़ के लिए रहम है। दूसरी ओर, URL-safe वर्णमाला को भी वही कंधा उचलना मिलता है: अंडरस्कोर स्टैंडर्ड टेबल में नहीं है, इसलिए FROM_BASE64('yv7K_g==') NULL है, भले ही लंबाई चार का साफ़ गुणज हो। कॉल करने से पहले आपको खुद वर्णमाला का अनुवाद करना पड़ता है, और नीचे URL-safe सेक्शन दिखाता है कि कैसे।

एक और ख़ासियत जानने लायक़ है: डिकोडर और एन्कोडर एक मेल खाती जोड़ी हैं। एन्कोडर अपने आउटपुट को 76 अक्षरों की लाइनों में तोड़ता है, और डिकोडर उन लाइन ब्रेक्स को नाश्ते में निगल लेता है। अगर कोई कॉलम इसी डेटाबेस परिवार के TO_BASE64() से भरा गया है, तो डिकोडिंग एक परफ़ेक्ट राउंड ट्रिप है। अगर कोई और ने भरा है, तो पढ़ते रहिए।

PostgreSQL: वह डिकोडर जो आवाज़ उठाता है

PostgreSQL अपने कोर में base64 को कम से कम वर्ज़न 7.2 से, 2002 की बात है, धारण करता आ रहा है, इसलिए बारीक अंतर से यह इस परिवार की सबसे पुरानी base64 मशीनरी है। कॉल decode(string, 'base64') है, और रिज़ल्ट bytea, यानी डेटाबेस का नेटिव बाइनरी टाइप। साथी encode(bytea, 'base64') उल्टी दिशा में जाता है, और यहाँ इसका ज़िक्र इसलिए है क्योंकि दोनों के बीच एक साझा फ़ॉर्मेटिंग अनुबंध है: RFC 2045 स्टाइल, जिसमें लाइनें 76 अक्षरों पर टूटती हैं। डिकोडर, अपने पक्ष में, इनपुट के हर जगह कैरेज रिटर्न, न्यूलाइन, स्पेस और टैब को नज़रअंदाज़ करता है।

SELECT decode('aGVsbG8gd29ybGQ=', 'base64') AS bytes;
SELECT length(decode('aGVsbG8gd29ybGQ=', 'base64')) AS byte_count;
SELECT convert_from(decode('aMOpbGxv', 'base64'), 'UTF8') AS text;

तीसरी पंक्ति ही वह है जिसकी आप बार-बार शरण लेंगे: convert_from() bytea को एक नामित एन्कोडिंग में टेक्स्ट में बदलता है, और यही वह कैरेक्टर सेट स्टेप है जिसकी बाइनरी डेटा को ज़रूरत होती है (इस पर बाद में अपने सेक्शन में विस्तार से बात होगी)। aMOpbGxv वापस héllo के रूप में आता है, एक्सेंटेड अक्षर समेत।

PostgreSQL खुद को इस फ़ील्ड से अलग करने वाली जगह "खराब कब" कॉलम है। इनवलुड इनपुट एक हार्ड एरर है, और एरर मैसेज बिल्कुल सटीक बताता है कि कौन-सा नियम टूटा:

  • वर्णमाला से बाहर का अक्षर: ERROR: invalid symbol "!" found while decoding base64 sequence
  • स्ट्रिंग के बीच में पैडिंग निशान: ERROR: unexpected "=" while decoding base64 sequence
  • ट्रंकेटेड इनपुट या ग़ायब पैडिंग: ERROR: invalid base64 end sequence, हिंट के साथ Input data is missing padding, is truncated, or is otherwise corrupted.
  • URL-safe अंडरस्कोर: ERROR: invalid symbol "_" found while decoding base64 sequence

डेटा-क्लीनिंग के काम के लिए, वह आवाज़ एक फ़ीचर है। क्वेरी फेल होती है, आपको रो दिखती है, आप स्रोत ठीक कर देते हैं। ट्रेड-ऑफ़ यह है कि एक मिलियन में से एक ज़हरीली रो पूरे बैच को रोक देती है, इसलिए प्रोडक्शन पाइपलाइन्स में लोग decode() कॉल करने से पहले अक्सर regex से प्री-फ़िल्टर करते हैं। और एक छोटा सा डिस्प्ले नोट: psql bytea को \x प्रीफ़िक्स वाले हेक्स में प्रिंट करता है, इसलिए \x68656c6c6f वही "hello" है जो MySQL क्लाइंट 0x68656C6C6F के रूप में दिखाता है। दो डायलैक्ट्स, दो हेक्स डायलैक्ट्स।

SQL Server: वह देर से आया

यहाँ है इस पूरी परिवार का चौंकाने वाला मोड़। SQL Server ने वर्ज़न 2025 में BASE64_DECODE() जारी किया, जो नवंबर 2025 में जनरली एवेलेबल हुआ। उसके पहले, एंटरप्राइज दुनिया का सबसे लोकप्रिय डेटाबेस 36 साल से बिना बिल्ट-इन base64 डिकोडर के था, और लोकप्रिय किस्सों में वर्कअराउंडों की भरमार थी। आधुनिक फ़ंक्शन साफ़-सुथरा है: यह varchar(n) या varchar(max) एक्सप्रेशन लेता है और varbinary लौटाता है (varchar(n) एक्सप्रेशन varbinary(8000) में मैप होता है, और varchar(max) एक्सप्रेशन varbinary(max) में), NULL सीधा पार हो जाता है।

SELECT BASE64_DECODE('aGVsbG8gd29ybGQ=') AS bytes;
SELECT CONVERT(VARCHAR(100), BASE64_DECODE('aGVsbG8gd29ybGQ=')) AS text;
SELECT BASE64_DECODE('yv7K_g') AS url_safe_also_works;

वही तीसरी पंक्ति सच में ख़ूबसूरत छू है: डिकोडर दोनों RFC 4648 वर्णमालाओं को स्वीकार करता है, + और / वाली स्टैंडर्ड और - और _ वाली URL-safe, और पैडिंग वैकल्पिक है। यह चारों व्हाइटस्पेस अक्षरों (न्यूलाइन, कैरेज रिटर्न, टैब, स्पेस) को भी नज़रअंदाज़ करता है। जब यह टूटता है, तो एरर Msg 9803, Level 16 होता है, टेक्स्ट Invalid data for type "Base64Decode" के साथ, और State वैल्यू बताता है कि आप किस नियम पर टूटे: state 20 तब जब अक्षर किसी भी वर्णमाला में न हो, state 21 तब जब सभी अक्षर वैलिड हों पर ऐसी शक्ल में हों जो base64 नहीं बना सकता, और state 23 तब जब पैडिंग बहुत ज़्यादा बार या बहुत जल्दी आ जाए।

अगर आप 2025 से पहले के किसी वर्ज़न पर फँसे हैं, तो क्लासिक वर्कअराउंड XML टाइप का सहारा लेता है, जो XML Schema के दौर से ही base64 को समझता आ रहा है:

SELECT CAST(N'' AS XML)
  .value('xs:base64Binary("aGVsbG8=")', 'VARBINARY(MAX)') AS legacy;

XML इंजन कॉन्स्टेंट को base64-डिकोड करता है और बाइट्स लौटा देता है। यह काम करता है, और यही वह चीज़ है जिसे एक पूरी पीढ़ी के SQL Server डेवलपर्स ने इस्तेमाल किया। इसके किनारे भी हैं: base64Binary टाइप शक्ल के सख़्त है, इसलिए MIME-रैप्ड स्ट्रिंग, जिसके अंदर लाइन ब्रेक्स हों, पार्स नहीं होगी, और आप वह काम करने के लिए XML मशीनरी की कीमत चुका रहे हैं जो एक फ़ंक्शन अब नेटिव रूप से करता है। इसे वह म्यूज़ियम पीस मानिए जो वह बन चुका है।

SQLite: वह डायलैक्ट जिसमें डिकोडर ही नहीं है

SQLite ही है वह अलग-थलग, और समझना कि क्यों, आपको बताता है कि इसे कैसे इस्तेमाल करें। कोर लाइब्रेरी एक छोटा, एम्बेडडेबल इंजन है, और base64 उसकी स्टैंडर्ड फ़ंक्शन लिस्ट में नहीं है। अगर कोई कॉलम base64 धारण करता है, तो डिकोडर चार जगहों में से एक से आना पड़ेगा: कमांड-लाइन शेल, एक लोडेबल एक्सटेंशन, होस्ट एप्लिकेशन के रजिस्टर किया हुआ कस्टम फ़ंक्शन, या शुद्ध SQL। यहाँ है हर एक, एक-एक करके।

CLI। वर्ज़न 3.41.0 (फ़रवरी 2023) से, sqlite3 कमांड-लाइन शेल के साथ एक base64() फ़ंक्शन आता है। यह टेक्स्ट आर्ग्यूमेंट को BLOB में डिकोड करता है, जिससे यह टर्मिनल से सीधे एक्सप्लोरटरी काम के लिए परफ़ेक्ट है:

$ sqlite3 app.db "SELECT hex(base64('aGVsbG8gd29ybGQ='));"
68656C6C6F20776F726C64

दो स्वभावें जानने लायक़ हैं। पहली, यह लीनेंट है: जो अक्षर यह नहीं पहचानता, उन्हें रिपोर्ट करने के बजाय छुड़ा दिया जाता है, इसलिए base64('!!!') एरर के बजाय ख़ाली BLOB लौटाता है। ज़िज्ञासा के लिए बढ़िया, ऑडिटिंग के लिए ख़तरनाक, क्योंकि आउटपुट में "खाली" और "ग़ायब" एक जैसे दिखते हैं। दूसरी, यह फ़ंक्शन शक्ल-बदलू है; BLOB आर्ग्यूमेंट को एन्कोड करके टेक्स्ट में बदल दिया जाता है (72 अक्षरों की लाइनों के साथ), जबकि टेक्स्ट आर्ग्यूमेंट को डिकोड करके BLOB में बदल दिया जाता है। एक ही नाम, दो काम, आर्ग्यूमेंट के टाइप से चुना जाता है। इस परिवार का कोई दूसरा डिकोडर ऐसा नहीं करता, इसलिए इनपुट टाइप दो बार पढ़िए।

शुद्ध SQL। कोर लाइब्रेरी में base64 नहीं है, पर रेक्रिसिव CTEs, अंकगणित, और (3.41.0 से) unhex() है, जो असली डिकोडर बनाने के लिए कुछ दर्जन लाइनों में काफ़ी है। रेसिपी: 64-रो की वर्णमाला टेबल, इनपुट को चार-अक्षरों के चंक्स में कटा हुआ, हर चंक एक 24-बिट नंबर में बदला, वह नंबर तीन बाइट्स में बँटा, और बाइट्स को हेक्स में इकट्ठा किया गया, और फिर unhex() उन्हें BLOB में बदलता है। यहाँ वह है, टेबल कॉलम पर काम करते हुए:

WITH RECURSIVE
b64(c, v) AS (
  SELECT 'A', 0 UNION ALL SELECT 'B', 1 UNION ALL SELECT 'C', 2
  UNION ALL SELECT 'D', 3 UNION ALL SELECT 'E', 4 UNION ALL SELECT 'F', 5
  UNION ALL SELECT 'G', 6 UNION ALL SELECT 'H', 7 UNION ALL SELECT 'I', 8
  UNION ALL SELECT 'J', 9 UNION ALL SELECT 'K', 10 UNION ALL SELECT 'L', 11
  UNION ALL SELECT 'M', 12 UNION ALL SELECT 'N', 13 UNION ALL SELECT 'O', 14
  UNION ALL SELECT 'P', 15 UNION ALL SELECT 'Q', 16 UNION ALL SELECT 'R', 17
  UNION ALL SELECT 'S', 18 UNION ALL SELECT 'T', 19 UNION ALL SELECT 'U', 20
  UNION ALL SELECT 'V', 21 UNION ALL SELECT 'W', 22 UNION ALL SELECT 'X', 23
  UNION ALL SELECT 'Y', 24 UNION ALL SELECT 'Z', 25 UNION ALL SELECT 'a', 26
  UNION ALL SELECT 'b', 27 UNION ALL SELECT 'c', 28 UNION ALL SELECT 'd', 29
  UNION ALL SELECT 'e', 30 UNION ALL SELECT 'f', 31 UNION ALL SELECT 'g', 32
  UNION ALL SELECT 'h', 33 UNION ALL SELECT 'i', 34 UNION ALL SELECT 'j', 35
  UNION ALL SELECT 'k', 36 UNION ALL SELECT 'l', 37 UNION ALL SELECT 'm', 38
  UNION ALL SELECT 'n', 39 UNION ALL SELECT 'o', 40 UNION ALL SELECT 'p', 41
  UNION ALL SELECT 'q', 42 UNION ALL SELECT 'r', 43 UNION ALL SELECT 's', 44
  UNION ALL SELECT 't', 45 UNION ALL SELECT 'u', 46 UNION ALL SELECT 'v', 47
  UNION ALL SELECT 'w', 48 UNION ALL SELECT 'x', 49 UNION ALL SELECT 'y', 50
  UNION ALL SELECT 'z', 51 UNION ALL SELECT '0', 52 UNION ALL SELECT '1', 53
  UNION ALL SELECT '2', 54 UNION ALL SELECT '3', 55 UNION ALL SELECT '4', 56
  UNION ALL SELECT '5', 57 UNION ALL SELECT '6', 58 UNION ALL SELECT '7', 59
  UNION ALL SELECT '8', 60 UNION ALL SELECT '9', 61 UNION ALL SELECT '+', 62
  UNION ALL SELECT '/', 63
),
chunks AS (
  SELECT name, b64, (LENGTH(b64) + 3) / 4 AS n
  FROM payload
),
seq(name, n, i) AS (
  SELECT name, n, 1 FROM chunks
  UNION ALL
  SELECT name, n, i + 1 FROM seq WHERE i < n
),
vals AS (
  SELECT s.name, s.i AS chunk_no, s.n,
         COALESCE((SELECT v FROM b64 WHERE c = substr(ch.b64, (s.i - 1) * 4 + 1, 1)), -1) AS v1,
         COALESCE((SELECT v FROM b64 WHERE c = substr(ch.b64, (s.i - 1) * 4 + 2, 1)), -1) AS v2,
         COALESCE((SELECT v FROM b64 WHERE c = substr(ch.b64, (s.i - 1) * 4 + 3, 1)), -1) AS v3,
         COALESCE((SELECT v FROM b64 WHERE c = substr(ch.b64, (s.i - 1) * 4 + 4, 1)), -1) AS v4
  FROM seq s
  JOIN chunks ch ON ch.name = s.name
),
hexes AS (
  SELECT name, chunk_no, n,
         (CASE WHEN v1 < 0 THEN 0 ELSE v1 END) * 262144 +
         (CASE WHEN v2 < 0 THEN 0 ELSE v2 END) * 4096 +
         (CASE WHEN v3 < 0 THEN 0 ELSE v3 END) * 64 +
         (CASE WHEN v4 < 0 THEN 0 ELSE v4 END) AS v24,
         CASE WHEN v2 >= 0 OR v3 >= 0 THEN 1 ELSE 0 END +
         CASE WHEN v3 >= 0 OR v4 >= 0 THEN 1 ELSE 0 END +
         CASE WHEN v4 >= 0 THEN 1 ELSE 0 END AS n_bytes
  FROM vals
),
acc(name, n, i, hx) AS (
  SELECT h.name, h.n, 1,
         (CASE WHEN h.n_bytes >= 1 THEN printf('%02X', h.v24 / 65536) ELSE '' END) ||
         (CASE WHEN h.n_bytes >= 2 THEN printf('%02X', (h.v24 / 256) % 256) ELSE '' END) ||
         (CASE WHEN h.n_bytes >= 3 THEN printf('%02X', h.v24 % 256) ELSE '' END)
  FROM hexes h
  WHERE h.chunk_no = 1
  UNION ALL
  SELECT a.name, a.n, a.i + 1,
         a.hx || (
           SELECT (CASE WHEN h.n_bytes >= 1 THEN printf('%02X', h.v24 / 65536) ELSE '' END) ||
                  (CASE WHEN h.n_bytes >= 2 THEN printf('%02X', (h.v24 / 256) % 256) ELSE '' END) ||
                  (CASE WHEN h.n_bytes >= 3 THEN printf('%02X', h.v24 % 256) ELSE '' END)
           FROM hexes h
           WHERE h.name = a.name AND h.chunk_no = a.i + 1
         )
  FROM acc a
  WHERE a.i < a.n
)
SELECT name, unhex(hx) AS restored
FROM acc
WHERE i = n;

इसे b64 कॉलम वाली टेबल पर चलाइए, और हर रो के लिए एक BLOB मिलेगा, कोई एक्सटेंशन नहीं, कोई एप्लिकेशन कोड नहीं। अंकगणित साधारण base64 है, बस इंटीजर के कपड़ों में: चारों अक्षरों में से हर एक छह बिट्स का योगदान देता है, बीच के दो अक्षर बाइट बॉउंड्री को पार करते हैं, और आख़िरी अक्षर के निचले दो बिट्स फेंक दिए जाते हैं। यह इस पेज का सबसे धीमा विकल्प है (एक रेक्रिसिव पास, साथ में हर चंक के लिए एक लुकअप), इसलिए इसे छोटे पेलोड्स और एक-दम पुरातत्त्व के लिए रखिए। लंबे समय तक चलने वाली एप्लिकेशन के लिए ईमानदार जवाब तीसरा विकल्प है: होस्ट लैंगुएज से एक-लाइन का कस्टम फ़ंक्शन रजिस्टर करें (Python के sqlite3 मॉड्यूल इसे दो लाइनों में कर देता है, create_function() और स्टैंडर्ड base64 मॉड्यूल से), और इंजन को इसे नेटिव की तरह कॉल करने दें। चौथा विकल्प, sqlean परिवार जैसे लोडेबल एक्सटेंशन, वही मौजूद है, पर इसका मतलब है एक अलग इंजन बिल्ड इंस्टॉल करना, जो अधिकांश टीमें पसंद नहीं करतीं।

DuckDB: सख़्त, छोटा, राय रखने वाला

DuckDB एक एनालिटिकल डेटाबेस है, जिसमें एक असली बाइनरी टाइप, BLOB, और उसके चारों ओर ब्लॉब फ़ंक्शनों का एक साफ़-सुथरा परिवार है। डिकोडर है from_base64(string), और यह अपने दोस्तों to_base64(), hex(), md5() और sha256() के बग़ल में उसी रेफ़रेंस पेज पर बैठा है, जहाँ अधिकांश DuckDB यूज़र्स उसे पहली बार मिलते हैं।

SELECT from_base64('aGVsbG8gd29ybGQ=') AS bytes;
SELECT decode(from_base64('aMOpbGxv')) AS text;
SELECT hex(from_base64('AAEC')) AS padding_optional;

तीसरी पंक्ति एक उम्मीद से ज़्यादा दयालु नियम दिखाती है: जब लंबाई चार का गुणज हो, तो पैडिंग का न होना कोई मुश्किल नहीं है, AAEC बखूबी बाइट्स 00 01 02 में डिकोड हो जाता है। सख़्ती तब दिखती है जब शक्ल ग़लत हो। DuckDB को चार का गुणज लंबाई चाहिए, बात ख़त्म, और कन्वर्ज़न एरर बिल्कुल यही कहता है:

SELECT from_base64('YWJ');
-- Conversion Error: Could not decode string "YWJ" as base64: length must be a multiple of 4

और दो राय हैं जिनका सम्मान करना ज़रूरी है। पहली, DuckDB का डिकोडर बस स्टैंडर्ड वर्णमाला बोलता है; अंडरस्कोर कोई ऐसा अक्षर नहीं जो यह पहचाने, इसलिए URL-safe टोकन्स को पहुँचने से पहले अनुवादित करना पड़ता है (रेसिपी URL-safe सेक्शन में है)। दूसरी, इसमें व्हाइटस्पेस के लिए बिल्कुल ही कोई सहनशीलता नहीं है। MIME-रैप्ड ईमेल एटैचमेंट, जिसके अंदर 76-अक्षरों की लाइन ब्रेक्स हों, फेल हो जाएगा, और दवा कॉल से पहले न्यूलाइन और कैरेज रिटर्न पर replace() चला देना है। और क्योंकि झटके को नरम करने के लिए कोई try_ वैरिएंट नहीं है, दयालु पैटर्न उसी क्वेरी में एक प्री-चेक है:

SELECT CASE
         WHEN b64 ~ '^[A-Za-z0-9+/]*={0,2}$'
          AND MOD(LENGTH(b64), 4) = 0
         THEN from_base64(b64)
       END AS maybe_bytes
FROM attachments;

पहले regex, फिर डिकोडर: क्वेरी किसी भी ऐसी चीज़ के लिए NULL लौटाती है जो कभी डिकोड न हो सकती, और डिकोडर को सिर्फ़ सही शक्ल वाला इनपुट दिखता है।

ClickHouse: कॉलम डिकोडर

ClickHouse का कोई अलग बाइनरी टाइप नहीं है; उसका String बखूबी बाइनरी-सेफ़ है, जिसका मतलब है कि स्ट्रिंग में डिकोड करना ही पूरा काम है, और पीछे कोई कन्वर्ज़न स्टेप नहीं आता। यह फ़ंक्शन वर्ज़न 18.16.0 (2018) से base64Decode() नाम के साथ चला आ रहा है, और साथ में MySQL स्टाइल का एलियास, FROM_BASE64(), भी है, ताकि पोर्ट की गई क्वेरीज़ को रीराइट करने की ज़रूरत न पड़े।

SELECT base64Decode('aGVsbG8gd29ybGQ=') AS text;
SELECT tryBase64Decode('definitely not base64') AS gentle;
SELECT base64URLDecode('aHR0cHM6Ly9jbGlja2hvdXNlLmNvbQ') AS url;

दूसरी पंक्ति ClickHouse की घर की स्टाइल को अमल में दिखाती है। इंजन को अपना try प्रीफ़िक्स बेहद प्यारा है: tryBase64Decode() फ़ेल्यूयर को निगल लेता है और ख़ाली स्ट्रिंग लौटाता है, जबकि सादा base64Decode() एक एक्सेप्शन फेंकता है, कोड INCORRECT_DATA के साथ, और मैसेज में दोषी वैल्यू का नाम होता है। अगर ख़राब रो को पाइपलाइन रोकनी चाहिए तो सादा फ़ॉर्म चुनिए, और अगर रिपोर्ट आगे बढ़नी चाहिए तो try फ़ॉर्म - और यह चुनाव जानबूझकर कीजिए, बेख़बरी में नहीं।

दो वर्ज़न नोट्स, क्योंकि ClickHouse तेज़ चलता है। 26.7 से पहले, इनपुट का व्हाइटस्पेस रिजेक्ट होता था; 26.7 से आगे, स्पेस, टैब, लाइन फ़ीड, कैरेज रिटर्न और फ़ॉर्म फ़ीड - सब नज़रअंदाज़ हो जाते हैं, और यही वह व्यवहार है जो ईमेल या टेक्स्ट एडिटर को छूने वाली हर चीज़ के लिए चाहिए। और आधुनिक डिकोडर अपने चार-अक्षर समूहों पर सही पैडिंग की उम्मीद रखता है, इसलिए कोई टोकन जो रास्ते में अपने बराबर निशान खो बैठा, बेस्ट-इफ़र्ट के बजाय एक्सेप्शन बन जाएगा। अगर कोई क्वेरी जो 2023 में चलती थी 2026 में फेंकने लगती है, तो डेटा को दोषी ठहराने से पहले सर्वर वर्ज़न देखिए।

Oracle: RAW, वरना कुछ नहीं

Oracle की base64 मशीनरी UTL_ENCODE PL/SQL पैकेज में बसती है, और उसका अपना अपना स्वभाव है: यह RAW लेता है और RAW लौटाता है, और कुछ और नहीं। टेक्स्ट अंदर नहीं, टेक्स्ट बाहर नहीं। VARCHAR2 कैरेक्टर डेटा है, जिससे कैरेक्टर सेट जुड़ा होता है; RAW कच्चे बाइट्स हैं; और पैकेज नक़ल करने से इनकार कर देता है कि वहाँ कुछ और भी हो। इसलिए काम की शक्ल एक तीन-तह की सैंडविच है: RAW में cast, डिकोड, फिर वापस टेक्स्ट में cast:

SELECT UTL_RAW.CAST_TO_VARCHAR2(
         UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW('aGVsbG8gd29ybGQ='))
       ) AS restored
FROM DUAL;

हर स्टेप अपनी जगह कमाता है। UTL_RAW.CAST_TO_RAW() टेक्स्ट के बाइट्स को RAW के रूप में दोबारा समझता है (डेटाबेस कैरेक्टर सेट में, जो आधुनिक डेप्लॉयमेंट में आमतौर पर AL32UTF8 होता है, इसलिए आपका UTF-8 इनपुट जैसे का वैसे ही सफ़र करता है)। UTL_ENCODE.BASE64_DECODE() असली काम करता है। और UTL_RAW.CAST_TO_VARCHAR2() रिज़ल्ट के बाइट्स को उसी डेटाबेस कैरेक्टर सेट में टेक्स्ट के रूप में दोबारा समझता है। किसी भी तह को छोड़िए और आपको टाइप-मिस्मैच एरर मिलेगा, जो कि Oracle का अपना फ़र्ज़ है - ख़ुलासा रहना।

इनवलुड इनपुट चुप NULL के बजाय PL/SQL एक्सेप्शन उठाता है, इसलिए बैच डिकोडिंग का घर किसी एक्सेप्शन हेंडलर के अंदर होना चाहिए जो दोषी रो को लॉग करे। पैकेज में साथियों के डिकोडरों का पूरा म्यूज़ियम भी है: MIME हेडर डिकोडिंग, quoted-printable, uudecode, टेक्स्ट एन्कोडिंग - सब उसी दौर के। आप ज़्यादातर base64 जोड़ी ही इस्तेमाल करेंगे, पर पड़ोसी समझाते हैं कि पैकेज इस तरह क़ायम क्यों है: Oracle चाहता था कि "ट्रांसपोर्ट के कपड़े पहने डेटा" का एक ही घर हो।

शुरू करने से पहले एक साइज़ ट्रैप जान लीजिए। साधारण SQL में, एक RAW वैल्यू की सीमा 2000 बाइट्स है, इसलिए वह base64 वैल्यू जो करीब 1500 कच्चे बाइट्स से ज़्यादा में डिकोड हो, एक ही SELECT स्टेटमेंट से बिल्कुल भी डिकोड नहीं हो सकती। बड़े पेलोड्स को PL/SQL लूप चाहिए, जो BLOB को 2000 (या कम) बाइट्स के चंक्स में पढ़े, हर टुकड़ा डिकोड करे, और रिज़ल्ट्स को फिर से जोड़ दे। यह पुराने स्कूल की बात है, पर यही Oracle का स्टैंडर्ड जवाब है, और यह उन जगहों में से एक है जहाँ भाषा की 1990s की टाइप सिस्टम अभी भी आपकी 2020s की क्वेरीज़ को गढ़ती है।

Snowflake: अपनी वर्णमाला साथ लाइए

Snowflake अपने बाइनरी टाइप (BINARY) को टेक्स्ट टाइप्स से अलग रखता है, और यह इस परिवार का सबसे कॉन्फ़िगर करने लायक़ डिकोडर देता है। कर्मठ है BASE64_DECODE_BINARY(input), जो BINARY लौटाता है, और वैकल्पिक दूसरा आर्ग्यूमेंट एक छोटी सी स्ट्रिंग है जो वर्णमाला को दोबारा परिभाषित करती है:

SELECT BASE64_DECODE_BINARY('aGVsbG8gd29ybGQ=') AS bytes;
SELECT TO_VARCHAR(BASE64_DECODE_BINARY('aMOpbGxv'), 'UTF-8') AS text;
SELECT TO_VARCHAR(BASE64_DECODE_BINARY('aHR0cHM6Ly9jbGlja2hvdXNlLmNvbQ', '-_'), 'UTF-8') AS url_safe;

उस वर्णमाला आर्ग्यूमेंट को ध्यान से पढ़िए, क्योंकि यह पोज़िशनल है। ज़्यादा से ज़्यादा तीन अक्षर माने जाते हैं: पहले दो वर्णमाला की जगहों 62 और 63 को ओवरराइड करते हैं (डिफ़ॉल्ट + और / हैं), और तीसरा पैडिंग अक्षर को ओवरराइड करता है (डिफ़ॉल्ट =)। "URL-safe वर्णमाला इस्तेमाल करो" कहने के लिए आप '-_' पास करते हैं। "URL-safe वर्णमाला, पर पैडिंग % से करो" कहने के लिए आपको तीनों अक्षर पास करने पड़ते हैं, '-_%', भले ही आप असल में सिर्फ़ पैडिंग अक्षर बदलना चाहते हों। अक्षर छोड़िए तो डिफ़ॉल्ट बरकरार रहते हैं; आप कोई जगह छोड़कर अगली भरी नहीं सकते।

दो साथी इससेट को पूरा करते हैं। BASE64_DECODE_STRING() डिकोड और टेक्स्ट कन्वर्ज़न एक ही कॉल में कर देता है, ताकि पेलोड टेक्स्ट हो तो आप TO_VARCHAR() से बच सकें। और TRY_ वैरिएंट्स, TRY_BASE64_DECODE_BINARY() और TRY_BASE64_DECODE_STRING(), ख़राब वैल्यू पर एरर उठाने के बजाय NULL लौटाते हैं, जो कि ClickHouse के try फ़ॉर्म का Snowflake संस्करण है।

बाइट्स से टेक्स्ट: कैरेक्टर सेट स्टेप

डिकोडिंग आपको बाइट्स सौंपता है। अगर पेलोड एक दस्तावेज़, नाम, या JSON टुकड़ा है, तो आपको एक और स्टेप देना है: एक नामित कैरेक्टर सेट में टेक्स्ट के रूप में तफ़सीर। यहीं से "टूट तो गया पर ग़लत दिखता है" निकलता है, क्योंकि बाइट्स की सिक्वेंस तभी शब्दों में बदलती है जब आप कह दें कि आप बाइट्स की कौन-सी भाषा पढ़ रहे हैं। टेबल छोटी है और याद रखने लायक़ है:

डायलैक्ट बाइट्स से टेक्स्ट इनवलुड सिक्वेंस
MySQL / MariaDB CONVERT(bin USING utf8mb4) दोबारा समझाया गया; कचरा अंदर, कचरा बाहर
PostgreSQL convert_from(bytes, 'UTF8') एरर उठाता है
SQL Server CAST(bin AS VARCHAR) लॉसी, कोलेशन पर निर्भर
Oracle UTL_RAW.CAST_TO_VARCHAR2(raw) डेटाबेस कैरेक्टर सेट में दोबारा समझाया जाता है
DuckDB decode(blob) कन्वर्ज़न एरर
ClickHouse ज़रूरत नहीं; String ही टेक्स्ट है n/a
Snowflake TO_VARCHAR(bin, 'UTF-8') एरर उठाता है
SQLite CAST(blob AS TEXT) बिल्कुल वैलिडेशन नहीं

यह फैलाव जानबूझकर चौड़ा है। PostgreSQL और DuckDB वैलिडेट करके मना करते हैं, जो आपके डाउनस्ट्रीम कोड को मोजिबेक से बचाता है। MySQL और Oracle चुपचाप दोबारा समझ लेते हैं, जो तेज़ है, पर इसका मतलब यह है कि डेटाबेस आपको उस Latin-1 पेलोड से नहीं बचा सकता जो UTF-8 दुनिया में आया हो। SQLite तो देखते ही नहीं, क्योंकि SQLite में TEXT वैल्यू बस टैग वाली बाइट्स हैं। प्रैक्टिकल नियम: कैरेक्टर सेट डिकोड करने से पहले तय कर लीजिए, उसे क्वेरी में लीटरल के रूप में लिखिए, और एक ऐसे पेलोड से टेस्ट कीजिए जिसमें कोई non-ASCII अक्षर हो (क्लासिक aMOpbGxv, जो héllo के लिए है, एक अच्छा कैनेरी है, क्योंकि यह हर ग़लत कैरेक्टर सेट में अलग तरह टूटता है)। सच में बाइनरी पेलोड्स के लिए, इस सेक्शन को बिल्कुल छोड़ दें और बाइट्स को बाइट्स की तरह ही रखिए।

JWT: कॉलम में तीन बिंदुओं की Base64

JSON Web Tokens सबसे आम base64 है, जो डेटाबेस में बैठा मिलेगा, क्योंकि ऑथेंटिकेशन इवेंट्स अपने टोकन्स के साथ लॉग होते हैं। JWT तीन बिंदु-अलग टुकड़ों से बँता है: एक हेडर, एक पेलोड, और एक साइनेचर। पहले दो JSON ऑब्जेक्ट्स हैं, जो base64 के रूप में पैक हैं, और यहीं वह मोड़ है जो लोगों को फँसाता है: JWT पैडिंग के बिना URL-safe वर्णमाला इस्तेमाल करते हैं, पैडिंग वाली स्टैंडर्ड शक्ल नहीं। / से एक नया पैथ सेगमेंट शुरू हो सकता है, जहाँ टोकन्स अक्सर सफ़र करते हैं, + को क्वेरी स्ट्रिंग में स्पेस की तरह पढ़ लिया जाता है, और पैडिंग के बराबर निशान बस औपचारिकता बन जाते, इसलिए स्पेसिफिकेशन (RFC 7515 और RFC 7519) ने - और _ पर स्विच किया और पैडिंग ही हटा दी।

इसलिए SQL में टोकन डिकोड करना चार-कदमी नृत्य है: बिंदुओं पर बँटो, URL-safe अक्षरों को वापस स्टैंडर्ड वर्णमाला में बदलो, पैडिंग वापस लाओ, और JSON को डिकोड करके पार्स करो। PostgreSQL, जिसके पास JSONB टाइप है, इसे करने का आरामदेह ठिकाना है:

WITH parts AS (
  SELECT split_part('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldiBVc2VyIiwiaWF0IjoxNTE2MjM5MDIyfQ.pDDL2Ljz7cK7vo9Ne4sMFMec1JMhasDUWa82vl-fYsw', '.', 1) AS header_b64,
         split_part('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldiBVc2VyIiwiaWF0IjoxNTE2MjM5MDIyfQ.pDDL2Ljz7cK7vo9Ne4sMFMec1JMhasDUWa82vl-fYsw', '.', 2) AS payload_b64
)
SELECT convert_from(
         decode(replace(replace(payload_b64, '-', '+'), '_', '/')
           || CASE MOD(LENGTH(payload_b64), 4)
                 WHEN 2 THEN '=='
                 WHEN 3 THEN '='
                 ELSE '' END,
           'base64'),
         'UTF8')::jsonb AS claims
FROM parts;

रिज़ल्ट एक JSONB वैल्यू है, जिसे आप किसी भी दूसरे कॉलम की तरह क्वेरी कर सकते हैं, और ऊपर वाले टोकन के लिए यह वापस {"iat": 1516239022, "sub": "1234567890", "name": "Dev User"} के रूप में आता है। रिज़ल्ट से एक क्लेम निकालना बस आगे की क्वेरी में claims->>'sub' है। पैडिंग की बहाली वही CASE एक्सप्रेशन है: base64url स्ट्रिंग जिसकी लंबाई चार के गुणज से दो कम हो, उसे दो बराबर निशान चाहिए, तीन कम होने पर एक, और ठीक गुणज होने पर कोई नहीं।

एक कदम और आगे बढ़िए और आप SQL में HS256 साइनेचर को वेरिफ़ाई भी कर सकते हैं, HMAC के लिए PostgreSQL के pgcrypto एक्सटेंशन से (अगर पहले से इंस्टॉल नहीं है, तो एक बार CREATE EXTENSION IF NOT EXISTS pgcrypto; से चालू करें)। साझा सीक्रेट के साथ header.payload पर साइनेचर दोबारा निकालो, उसे उसी base64url शक्ल में डालो, और तुलना करो:

WITH parts AS (
   SELECT split_part('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldiBVc2VyIiwiaWF0IjoxNTE2MjM5MDIyfQ.pDDL2Ljz7cK7vo9Ne4sMFMec1JMhasDUWa82vl-fYsw', '.', 1) AS header_b64,
          split_part('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldiBVc2VyIiwiaWF0IjoxNTE2MjM5MDIyfQ.pDDL2Ljz7cK7vo9Ne4sMFMec1JMhasDUWa82vl-fYsw', '.', 2) AS payload_b64
 )
 SELECT rtrim(replace(replace(
          encode(hmac((header_b64 || '.' || payload_b64)::bytea,
                      'sql-secret-key'::bytea, 'sha256'), 'base64'),
            '+', '-'),
            '/', '_'),
          '=') = 'pDDL2Ljz7cK7vo9Ne4sMFMec1JMhasDUWa82vl-fYsw' AS valid
 FROM parts;

hmac() कॉल डिजस्ट बनाता है, encode(..., 'base64') उसे पैक करता है, और तीन स्ट्रिंग ऑपरेशन्स उसे उस पैडिंग-रहित URL-safe शक्ल में ढालते हैं जो टोकन धारण करता है। ऊपर वाले टोकन और सीक्रेट के लिए, जवाब एक ख़ुशमिज़ाज t है। पर सावधानियाँ भी साथ रखिए: यह सिर्फ़ HMAC एल्गोरिद्म (HS256, HS384, HS512) के लिए काम करता है, साझा सीक्रेट को डेटाबेस स्टेटमेंट के अंदर रखता है, और यह रिपोर्टिंग, ऑडिटिंग और डिबगिंग के लिए बना है। जो कुछ असल में एक्सेस का गेट करता है, उसे असली JWT लाइब्रेरी से एप्लिकेशन लेयर में वेरिफ़ाई करना चाहिए।

Data URLs: स्ट्रिंग के अंदर की इमेज

Data URL फ़ॉर्मेट (RFC 2397) वेब का तरीका है फ़ाइल को लिंक के अंदर इनलाइन करने का: data:image/png;base64, और उसके बाद फ़ाइल का base64। ब्राउज़र उन्हें क्लिपबोर्ड से पेस्ट करते हैं, सिंगल-पेज ऐप्स छोटी इमेजेज़ उनमें एम्बेड करती हैं, और उनमें से हर एक फ़्लो अंत-तः डेटाबेस कॉलम में लंबी टेक्स्ट वैल्यू बनकर उतरता है। फ़ॉर्मेट है data:{media type}[;{parameters}][;base64],{data}, और डिकोडिंग के लिए अहम वही हिस्सा है जो पहले कॉमा के बाद आता है, क्योंकि वहाँ base64 पेलोड शुरू होता है।

SELECT uri,
       CAST(FROM_BASE64(SUBSTRING(uri, LOCATE(',', uri) + 1)) AS BINARY) AS png_bytes
FROM uploads
WHERE uri LIKE 'data:image/png;base64,%';

MySQL में यही पूरा काम है: कॉमा ढूँढो, उसके पार जाओ, डिकोड करो, और अब आपकी पकड़ में इमेज के बाइट्स हैं एक बाइनरी एक्सप्रेशन में, जिसे आप BLOB कॉलम में स्टोर कर सकते हैं या डीडुप्लिकेशन के लिए हैश कर सकते हैं। दूसरे डायलैक्ट्स फ़ंक्शन बदल देते हैं (ज़्यादातर में SUBSTR() और INSTR(), कुछ में substring() और position()), पर शक्ल वही रहती है।

तीन वार्निंग्स। पहली, हर data URL base64 नहीं होता; ;base64 मार्कर के बिना data URL पर्सेंट-एन्कोडेड टेक्स्ट धारण करता है, और उसे base64 डिकोडर में डालना वह ग़लती है जो ऊपर वाला LIKE फ़िल्टर रोकने के लिए मौजूद है। दूसरी, प्रीफ़िक्स में मीडिया टाइप एक दावा है, तथ्य नहीं; वही स्ट्रिंग image/png कह सकती है और अंदर JPEG हो। अगर कंटेंट मायने रखता है, तो डिकोडेड रिज़ल्ट के मैजिक बाइट्स जाँचिए (PNG 89 50 4E 47 से शुरू होता है, JPEG FF D8 से)। तीसरी, data URLs बड़े होते हैं। 4-मेगापिक्सेल फ़ोटो करीब 5.5-मेगाबाइट स्ट्रिंग बन जाती है, जो कॉलम-साइज़ और मेमोरी की बातचीत है, स्ट्रिंग-फ़ंक्शन की नहीं।

URL-safe Base64: वह वर्णमाला जो सफ़र करती है

RFC 4648 की सेक्शन 5 ने base64 के लिए दूसरी वर्णमाला परिभाषित की, क्योंकि मूल वर्णमाला में दो ऐसे अक्षर हैं जिनके URL सिंटैक्स में अपने काम हैं। प्लस निशान क्वेरी पैरामीटर्स के वैल्यू जोड़ने का काम करता है, स्लैश पैथ्स को अलग करने का, और पैडिंग के बराबर निशान का पर्सेंट-एन्कोडिंग उसी पल हो जाती है जब वह क्वेरी स्ट्रिंग से मिलता है। URL-safe वैरिएंट + की जगह - और / की जगह _ रखता है (दोनों URL में बेज़ारह), और JWT स्पेसिफिकेशन उस पर पैडिंग बिल्कुल ही हटाने देता है। रिज़ल्ट लिंक्स, पैथ सेगमेंट्स, फ़ाइल-नेम और फ़्रैगमेंट आइडेंटिफ़ायर्स से बिना एक भी पर्सेंट निशान के सफ़र करता है।

आप इसे डेटाबेस में ज़्यादातर इसलिए मिलेंगे क्योंकि टोकन्स और लिंक्स यहाँ स्टोर किए गए, इसलिए नहीं कि डेटा यहाँ पैदा हुआ हो। यहाँ देखिए कि कौन इसे नेटिव तरीक़े से संभाल सकता है और कौन को दो मिनट की मैन्युअल चाहिए:

डायलैक्ट नेटिव URL-safe डिकोडिंग नोट्स
SQL Server 2025+ BASE64_DECODE() दोनों वर्णमालाओं को स्वीकार करता है अनुवाद की बिल्कुल ज़रूरत नहीं
ClickHouse 24.6+ base64URLDecode() + और / को भी स्वीकार करता है
Snowflake BASE64_DECODE_BINARY(s, '-_') वर्णमाला पोज़िशनल आर्ग्यूमेंट के रूप में
MySQL / MariaDB कोई नहीं अक्षरों का अनुवाद कीजिए, फ़ेल्यूयर पर NULL की उम्मीद रखिए
PostgreSQL कोई नहीं अक्षरों का अनुवाद कीजिए, फ़ेल्यूयर पर एरर की उम्मीद रखिए
Oracle कोई नहीं RAW cast से पहले अक्षरों का अनुवाद कीजिए
DuckDB कोई नहीं (अंडरस्कोर रिजेक्ट करता है) अक्षरों का अनुवाद कीजिए, लंबाई चार का गुणज रखिए
SQLite CLI कोई नहीं अक्षरों का अनुवाद कीजिए; डिकोडर जो नहीं जानता उसे छुड़ा देता है

मैन्युअल दो REPLACE() कॉल और पैडिंग की बहाली है, और यह हर डायलैक्ट पर वही है। PostgreSQL में यह ऐसे पढ़ा जाता है:

SELECT convert_from(
         decode(replace(replace('aGVsbG8', '-', '+'), '_', '/')
           || CASE MOD(LENGTH('aGVsbG8'), 4)
                 WHEN 2 THEN '=='
                 WHEN 3 THEN '='
                 ELSE '' END,
           'base64'),
         'UTF8') AS text;

- को वापस + में बदलो, _ को वापस / में बदलो, लंबाई के modulo 4 के हिसाब से ग़ायब पैडिंग जोड़ो, और वहाँ से स्टैंडर्ड डिकोडर काम सँभाल लेता है। इनपुट aGVsbG8 ("hello" का पैडिंग-रहित URL-safe रूप) उसी शब्द के रूप में वापस आता है। दो ग़लतियाँ जो बार-बार होती हैं, वही हैं जो CASE एक्सप्रेशन रोकता है: पैडिंग भूल जाना, जिससे सख़्त डिकोडर चार का गुणज न होने वाली लंबाई को रिजेक्ट करते हैं, और अक्षरों के अनुवाद को छोड़ देना, जिससे URL-safe वर्णमाला न जाने वाला डिकोडर अंडरस्कोर पर दम तोड़ देता है। अनुवाद एक बार लिखो, अपने डेटाबेस में रियूज़ेबल फ़ंक्शन के रूप में, और पूरा मुद्दा दोहराना बंद हो जाएगा।

फ़ाइलें, ब्लॉब्स और बड़ी चीज़ें

डिकोडिंग ही वह रास्ता है जिससे फ़ाइलें कॉलम से बाहर आती हैं, और हर डायलैक्ट का निकलने का रास्ता थोड़ा अलग है। DuckDB में राउंड ट्रिप दो स्टेटमेंट्स हैं, एक फ़ाइल को BLOB में पढ़ने की और एक डिकोडेड बाइट्स को वापस बाहर लिखने की:

SELECT filename, octet_length(content) AS size
 FROM read_blob('/data/uploads/*.png');

पढ़ने वाला पक्ष: read_blob() एक टेबल फ़ंक्शन है जो फ़ाइल नाम, नामों की लिस्ट, या ग्लोब पैटर्न स्वीकार करती है और हर फ़ाइल के लिए filename और content कॉलम लौटाती है। लिखने वाला पक्ष अपनी ही statement है: BLOB फ़ॉर्मेट के साथ COPY कच्चे बाइट्स लिखता है, कोई क्वोटींग नहीं, कोई एस्केपिंग नहीं, बिल्कुल वह जो डिकोडेड पेलोड को चाहिए।

COPY (SELECT from_base64(b64) FROM attachments WHERE id = 42)
 TO '/data/restored/cat.png' (FORMAT BLOB);

PostgreSQL का निकलने का रास्ता large object API है। large object सर्वर-साइड बाइनरी चंक स्टोरेज है, जिसका पता OID से जाता है, और lo_export() एक को डेटाबेस सर्वर पर फ़ाइल के रूप में लिख देता है। इसके लिए सुपरयूज़र अधिकार या pg_write_server_files प्रिविलेज चाहिए, और डिस्टिनेशन वह पैथ होना चाहिए जिस पर सर्वर प्रोसेस लिख सके, इसलिए असलियत में यह मेइन्टेनेंस स्क्रिप्ट्स का काम है, एप्लिकेशन कोड का नहीं:

SELECT lo_export(12345, '/tmp/attachments/cat.png');

MySQL के पास बस रिस्ट्रिक्टिव SELECT ... INTO DUMPFILE एस्केप हैच है (एक रो, सर्वर-साइड पैथ, FILE प्रिविलेज), और SQL Server के पास साधारण-SQL फ़ाइल राइटर बिल्कुल नहीं है (डिस्क पर लिखना क्लाइंट या एजेंट का काम है, उसके एक्सपोर्ट टूलिंग के ज़रिए), जो एक न्यायसंगत डिज़ाइन है: डेटाबेस बाइट्स स्टोर करता है, एप्लिकेशन तय करता है कि फ़ाइल कहाँ रखनी चाहिए। SQLite स्पेक्ट्रम के दूसरे छोर पर बैठा है, जहाँ एप्लिकेशन खुद होस्ट है, और होस्ट लैंगुएज के एक कॉल में BLOB कॉलम सीधे डिस्क पर लिखा जा सकता है।

फिर हैं सीमाएँ, जो उन डेटाबेस से ज़्यादा अलग-अलग हैं जो सब एक जैसे होने का दिखावा करते हैं:

डायलैक्ट बाइनरी टाइप प्रैक्टिकल सीमा
PostgreSQL bytea हर वैल्यू के लिए 1 GB
MySQL / MariaDB BLOB family max_allowed_packet (MySQL 8 में डिफ़ॉल्ट 64 MB)
SQL Server varbinary(max) हर वैल्यू के लिए 2 GB
Oracle RAW / BLOB RAW: SQL में 2000 बाइट्स, BLOB: PL/SQL चंकिंग के साथ 4 GB
SQLite BLOB फ़ाइल और मेमोरी जितना दें
DuckDB BLOB बहुत बड़ा; मेमोरी और डिस्क तय करती हैं
ClickHouse String कॉलम साइज़ वर्चुअल है, रोएँ ही इकाई हैं
Snowflake BINARY डिफ़ॉल्ट हर वैल्यू के लिए 8 MB (सादा BINARY कॉलम); एक्सप्लिसिट BINARY(N) के साथ 64 MB तक

MySQL वाली रो एक कहानी का हक़ रखती है, क्योंकि वही है जो प्रोडक्शन में लोगों को चौंकाती है। max_allowed_packet क्लाइंट और सर्वर के बीच एक पैकेट का साइज़ सीमाबद्ध करता है, और base64 स्ट्रिंग उस पैकेट का हिस्सा है। 50-मेगाबाइट फ़ोटो का base64 करीब 67-मेगाबाइट स्ट्रिंग है, जो 64-मेगाबाइट डिफ़ॉल्ट से बड़ी है, और रिज़ल्ट वह एरर नहीं है जिसे आप क्वेरी में पढ़ सकें: यह ट्रंकेटेड या NULL वैल्यू है, जो डेटा करप्शन जैसी दिखती है। अगर आप बड़ी फ़ाइलें MySQL कॉलम से पार करवा रहे हैं, तो शुरू करने से पहले वह लीमिट जाँच लीजिए, और याद रखिए कि एन्कोडेड रूप, कच्चे बाइट्स नहीं, ही उस पर गिनता है।

ईमेल रैप्स और MIME लाइनें

जो base64 ईमेल सिस्टम से गुज़रकर बचा है, वह एक यादगार लाता है: लाइन ब्रेक्स। MIME, वह स्टैंडर्ड्स की टोली जो ईमेल को बाइनरी एटैचमेंट धारण करने देती है (RFC 2045, सेक्शन 6.8), base64 आउटपुट को 76 अक्षरों पर रैप करती है और लाइनों को एक कैरेज रिटर्न और एक लाइन फ़ीड से ख़त्म करती है। रैप इसलिए है क्योंकि पुराने ईमेल नेटवर्क उससे लंबी लाइनों पर भरोसा नहीं कर सकते थे, और तब से यह फ़ॉर्मेट आदत की तरह आगे आया है। इसलिए डेटाबेस कॉलम में स्टोर किया हुआ एटैचमेंट अक्सर base64 स्ट्रिंग होता है जिसमें हर 76 अक्षरों पर एक लाइन ब्रेक है, और आपका डिकोडर उन लाइन ब्रेक्स के साथ का रिश्ता तय करता है कि काम एक statement का है या दो का।

डिकोडर रैप निगलता है? अगर नहीं
MySQL / MariaDB FROM_BASE64() हाँ -
PostgreSQL decode() हाँ -
SQL Server BASE64_DECODE() हाँ -
SQLite CLI base64() हाँ -
ClickHouse 26.7+ हाँ -
ClickHouse 26.7 से पहले नहीं पहले व्हाइटस्पेस हटाइए
DuckDB from_base64() नहीं पहले व्हाइटस्पेस हटाइए
Oracle UTL_ENCODE.BASE64_DECODE() नहीं PL/SQL लेयर में व्हाइटस्पेस हटाइए

"पहले हटाओ" की दवा एक एक्सप्रेशन है, और हमेशा सेफ़ है, क्योंकि व्हाइटस्पेस base64 वर्णमाला का हिस्सा नहीं है: कोई काय़दा-मंद पेलोड स्पेस, टैब, या लाइन ब्रेक धारण नहीं कर सकता, इसलिए उन्हें हटाना जानकारी को नष्ट नहीं कर सकता। PostgreSQL में रिवाज़ एक ही regexp_replace() है:

SELECT decode(regexp_replace(attachment_b64, '\s', '', 'g'), 'base64')
FROM email_attachments;

हर व्हाइटस्पेस अक्षर, लाइन ब्रेक्स समेत, जाते हैं, और डिकोडर को एक साफ़, लगातार स्ट्रिंग दिखती है। DuckDB में इसे चलाइए (दोनों लाइन-ब्रेक अक्षरों पर उसके replace() के साथ) या 26.7 से पहले वाले ClickHouse में, और रैप्ड एटैचमेंट बिल्कुल अनरैप्ड जैसा डिकोड हो जाएगा।

API पेलोड्स, कॉन्फ़िग्स और ऑथ हेडर्स

अलग-अलग फ़ंक्शनों से पीछे हटिए और एक पैटर्न दिखता है: डेटाबेस कॉलम में base64 लगभग हमेशा तीन चीज़ों में से एक होता है। JSON दस्तावेज़ के अंदर एक फ़ील्ड (इमेज, सर्टिफ़िकेट, या वह फ़ाइल जिसे API ने इनलाइन करने का फ़ैसला किया)। एक कॉन्फ़िगरेशन वैल्यू (किसी सीक्रेट या क्रेडेंशियल को किसी टूल को base64 में ही पसंद है, क्योंकि base64 YAML फ़ाइल की एक लाइन पर ऐसे बसता है - कोई क्वाइट्स नहीं, कोई न्यूलाइन्स नहीं, कोई बैकस्लाश नहीं)। या एक ऑथेंटिकेशन आर्टिफैक्ट (Basic ऑथ हेडर, स्टोर टोकन, सेशन ब्लॉब)। यहाँ है हर एक, अपनी डिकोडिंग शक्ल के साथ।

JSON फ़ील्ड्स। JSON टेक्स्ट के रूप में आया, फ़ील्ड एक स्ट्रिंग है, और base64 उसके अंदर छुपा है। फ़ील्ड को अपने डायलैक्ट के JSON फ़ंक्शन से निकालिए, फिर डिकोड कीजिए। MySQL में पूरा चेन एक ही एक्सप्रेशन है:

SELECT event_id,
       CAST(FROM_BASE64(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.image'))) AS BINARY) AS image_bytes
FROM api_events
WHERE JSON_TYPE(JSON_EXTRACT(payload, '$.image')) = 'STRING';

PostgreSQL वही काम JSONB से करता है, जहाँ ->> ऑपरेटर से फ़ील्ड टेक्स्ट के रूप में बाहर आता है और decode() काम सँभाल लेता है। आख़िरी लाइन का JSON_TYPE गार्ड दिखने से ज़्यादा मायने रखता है: यह डिकोडर को उन रोओं से दूर रखता है जहाँ फ़ील्ड एक नंबर, नेस्टेड ऑब्जेक्ट, या ग़ायब है, और MySQL में वही रोएँ वरना आपके "कितने इवेंट्स में इमेज थी" के हिसाब में चुपचाप NULL डाल देतीं।

ऑथेंटिकेशन हेडर्स। Basic ऑथ हेडर लीटरल स्ट्रिंग Basic है, जिसके बाद username:password का base64 आता है। इसे SQL में डिकोड करना एक सबस्ट्रिंग और एक स्प्लिट है, और यही वजह है कि लोग ऐसा करते हैं (आमतौर पर यह ऑडिट करने के लिए कि कौन-से यूज़र्स कौन-से एंडपॉइंट्स छूते हैं, पासवर्ड वेरिफ़ाई करने के लिए नहीं, जो डेटाबेस को कभी क्लिअरटेक्स्ट में नहीं देखना चाहिए):

SELECT request_id,
       SUBSTRING_INDEX(CAST(FROM_BASE64(SUBSTRING(header_value, 7)) AS CHAR), ':', 1) AS username,
       SUBSTRING_INDEX(CAST(FROM_BASE64(SUBSTRING(header_value, 7)) AS CHAR), ':', -1) AS secret
FROM http_log
WHERE header_name = 'Authorization'
  AND header_value LIKE 'Basic %';

SUBSTRING(header_value, 7) Basic प्रीफ़िक्स उतार देता है, डिकोडर मूल टेक्स्ट बहाल करता है, और दो SUBSTRING_INDEX() कॉल उसे कॉलन पर बँटा देते हैं, पहला हिस्सा यूज़र के लिए, आख़िरी हिस्सा सीक्रेट के लिए। PostgreSQL में वही क्वेरी substring() और split_part() इस्तेमाल करती है।

कॉन्फ़िगरेशन वैल्यूज़। यहाँ डिकोड दिशा ऑडिट जॉब है: किसी ने कॉन्फ़िग टेबल में सीक्रेट को base64 के रूप में स्टोर किया (Kubernetes से मिली आदत, जहाँ सीक्रेट वैल्यूज़ rest की स्थिति में base64 होती हैं), और आप देखना चाहते हैं कि अंदर असल में क्या है, या आप वह एक्सपोर्ट बना रहे हैं जो नया एनवायरनमेंट ख़पेगा। शक्ल है हर वैल्यू के लिए एक SELECT, और अगर वैल्यू टेक्स्ट है तो कैरेक्टर सेट स्टेप लागू होता है:

SELECT name,
       CONVERT(FROM_BASE64(value) USING utf8mb4) AS plaintext
FROM app_config
WHERE name LIKE '%_secret%';

उस रिज़ल्ट के साथ उतनी ही सावधानी बरतिए जितनी वह माँगता है। आपने बस स्टोर सीक्रेट्स को दिखने वाली क्वेरी आउटपुट में बदल दिया; सुनिश्चित कीजिए कि क्वेरी चलाने वाला अकाउंट बस उतने ही अधिकारों वाला है जितने चाहिए, रिज़ल्ट लॉग में कॉपी न हो, और कॉन्फ़िग में base64 की आदत को एक और दृष्टि दी जाए। Base64 ट्रांसपोर्ट है, ख़ज़ाना नहीं, और ऑडिट क्वेरी वही पल है जब यह साफ़ दिखने लगता है।

वे पिटफ़ॉल्स जो काटते हैं

इस लिस्ट का हर पिटफ़ॉल कम से कम एक कोडबेस में दोपहर भर का है, और हर एक SQL डायलैक्ट्स के base64 संभालने के तरीके का है, base64 खुद का नहीं।

  • चुप NULL। MySQL और MariaDB ख़राब इनपुट को शिकायत किए बिना NULL में डिकोड कर देते हैं। ऐसी रिपोर्ट में जो डिकोडेड वैल्यू पर जॉइन करती है, वहाँ वही रोएँ बस ग़ायब हो जाती हैं, और "0 रो" व "0 रो, क्योंकि उनमें से 14 ज़हरीली थीं" का फ़र्क़ तब तक अदृश्य रहता है जब तक कोई पूछ न उठाए कि हिसाब क्यों नहीं बँटता। अगर आपका डिकोडर चुपकाट वाला है, तो अपने NULLs को जानबूझकर गिनिए।
  • चार-का-गुणज नियम, असमान रूप से लागू। लंबाई चार का गुणज न हो, वह स्ट्रिंग base64 नहीं है, पर डायलैक्ट्स कर क्या जाएं उस पर, इसमें आपस में मतभेद रखते हैं: PostgreSQL एरर उठाता है, DuckDB कन्वर्ज़न एरर, ClickHouse एक्सेप्शन, MySQL NULL लौटाता है, और SQLite CLI चुपचाप जो कर पाता है वही डिकोड करता है। वही डेटा फ़ाइल पाँच डेटाबेस पर पाँच अलग-अलग नतीजे देती है, और इसीलिए "Postgres में चला था" कोई टेस्ट नहीं है।
  • वर्णमाला का मेल न होना। URL-safe टोकन (JWT, लिंक, फ़ाइल-नेम) को स्टैंडर्ड-वर्णमाला वाले डिकोडर में डालना: SQL Server स्वीकार करता है, ClickHouse का base64URLDecode() स्वीकार करता है, Snowflake सही आर्ग्यूमेंट के साथ स्वीकार करता है, और बाकी हर कोई या तो NULL लौटाता है, एरर उठाता है, या - SQLite CLI की तरह - अंडरस्कोर चुपचाप गिराकर ग़लत बाइट्स सौंप देता है। ग़लत-बाइट्स वाला मामला ही ख़राब वाला है, क्योंकि नतीजा सही जैसा दिखता है।
  • MIME रैप। रैप की गई इनपुट को ऐसे डिकोडर में डालना जो लाइन ब्रेक्स नहीं निगलता (DuckDB, 26.7 से पहले वाला ClickHouse, Oracle) फेल होता है, और फ़ेल्यूयर अक्सर ऐसा दिखता है कि "आख़िरी 76 अक्षर कचरा हैं", न कि "यहाँ एक न्यूलाइन है", क्योंकि एरर ब्रेक के बाद वाले अक्षर की ओर इशारा करता है।
  • डिस्प्ले ट्रिक। mysql क्लाइंट बाइनरी को हेक्स में प्रिंट करता है, psql bytea को \x-हेक्स में, Snowflake BINARY को हेक्स में, और Oracle RAW को हेक्स में। चार क्लाइंट्स, चार हेक्स नोटेशन, और एक बहुत ही इंसानी ग़लती कि स्क्रीन पर अंक दिख रहे हैं, इसलिए डेटा ख़राब हो गया है। आँखों से रिज़ल्ट पढ़ने से पहले हमेशा एक्सप्लिसिट रूप से कन्वर्ट कीजिए।
  • ग़लत जगह पैडिंग। बराबर निशान सिर्फ़ आख़िर में जायज़ है, एक या दो। YQ==BQ== जैसी स्ट्रिंग दो वैलिड समूह हैं जो एक कपड़े में बँटे हैं, सख़्त डिकोडर इसे रिजेक्ट करते हैं, जबकि लीनेंट वाले इसे किसी के नहीं माँगे हुए किसी चीज़ में डिकोड कर देते हैं। अगर स्टोर वैल्यू के बीच में कभी पैडिंग दिखे, तो जिस एन्कोडर ने उसे लिखा था, वह ख़राब है, और डेटा ठीक करना एक बार का काम है।
  • कैरेक्टर सेट की चौंकाने वाली बात। डिकोडिंग सफल होती है, टेक्स्ट वापस आता है, और एक्सेंट ग़लत हैं। बाइट्स ठीक थे; तफ़सीर नहीं थी। यही वह CONVERT(... USING latin1) है जो utf8mb4 होना चाहिए था, यही वह CAST(bin AS VARCHAR) है जो ऐसे कोलेशन में चला था जो इनवलुड सिक्वेंस निगल लेता है, और SQLite का वह CAST(blob AS TEXT) जो कभी जाँच ही नहींता। क्वेरी में कैरेक्टर सेट को लीटरल के रूप में पिन कीजिए, और एक्सेंटेड कैनेरी से टेस्ट कीजिए।
  • सीमाएँ। Oracle की SQL स्टेटमेंट्स में 2000-बाइट RAW लीमिट, MySQL का max_allowed_packet जो एन्कोडेड साइज़ पर कर लेता है, PostgreSQL की 1-GB bytea सीमा, Snowflake की 8-MB डिफ़ॉल्ट BINARY लंबाई। हर एक डॉक्यूमेंट है, हर एक प्रोडक्शन में मिलता है, और हर एक वह साइज़ चेक है जिसे आप डेटा बड़ा होने से पहले लिख सकते थे।
  • डिकोडेड बाइट्स पर भरोसा। Base64 कुछ भी धारण कर सकता है, क्वाइट्स से भरी स्ट्रिंग समेत। डिकोडिंग सैनिटाइज़िंग नहीं है। चाहे आप डिकोडेड टेक्स्ट के साथ क्या ही करें (तुलना, लॉग, दूसरे statement में जोड़ना), उसे वही साधारण रक्षा चाहिए, और base64 राउंड ट्रिप के बाद पैरामीटाइज़्ड क्वेरी वही पैरामीटाइज़्ड क्वेरी है।

सही पक्ष पर कैसे बनें

  • पहले टाइप तय कीजिए, फ़ंक्शन नहीं। क्या पेलोड बाइनरी है या टेक्स्ट? बाइनरी BLOB/bytea/varbinary में जाता है और वहीं रहता है। टेक्स्ट एक्सप्लिसिट एन्कोडिंग के साथ कैरेक्टर सेट स्टेप से गुज़रता है। SQL में base64 दर्द का आधा हिस्सा वह बाइनरी पेलोड है जो टेक्स्ट कॉलम में चली गई (या उल्टा) और अब इंटरप्रेट हो रहा है।
  • डिकोड से पहले वैलिडेट कीजिए, या नरम डिकोड कीजिए। वर्णमाला पर regex और लंबाई-modulo-four जाँच का कुछ ख़र्च नहीं है, और यह बैच-रोकने वाला एरर बदलकर NULL बना देता है जिसे आप गिन सकते हैं। जहाँ डायलैक्ट try फ़ॉर्म दे (ClickHouse का tryBase64Decode, Snowflake का TRY_BASE64_DECODE_BINARY), उसे रिपोर्टिंग के लिए इस्तेमाल कीजिए, और सख़्त फ़ॉर्म उन पाइपलाइन्स के लिए रखिए जो अनुमान नहीं लगा सकतीं।
  • डायलैक्ट का वर्ज़न-चेक कीजिए, सिर्फ़ डेटाबेस का नहीं। ClickHouse 26.7 ने व्हाइटस्पेस हांडलिंग बदली, SQL Server 2025 पहली रिलीज़ है जिसमें फ़ंक्शन है ही, SQLite CLI को 3.41 चाहिए, और ClickHouse की पैडिंग उम्मीदें समय के साथ सख़्त होती गईं। "यह ClickHouse है" कोई स्पेसिफिकेशन नहीं है; "यह ClickHouse 24.8 है" वह है।
  • हर कॉलम की वर्णमाला डॉक्यूमेंट कीजिए। वह कॉलम जिसमें स्टैंडर्ड और URL-safe दोनों base64 हो सकता है, वही कॉलम है जो अगले डेवलपर को भ्रमित करेगा। अगर डेटा JWTs से आ रहा है, तो स्कीमा कॉमेंट में कह दीजिए; अगर MIME एटैचमेंट्स से आ रहा है, तो वही कह दीजिए। डिकोडर चुनाव कॉलम की ख़ासियत है, क्वेरी की नहीं।
  • बाइट्स स्टोर कीजिए, किनारे पर एन्कोड कीजिए। अगर स्कीमा आपकी पकड़ में है, तो BLOB कॉलम और API लेयर में एन्कोडिंग, स्टोरेज के लिए, इंडेक्सिंग के लिए, और हर भविष्य की क्वेरी के लिए base64 टेक्स्ट कॉलम से बेहतर है। कॉलम में base64 एक कम्पैटिबिलिटी कर है, और कर एक बार चुकाना सबसे अच्छा है - किनारे पर।
  • कैनेरी के साथ राउंड-ट्रिप कीजिए। नए डिकोड पैथ पर भरोसा करने से पहले, एक ज्ञात पेलोड को उसी डेटाबेस में एन्कोड और डिकोड दोनों से गुज़ारिए और तुलना कीजिए। कैनेरी में एक non-ASCII अक्षर होना चाहिए (ताकि कैरेक्टर सेट स्टेप पर परख हो), एक ऐसी लंबाई जो पैडिंग पूँछ छोड़े (ताकि पैडिंग नियमों पर परख हो), और URL-safe पैथ्स के लिए कहीं - या _ (ताकि वर्णमाला अनुवाद पर परख हो)।
  • सीक्रेट्स को क्वेरी टेक्स्ट से दूर रखिए। pgcrypto से JWT वेरिफ़िकेशन साझा सीक्रेट को statement में रखता है; कॉन्फ़िग ऑडिट्स क्लिअरटेक्स्ट सीक्रेट्स को रिज़ल्ट में रखते हैं। दोनों जायज़ काम हैं, पर वे रिस्ट्रिक्टेड अकाउंट, साफ़ लॉग, और रिव्यू का हक़ रखते हैं, प्रोडक्शन कनेक्शन स्ट्रिंग और SELECT * INTO OUTFILE का नहीं।

SQL में अनपैकिंग का छोटा इतिहास

base64 फ़ॉर्मेट खुद इंटरनेट के कामकेदार हिस्से से पुराना है। इसे 1990s के मध्य MIME के लिए स्टैंडर्ड बनाया गया (RFC 2045, सेक्शन 6.8, जिसने RFC 1521 की जगह ले ली - 1993 की वह MIME message-body स्पेसिफिकेशन जिसमें वह एन्कोडिंग थी), और नाम बस एक गिनती है: वर्णमाला में 64 अक्षर हैं। URL-safe वैरिएंट 2006 में RFC 4648 के साथ आया, और 2015 की JWT स्पेसिफिकेशन ने वह वैरिएंट बना दिया जो आप टोकन कॉलम में असल में देखते हैं। पर डेटाबेसों ने हर एक ने फ़ॉर्मेट से अपने अपने स्केजूल पर मुलाक़ात की, और स्केजूल हर एक की आत्मा के बारे में कुछ कहता है।

2002। PostgreSQL 7.2 में base64 पहले से encode() और decode() का पहली-श्रेणी फ़ॉर्मेट है - Oracle के 9i दौर के UTL_ENCODE से समकालीन, और इस परिवार में बारीक अंतर से सबसे पुराना base64 सपोर्ट। एक डेटाबेस जिसके पास असली बाइनरी टाइप और फ़ॉर्मेट आर्ग्यूमेंट था, वह जल्दी पहुँच गया, क्योंकि जवाब एक इनिम वैल्यू दूर था।

2000s की शुरुआत। Oracle का UTL_ENCODE पैकेज 9i दौर में दिखा, base64 को MIME हेडर, quoted-printable और uuecode फ़ंक्शनों के बग़ल लेकर। RAW अंदर, RAW बाहर - जो बिल्कुल Oracle-जैसा है - और वह उसी शक्ल को एक चतुर्थांश सदी से बनाए हुए है।

2013। MySQL 5.6 ने TO_BASE64() और FROM_BASE64() जोड़े, और MariaDB 10.0 ने दोनों को फ़ॉर्क में ले लिया। जोड़ी 76-अक्षर लाइनों से एन्कोड करती है और व्हाइटस्पेस सहनशीलता के साथ डिकोड करती है, एक मेल खाता सेट जो दर्जन भर मेजर वर्ज़न्स से बदला नहीं।

2018। ClickHouse 18.16 ने base64Decode() उसके MySQL स्टाइल एलियास के साथ जारी किया, क्योंकि कॉलमर दुनिया वर्कलोड्स इम्पोर्ट कर रही थीं जिनके लॉग स्कीमाज़ में पहले से base64 थी।

2023। SQLite 3.41.0 ने base64() और उसका base85 भाई कमांड-लाइन शेल में एप्लिकेशन-डिफाइंड फ़ंक्शन्स के रूप में जोड़ा। कोर लाइब्रेरी, अपने किरदार के हिसाब से, कुछ नहीं पाती; शेल, जहाँ इंसान असल में SQLite डेटाबेस को छूते हैं, वहाँ टूल मिलता है।

2025। SQL Server 2025, नवंबर 2025 में जनरली एवेलेबल, ने 36 साल के अंतराल के बाद T-SQL में BASE64_DECODE() और BASE64_ENCODE() जोड़े। रिलीज़ नोट्स उन्हें एक मध्यम फ़ीचर की तरह लेते हैं; कम्युनिटी उन्हें बचाव की तरह।

पैटर्न देखते ही साफ़ हो जाता है। असली बाइनरी टाइप और फ़ॉर्मेट आर्ग्यूमेंट वाले डेटाबेस (PostgreSQL, और अपने तरीक़े से Oracle) को base64 उसी दिन मिला जब ज़रूरत साफ़ दिखी। बाकी (MySQL, SQL Server) ने उसे स्ट्रिंग की सुविधा माना और स्केजूल वही किया। और एम्बेडडेबल इंजन (SQLite) आज भी इसे होस्ट एप्लिकेशन का काम मानता है, CLI को एक दयालु अपवाद की तरह।

बातें जो मुस्कुराहट लाएँगी

  • SQL Server ने 1989 से 2025 तक base64 डिकोडर के बिना बिताए, और कम्युनिटी का जवाब था CAST(N'' AS XML) के अंदर एक XML फ़ंक्शन, नाम xs:base64Binary()। एंटरप्राइज़ क्वेरीज़ की पूरी एक पीढ़ी ने XML पार्सर के रास्ते टोकन्स डिकोड किए, क्योंकि XML पार्सर base64 को 2001 से समझता था, और SQL इंजन नहीं।
  • SQLite CLI का base64() इस परिवार का एकमात्र शकल-बदलू है: BLOB दो तो एन्कोड करता है, टेक्स्ट दो तो डिकोड करता है। फ़ंक्शन अपने आर्ग्यूमेंट के टाइप के हिसाब से अपना काम बदल लेता है, जो SQL की एक छोटी सी टेलीपैथी है और असावधान लोगों के लिए असली जाल।
  • PostgreSQL का एन्कोडर 1996 के MIME स्टैंडर्ड की तरह बिल्कुल 76 अक्षरों पर रैप करता है, सिवाय इस बात के कि लाइनों को एक अकेले न्यूलाइन से ख़त्म करता है, स्टैंडर्ड के कैरेज रिटर्न और न्यूलाइन की जगह। स्पेसिफिकेशन के बीस साल बाद, एक अक्षर कम। डिकोडर दोनों को नज़रअंदाज़ करता है, इसलिए इस क्रांति का पता तभी चलता है जब आप आउटपुट का diff लें।
  • mysql क्लाइंट में, SELECT FROM_BASE64('aGVsbG8=') 0x68656C6C6F प्रिंट करता है। न इसलिए कि डेटा हेक्स है, और न इसलिए कि कुछ ग़लत है, बस इसलिए कि क्लाइंट ने, आपकी जगह, तय कर लिया कि बाइनरी स्ट्रिंग्स को हेक्स में दिखाना चाहिए। उस सेटिंग का नाम है binary-as-hex, और यह हज़ारों डेवलपर्स को यकीन दिला चुका है कि उनका डिकोडर ख़राब है।
  • Oracle का SQL-level RAW टाइप 2000 बाइट्स पर बँधा है, इसलिए 3-किलोबाइट सर्टिफ़िकेट को SQL statement में RAW लीटरल के रूप में पेस्ट भी नहीं किया जा सकता। डिकोडिंग PL/SQL में, चंक्स में, लूप के साथ ही होनी चाहिए। लीमिट 1990s की है; लूप आज भी मंज़ूर जवाब है।
  • Snowflake हर रिज़ल्ट सेट में BINARY वैल्यूज़ को हेक्स में दिखाता है, इसलिए "hello" की पूरी तरह सफल डिकोडिंग आपकी स्क्रीन पर 68656C6C6F के रूप में उतरती है। दो डायलैक्ट्स, दो हेक्स डिस्प्ले, एक एक जैसा बेचैन होने का अहसास।
  • ClickHouse अपने नेटिव base64Decode() के बग़ल में एलियास FROM_BASE64() बनाए रखता है, MySQL की शरनार्थियों के लिए एक छोटी सी सुविधा, जिनके साथ वे ऐसी क्वेरीज़ लेकर आईं जो वरना चलती ही नहीं।
  • पूरी परिवार एक चुपकी सी बात साझा करती है: base64 बाहर जाते वक़्त 33 पर्सेंट का कर है और अंदर आते वक़्त 25 पर्सेंट की लौटाई, और यहाँ के आठों डिकोडरों में से कोई भी इसे पूछे बिना नहीं बताएगा। फ़ॉर्मेट कपड़ा है; अलमारी मुफ़्त है; सिलाई ही इस लेख की बात है।

आगे बढ़ते रहिए

यह लेख नक़ाब उतारने का था: हर डायलैक्ट का फ़ंक्शन, उसकी स्वभाव, और वे पेलोड्स (JWTs, data URLs, रैप्ड ईमेल, JSON फ़ील्ड्स, कॉन्फ़िग वैल्यूज़, ऑथ हेडर्स) जो उसे पहने होते हैं। दूसरी दिशा ख़ुद एक जानवर है, अपने ही सरप्राइज़ के साथ: कौन-से एन्कोडर अपने आउटपुट को 76 अक्षरों पर रैप करते हैं और कौन नहीं, टोकन्स की उम्मीद वाली URL-safe, पैडिंग-रहित शक्ल कैसे बनाएं, वह साइज़ गणित जो आपकी कॉलम चौड़ाई तय करती है, और SQL Server के 36 साल के अंतराल का उन लोगों के लिए क्या मतलब है जो अभी भी पुराने वर्ज़न पर हैं। सारा वह, TO_BASE64() से लेकर BASE64_ENCODE() तक, SQL की संबंधित Base64 एन्कोडिंग आर्टिकल में विस्तार से कवर है, जो इसी पेज से लिंक है। यहाँ डिकोड कीजिए, वहाँ एन्कोड कीजिए, और पूरा राउंड ट्रिप एक दोपहर में समा जाता है।

अंतिम अपडेट: 2026-09-08

संबंधित लेख: SQL में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड