Skip to content

多段式限定名稱 ​

本頁包含多段式名稱怎麼拆成一條路徑、以及右對齊猜錯時整條往左挪的規則。 提交時要補幾段見插入文字。

限定字是一條路徑,不是一個識別字 ​

點號前方那幾段一起讀進 SqlObjectPath(Core/Parsing),最右邊一段是結構描述或 別名,往左依序是資料庫與連結伺服器。只讀最右邊一段有兩個症狀,而兩個都沒有徵兆: 清單改列目前連線的 dbo 物件,而剝完之後的位置判斷停在 FROM LibArchive. 上, 連 FROM 都看不到,建議目標退成 Any——關鍵字與片段於是混了進來。

三條規則跟著路徑走,各寫一份的話同一個名稱會在某條路徑上認得、在另一條上不認得:

  • 右對齊。 省略一律從左邊省,所以最右邊永遠是名稱(限定字則是結構描述)。
  • 空的中間段當成沒寫。 LibArchive.. 少的是結構描述,不是資料庫。存成空字串的話 下游會拿它去比對,而沒有任何結構描述叫做空字串。
  • 超過上限就整個不認。 取最右邊那幾段的話,使用者打錯的一串名稱會安靜地 變成一個查得到的東西。

尾端的點號屬於正在輸入的那個名稱,位置分析因此由整個名稱之前的東西決定位置。 當成一個算完的運算元的話,限定字之後一律是 Any,而那讓 FROM a, dbo. 在位置上 與 SELECT dbo. 沒有差別。數值不受影響:詞法分析把 1. 掃成一個數值詞元。

點號只從程式碼讀。 往回讀字面值之前先剝到最後一個詞元的結尾,尾端註解不算:讀原文的話, -- Uses Lib_Reader. 下一行打的字成了點號之後的名稱,關鍵字全被目標過濾擋掉。

多段的限定字不會被當成別名:別名只有一段。拿最右邊那一段去比對別名的話, 剛好取名叫 dbo 的別名會把清單換成它的欄位。

「有沒有限定字」一律問 QualifierPath 而不是問 Qualifier:LibArchive.. 有路徑 卻沒有結構描述那一段,問錯的症狀是插入文字自己補上 [dbo].,寫出 LibArchive..[dbo].[Loan]。

右對齊猜錯時,整條往左挪 ​

一段限定字的 dbo.、LibArchive.、LibMirror. 在文字上是同一個形狀,右對齊只能 一律先猜結構描述。猜錯沒有徵兆:清單一筆都比不中,畫面上只是「沒有建議」。

分辨要的是這條連線上的三份名單(結構描述、資料庫、連結伺服器),那是中繼資料的事。 因此 SqlQualifierResolver(Metadata)只回答最左邊那一段是什麼,段位怎麼跟著挪 算在 SqlObjectPath.TryRealign 裡。比對順序是結構描述、資料庫、連結伺服器——越近的 越可信,而名稱撞在一起時選遠的會安靜地把清單換成另一台伺服器的內容。

挪的結果記在 QualifierEnd(限定字停在哪一格),而不是旁邊多一個旗標:

限定字QualifierEnd清單插入文字補結構描述
(無)—本地物件與關鍵字;接得住物件的位置另加結構描述、資料庫與連結伺服器看 QualifyObjectNames
dbo.結構描述該結構描述的物件否,已經寫了
LibArchive..結構描述(空格)該資料庫全部物件否,補了會變四段式
LibArchive.資料庫該資料庫的結構描述與全部物件是,且不看設定
LibMirror.伺服器該伺服器的資料庫—
LibMirror.LibArchive.資料庫該資料庫的結構描述與全部物件是,且不看設定

「接得住物件的位置」由 SuggestionContextFilter.IsQualifiedNameStart 一處決定,名稱的 三種開頭共用;USE 只收資料庫,新物件名稱的第一段(CREATE PROCEDURE )只收結構描述, 見子句邊界。清單裡的結構描述讀 SqlDatabaseSnapshot.SchemasWithObjects, 底下沒有物件的(guest、db_denydatareader 這類角色同名的)不列;認限定字仍讀完整的 Schemas,否則空結構描述與資料庫同名時會被改認成資料庫。

最後一欄那兩個「不看設定」是語法必需,不是偏好:LibArchive.Loan 是兩段式,會被讀成 「結構描述 LibArchive」,而那個結構描述並不存在。理由與 QuoteIfNeeded 那條一樣 ——關掉一個為了少打幾個字的設定,不代表要產生無效語法。

重新對齊在問清單之前做完一次(ISqlCompletionMetadata.ResolveQualifierAsync),過濾、 插入文字與目錄選擇讀的是同一份。各自再判一次的話,症狀是清單列得出來、Tab 下去卻 少一段。已經挪過的不再挪第二次:重複套用會把正確的路徑推出段數上限。

提交那一端的上下文是從文字重新分析的(範圍與位置都要以當下的文字驗一次), 於是又回到右對齊的原判。答案因此跟著 session 走:建立清單時把「最左邊那一段落在 哪一格」(SqlObjectPath.LeftmostSlot)記在 session 上,提交時照同一個 TryRealign 挪回去。再問一次中繼資料不行——那要送查詢,而提交在按鍵路徑上;不挪則是 IsLocal 說謊,跨資料庫的名稱在提交那一端看起來像本地的。

名稱的中間段(結構描述、資料庫、連結伺服器)提交時只寫名稱本身,點號留給 使用者自己打。提交一筆建議的意思是「我要這個名稱」,不是「我要繼續往下走」—— 選了資料庫想直接換行去寫別的人,得先退掉一個他沒要求的字元。接續本來就有人做: 打出點號會讓上下文整個換掉,SqlCompletionTriggers 因此重開清單,每一段都一樣。

那條重開規則會擋掉小數(1. 的點號前面是數字,使用者在打的是一個數字)。因此它 要看原文而不是只看剝好的那一段:以位址命名的連結伺服器([192.0.2.10].)剝掉 方括號之後也以數字開頭,而方括號本身已經把話說完了。

哪些位置列得出第一段,由 IsQualifiedNameStart 一處決定:凡是接得住一個資料庫物件 的位置都算——FROM、JOIN、運算式裡的純量函式、EXEC 的程序、APPLY 的資料表值 函式、NEXT VALUE FOR 的序列。逐個位置補的話,漏掉的那一個沒有徵兆:使用者只會 看到「這裡沒有建議」,而語法明明合法。特例有兩個:USE 的資料庫是整句的 終點而不是第一段;新物件名稱的第一段只接結構描述,名字本身還在點號之後。

以 Apache-2.0 授權條款發布 · 專為 SSMS 22 設計