日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【ORACLE】详解oracle数据库UTL_RAW包各个函数的模拟算法

發布時間:2023/12/20 数据库 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【ORACLE】详解oracle数据库UTL_RAW包各个函数的模拟算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

這篇文章可能是你至今(2022-02-11)能在互聯網看到的,關于utl_raw包的邏輯說得最深入的一篇文章了。

由于最近在復刻oracle中自帶的包到其他數據庫,因此需要對oracle中的包的邏輯進行解析。
比如UTL_RAW這個包,以前用得挺多,但沒深究其函數邏輯,這次仔細分析,發現了有一些函數涉及到了一些計算機基本原理及IEEE標準,比較有意思,因此寫一篇這樣的文章來分享。

函數清單

先上官方文檔 UTL_RAW

再貼個函數清單,稍微翻譯了下,方便理解

SubprogramDescription中文描述
BIT_AND FunctionPerforms bitwise logical “and” of the values in?RAW?r1?with?RAW?r2?and returns the “anded” result?RAW計算兩個raw的“位與”并返回結果的RAW
BIT_COMPLEMENT FunctionPerforms bitwise logical “complement” of the values in?RAW?r?and returns the “complement’ed” result?RAW對 in 中的值執行按位邏輯“補碼”RAW?r并返回“補碼”結果RAW
BIT_OR FunctionPerforms bitwise logical “or” of the values in?RAW?r1?with?RAW?r2?and returns the “or’d” result?RAW計算兩個raw的“位或”并返回結果的RAW
BIT_XOR FunctionPerforms bitwise logical “exclusive or” of the values in?RAW?r1?with?RAW?r2?and returns the “xor’d” result?RAW計算兩個raw的“位異或”并返回結果的RAW
CAST_FROM_BINARY_DOUBLE FunctionReturns the?RAW?binary representation of a?BINARY_DOUBLE?value返回值的二進制?RAW表示的雙精度浮點
CAST_FROM_BINARY_FLOAT FunctionReturns the?RAW?binary representation of a?BINARY_FLOAT?value返回值的二進制?RAW表示的單精度浮點
CAST_FROM_BINARY_INTEGER FunctionReturns the?RAW?binary representation of a?BINARY_INTEGER?value返回值的二進制?RAW表示的整數
CAST_FROM_NUMBER FunctionReturns the?RAW?binary representation of a?NUMBER?value返回值的二進制?RAW表示的數值
CAST_TO_BINARY_DOUBLE FunctionCasts the?RAW?binary representation of a?BINARY_DOUBLE?into a?BINARY_DOUBLE將一個RAW二進制表示形式的雙精度浮點轉換為 雙精度浮點數字
CAST_TO_BINARY_FLOAT FunctionCasts the?RAW?binary representation of a?BINARY_FLOAT?into a?BINARY_FLOAT將一個RAW二進制表示形式的單精度浮點轉換為 單精度浮點數字
CAST_TO_BINARY_INTEGER FunctionCasts the?RAW?binary representation of a?BINARY_INTEGER?into a?BINARY_INTEGER將一個RAW二進制表示形式的整數轉換為 數字
CAST_TO_NUMBER FunctionCasts the?RAW?binary representation of a?NUMBER?into a?NUMBER將一個RAW二進制表示形式數值轉換為 成一個數值
CAST_TO_NVARCHAR2 FunctionConverts a?RAW?value into a?VARCHAR2?value將RAW值轉換為NVARCHAR2值
CAST_TO_RAW FunctionConverts a?VARCHAR2?value into a?RAW?value將VARCHAR2值轉換為RAW值
CAST_TO_VARCHAR2 FunctionConverts a RAW value into a?VARCHAR2?value將 RAW 值轉換為VARCHAR2值
COMPARE FunctionCompares?RAW?r1?against?RAW?r2比較兩個raw
CONCAT FunctionConcatenates up to 12?RAWs?into a single?RAW最多可將 12 個連接RAWs成一個RAW
CONVERT FunctionConverts?RAW?r?from character set?from_charset?to character set?to_charset?and returns the resulting?RAW將一個raw從字符集from_charset轉換為字符集to_charset并返回結果RAW
COPIES FunctionReturns?n?copies of?r?concatenated together返回n個重復的raw拼接的結果
LENGTH FunctionReturns the length in bytes of a?RAW?r返回一個RAW的字節長度
OVERLAY FunctionOverlays the specified portion of target?RAW?with overlay?RAW, starting from byte position?pos?of target and proceeding for?len?bytes使用指定的RAW,對目標raw的pos字節位置開始,len字節長度進行覆蓋
REVERSE FunctionReverses a byte sequence in?RAW?r?from end to end反轉RAW字節序列
SUBSTR FunctionReturns?len?bytes, starting at?pos?from?RAW?r對一個raw,從pos位置開始,截取len字節,返回結果
TRANSLATE FunctionTranslates the bytes in the input?RAW?r?according to the bytes in the translation?RAWs?from_set?and?to_set對于輸入的raw,?將from_set中的字節逐個替換成to_set中對應位置的字節
TRANSLITERATE FunctionConverts the bytes in the input?RAW?r?according to the bytes in the transliteration?RAWs?from_set?and?to_set實際上和translate差不多,但多了個補充長度的參數
XRANGE FunctionReturns a?RAW?containing all valid 1-byte encodings in succession, beginning with the value?start_byte?and ending with the value?end_byte從start_byte開始到end_byte的所有值拼接成一個raw返回

