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安全错误
数据库的锁怎样保障安全
信息科网络安全协议书
初中社交网络安全教育
信用软件开发商
社会救助失信对象数据库
转发网络安全运行中心通知
网络安全事故可能导致的危害英文
数据库spring免费
深圳六狐网络技术有限公司
华为手里代理服务器
烟草行业基层单位网络安全
一键安装软件开发
电脑打印服务器怎么关闭
对公司软件开发方面建议
环境工程的网络安全应用事例
网络安全等级划分几组
怎么安装数据库2012
远程数据库英文
软件开发企业核定征收政策
oa账号密码存在数据库怎么查
青年网络安全员
数据库设计用什么技术
590分理科想学软件开发
吉安委网络安全信息中心主任
信息化时代与网络安全
深圳crm软件开发团队
版本火车 软件开发
网络安全协会建立专家库的意义
知网中文科技期刊数据库
沙狐网络技术
网络安全事例部队