下面講解了如何在一次操作符調(diào)用中確定所使用的究竟是哪個(gè)操作符繁堡。請(qǐng)注意這個(gè)過(guò)程間接受被調(diào)用操作符的優(yōu)先級(jí)影響揭措。詳閱?\u0013WEDRIVE_FILE {\"fileName\":\"操作符優(yōu)先級(jí)\",\"fileType\":\"Link\",\"fileExt\":\"AutoLink\",\"fileId\":\"\",\"spaceId\":\"\",\"fileUrl\":\"http://www.oushu.com/docs/ch/sql-lexical-structure.html#id15\",\"layoutType\":\"inline\"}\u0014操作符優(yōu)先級(jí)\u0015?订雾。\n操作符類(lèi)型解析\n從系統(tǒng)表pg_operator中選出要考慮的操作符夺溢。 如果使用了一個(gè)不帶模式修飾的操作符名(常見(jiàn)的狀況)登澜, 那么認(rèn)為該操作符是那些在當(dāng)前搜索路徑中名字和參數(shù)個(gè)數(shù)都匹配的操作符 (參閱?\u0013WEDRIVE_FILE {\"fileName\":\"模式搜索路徑\",\"fileType\":\"Link\",\"fileExt\":\"AutoLink\",\"fileId\":\"\",\"spaceId\":\"\",\"fileUrl\":\"http://www.oushu.com/docs/ch/schemas.html#id4\",\"layoutType\":\"inline\"}\u0014模式搜索路徑\u0015?)淹辞。如果給出一個(gè)帶修飾的操作符名, 那么只考慮指定模式中的操作符竭翠。\n如果搜索路徑中找到了多個(gè)相同參數(shù)類(lèi)型的操作符振坚,那么只考慮最早出現(xiàn)在路徑中的那一個(gè)。 但是不同參數(shù)類(lèi)型的操作符將被平等看待斋扰,而不管它們?cè)诼窂街械奈恢萌绾味砂恕n查找精確接受輸入?yún)?shù)類(lèi)型的操作符。如果找到一個(gè)(在一組被考慮的操作符中传货, 可能只存在一個(gè)精確匹配的)屎鳍,則用之。\n如果一個(gè)雙目操作符調(diào)用中的一個(gè)參數(shù)是unknown類(lèi)型问裕, 則在本次檢查中假設(shè)其與另一個(gè)參數(shù)類(lèi)型相同逮壁。包括兩個(gè)unknown 輸入的調(diào)用或一個(gè)一元帶有unknown輸入的操作符,將絕不會(huì)在此處找到匹配粮宛。\n查找最佳匹配貌踏。\na. 拋棄那些輸入類(lèi)型不匹配并且也不能隱式轉(zhuǎn)換成匹配的候選操作符。 unknown文本在這種情況下可以轉(zhuǎn)換成任何東西窟勃。 如果只剩下一個(gè)候選項(xiàng),則用之逗堵,否則繼續(xù)下一步秉氧。\nb. 遍歷所有候選操作符,保留那些輸入類(lèi)型匹配最準(zhǔn)確的蜒秤。(此時(shí)汁咏,域被看作和他們的基本類(lèi)型相同亚斋。) 如果沒(méi)有一個(gè)操作符能被保留,則保留所有候選攘滩。如果只剩下一個(gè)候選項(xiàng)帅刊,則用之,否則繼續(xù)下一步漂问。\nc. 遍歷所有候選操作符赖瞒,保留那些需要類(lèi)型轉(zhuǎn)換時(shí)接受(屬于輸入數(shù)據(jù)類(lèi)型的類(lèi)型范疇的)首選類(lèi)型位置最多的操作符。如果沒(méi)有接受首選類(lèi)型的操作符蚤假,則保留所有候選栏饮。如果只剩下一個(gè)候選項(xiàng),則用之磷仰,否則繼續(xù)下一步袍嬉。\nd. 如果有任何輸入?yún)?shù)是unknown類(lèi)型,檢查剩余的候選操作符對(duì)應(yīng)參數(shù)位置的類(lèi)型范疇灶平。 在每一個(gè)能夠接受字符串類(lèi)型范疇的位置使用 string類(lèi)型(這種對(duì)字符串的偏愛(ài)是合適的伺通, 因?yàn)?unknown 文本確實(shí)像字符串)。另外逢享,如果所有剩下的候選操作符都接受相同的類(lèi)型范疇罐监, 則選擇該類(lèi)型范疇,否則拋出一個(gè)錯(cuò)誤(因?yàn)樵跊](méi)有更多線索的條件下無(wú)法作出正確的選擇)拼苍。然后笑诅, 如果任意候選操作符在某個(gè)給定的參數(shù)位置接受一個(gè)首選類(lèi)型, 則拋棄那些在該參數(shù)位置接受非首選類(lèi)型的候選操作符疮鲫。\n如果只有一個(gè)操作符符合吆你,那么使用它。否則俊犯,產(chǎn)生一個(gè)錯(cuò)誤妇多。\n下面是一些例子。\n例.階乘操作符類(lèi)型解析\n在系統(tǒng)表中里只有一個(gè)階乘操作符燕侠,它以double precision類(lèi)型作為參數(shù)者祖。掃描器給下面查詢(xún)表達(dá)式的參數(shù)賦予integer的初始類(lèi)型:\nSELECT 2 ^ 3 AS \"exp\";exp-----8(1 row)\n分析器對(duì)參數(shù)做類(lèi)型轉(zhuǎn)換,查詢(xún)等效于:\nSELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS \"exp\";\n例.字符串連接操作符類(lèi)型分析\n一種字符串風(fēng)格的語(yǔ)法既可以用于字符串也可以用于復(fù)雜的擴(kuò)展類(lèi)型绢彤。 未聲明類(lèi)型的字符串將被所有可能的候選操作符匹配七问。\n有一個(gè)未聲明的參數(shù)的例子:\nSELECT text 'abc' || 'def' AS \"text and unknown\";text and unknown------------------abcdef(1 row)\n本例中分析器尋找兩個(gè)參數(shù)都是text的操作符, 因此第二個(gè)參數(shù)就被認(rèn)為是text類(lèi)型茫舶。\n下面是連接兩個(gè)未聲明類(lèi)型的值:\nSELECT 'abc' || 'def' AS \"unspecified\";unspecified-------------abcdef(1 row)\n因?yàn)椴樵?xún)中沒(méi)有聲明任何類(lèi)型械巡,所以本例中對(duì)類(lèi)型沒(méi)有任何初始提示,因此,分析器查找所有候選操作符,發(fā)現(xiàn)既存在接受字符串類(lèi)型范疇的操作符也存在接受位串類(lèi)型范疇的操作符讥耗。因?yàn)樽址?lèi)型范疇是首選有勾,所以選擇字符串類(lèi)型范疇的首選類(lèi)型text 作為解析未知類(lèi)型文本的聲明類(lèi)型。\n例.絕對(duì)值和取反操作符類(lèi)型分析\nOushuDB 操作符表里面有幾條記錄對(duì)應(yīng)于前綴操作符@古程, 它們都用于為各種數(shù)值類(lèi)型實(shí)現(xiàn)絕對(duì)值操作蔼卡。其中之一用于float8類(lèi)型, 它是數(shù)值類(lèi)型范疇中的首選類(lèi)型挣磨。因此雇逞,在面對(duì)非數(shù)值輸入的時(shí)候,OushuDB 會(huì)使用該類(lèi)型:\nSELECT @ '-4.5' AS \"abs\";abs-----4.5(1 row)\n此處趋急,系統(tǒng)在應(yīng)用選定的操作符之前隱式的轉(zhuǎn)換text類(lèi)型為float8類(lèi)型喝峦。 我們可以驗(yàn)證它是float8而不是其它類(lèi)型:\nSELECT @ '-4.5e500' AS \"abs\";ERROR: \"-4.5e500\" is out of range for type double precision\n另一方面,前綴操作符~(按位取反)只為整數(shù)數(shù)據(jù)類(lèi)型定義呜达, 而不為float8定義谣蠢。因此,如果我們用~做類(lèi)似的實(shí)驗(yàn)將得到:\nSELECT ~ '20' AS \"negation\";ERROR: operator is not unique: ~ \"unknown\"HINT: Could not choose a best candidate operator. You may need to add explicit type casts.\n這是因?yàn)橄到y(tǒng)無(wú)法決定幾個(gè)可能的~操作符中究竟應(yīng)該使用哪一個(gè)查近。 我們可以用明確地類(lèi)型轉(zhuǎn)換來(lái)幫它:\nSELECT ~ CAST('20' AS int8) AS \"negation\";negation-----------21(1 row)\n"},"apool":{"numToAttrib":{"0":["author","p.1688850050195909"],"1":["font-family","Lato, proxima-nova, \"Helvetica Neue\", Arial, sans-serif"],"2":["font-size","12pt"],"3":["bold","false"],"4":["italic","false"],"5":["color","rgb(64, 64, 64)"],"6":["background-color","rgb(252, 252, 252)"],"7":["letter-spacing","0pt"],"8":["field-char-type","begin"],"9":["field-char-type","separate"],"10":["field-char-type","end"],"11":["pap-specialIndent","0pt"],"12":["pap-line","1.3"],"13":["pap-line-rule","auto"],"14":["snapToGrid","1"],"15":["bold","true"],"16":["pap-left-indent","18pt"],"17":["pap-list-id","q1qoua"],"18":["pap-list-level","0"],"19":["pap-list-template-id","4m57z3"],"20":["pap-list-level","1"],"21":["font-family","Consolas, \"Andale Mono WT\", \"Andale Mono\", \"Lucida Console\", \"Lucida Sans Typewriter\", \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\", \"Liberation Mono\", \"Nimbus Mono L\", Monaco, \"Courier New\", Courier, monospace"],"22":["font-size","9pt"],"23":["color","rgb(51, 51, 51)"],"24":["background-color","none"],"25":["color","rgb(0, 153, 153)"],"26":["color","rgb(221, 17, 68)"],"27":["color","rgb(0, 134, 179)"]},"nextNum":28},"keyFramesInfo":{"frames":[],"src":"copy"}}","storyAtexts":[{"storyId":"LSTTMP","atext":"{"atext":{"attribs":"01234567+101894a67+1018a67+1b18a67+101cd4e67+1012f4g67+1018h4i67+101cj4k67+1","text":"\n\n\n\n\n\n\n\n"},"apool":{"numToAttrib":{"0":["list-start","0"],"1":["list-text","%1."],"2":["list-format","number"],"3":["pap-left-indent","0em"],"4":["pap-specialIndent","0em"],"5":["pap-list-level","0"],"6":["pap-list-template-id","4m57z3"],"7":["author","p.1688850050195909"],"8":["list-format","lowerLetter"],"9":["pap-left-indent","2em"],"10":["pap-list-level","1"],"11":["list-start","4"],"12":["list-format","lowerRoman"],"13":["pap-left-indent","4em"],"14":["pap-list-level","2"],"15":["pap-left-indent","6em"],"16":["pap-list-level","3"],"17":["pap-left-indent","8em"],"18":["pap-list-level","4"],"19":["pap-left-indent","10em"],"20":["pap-list-level","5"]},"nextNum":21},"keyFramesInfo":{"frames":[],"src":"copy"}}"}],"srcGlobalPadId":"w2_ACwAzAYZAEwNgTCtvXoR5q0TibBjC"}" data-version="1.0.0"></melo-data>
下面講解了如何在一次操作符調(diào)用中確定所使用的究竟是哪個(gè)操作符眉踱。請(qǐng)注意這個(gè)過(guò)程間接受被調(diào)用操作符的優(yōu)先級(jí)影響。詳閱 操作符優(yōu)先級(jí) 霜威。
操作符類(lèi)型解析
-
從系統(tǒng)表pg_operator中選出要考慮的操作符谈喳。 如果使用了一個(gè)不帶模式修飾的操作符名(常見(jiàn)的狀況), 那么認(rèn)為該操作符是那些在當(dāng)前搜索路徑中名字和參數(shù)個(gè)數(shù)都匹配的操作符 (參閱 模式搜索路徑 )戈泼。如果給出一個(gè)帶修飾的操作符名婿禽, 那么只考慮指定模式中的操作符。
- 如果搜索路徑中找到了多個(gè)相同參數(shù)類(lèi)型的操作符大猛,那么只考慮最早出現(xiàn)在路徑中的那一個(gè)扭倾。 但是不同參數(shù)類(lèi)型的操作符將被平等看待,而不管它們?cè)诼窂街械奈恢萌绾巍?/li>
-
查找精確接受輸入?yún)?shù)類(lèi)型的操作符挽绩。如果找到一個(gè)(在一組被考慮的操作符中膛壹, 可能只存在一個(gè)精確匹配的),則用之唉堪。
- 如果一個(gè)雙目操作符調(diào)用中的一個(gè)參數(shù)是unknown類(lèi)型模聋, 則在本次檢查中假設(shè)其與另一個(gè)參數(shù)類(lèi)型相同。包括兩個(gè)unknown 輸入的調(diào)用或一個(gè)一元帶有unknown輸入的操作符唠亚,將絕不會(huì)在此處找到匹配链方。
查找最佳匹配。
a. 拋棄那些輸入類(lèi)型不匹配并且也不能隱式轉(zhuǎn)換成匹配的候選操作符灶搜。 unknown文本在這種情況下可以轉(zhuǎn)換成任何東西侄柔。 如果只剩下一個(gè)候選項(xiàng)共啃,則用之,否則繼續(xù)下一步暂题。
b. 遍歷所有候選操作符,保留那些輸入類(lèi)型匹配最準(zhǔn)確的究珊。(此時(shí)薪者,域被看作和他們的基本類(lèi)型相同。) 如果沒(méi)有一個(gè)操作符能被保留剿涮,則保留所有候選言津。如果只剩下一個(gè)候選項(xiàng),則用之取试,否則繼續(xù)下一步悬槽。
c. 遍歷所有候選操作符,保留那些需要類(lèi)型轉(zhuǎn)換時(shí)接受(屬于輸入數(shù)據(jù)類(lèi)型的類(lèi)型范疇的)首選類(lèi)型位置最多的操作符瞬浓。如果沒(méi)有接受首選類(lèi)型的操作符初婆,則保留所有候選。如果只剩下一個(gè)候選項(xiàng)猿棉,則用之磅叛,否則繼續(xù)下一步。
d. 如果有任何輸入?yún)?shù)是unknown類(lèi)型萨赁,檢查剩余的候選操作符對(duì)應(yīng)參數(shù)位置的類(lèi)型范疇弊琴。 在每一個(gè)能夠接受字符串類(lèi)型范疇的位置使用 string類(lèi)型(這種對(duì)字符串的偏愛(ài)是合適的, 因?yàn)?unknown 文本確實(shí)像字符串)杖爽。另外敲董,如果所有剩下的候選操作符都接受相同的類(lèi)型范疇, 則選擇該類(lèi)型范疇慰安,否則拋出一個(gè)錯(cuò)誤(因?yàn)樵跊](méi)有更多線索的條件下無(wú)法作出正確的選擇)腋寨。然后, 如果任意候選操作符在某個(gè)給定的參數(shù)位置接受一個(gè)首選類(lèi)型泻帮, 則拋棄那些在該參數(shù)位置接受非首選類(lèi)型的候選操作符精置。
- 如果只有一個(gè)操作符符合,那么使用它锣杂。否則脂倦,產(chǎn)生一個(gè)錯(cuò)誤。
下面是一些例子元莫。
例.階乘操作符類(lèi)型解析
在系統(tǒng)表中里只有一個(gè)階乘操作符赖阻,它以double precision類(lèi)型作為參數(shù)。掃描器給下面查詢(xún)表達(dá)式的參數(shù)賦予integer的初始類(lèi)型:
SELECT 2 ^ 3 AS "exp";exp-----8(1 row)
分析器對(duì)參數(shù)做類(lèi)型轉(zhuǎn)換踱蠢,查詢(xún)等效于:
SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "exp";
例.字符串連接操作符類(lèi)型分析
一種字符串風(fēng)格的語(yǔ)法既可以用于字符串也可以用于復(fù)雜的擴(kuò)展類(lèi)型火欧。 未聲明類(lèi)型的字符串將被所有可能的候選操作符匹配棋电。
有一個(gè)未聲明的參數(shù)的例子:
SELECT text 'abc' || 'def' AS "text and unknown";text and unknown------------------abcdef(1 row)
本例中分析器尋找兩個(gè)參數(shù)都是text的操作符, 因此第二個(gè)參數(shù)就被認(rèn)為是text類(lèi)型苇侵。
下面是連接兩個(gè)未聲明類(lèi)型的值:
SELECT 'abc' || 'def' AS "unspecified";unspecified-------------abcdef(1 row)
因?yàn)椴樵?xún)中沒(méi)有聲明任何類(lèi)型赶盔,所以本例中對(duì)類(lèi)型沒(méi)有任何初始提示,因此,分析器查找所有候選操作符榆浓,發(fā)現(xiàn)既存在接受字符串類(lèi)型范疇的操作符也存在接受位串類(lèi)型范疇的操作符于未。因?yàn)樽址?lèi)型范疇是首選,所以選擇字符串類(lèi)型范疇的首選類(lèi)型text 作為解析未知類(lèi)型文本的聲明類(lèi)型陡鹃。
例.絕對(duì)值和取反操作符類(lèi)型分析
OushuDB 操作符表里面有幾條記錄對(duì)應(yīng)于前綴操作符@烘浦, 它們都用于為各種數(shù)值類(lèi)型實(shí)現(xiàn)絕對(duì)值操作。其中之一用于float8類(lèi)型萍鲸, 它是數(shù)值類(lèi)型范疇中的首選類(lèi)型闷叉。因此,在面對(duì)非數(shù)值輸入的時(shí)候脊阴,OushuDB 會(huì)使用該類(lèi)型:
SELECT @ '-4.5' AS "abs";abs-----4.5(1 row)
此處握侧,系統(tǒng)在應(yīng)用選定的操作符之前隱式的轉(zhuǎn)換text類(lèi)型為float8類(lèi)型。 我們可以驗(yàn)證它是float8而不是其它類(lèi)型:
SELECT @ '-4.5e500' AS "abs";ERROR: "-4.5e500" is out of range for type double precision
另一方面蹬叭,前綴操作符~(按位取反)只為整數(shù)數(shù)據(jù)類(lèi)型定義藕咏, 而不為float8定義。因此秽五,如果我們用~做類(lèi)似的實(shí)驗(yàn)將得到:
SELECT ~ '20' AS "negation";ERROR: operator is not unique: ~ "unknown"HINT: Could not choose a best candidate operator. You may need to add explicit type casts.
這是因?yàn)橄到y(tǒng)無(wú)法決定幾個(gè)可能的~操作符中究竟應(yīng)該使用哪一個(gè)孽查。 我們可以用明確地類(lèi)型轉(zhuǎn)換來(lái)幫它:
SELECT ~ CAST('20' AS int8) AS "negation";negation-----------21(1 row)