Oops. I found a bug with it.
Revised patches included.
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
>> 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)
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 27 Jun 2011 01:51:11 -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
***************
*** 72,77 ****
--- 74,82 ----
static void *
ts_register_func(POOL_SELECT_RESULT *res)
{
+ /* Number of result columns included in res */
+ #define NUM_COLS 3
+
TSRel *rel;
int i;
***************
*** 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;
--- 87,108 ----
for (i = 0; i < res->numrows; i++)
{
! int index = 0;
!
! rel->attr[i].attrname = strdup(res->data[i * NUM_COLS + index]);
! index++;
!
! if (res->data[i * NUM_COLS + index])
! rel->attr[i].adsrc = strdup(res->data[i * NUM_COLS + index]);
! else
! rel->attr[i].adsrc = NULL;
!
! index++;
!
! rel->attr[i].use_timestamp = *(res->data[i * NUM_COLS + index]) == 't';
! pool_debug("attrname %s adsrc %s use_timestamp = %d",
! rel->attr[i].attrname, (rel->attr[i].adsrc? rel->attr[i].adsrc:"NULL"),
! 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" \
--- 126,132 ----
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" \
--- 138,144 ----
" 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));
--- 365,375 ----
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++;
}
--- 432,441 ----
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));
--- 446,456 ----
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)
--- 462,476 ----
/*
* 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++;
}
}
--- 493,499 ----
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));
}
}
}
}
--- 514,536 ----
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;
--- 582,591 ----
{
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 ****
--- 855,893 ----
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
[email protected]
http://pgfoundry.org/mailman/listinfo/pgpool-hackers