此包中的大部分函數,均已使用openGauss的plpgsql語言進行了實現,可結合代碼來閱讀本文,代碼地址
https://gitee.com/darkathena/opengauss-oracle/blob/main/oracle-package/utl_raw.sql

詳解

注意,由于oracle中,sql語言可以隱式的將十六進制字符串轉換成raw類型,所以注意下文中十六進制的參數的類型應該均為raw。在plsql中,則需要使用hextoraw函數進行顯式的轉換以確保輸入參數的準確性

1.BIT_AND

作用:
計算位與
例:

SELECT UTL_RAW.BIT_AND('F0','BA') FROM DUAL --輸出:B0

算法:
十六進制 F0 轉二進制 11110000
十六進制 BA 轉二進制 10111010
兩個數字按位,逐個進行匹配,相等輸出1,不等輸出0
得10110000,然后轉十六進制,得B0

2.BIT_OR

作用:
計算位或
例:

SELECT UTL_RAW.BIT_OR('F0','BA') FROM DUAL --輸出:FA

算法:
十六進制 F0 轉二進制 11110000
十六進制 BA 轉二進制 10111010
兩個數字按位,逐個進行匹配,至少有個1則輸出1,都是0則輸出0
得11111010,然后轉十六進制,得FA

3.BIT_XOR

作用:
計算位異或
例:

SELECT UTL_RAW.BIT_XOR('F0','BA') FROM DUAL --輸出:4A

算法:
十六進制 F0 轉二進制 11110000
十六進制 BA 轉二進制 10111010
兩個數字按位,逐個進行匹配,相等輸出0,不等輸出1
得01001010,然后轉十六進制,得4A

4.BIT_COMPLEMENT

作用:
計算補碼
例:

select UTL_RAW.BIT_COMPLEMENT('EA') FROM DUAL --輸出:15

算法:
EA轉二進制 11101010
用二進制 11111111減去它(或者理解為1變0,0變1),
得二進制 00010101,再轉十六進制,得15

5.CONCAT

作用:
拼接多個raw,最多拼12個
例:

select UTL_RAW.CONCAT('EAAB','3A') FROM DUAL --輸出 :EAAB3A

算法:
EAAB 轉二進制 1110101010101011
3A 轉二進制 00111010
計算第二個參數,字節長度為1,占8位,因此第一個參數的二進制向左移動8位,
得111010101010101100000000,
然后加上第二個參數的2進制,得 111010101010101100111010,轉十六進制得 EAAB3A
(可以看到,此例如果是把十六進制數值當成字符串來進行拼接,結果是一樣的,但要注意是按字節長度拼接,比如 “FF"拼"F”,得到應該是 “FF0F”,而不是字符串拼接的"FFF")

6.LENGTH

作用:
計算長度,單位:字節
例:

select UTL_RAW.LENGTH('EAEA') FROM DUAL --輸出:2

算法:
EAEA轉二進制 1110101011101010
從后往前數,8位為1個字節,不足8位的前面補0
(可以將十六進制數值視同為字符串,該字符串長度的一半即為原數據的字節長度,但同樣要注意省去了前面的0的情況,比如"FFF"按字符串的長度是1.5,明顯不對,應該計算"0FFF"長度的一半)

