千家信息网

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怎么实现用户自定义"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0