PostgreSQL怎么实现用户自定义
发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,本篇内容介绍了"PostgreSQL怎么实现用户自定义"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
千家信息网最后更新 2025年02月01日PostgreSQL怎么实现用户自定义
本篇内容介绍了"PostgreSQL怎么实现用户自定义"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Bison输入文件的组成:
%{Declarations%}Definitions%%Productions%%User subroutines
一、User subroutines
用户自定义例程会原封不动的拷贝到gram.c文件中,详细请参考gram.c文件.
二、源码
下面是gram.y用户自定义部分的源码
/* * The signature of this function is required by bison. However, we * ignore the passed yylloc and instead use the last token position * available from the scanner. */static voidbase_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg){ parser_yyerror(msg);}static RawStmt *makeRawStmt(Node *stmt, int stmt_location){ RawStmt *rs = makeNode(RawStmt); rs->stmt = stmt; rs->stmt_location = stmt_location; rs->stmt_len = 0; /* might get changed later */ return rs;}/* Adjust a RawStmt to reflect that it doesn't run to the end of the string */static voidupdateRawStmtEnd(RawStmt *rs, int end_location){ /* * If we already set the length, don't change it. This is for situations * like "select foo ;; select bar" where the same statement will be last * in the string for more than one semicolon. */ if (rs->stmt_len > 0) return; /* OK, update length of RawStmt */ rs->stmt_len = end_location - rs->stmt_location;}static Node *makeColumnRef(char *colname, List *indirection, int location, core_yyscan_t yyscanner){ /* * Generate a ColumnRef node, with an A_Indirection node added if there * is any subscripting in the specified indirection list. However, * any field selection at the start of the indirection list must be * transposed into the "fields" part of the ColumnRef node. */ ColumnRef *c = makeNode(ColumnRef); int nfields = 0; ListCell *l; c->location = location; foreach(l, indirection) { if (IsA(lfirst(l), A_Indices)) { A_Indirection *i = makeNode(A_Indirection); if (nfields == 0) { /* easy case - all indirection goes to A_Indirection */ c->fields = list_make1(makeString(colname)); i->indirection = check_indirection(indirection, yyscanner); } else { /* got to split the list in two */ i->indirection = check_indirection(list_copy_tail(indirection, nfields), yyscanner); indirection = list_truncate(indirection, nfields); c->fields = lcons(makeString(colname), indirection); } i->arg = (Node *) c; return (Node *) i; } else if (IsA(lfirst(l), A_Star)) { /* We only allow '*' at the end of a ColumnRef */ if (lnext(l) != NULL) parser_yyerror("improper use of \"*\""); } nfields++; } /* No subscripting, so all indirection gets added to field list */ c->fields = lcons(makeString(colname), indirection); return (Node *) c;}static Node *makeTypeCast(Node *arg, TypeName *typename, int location){ TypeCast *n = makeNode(TypeCast); n->arg = arg; n->typeName = typename; n->location = location; return (Node *) n;}static Node *makeStringConst(char *str, int location){ A_Const *n = makeNode(A_Const); n->val.type = T_String; n->val.val.str = str; n->location = location; return (Node *)n;}static Node *makeStringConstCast(char *str, int location, TypeName *typename){ Node *s = makeStringConst(str, location); return makeTypeCast(s, typename, -1);}static Node *makeIntConst(int val, int location){ A_Const *n = makeNode(A_Const); n->val.type = T_Integer; n->val.val.ival = val; n->location = location; return (Node *)n;}static Node *makeFloatConst(char *str, int location){ A_Const *n = makeNode(A_Const); n->val.type = T_Float; n->val.val.str = str; n->location = location; return (Node *)n;}static Node *makeBitStringConst(char *str, int location){ A_Const *n = makeNode(A_Const); n->val.type = T_BitString; n->val.val.str = str; n->location = location; return (Node *)n;}static Node *makeNullAConst(int location){ A_Const *n = makeNode(A_Const); n->val.type = T_Null; n->location = location; return (Node *)n;}static Node *makeAConst(Value *v, int location){ Node *n; switch (v->type) { case T_Float: n = makeFloatConst(v->val.str, location); break; case T_Integer: n = makeIntConst(v->val.ival, location); break; case T_String: default: n = makeStringConst(v->val.str, location); break; } return n;}/* makeBoolAConst() * Create an A_Const string node and put it inside a boolean cast. */static Node *makeBoolAConst(bool state, int location){ A_Const *n = makeNode(A_Const); n->val.type = T_String; n->val.val.str = (state ? "t" : "f"); n->location = location; return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);}/* makeRoleSpec * Create a RoleSpec with the given type */static RoleSpec *makeRoleSpec(RoleSpecType type, int location){ RoleSpec *spec = makeNode(RoleSpec); spec->roletype = type; spec->location = location; return spec;}/* check_qualified_name --- check the result of qualified_name production * * It's easiest to let the grammar production for qualified_name allow * subscripts and '*', which we then must reject here. */static voidcheck_qualified_name(List *names, core_yyscan_t yyscanner){ ListCell *i; foreach(i, names) { if (!IsA(lfirst(i), String)) parser_yyerror("syntax error"); }}/* check_func_name --- check the result of func_name production * * It's easiest to let the grammar production for func_name allow subscripts * and '*', which we then must reject here. */static List *check_func_name(List *names, core_yyscan_t yyscanner){ ListCell *i; foreach(i, names) { if (!IsA(lfirst(i), String)) parser_yyerror("syntax error"); } return names;}/* check_indirection --- check the result of indirection production * * We only allow '*' at the end of the list, but it's hard to enforce that * in the grammar, so do it here. */static List *check_indirection(List *indirection, core_yyscan_t yyscanner){ ListCell *l; foreach(l, indirection) { if (IsA(lfirst(l), A_Star)) { if (lnext(l) != NULL) parser_yyerror("improper use of \"*\""); } } return indirection;}/* extractArgTypes() * Given a list of FunctionParameter nodes, extract a list of just the * argument types (TypeNames) for input parameters only. This is what * is needed to look up an existing function, which is what is wanted by * the productions that use this call. */static List *extractArgTypes(List *parameters){ List *result = NIL; ListCell *i; foreach(i, parameters) { FunctionParameter *p = (FunctionParameter *) lfirst(i); if (p->mode != FUNC_PARAM_OUT && p->mode != FUNC_PARAM_TABLE) result = lappend(result, p->argType); } return result;}/* extractAggrArgTypes() * As above, but work from the output of the aggr_args production. */static List *extractAggrArgTypes(List *aggrargs){ Assert(list_length(aggrargs) == 2); return extractArgTypes((List *) linitial(aggrargs));}/* makeOrderedSetArgs() * Build the result of the aggr_args production (which see the comments for). * This handles only the case where both given lists are nonempty, so that * we have to deal with multiple VARIADIC arguments. */static List *makeOrderedSetArgs(List *directargs, List *orderedargs, core_yyscan_t yyscanner){ FunctionParameter *lastd = (FunctionParameter *) llast(directargs); int ndirectargs; /* No restriction unless last direct arg is VARIADIC */ if (lastd->mode == FUNC_PARAM_VARIADIC) { FunctionParameter *firsto = (FunctionParameter *) linitial(orderedargs); /* * We ignore the names, though the aggr_arg production allows them; * it doesn't allow default values, so those need not be checked. */ if (list_length(orderedargs) != 1 || firsto->mode != FUNC_PARAM_VARIADIC || !equal(lastd->argType, firsto->argType)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("an ordered-set aggregate with a VARIADIC direct argument must have one VARIADIC aggregated argument of the same data type"), parser_errposition(exprLocation((Node *) firsto)))); /* OK, drop the duplicate VARIADIC argument from the internal form */ orderedargs = NIL; } /* don't merge into the next line, as list_concat changes directargs */ ndirectargs = list_length(directargs); return list_make2(list_concat(directargs, orderedargs), makeInteger(ndirectargs));}/* insertSelectOptions() * Insert ORDER BY, etc into an already-constructed SelectStmt. * * This routine is just to avoid duplicating code in SelectStmt productions. */static voidinsertSelectOptions(SelectStmt *stmt, List *sortClause, List *lockingClause, Node *limitOffset, Node *limitCount, WithClause *withClause, core_yyscan_t yyscanner){ Assert(IsA(stmt, SelectStmt)); /* * Tests here are to reject constructs like * (SELECT foo ORDER BY bar) ORDER BY baz */ if (sortClause) { if (stmt->sortClause) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple ORDER BY clauses not allowed"), parser_errposition(exprLocation((Node *) sortClause)))); stmt->sortClause = sortClause; } /* We can handle multiple locking clauses, though */ stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause); if (limitOffset) { if (stmt->limitOffset) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple OFFSET clauses not allowed"), parser_errposition(exprLocation(limitOffset)))); stmt->limitOffset = limitOffset; } if (limitCount) { if (stmt->limitCount) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple LIMIT clauses not allowed"), parser_errposition(exprLocation(limitCount)))); stmt->limitCount = limitCount; } if (withClause) { if (stmt->withClause) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple WITH clauses not allowed"), parser_errposition(exprLocation((Node *) withClause)))); stmt->withClause = withClause; }}static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg){ SelectStmt *n = makeNode(SelectStmt); n->op = op; n->all = all; n->larg = (SelectStmt *) larg; n->rarg = (SelectStmt *) rarg; return (Node *) n;}/* SystemFuncName() * Build a properly-qualified reference to a built-in function. */List *SystemFuncName(char *name){ return list_make2(makeString("pg_catalog"), makeString(name));}/* SystemTypeName() * Build a properly-qualified reference to a built-in type. * * typmod is defaulted, but may be changed afterwards by caller. * Likewise for the location. */TypeName *SystemTypeName(char *name){ return makeTypeNameFromNameList(list_make2(makeString("pg_catalog"), makeString(name)));}/* doNegate() * Handle negation of a numeric constant. * * Formerly, we did this here because the optimizer couldn't cope with * indexquals that looked like "var = -4" --- it wants "var = const" * and a unary minus operator applied to a constant didn't qualify. * As of Postgres 7.0, that problem doesn't exist anymore because there * is a constant-subexpression simplifier in the optimizer. However, * there's still a good reason for doing this here, which is that we can * postpone committing to a particular internal representation for simple * negative constants. It's better to leave "-123.456" in string form * until we know what the desired type is. */static Node *doNegate(Node *n, int location){ if (IsA(n, A_Const)) { A_Const *con = (A_Const *)n; /* report the constant's location as that of the '-' sign */ con->location = location; if (con->val.type == T_Integer) { con->val.val.ival = -con->val.val.ival; return n; } if (con->val.type == T_Float) { doNegateFloat(&con->val); return n; } } return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n, location);}static voiddoNegateFloat(Value *v){ char *oldval = v->val.str; Assert(IsA(v, Float)); if (*oldval == '+') oldval++; if (*oldval == '-') v->val.str = oldval+1; /* just strip the '-' */ else v->val.str = psprintf("-%s", oldval);}static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location){ Node *lexp = lexpr; /* Look through AEXPR_PAREN nodes so they don't affect flattening */ while (IsA(lexp, A_Expr) && ((A_Expr *) lexp)->kind == AEXPR_PAREN) lexp = ((A_Expr *) lexp)->lexpr; /* Flatten "a AND b AND c ..." to a single BoolExpr on sight */ if (IsA(lexp, BoolExpr)) { BoolExpr *blexpr = (BoolExpr *) lexp; if (blexpr->boolop == AND_EXPR) { blexpr->args = lappend(blexpr->args, rexpr); return (Node *) blexpr; } } return (Node *) makeBoolExpr(AND_EXPR, list_make2(lexpr, rexpr), location);}static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location){ Node *lexp = lexpr; /* Look through AEXPR_PAREN nodes so they don't affect flattening */ while (IsA(lexp, A_Expr) && ((A_Expr *) lexp)->kind == AEXPR_PAREN) lexp = ((A_Expr *) lexp)->lexpr; /* Flatten "a OR b OR c ..." to a single BoolExpr on sight */ if (IsA(lexp, BoolExpr)) { BoolExpr *blexpr = (BoolExpr *) lexp; if (blexpr->boolop == OR_EXPR) { blexpr->args = lappend(blexpr->args, rexpr); return (Node *) blexpr; } } return (Node *) makeBoolExpr(OR_EXPR, list_make2(lexpr, rexpr), location);}static Node *makeNotExpr(Node *expr, int location){ return (Node *) makeBoolExpr(NOT_EXPR, list_make1(expr), location);}static Node *makeAArrayExpr(List *elements, int location){ A_ArrayExpr *n = makeNode(A_ArrayExpr); n->elements = elements; n->location = location; return (Node *) n;}static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location){ SQLValueFunction *svf = makeNode(SQLValueFunction); svf->op = op; /* svf->type will be filled during parse anaXXXis */ svf->typmod = typmod; svf->location = location; return (Node *) svf;}static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location){ XmlExpr *x = makeNode(XmlExpr); x->op = op; x->name = name; /* * named_args is a list of ResTarget; it'll be split apart into separate * expression and name lists in transformXmlExpr(). */ x->named_args = named_args; x->arg_names = NIL; x->args = args; /* xmloption, if relevant, must be filled in by caller */ /* type and typmod will be filled in during parse anaXXXis */ x->type = InvalidOid; /* marks the node as not analyzed */ x->location = location; return (Node *) x;}/* * Merge the input and output parameters of a table function. */static List *mergeTableFuncParameters(List *func_args, List *columns){ ListCell *lc; /* Explicit OUT and INOUT parameters shouldn't be used in this syntax */ foreach(lc, func_args) { FunctionParameter *p = (FunctionParameter *) lfirst(lc); if (p->mode != FUNC_PARAM_IN && p->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"))); } return list_concat(func_args, columns);}/* * Determine return type of a TABLE function. A single result column * returns setof that column's type; otherwise return setof record. */static TypeName *TableFuncTypeName(List *columns){ TypeName *result; if (list_length(columns) == 1) { FunctionParameter *p = (FunctionParameter *) linitial(columns); result = copyObject(p->argType); } else result = SystemTypeName("record"); result->setof = true; return result;}/* * Convert a list of (dotted) names to a RangeVar (like * makeRangeVarFromNameList, but with position support). The * "AnyName" refers to the any_name production in the grammar. */static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner){ RangeVar *r = makeNode(RangeVar); switch (list_length(names)) { case 1: r->catalogname = NULL; r->schemaname = NULL; r->relname = strVal(linitial(names)); break; case 2: r->catalogname = NULL; r->schemaname = strVal(linitial(names)); r->relname = strVal(lsecond(names)); break; case 3: r->catalogname = strVal(linitial(names)); r->schemaname = strVal(lsecond(names)); r->relname = strVal(lthird(names)); break; default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper qualified name (too many dotted names): %s", NameListToString(names)), parser_errposition(position))); break; } r->relpersistence = RELPERSISTENCE_PERMANENT; r->location = position; return r;}/* Separate Constraint nodes from COLLATE clauses in a ColQualList */static voidSplitColQualList(List *qualList, List **constraintList, CollateClause **collClause, core_yyscan_t yyscanner){ ListCell *cell; ListCell *prev; ListCell *next; *collClause = NULL; prev = NULL; for (cell = list_head(qualList); cell; cell = next) { Node *n = (Node *) lfirst(cell); next = lnext(cell); if (IsA(n, Constraint)) { /* keep it in list */ prev = cell; continue; } if (IsA(n, CollateClause)) { CollateClause *c = (CollateClause *) n; if (*collClause) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple COLLATE clauses not allowed"), parser_errposition(c->location))); *collClause = c; } else elog(ERROR, "unexpected node type %d", (int) n->type); /* remove non-Constraint nodes from qualList */ qualList = list_delete_cell(qualList, cell, prev); } *constraintList = qualList;}/* * Process result of ConstraintAttributeSpec, and set appropriate bool flags * in the output command node. Pass NULL for any flags the particular * command doesn't support. */static voidprocessCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner){ /* defaults */ if (deferrable) *deferrable = false; if (initdeferred) *initdeferred = false; if (not_valid) *not_valid = false; if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED)) { if (deferrable) *deferrable = true; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); } if (cas_bits & CAS_INITIALLY_DEFERRED) { if (initdeferred) *initdeferred = true; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked DEFERRABLE", constrType), parser_errposition(location))); } if (cas_bits & CAS_NOT_VALID) { if (not_valid) *not_valid = true; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NOT VALID", constrType), parser_errposition(location))); } if (cas_bits & CAS_NO_INHERIT) { if (no_inherit) *no_inherit = true; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is CHECK, UNIQUE, or similar */ errmsg("%s constraints cannot be marked NO INHERIT", constrType), parser_errposition(location))); }}/*---------- * Recursive view transformation * * Convert * * CREATE RECURSIVE VIEW relname (aliases) AS query * * to * * CREATE VIEW relname (aliases) AS * WITH RECURSIVE relname (aliases) AS (query) * SELECT aliases FROM relname * * Actually, just the WITH ... part, which is then inserted into the original * view definition as the query. * ---------- */static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query){ SelectStmt *s = makeNode(SelectStmt); WithClause *w = makeNode(WithClause); CommonTableExpr *cte = makeNode(CommonTableExpr); List *tl = NIL; ListCell *lc; /* create common table expression */ cte->ctename = relname; cte->aliascolnames = aliases; cte->ctequery = query; cte->location = -1; /* create WITH clause and attach CTE */ w->recursive = true; w->ctes = list_make1(cte); w->location = -1; /* create target list for the new SELECT from the alias list of the * recursive view specification */ foreach (lc, aliases) { ResTarget *rt = makeNode(ResTarget); rt->name = NULL; rt->indirection = NIL; rt->val = makeColumnRef(strVal(lfirst(lc)), NIL, -1, 0); rt->location = -1; tl = lappend(tl, rt); } /* create new SELECT combining WITH clause, target list, and fake FROM * clause */ s->withClause = w; s->targetList = tl; s->fromClause = list_make1(makeRangeVar(NULL, relname, -1)); return (Node *) s;}/* parser_init() * Initialize to parse one query string */voidparser_init(base_yy_extra_type *yyext){ yyext->parsetree = NIL; /* in case grammar forgets to set it */}
"PostgreSQL怎么实现用户自定义"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
用户
文件
内容
更多
源码
知识
实用
原封不动
学有所成
接下来
困境
实际
情况
拷贝
文章
案例
编带
网站
行业
过程
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
保障网络安全要以法治为根基
临海定制软件开发设备制造
excel无法导入数据库
Access中创建表或数据库
数据库程序操作题
江阴大型软件开发项目信息
测试软件开发电脑配置笔记本
软件开发部长工作
it公司软件开发指南
权威的古诗词数据库
绝地求生出现找不到服务器怎么办
老电脑制作电影服务器
it公司软件开发
公安网络技术专业测试
合肥口碑好的网络技术服务有哪些
沈阳市软件开发排名
数据库 查看系统用户密码
广东省电子研究所网络安全
sql服务器和数据库用户区别
网络安全架构徐云峰
kys电影快捷指令未连接服务器
网络安全行业资质申请
做网站需要数据库吗
怎么管理移动云服务器
快速生成最大数据库
护苗网络安全教育目标
简述你身边的网络安全威胁实例
文本数据库下载
服务器加装pcie硬盘
太原租车软件开发