7.SUBSTR

作用:
按字節截取
例:

select UTL_RAW.SUBSTR('ABCDEF12345',3,2) FROM DUAL --輸出:EF12

算法:
(轉二進制過程略)
AB 為一個字節, CD為一個字節,從第3字節 EF 開始,截取 2個字節長度,即 EF 12
(和字符串的substr類似,可以理解為2個字符一組,第3個參數為空時表示一直截到最后;第2個參數同樣支持負數,即從倒數第n位開始截;但是第3個參數要截的長度不能超過raw的剩余長度,否則會報錯ora-06502)

8.COPIES

作用:
復制自己成多份
例:

select utl_raw.COPIES('1A1B',3) FROM DUAL --輸出:1A1B1A1B1A1B

算法:
(轉二進制過程略)
1A1B字節長度為2,往左移兩個字節長度,得1A1B0000
再加上自己,得1A1B1A1B,繼續左移兩個字節長度,得1A1B1A1B0000
再加上自己,得1A1B1A1B1A1B
可以發現左移次數為第2個參數減1次
(也可以簡單的視為字符串拼接,但同樣要注意前面補0,比如utl_raw.COPIES(‘FFF’,2) 的結果應該是0FFF0FFF)

9.REVERSE

作用:
按字節進行翻轉
例:

select utl_raw.REVERSE('01020304') from dual --輸出:04030201

算法:
(轉二進制過程略)
01020304字節長度為4,
取第4個字節04,左移3個字節,得04000000
取第3個字節03,左移2個字節,得00030000
取第2個字節02,左移1個字節,得00000200
取第1個字節01,得00000001
把上面4個數加起來,得04030201
(也可以簡單的視為字符串,只不過是2個字符為一組進行翻轉,不要忘了補0)

10.XRANGE

作用:
根據傳入的兩個參數作為開始數值和結束數值,以1遞增,生成一串序列,注意兩個參數均只接受第一個字節,后面的字節會被忽略
例:

select utl_raw.XRANGE('0A','12') FROM DUAL --輸出:0A0B0C0D0E0F101112

算法:
(轉二進制過程略)
0A左移一個字節,得0A00,然后0A加1,得0B,0A00加上0B得0A0B
0A0B左移一個字節,得0A0B00,然后0B加1得0C,0A0B00加上0C得0A0B0C
循環下去,直至中間某次加1后的值等于第二個參數12,加上最后一個值后返回結果,
得0A 0B 0C 0D 0E 0F 10 11 12

11.TRANSLITERATE

作用:
按字節進行替換,(由于第二個參數和第三個參數的長度允許不一致,因此以填充碼的方式,確保原數據和輸出結果的長度一致)
例:

select utl_raw.transliterate( '010203040502', '0809', '01020304', '0a' ) FROM DUAL --輸出:08090A0A0509

算法:
(轉二進制過程略)
第一個參數是原數據,第二個參數是要替換成的數據,第三個參數是要查找的數據,第4個參數是填充碼
此例中,對第一個參數進行以下字節的覆蓋
01 -> 08
02 -> 09
03 -> 空(取填充碼0A)
04 -> 空(取填充碼0A)
得輸出結果 08 09 0A 0A 05 09

12.TRANSLATE

作用:
按字節進行替換(無填充碼參數,因此輸入和輸出的長度可能不一致)
例:

select utl_raw.translate( '0102030405', '0203', '06' ) from dual --輸出 01060405

算法:
和TRANSLITERATE函數類似,不過沒有填充碼,沒對應上的則替換成空(二進制數據需要右移),而且注意第二個參數和第三個參數反過來了

13.OVERLAY

作用:
按指定開始字節及長度覆寫字節數據
用法:
第一個參數為覆寫碼,第二個參數為原始數據,第3個參數為開始字節位置(默認值為1,表示從第一個字節開始),第4個參數為覆蓋字節長度(默認值為剩余的所有字節長度),第5個參數為填充碼(默認值為00)

select utl_raw.overlay( 'AABB', '010203' ) from dual --輸出 AABB03 select utl_raw.overlay( 'AABB', '010203', 2 ) from dual --輸出 01AABB select utl_raw.overlay( 'AABB', '010203', 5 ) from dual --輸出 01020300AABB select utl_raw.overlay( 'AABB', '010203', 2, 1 ) from dual --輸出 01AA03 select utl_raw.overlay( 'AABB', '010203', 5, 1, 'FF' ) from dual --輸出 010203FFAA

