Re: [HACKERS] Re: [HACKERS] Is it necessary to rewrite table while increasing the scale of datatype numeric?

2013-09-16 Thread wangshuo

"wangs...@highgo.com.cn"  wrote:


I modified the code for this situation.I consider it very simple.



It will does not modify the table file, when the scale has been
increased exclusively.




Kevin Grittner  wrote:

This patch would allow data in a column which was not consistent
with the column definition:

test=# create table n (val numeric(5,2));
CREATE TABLE
test=# insert into n values ('123.45');
INSERT 0 1
test=# select * from n;
  val  

 123.45
(1 row)

test=# alter table n alter column val type numeric(5,4);
ALTER TABLE
test=# select * from n;
  val  

 123.45
(1 row)

Without your patch the ALTER TABLE command gets this error (as it
should):

test=# alter table n alter column val type numeric(5,4);
ERROR:  numeric field overflow
DETAIL:  A field with precision 5, scale 4 must round to an absolute
value less than 10^1.

--
Kevin Grittner
EDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Thanks for your reply and test.
I had added a new function named ATNumericColumnChangeRequiresCheck to 
check the data

when the scale of numeric increase.
Now,the ALTER TABLE command could prompt this error:

postgres=# alter table tt alter  COLUMN t1 type numeric (5,4);
ERROR:  numeric field overflow
DETAIL:  A field with precision 5, scale 4 must round to an absolute 
value less than 10^1.

STATEMENT:  alter table tt alter  COLUMN t1 type numeric (5,4);
ERROR:  numeric field overflow
DETAIL:  A field with precision 5, scale 4 must round to an absolute 
value less than 10^1.


I packed a new patch about this modification.

I think this  ' altering field  type model ' could modify all the type 
in database.
Make different modification to column‘s datatype for different 
situation.
For example when you modify the scale of numeric, if you think that the 
5.0 and 5.00 is different,

the table file must be rewritten; otherwise, needn't be rewritten.


 Wang Shuo
 HighGo Software Co.,Ltd.
 September 16, 2013
diff -uNr b/src/backend/commands/tablecmds.c a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c	2013-08-31 17:11:00.529744869 +0800
+++ a/src/backend/commands/tablecmds.c	2013-09-16 16:33:49.527455560 +0800
@@ -367,7 +367,10 @@
 	  AlteredTableInfo *tab, Relation rel,
 	  bool recurse, bool recursing,
 	  AlterTableCmd *cmd, LOCKMODE lockmode);
-static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
+static void ATNumericColumnChangeRequiresCheck(AlteredTableInfo *tab);
+static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno,
+	int32 oldtypemod, int32 newtypemod,
+			AlteredTableInfo *tab);
 static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	  AlterTableCmd *cmd, LOCKMODE lockmode);
 static void ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
@@ -7480,7 +7483,7 @@
 		newval->expr = (Expr *) transform;
 
 		tab->newvals = lappend(tab->newvals, newval);
-		if (ATColumnChangeRequiresRewrite(transform, attnum))
+		if (ATColumnChangeRequiresRewrite(transform, attnum, attTup->atttypmod, targettypmod, tab))
 			tab->rewrite = true;
 	}
 	else if (transform)
@@ -7520,6 +7523,102 @@
 }
 
 /*
+ * check the data when the scale of numeric increase
+ */
+
+static void
+ATNumericColumnChangeRequiresCheck(AlteredTableInfo *tab)
+{
+	Relation	oldrel;
+	TupleDesc	oldTupDesc;
+	int			i;
+	ListCell   *l;
+	EState	   *estate;
+	ExprContext *econtext;
+	bool	   *isnull;
+	TupleTableSlot *oldslot;
+	HeapScanDesc scan;
+	HeapTuple	tuple;
+	Snapshot	snapshot;
+	List	   *dropped_attrs = NIL;
+	ListCell   *lc;
+	Datum	   *values;
+
+	/*
+	 * Open the relation(s).  We have surely already locked the existing
+	 * table.
+	 */
+
+	oldrel = heap_open(tab->relid, NoLock);
+	oldTupDesc = tab->oldDesc;
+
+	for (i = 0; i < oldTupDesc->natts; i++)
+	{
+		if (oldTupDesc->attrs[i]->attisdropped)
+			dropped_attrs = lappend_int(dropped_attrs, i);
+	}
+	/*
+	 * Generate the constraint and default execution states
+	 */
+
+	estate = CreateExecutorState();	
+
+	foreach(l, tab->newvals)
+	{
+		NewColumnValue *ex = lfirst(l);
+
+		/* expr already planned */
+		ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
+	}
+
+	econtext = GetPerTupleExprContext(estate);
+	oldslot = MakeSingleTupleTableSlot(oldTupDesc);
+	
+	/* Preallocate values/isnull arrays */
+	i = oldTupDesc->natts;
+	values = (Datum *) palloc(i * sizeof(Datum));
+	isnull = (bool *) palloc(i * sizeof(bool));
+	memset(values, 0, i * sizeof(Datum));
+	memset(isnull, true, i * sizeof(bool));
+
+	/*
+	 * Scan through the rows, generating a new row if needed and then
+	 * checking all the constraints.
+	 */
+	snapshot = RegisterSnapshot(GetLatestSnapshot());
+	scan = heap_beginscan(oldrel, snapshot, 0, NULL);
+	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	{
+		foreach(lc, dropped_attrs)
+			isnull[lfirst_int(lc)] = true;
+
+		heap_deform_tuple(tuple, oldTupDesc, values, isnull);
+		ExecStoreTuple(t

[HACKERS] Re: [HACKERS] Re: [HACKERS] Is it necessary to rewrite table while increasing the scale of datatype numeric?

2013-09-06 Thread Kevin Grittner
"wangs...@highgo.com.cn"  wrote:

> I modified the code for this situation.I consider it very simple.

> It will does not modify the table file, when the scale has been
> increased exclusively.

This patch would allow data in a column which was not consistent
with the column definition:

test=# create table n (val numeric(5,2));
CREATE TABLE
test=# insert into n values ('123.45');
INSERT 0 1
test=# select * from n;
  val  

 123.45
(1 row)

test=# alter table n alter column val type numeric(5,4);
ALTER TABLE
test=# select * from n;
  val  

 123.45
(1 row)

Without your patch the ALTER TABLE command gets this error (as it
should):

test=# alter table n alter column val type numeric(5,4);
ERROR:  numeric field overflow
DETAIL:  A field with precision 5, scale 4 must round to an absolute value less 
than 10^1.

--
Kevin Grittner
EDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers