PostgreSQL怎么实现用户自定义
发表于:2025-02-19 作者:千家信息网编辑
千家信息网最后更新 2025年02月19日,本篇内容介绍了"PostgreSQL怎么实现用户自定义"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
千家信息网最后更新 2025年02月19日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安全错误
数据库的锁怎样保障安全
重庆交易软件开发服务
数据库原理与技术实验报告2
佛山软件开发培训多少钱
lol关闭服务器连接
数据库缓存技术了解
日本橙皮书数据库pdf
网络安全爆破工程师培训
微电影网络安全吗
百度怎么关闭网络安全警告
中央企业网络安全技术决赛
恩施靠谱的软件开发
湖北发票安全服务器地址
中山财务机器人rpa软件开发
盐城企业软件开发价格
数据库系统体系结构映像
软件开发过程是什么图
软件开发本几年一换
网络技术工作室做什么
达梦数据库切换主备
流行的数据库有哪些
网络工程专业和网络技术工程
计算机网络技术资料文章
软件开发风险分析包括那三个部分
服务器如何接电脑显示器
什么叫网络安全责任保护
软件开发中重要的名词
全县服务器安装汇报
xx局网络安全宣传活动
如何加入网络安全联盟
征途一键端数据库连接