算法:(以最后一個為例)
(轉二進制過程略)
AABB 字節長度為 2,已經超過第4個參數1個字節的長度,因此截斷,只取第1個字節AA
010203 字節長度為 3
從第5個字節開始覆寫,已經超過原始數據長度,差值為2,因此010203先左移1個字節,得 01020300
由于還未到第5個字節,所以加上填充碼FF,得010203FF,
再左移1個字節,得010203FF00,在第5位加上覆寫碼AA,得010203FFAA

14.COMPARE

作用:
按字節從左至右的順序比較兩個raw的差異,返回第一個不匹配的字節位置,如果完全匹配則返回0
用法:
第一個參數raw,第二個參數raw,第3個參數為填充碼(默認值為00),返回一個整數

SELECT utl_raw.compare( '010203', '01020304', '04' ) from dual --輸出 0 SELECT utl_raw.compare( '01050304', '01020304' ) --輸出 2

算法:
(轉二進制過程略)
第一例,由于前兩個參數長度不一致,且第一個參數長度較短,因此使用第三個參數對其進行填充至相同長度,得 01020304,所以兩個完全一致,返回0
第二例,可以發現第二個字節 05 不等于 02,因此返回2

15.CAST_TO_RAW

作用:
將varchar2類型的數據的二進制數據轉換成raw類型
例:

select UTL_RAW.cast_to_RAW('DarkAthena') from dual --輸出 4461726B417468656E61 select UTL_RAW.cast_to_RAW('123') from dual --輸出 313233 select UTL_RAW.cast_to_RAW(convert('測試','AL32UTF8')) from dual --輸出 E6B58BE8AF95

算法:
略,
注意第二例,傳入的參數是字符,不是數字,
第三例中,對于非單字節字符,強制指定字符集進行寫入,否則寫入的raw不可控

16.CAST_TO_VARCHAR2

作用:
將raw格式的字符串使用數據庫默認字符集轉換回VARCHAR2(其實就是CAST_TO_RAW函數的逆向函數)
例:

select UTL_RAW.cast_to_RAW('4461726B417468656E61') from dual --輸出 DarkAthena

算法:
略,
注意,由于此函數不能指定字符集,因此轉換回來可能會亂碼,可以使用utl_i18n.raw_to_char這個函數進行替代

17.CONVERT

作用:
轉換RAW的字符集
例:

--先用cast_to_RAW獲得一個raw select UTL_RAW.cast_to_RAW(convert('測試','AL32UTF8')) from dual --輸出 E6B58BE8AF95 --轉換成gbk select UTL_RAW.CONVERT('E6B58BE8AF95','ZHS16GBK','AL32UTF8') FROM DUAL --輸出 B2E2CAD4

算法:略
可用下列方式驗證

select UTL_RAW.cast_to_RAW(convert('測試','ZHS16GBK')) from dual --輸出 B2E2CAD4

18.CAST_FROM_BINARY_INTEGER

作用:
將一個整數的二進制數據轉換成RAW
用法:第1個參數為要進行轉換的整數,第二個參數為大端還是小端,默認大端為1,小端為2,傳3為取機器配置的端

select utl_raw.cast_from_binary_integer(65280) from dual --輸出 0000FF00 select utl_raw.cast_from_binary_integer(65280,2) from dual --輸出 00FF0000

算法:
其實就是把十進制的整數轉換成其二進制數據的十六進制展現形式,但最長只能4個字節,可轉換的整數范圍為
-2147483648~2147483647
即大端7FFFFFFF~80000000
(7FFFFFFF及以下為正整數,80000000及以上為負整數,00000000為0,FFFFFFFF為-1)
但是要注意第2個參數,關于大小端是什么意思,可自行搜索,不過在結果展現上來看,其實小端就是把大端按字節給翻轉了

19.CAST_TO_BINARY_INTEGER

作用:
將一個整數的raw轉換回整數,其實就是CAST_FROM_BINARY_INTEGER的逆向函數
用法:第1個參數為要進行轉換的raw,第二個參數為大端還是小端,默認大端為1,小端為2,傳3為取機器配置的端

