> On 24-06-11 10:15, Tatsuo Ishii wrote: >>> Any chance that this idea will be implemented anytime soon? >>> http://lists.pgfoundry.org/pipermail/pgpool-hackers/2011-May/000716.html >> >> Revisiting it now. Since nobody proposed patches for this, I've been >> starting coding now:-) The rewriting code is quite complex and I am >> not sure whether I could finish the work by the end of this >> weekend. Let me try out... > > Wow, I am impressed. I hope you will succeed. > > As a matter of fact, a colleague of mine created a patch that handles one > specific case: timezone('utc'::text, now()), which is the most important > case for us. > > He told me that the code is too complex for him to quickly handle the > generic case, so he added this specific case instead. I can't imagine the > patch being useful to you, but if you want to look at it, let me know.
I have finished the work so far. However I could not make it work for extended protocol. This means still Java programs or PHP PDO programs are still remain same as they were. So I am not sure includes patches is usefull for you or not. What I did was, extract default expressions (such as timezone('utc'::text, now()) from the system catalog and get the result to replace a query. So you could use any expressions including now() for default values. To adopt the cases for extended protocol, probably I need to modify bind_rewrite_timestamp. Here are test cases: create table t1(i int, t timestamp default timezone('utc'::text, now()), t2 timestamp default current_timestamp); CREATE TABLE begin; BEGIN insert into t1 values(1, now()); INSERT 0 1 insert into t1 default values; INSERT 0 1 insert into t1 values(2); INSERT 0 1 insert into t1 values(3, default); INSERT 0 1 insert into t1(i) values(4); INSERT 0 1 update t1 set i = 100 where i is null; UPDATE 1 update t1 set i = 101,t = current_timestamp where i = 100; UPDATE 1 select * from t1 where i = 101; i | t | t2 -----+----------------------------+---------------------------- 101 | 2011-06-25 17:18:30.676202 | 2011-06-25 17:18:30.676202 (1 row) update t1 set i = 102,t = default where i = 101; UPDATE 1 select * from t1; i | t | t2 -----+----------------------------+---------------------------- 1 | 2011-06-25 17:18:30.676202 | 2011-06-25 17:18:30.676202 2 | 2011-06-25 08:18:30.676202 | 2011-06-25 17:18:30.676202 3 | 2011-06-25 08:18:30.676202 | 2011-06-25 17:18:30.676202 4 | 2011-06-25 08:18:30.676202 | 2011-06-25 17:18:30.676202 102 | 2011-06-25 08:18:30.676202 | 2011-06-25 17:18:30.676202 (5 rows) -- Tatsuo Ishii SRA OSS, Inc. Japan English: http://www.sraoss.co.jp/index_en.php Japanese: http://www.sraoss.co.jp
Index: pool_timestamp.c =================================================================== RCS file: /cvsroot/pgpool/pgpool-II/pool_timestamp.c,v retrieving revision 1.17 diff -c -r1.17 pool_timestamp.c *** pool_timestamp.c 21 Jun 2011 07:24:00 -0000 1.17 --- pool_timestamp.c 25 Jun 2011 08:19:07 -0000 *************** *** 34,40 **** typedef struct { ! char *attrname; int use_timestamp; } TSAttr; --- 34,41 ---- typedef struct { ! char *attrname; /* attribute name */ ! char *adsrc; /* default value expression */ int use_timestamp; } TSAttr; *************** *** 63,68 **** --- 64,70 ---- static bool rewrite_timestamp_update(UpdateStmt *u_stmt, TSRewriteContext *ctx); static char *get_current_timestamp(POOL_CONNECTION_POOL *backend); static Node *makeTsExpr(TSRewriteContext *ctx); + static A_Const *makeStringConstFromQuery(POOL_CONNECTION_POOL *backend, char *expression); bool raw_expression_tree_walker(Node *node, bool (*walker) (), void *context); #define MAX_RELCACHE 32 *************** *** 82,91 **** for (i = 0; i < res->numrows; i++) { ! rel->attr[i].attrname = strdup(res->data[i * 2]); ! rel->attr[i].use_timestamp = *(res->data[i * 2 + 1]) == 't'; ! pool_debug("attrname %s use_timestamp = %d", ! rel->attr[i].attrname, rel->attr[i].use_timestamp); } rel->relnatts = res->numrows; --- 84,95 ---- for (i = 0; i < res->numrows; i++) { ! rel->attr[i].attrname = strdup(res->data[i * 3]); ! if (res->data[i * 2 + 1]) ! rel->attr[i].adsrc = strdup(res->data[i * 3 + 1]); ! rel->attr[i].use_timestamp = *(res->data[i * 3 + 2]) == 't'; ! pool_debug("attrname %s adsrc %s use_timestamp = %d", ! rel->attr[i].attrname, rel->attr[i].adsrc, rel->attr[i].use_timestamp); } rel->relnatts = res->numrows; *************** *** 109,115 **** static TSRel* relcache_lookup(TSRewriteContext *ctx) { ! #define ATTRDEFQUERY "SELECT attname, coalesce((d.adsrc = 'now()' OR d.adsrc LIKE '%%''now''::text%%')" \ " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ " a.atttypid = 'timestamp with time zone'::regtype::oid OR" \ " a.atttypid = 'date'::regtype::oid OR" \ --- 113,119 ---- static TSRel* relcache_lookup(TSRewriteContext *ctx) { ! #define ATTRDEFQUERY "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%')" \ " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ " a.atttypid = 'timestamp with time zone'::regtype::oid OR" \ " a.atttypid = 'date'::regtype::oid OR" \ *************** *** 121,127 **** " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.relname = '%s'" \ " ORDER BY a.attnum" ! #define ATTRDEFQUERY2 "SELECT attname, coalesce((d.adsrc = 'now()' OR d.adsrc LIKE '%%''now''::text%%')" \ " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ " a.atttypid = 'timestamp with time zone'::regtype::oid OR" \ " a.atttypid = 'date'::regtype::oid OR" \ --- 125,131 ---- " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.relname = '%s'" \ " ORDER BY a.attnum" ! #define ATTRDEFQUERY2 "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%')" \ " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ " a.atttypid = 'timestamp with time zone'::regtype::oid OR" \ " a.atttypid = 'date'::regtype::oid OR" \ *************** *** 348,354 **** if (relcache->attr[i].use_timestamp) { rewrite = true; ! values = lappend(values, makeTsExpr(ctx)); } else values = lappend(values, makeNode(SetToDefault)); --- 352,362 ---- if (relcache->attr[i].use_timestamp) { rewrite = true; ! if (ctx->rewrite_to_params) ! values = lappend(values, makeTsExpr(ctx)); ! else ! values = lappend(values, ! makeStringConstFromQuery(ctx->backend, relcache->attr[i].adsrc)); } else values = lappend(values, makeNode(SetToDefault)); *************** *** 411,417 **** if (relcache->attr[i].use_timestamp == true && IsA(lfirst(lc_val), SetToDefault)) { rewrite = true; ! lfirst(lc_val) = makeTsExpr(ctx); } i++; } --- 419,428 ---- if (relcache->attr[i].use_timestamp == true && IsA(lfirst(lc_val), SetToDefault)) { rewrite = true; ! if (ctx->rewrite_to_params) ! lfirst(lc_val) = makeTsExpr(ctx); ! else ! lfirst(lc_val) = makeStringConstFromQuery(ctx->backend, relcache->attr[i].adsrc); } i++; } *************** *** 422,428 **** if (relcache->attr[i].use_timestamp == true) { rewrite = true; ! values = lappend(values, makeTsExpr(ctx)); } else values = lappend(values, makeNode(SetToDefault)); --- 433,443 ---- if (relcache->attr[i].use_timestamp == true) { rewrite = true; ! if (ctx->rewrite_to_params) ! values = lappend(values, makeTsExpr(ctx)); ! else ! values = lappend(values, ! makeStringConstFromQuery(ctx->backend, relcache->attr[i].adsrc)); } else values = lappend(values, makeNode(SetToDefault)); *************** *** 434,445 **** /* * INSERT INTO rel(col1, col2) VALUES (val, val2) * ! * if timestamp column does not given by column list * add colname to column list and add timestamp to values list. */ int append_columns = 0; ResTarget *col; for (i = 0; i < relcache->relnatts; i++) { if (relcache->attr[i].use_timestamp == false) --- 449,463 ---- /* * INSERT INTO rel(col1, col2) VALUES (val, val2) * ! * if timestamp column is not given by column list * add colname to column list and add timestamp to values list. */ int append_columns = 0; + int *append_columns_list; ResTarget *col; + append_columns_list = (int *)malloc(sizeof(int)*relcache->relnatts); + for (i = 0; i < relcache->relnatts; i++) { if (relcache->attr[i].use_timestamp == false) *************** *** 462,468 **** col->indirection = NIL; col->val = NULL; i_stmt->cols = lappend(i_stmt->cols, col); ! append_columns++; } } --- 480,486 ---- col->indirection = NIL; col->val = NULL; i_stmt->cols = lappend(i_stmt->cols, col); ! append_columns_list[append_columns++] = i; } } *************** *** 483,497 **** if (relcache->attr[i].use_timestamp == true && IsA(lfirst(lc_val), SetToDefault)) { rewrite = true; ! lfirst(lc_val) = makeTsExpr(ctx); } } /* add ts_const to values list */ for (i = 0; i < append_columns; i++) { ! values = lappend(values, makeTsExpr(ctx)); } } } } --- 501,523 ---- if (relcache->attr[i].use_timestamp == true && IsA(lfirst(lc_val), SetToDefault)) { rewrite = true; ! if (ctx->rewrite_to_params) ! lfirst(lc_val) = makeTsExpr(ctx); ! else ! lfirst(lc_val) = makeStringConstFromQuery(ctx->backend, relcache->attr[i].adsrc); } } /* add ts_const to values list */ for (i = 0; i < append_columns; i++) { ! if (ctx->rewrite_to_params) ! values = lappend(values, makeTsExpr(ctx)); ! else ! values = lappend(values, ! makeStringConstFromQuery(ctx->backend, relcache->attr[append_columns_list[i]].adsrc)); } + free(append_columns_list); } } } *************** *** 543,549 **** { if (relcache->attr[i].use_timestamp) { ! res->val = (Node *) makeTsExpr(ctx); rewrite = true; } break; --- 569,578 ---- { if (relcache->attr[i].use_timestamp) { ! if (ctx->rewrite_to_params) ! res->val = (Node *) makeTsExpr(ctx); ! else ! res->val = (Node *)makeStringConstFromQuery(ctx->backend, relcache->attr[i].adsrc); rewrite = true; } break; *************** *** 813,818 **** --- 842,880 ---- return new_msg; } + static A_Const *makeStringConstFromQuery(POOL_CONNECTION_POOL *backend, char *expression) + { + A_Const *con; + POOL_SELECT_RESULT *res; + POOL_STATUS status; + char query[1024]; + int len; + char *str; + + snprintf(query, sizeof(query), "SELECT %s", expression); + status = do_query(MASTER(backend), query, &res, MAJOR(backend)); + if (status != POOL_CONTINUE) + { + pool_error("makeStringConstFromQuery: do_query faild"); + return NULL; + } + + if (res->numrows != 1) + { + free_select_result(res); + return NULL; + } + + len = strlen(res->data[0]) + 1; + str = palloc(len); + strcpy(str, res->data[0]); + free_select_result(res); + + con = makeNode(A_Const); + con->val.type = T_String; + con->val.val.str = str; + return con; + } /* from nodeFuncs.c start */
_______________________________________________ Pgpool-hackers mailing list Pgpool-hackers@pgfoundry.org http://pgfoundry.org/mailman/listinfo/pgpool-hackers