> 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

Reply via email to