十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
这篇文章主要介绍了PostgreSQL如何实现输出,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
新源网站制作公司哪家好,找创新互联!从网页设计、网站建设、微信开发、APP开发、响应式网站等网站项目制作,到程序开发,运营维护。创新互联自2013年创立以来到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联。
参照current_date函数,首先通过日志跟踪其parse tree,重点关注targetList
2019-04-19 17:06:15.591 CST,"xdb","testdb",1693,"[local]",5cb98b16.69d,3,"SELECT",2019-04-19 16:47:18 CST,3/4,0,LOG,00000,"parse tree:"," {QUERY :commandType 1 ... :targetList ( {TARGETENTRY :expr {SQLVALUEFUNCTION :op 0 :type 1082 :typmod -1 :location 7 } :resno 1 :resname current_date :ressortgroupref 0 :resorigtbl 0 :resorigcol 0 :resjunk false } ) ... :stmt_len 27 }
分析源代码,找到与输出相关的文件是src/backend/parser/parse_target.c,相关的函数为transformTargetEntry,跟踪此函数,打印调用栈:
(gdb) bt #0 transformTargetEntry (pstate=0x16afae8, node=0x16af770, expr=0x0, exprKind=EXPR_KIND_SELECT_TARGET, colname=0x0, resjunk=false) at parse_target.c:93 #1 0x000000000060b1f9 in transformTargetList (pstate=0x16afae8, targetlist=0x16af828, exprKind=EXPR_KIND_SELECT_TARGET) at parse_target.c:191 #2 0x00000000005b1e3a in transformSelectStmt (pstate=0x16afae8, stmt=0x16af938) at analyze.c:1243 #3 0x00000000005b03db in transformStmt (pstate=0x16afae8, parseTree=0x16af938) at analyze.c:301 #4 0x00000000005b02b6 in transformOptionalSelectInto (pstate=0x16afae8, parseTree=0x16af938) at analyze.c:246 #5 0x00000000005b0174 in transformTopLevelStmt (pstate=0x16afae8, parseTree=0x16afa50) at analyze.c:196 #6 0x00000000005affcc in parse_analyze (parseTree=0x16afa50, sourceText=0x16aed78 "select current_date from t1;", paramTypes=0x0, numParams=0, queryEnv=0x0) at analyze.c:116 #7 0x00000000008bb78c in pg_analyze_and_rewrite (parsetree=0x16afa50, query_string=0x16aed78 "select current_date from t1;", paramTypes=0x0, numParams=0, queryEnv=0x0) at postgres.c:689 #8 0x00000000008bbddd in exec_simple_query (query_string=0x16aed78 "select current_date from t1;") at postgres.c:1070 #9 0x00000000008c01f3 in PostgresMain (argc=1, argv=0x16dcd28, dbname=0x16dcb90 "testdb", username=0x16aba98 "xdb") at postgres.c:4182 #10 0x000000000081e0ce in BackendRun (port=0x16d0b50) at postmaster.c:4361 #11 0x000000000081d841 in BackendStartup (port=0x16d0b50) at postmaster.c:4033 #12 0x0000000000819c3b in ServerLoop () at postmaster.c:1706 #13 0x00000000008194f1 in PostmasterMain (argc=1, argv=0x16a9a50) at postmaster.c:1379 #14 0x0000000000742993 in main (argc=1, argv=0x16a9a50) at main.c:228
其中FigureColnameInternal函数为current_date设置输出列名,添加以下代码,则实现输出sysdate:
//Hacker : 添加系统列 case SVFOP_ZZ_SYSDATE: *name = "sysdate";//zz_sysdate -> sysdate return 2;
相关源码解读
/* * transformTargetEntry() * Transform any ordinary "expression-type" node into a targetlist entry. * This is exported so that parse_clause.c can generate targetlist entries * for ORDER/GROUP BY items that are not already in the targetlist. * 转换所有普通的"表达式类型expression-type"节点为tagetlist条目. * TargetEntry作为输出参数以便parse_clause.c * 可以为ORDER/GROUP BY等未在targetlist中的items生成targetlist条目 * * node the (untransformed) parse tree for the value expression. * node 未经变换的值表达式 * * expr the transformed expression, or NULL if caller didn't do it yet. * expr 已转换的表达式,如调用者未转换则为NULL * * exprKind expression kind (EXPR_KIND_SELECT_TARGET, etc) * exprKind 表达式类型(如EXPR_KIND_SELECT_TARGET等) * * colname the column name to be assigned, or NULL if none yet set. * colname 分配的列名或者为NULL * * resjunk true if the target should be marked resjunk, ie, it is not * wanted in the final projected tuple. * resjunk 如目标应标记为resjunk,则为T,比如该列不希望投影为最终的元组 */ TargetEntry * transformTargetEntry(ParseState *pstate, Node *node, Node *expr, ParseExprKind exprKind, char *colname, bool resjunk) { /* Transform the node if caller didn't do it already */ //expr为NULL,则转换之 if (expr == NULL) { /* * If it's a SetToDefault node and we should allow that, pass it * through unmodified. (transformExpr will throw the appropriate * error if we're disallowing it.) */ if (exprKind == EXPR_KIND_UPDATE_SOURCE && IsA(node, SetToDefault)) expr = node; else expr = transformExpr(pstate, node, exprKind); } if (colname == NULL && !resjunk) { /* * Generate a suitable column name for a column without any explicit * 'AS ColumnName' clause. * 如非显式指定列名(AS ColumnName),产生一个合适的列名 */ colname = FigureColname(node); } //返回TargetEntry return makeTargetEntry((Expr *) expr, (AttrNumber) pstate->p_next_resno++, colname, resjunk); } /* * FigureColname - * if the name of the resulting column is not specified in the target * list, we have to guess a suitable name. The SQL spec provides some * guidance, but not much... * * Note that the argument is the *untransformed* parse tree for the target * item. This is a shade easier to work with than the transformed tree. */ char * FigureColname(Node *node) { char *name = NULL; (void) FigureColnameInternal(node, &name); if (name != NULL) return name; /* default result if we can't guess anything */ return "?column?"; } /* * FigureColnameInternal - * internal workhorse for FigureColname * * Return value indicates strength of confidence in result: * 0 - no information * 1 - second-best name choice * 2 - good name choice * The return value is actually only used internally. * If the result isn't zero, *name is set to the chosen name. */ static int FigureColnameInternal(Node *node, char **name) { int strength = 0; if (node == NULL) return strength; switch (nodeTag(node)) { ... case T_SQLValueFunction: /* make these act like a function or variable */ switch (((SQLValueFunction *) node)->op) { case SVFOP_CURRENT_DATE: *name = "current_date"; return 2; ... //Hacker : 添加系统列 case SVFOP_ZZ_SYSDATE: *name = "sysdate";//zz_sysdate -> sysdate return 2; } break; ... } }
感谢你能够认真阅读完这篇文章,希望小编分享的“PostgreSQL如何实现输出”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!