select utl_raw.cast_to_binary_integer('18FCFFFF') from dual --輸出 419233791 select utl_raw.cast_to_binary_integer('18FCFFFF') from dual --輸出 -1000

算法:
略,注意此處可以傳入小于或者等于4個字節的raw,超過4個字節會報錯

20.CAST_FROM_NUMBER

作用:
獲得一個number類型值存儲的二進制數據
例:

select utl_raw.cast_from_number(1.1) from dual --輸出 C1020B select utl_raw.cast_from_number(-1.1) from dual --輸出 3E645B66

算法:
這里內容會比較多,目前國內很難找到關于這個算法的中文說明,用英文關鍵詞去搜也很難找到,但是我搜到了一個CSDN上08年的帖子
關于utl_raw.cast_to_number

這位兄弟啟發了我,讓我能稍微看懂了一點,于是我模擬了幾組數據,嘗試在excel中按照此方式進行轉換
從RAW解析正數

從RAW解析負數

模擬成功,但是這只是RAW到NUMBER,如果要計算NUMBER到RAW,得把這個步驟完全反過來

另外,我還根據193、101這些特殊的數字,找到了oracle的官方文檔
3 Datatypes

模擬計算表格文件下載

21.CAST_TO_NUMBER

作用:
將一個number值存儲的二進制數據轉換回number,其實就是CAST_FROM_NUMBER的逆向函數
例:

select utl_raw.CAST_TO_NUMBER (C1020B) from dual --輸出 1.1 select utl_raw.cast_from_number(3E645B66) from dual --輸出 -1.1

算法:
略,見上面的CAST_FROM_NUMBER

22.CAST_TO_NVARCHAR2

作用:
把RAW轉換回NVARCHAR2
例:

select utl_raw.CAST_TO_NVARCHAR2('6D4B8BD5') from dual --輸出:測試

算法:
其實NVARCHAR2類型就是用unicode編碼來存儲數據,可以使用unistr或者asciistr函數驗證

select asciistr('測試') from dual --輸出: \6D4B\8BD5 select unistr('\6D4B\8BD5') from dual --輸出: 測試

但是,要注意的是,對于ascii字符集中的字符(單字節字符),NVARCHAR2存儲的每個字符的字節前面都要補1個00字節,確保每個字符占的存儲空間都是2個字節,比如
NVARCHAR2類型的 “測試12ab” 存儲的二進制數據(十六進制形式)為 6D4B 8BD5 0031 0032 0061 0062
而asciistr函數并不會對除"\"以外的單字節字符進行轉換

23.CAST_FROM_BINARY_FLOAT/CAST_TO_BINARY_FLOAT/CAST_FROM_BINARY_DOUBLE/CAST_TO_BINARY_DOUBLE

最后還剩4個函數,分別是轉換單精度浮點和雙精度浮點的
這個其實是遵循 IEEE二進制浮點數算術標準(IEEE 754)(百度百科)
所以暫不細說了,前面能看懂的自然能看懂百科里說的算法。
但要注意的是,由于這兩種浮點數值存在精度問題,經常會出現類似10.00000000000000001或者9.9999999999999999這種奇葩的數據,因此不建議在需要準確數值的場景下使用,建議使用number類型

總結

有人可能會說,既然oracle提供了這些函數,直接用就好了么,干嘛去分析原理?
首先,如果要讓oracle數據庫里的對象能實現真正的無縫遷移至其他數據庫,肯定需要在其他數據庫內對oracle里的邏輯進行模擬,此時必須清楚oracle里的邏輯是怎樣的;
其次,了解這些原理后,能對以后開發時應該選擇哪種數據類型或者使用哪個函數提供指導依據,比如哪種方式計算快或者怎么存儲更節省空間。比如這個問答中的回復就使用到了相關知識 oracle里面number(20,2)數據類型,數據精度是20,小數位數是2。那它的數據長度是多少?

  • 本文作者: DarkAthena
  • 本文鏈接: https://www.darkathena.top/archives/about-utl-raw-and-emulate-cal
  • 版權聲明: 本博客所有文章除特別聲明外,均采用CC BY-NC-SA 3.0 許可協議。轉載請注明出處!

總結

以上是生活随笔為你收集整理的【ORACLE】详解oracle数据库UTL_RAW包各个函数的模拟算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。