PostgreSQL怎么实现用户自定义
发表于:2024-11-15 作者:千家信息网编辑
千家信息网最后更新 2024年11月15日,本篇内容介绍了"PostgreSQL怎么实现用户自定义"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
千家信息网最后更新 2024年11月15日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安全错误
数据库的锁怎样保障安全
太荒初境服务器版本过低
计算网络技术和软件技术
软件开发公司不靠谱
数据库技术和电子商务的关系
一级服务器 二级服务器
计算机网络技术3 2
山东省的网络技术公司地址
软件开发英语小作文
博网络技术有限公司怎么样
网络安全期一般是几个月
网络安全专用设备分类
墨香数据库修改问题
维护网络安全加强法制教育
济南宇泉网络技术是干嘛的
有关网络安全标题
管理多个服务器工具下载
网络安全问题应急方案
江西在线软件开发
弱电软件开发
天镇现代化网络安全服务保障
拓迈网络技术有限公司
嘉信理财服务器
江西创新服务器购买
重庆小程序软件开发公司
大一计算机网络技术实验报告
js点击清除数据库
mfc中未发现数据库源
软件开发课程与教学
数据库除操作的过程
香港理工大学计算机网络安全硕士