背景:修改pg內核,在創建表時,表名不能和當前的用戶名同名。 首先我們知道DefineRelation此函數是最終創建表結構的函數,最主要的參數是CreateStmt這個結構,該結構如下 結構中relation中包含了catalogname,schemaname,relname此時的relname就 ...
背景:修改pg內核,在創建表時,表名不能和當前的用戶名同名。
首先我們知道DefineRelation此函數是最終創建表結構的函數,最主要的參數是CreateStmt這個結構,該結構如下
typedef struct CreateStmt { NodeTag type; RangeVar *relation; /* relation to create */ List *tableElts; /* column definitions (list of ColumnDef) */ List *inhRelations; /* relations to inherit from (list of * inhRelation) */ TypeName *ofTypename; /* OF typename */ List *constraints; /* constraints (list of Constraint nodes) */ List *options; /* options from WITH clause */ OnCommitAction oncommit; /* what do we do at COMMIT? */ char *tablespacename; /* table space to use, or NULL */ bool if_not_exists; /* just do nothing if it already exists? */ } CreateStmt;
結構中relation中包含了catalogname,schemaname,relname此時的relname就能夠順利的拿到。
tableElts 這個list定義了表結構中的所有列名,如若想增加個非隱藏列,可以append進去。
下圖是創建一個簡單表,PG內部函數的調用過程:
在PG backend上敲入的sql,入口函數都是exec_simple_query,把這串sql解析,重寫後生產執行計劃。
附帶一個PG內核刪除的函數,將query結構反解析出sql的函數
char * deparse_query_def(Query *query) { StringInfoData buf; initStringInfo(&buf); get_query_def(query, &buf, NIL, NULL, PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 0); return buf.data; }
如果想很好的看清query以及subquery重寫以後的任務是什麼,可以將此函數編譯進pg內核。
在ProcessUtility這個過程中有鉤子函數可以掛接,可以根據nodeTag(parseTree)的類型來分別進行處理,例如cstore_fdw中T_DropStmt這種操作的時候,將物理文件刪除
這個鉤子的用處還可以控制某些操作加入你想的內容。
我們可以在ProcessUtilitySlow這個函數進行內核修改,加入對當前用戶名獲取,並從CreateStmt結構中的relname進行對比,然後控制是否創建表或者進行報錯信息。
獲取當前用戶名如下
Datum current_user(PG_FUNCTION_ARGS) { PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId())))); }
此函數是PG的內部函數,使用效果是:
postgres=# select CURRENT_USER; current_user -------------- postgres (1 row)
按照這樣的做法就能夠完成背景下的內容了。
PS:通常還有幾個搭配函數使用->DefineRelation->CommandCounterIncrement->transformRelOptions
->heap_reloptions->NewRelationCreateToastTable[AlterTableCreateToastTable]
註:未經同意,不得轉載!