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
Pgpool-hackers@pgfoundry.org
http://pgfoundry.org/mailman/listinfo/pgpool-hackers

Reply via email to