函式與系統物件的補全範圍
本頁包含建議清單收哪些函式與系統物件、資料表值函式與純量函式為什麼分開。 清單怎麼排名與觸發見補全。
資料表值函式與純量函式分開
SuggestionKind.TableFunction 與 SuggestionKind.Function 是兩類:前者是內嵌 (IF)與多語句(TF)資料表值函式,後者是純量函式。中繼資料層的 SqlObjectKinds.IsDataSource 早就這樣分了,只有建議項這一層曾經把三種函式壓成 同一類——症狀是 FROM dbo.fn_ 之後整份清單一個函式都沒有, 而使用者看不出它和資料表有什麼不同。
分完之後三個位置各自對了:
FROM、JOIN、USING之後多列資料表值函式,純量函式仍然不列—— 它回傳的是一個值,放在那裡剖析不過。APPLY之後只列資料表值函式。那個位置文法上要的是資料表值函式或衍生資料表,CROSS APPLY dbo.Loan剖析得過卻沒有意義;而純量函式從前是連帶列出來的雜訊。 認的是APPLY一個字,前面的CROSS與OUTER不改變後面要什麼。ALTER FUNCTION、DROP FUNCTION之後兩種都列:兩種都改得動也刪得掉。
反過來也不能把資料表值函式併進 Table:那樣 ALTER FUNCTION 之後就列不出它們了。
APPLY 有自己的 CompletionTarget 而不是共用 Function,還有第二個好處: CompletionTarget.Function 因此收斂成「ALTER/DROP FUNCTION 的那個名稱」, 提交時分得出「這裡要補括號」還是「這裡只要名稱」——見函式呼叫。
系統物件只在三個位置拉進來
sys.objects、sys.dm_exec_requests、sp_executesql、sp_help 這些原本一個都列不出來 ——第一層查詢寫死 is_ms_shipped = 0,結構描述清單也明確排除了 sys 與 INFORMATION_SCHEMA。
它們現在有自己的查詢,而且與第一層分開、只在被問到時才跑:光是一個使用者資料庫 底下就有一兩千列,併進第一層等於每一次開啟查詢視窗都多付兩倍代價,換來的東西九成的 時間沒有人要。只有三個位置會問:
- 使用者自己打出了
sys.或INFORMATION_SCHEMA. - 游標在
EXEC之後——sp_executesql、sp_help一律不加結構描述就呼叫 - 敘述把系統物件寫成了資料來源(
FROM sys.triggers)
第三個位置要的不是那份清單而是那一張表的欄位:SELECT | 與 WHERE | 只讀快取, 而快取要等到有人去載。載入接在欄位預熱上(SqlMetadataService.WarmColumns), 名稱的解析則收斂在 SqlMetadataCatalog.FindObjectsAsync——第一層答不出來而限定字正是 那兩個結構描述時,順手把系統物件載進來,載完併回同一份快照。少了這一條的症狀是 FROM sys.triggers 之後每一個位置都列不出欄位,而畫面上只是什麼都沒發生。
併回快照(SqlDatabaseSnapshot.WithSystemObjects)而不是各自留一份:「這個名稱是哪個 物件」在建議清單、SELECT * 展開、滑鼠停留與 F12 上是同一個問題。但不併進 Objects——那一份是列給使用者看的清單,只有 Find 在限定字是系統結構描述時才問得到 系統物件。沒有限定字時一個都不列:FROM triggers 在 T-SQL 裡本來就不成立。
欄位本身要改問 sys.all_columns:sys.columns 只收使用者物件,拿它去問系統檢視的 結果是「查詢成功,但一個欄位都沒有」,而那與權限不足看起來一模一樣。兩條查詢由同一份 本體組出來(SqlMetadataQueries.ColumnsFor),不是抄成兩份。模組的參數與定義同理, 改問 sys.all_parameters 與 sys.all_sql_modules;少了後者,sp_help 的預覽會把 取不到定義誤報成加密或沒有權限。
ALTER PROCEDURE 不算,雖然它的目標同樣是預存程序:系統程序改不動,列出來只會讓 使用者選到一個改不了的東西,與內建函式不進 ALTER FUNCTION 是同一條理由。
游標定位(Ctrl+F12、Ctrl+點擊、滑鼠停留)另有一條退路,規則在 Metadata/Model/SqlSystemObjectFallback:使用者物件找不到時,限定字是系統結構描述、或未限定的 sp_/xp_ 名稱(比照 SQL Server 的解析視為 sys),改問同一支 FindObjectsAsync;使用者自己的同名物件永遠先找。滑鼠停留不等查詢,沒命中就排一次背景預載,下一次停留才認得出來。寫了說明的系統程序根本不走到這裡,見內建說明。
這一份也刻意不設有效期:系統物件跟著 SQL Server 的版本走,不會在一次工作階段 中途變動,查一次就用到換連線為止。
sys 與 INFORMATION_SCHEMA 這兩個結構描述名稱則不必等中繼資料——它們在每一個 資料庫裡都存在,是產品事實而不是誰的 schema。少了這兩筆的話,使用者連「打 sys 再按 Tab」這條路都沒有。
這兩筆只出現在接得到系統物件的位置(SqlCompletionContext.WantsSystemSchemas): 運算式、資料來源、APPLY 與 EXEC。ALTER/DROP 的函式、檢視、預存程序與序列 不列,理由同上:系統物件改不動也刪不掉。提交只寫名稱,與資料庫裡的結構描述相同, 見限定名稱。
DROP 家族與它們對稱:DROP PROCEDURE、DROP FUNCTION、DROP VIEW 之後同樣 只列那一類,但意圖是 Reference——那個位置要的只是一個名稱,把整份定義放進去 反而讓語句不合法。少寫哪一條都沒有徵兆,只是使用者在那個位置沒有清單。
觸發程序、序列與使用者自訂的資料表型別只在自己的位置出現,不進一般清單。 理由與全域變數同一條:SELECT tr 不該冒出觸發程序,而 EXEC 之後選到一個觸發 程序一定執行失敗。觸發程序算模組(OBJECT_DEFINITION 拿得到定義),所以 ALTER TRIGGER 與 ALTER PROCEDURE 一樣直接展開完整定義。
這三種都不在 sys.objects 的原白名單裡,第一層查詢因此多收 TR、TA、SO, 並把 sys.table_types 另外 UNION 進來貼上 TT 標籤——與同義字的 SN 同一個做法。 資料表型別取的是 type_table_object_id 而不是 user_type_id:快取以 object_id 為鍵, 用型別自己的識別碼會與真的物件撞在一起,而那個 object_id 同時正好是它的欄位在 sys.columns 裡的鍵,於是欄位與滑鼠停留提示都不必另外接。
這一份不對資料庫送出任何查詢,因此與「列出資料庫物件」的設定無關; 也只在游標真的落在資料來源位置、而且沒有限定字時才掃——FROM dbo. 之後不該 出現沒有結構描述的名稱,而這條路徑在每一次按鍵上。
ap → Tab → 選取程序 → Tab,編輯器會直接放進該程序可執行的完整定義, 可以立刻修改並更新。定義開頭的 CREATE 或 CREATE OR ALTER 會改寫成 ALTER, 主體完全不動(主體裡的 CREATE TABLE #tmp 之類的語句不受影響),游標停在標頭的 物件名稱之後。ALTER FUNCTION、ALTER VIEW、ALTER TRIGGER 走的是同一份展開, 行為完全一致——那四種在 SqlObjectKinds.IsModule 裡是同一類,OBJECT_DEFINITION 都拿得到定義。
定義取不到時維持只插入名稱,並在診斷紀錄裡寫明;原因的判別見 相容。