Since 8.3, the system provides automatic I/O conversion casts between the built-in string types and other types, but there's currently no way for a user to declare additional casts using the I/O functions. You can always create a simple SQL function to do that, but it seems like we should provide a direct interface for that. I propose the syntax:

CREATE CAST (<source> AS <target>) WITH INOUT [AS IMPLICIT | AS ASSIGNMENT]

Conveniently, INOUT is already a col_name_keyword, so this works without any conflicts or new keywords.

This would be very useful for those who want relax some built-in automatic assignment casts to implicit casts, 8.2 style, as well as anyone creating a user-defined data type with casts that can be implemented with the I/O functions.

Patch attached. I'm using a magic OID "1" in pg_cast.castfunc field to mark these extra I/O conversion casts. Perhaps we want to have a separate field for that or something, but that was a quick way to get started.

Anyone else think this is a good idea? Thoughts on the implementation?

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com
Index: src/backend/commands/functioncmds.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/commands/functioncmds.c,v
retrieving revision 1.98
diff -c -r1.98 functioncmds.c
*** src/backend/commands/functioncmds.c	18 Jul 2008 03:32:52 -0000	1.98
--- src/backend/commands/functioncmds.c	29 Aug 2008 10:56:49 -0000
***************
*** 1474,1479 ****
--- 1474,1481 ----
  
  		ReleaseSysCache(tuple);
  	}
+ 	else if (stmt->coerceviaio)
+ 		funcid = IOCOERCE_FUNCOID;
  	else
  	{
  		int16		typ1len;
***************
*** 1589,1595 ****
  	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  
  	/* dependency on function */
! 	if (OidIsValid(funcid))
  	{
  		referenced.classId = ProcedureRelationId;
  		referenced.objectId = funcid;
--- 1591,1597 ----
  	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  
  	/* dependency on function */
! 	if (OidIsValid(funcid) && funcid != IOCOERCE_FUNCOID)
  	{
  		referenced.classId = ProcedureRelationId;
  		referenced.objectId = funcid;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.618
diff -c -r2.618 gram.y
*** src/backend/parser/gram.y	18 Jul 2008 03:32:52 -0000	2.618
--- src/backend/parser/gram.y	29 Aug 2008 09:29:22 -0000
***************
*** 4534,4539 ****
--- 4534,4550 ----
  					n->context = (CoercionContext) $10;
  					$$ = (Node *)n;
  				}
+ 			| CREATE CAST '(' Typename AS Typename ')'
+ 					WITH INOUT cast_context
+ 				{
+ 					CreateCastStmt *n = makeNode(CreateCastStmt);
+ 					n->sourcetype = $4;
+ 					n->targettype = $6;
+ 					n->func = NULL;
+ 					n->coerceviaio = true;
+ 					n->context = (CoercionContext) $10;
+ 					$$ = (Node *)n;
+ 				}
  		;
  
  cast_context:  AS IMPLICIT_P					{ $$ = COERCION_IMPLICIT; }
Index: src/backend/parser/parse_coerce.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/parser/parse_coerce.c,v
retrieving revision 2.163
diff -c -r2.163 parse_coerce.c
*** src/backend/parser/parse_coerce.c	30 Jul 2008 21:23:17 -0000	2.163
--- src/backend/parser/parse_coerce.c	29 Aug 2008 09:38:51 -0000
***************
*** 1745,1751 ****
  		if (ccontext >= castcontext)
  		{
  			*funcid = castForm->castfunc;
! 			if (OidIsValid(*funcid))
  				result = COERCION_PATH_FUNC;
  			else
  				result = COERCION_PATH_RELABELTYPE;
--- 1745,1756 ----
  		if (ccontext >= castcontext)
  		{
  			*funcid = castForm->castfunc;
! 			if (*funcid == IOCOERCE_FUNCOID)
! 			{
! 				result = COERCION_PATH_COERCEVIAIO;
! 				*funcid = InvalidOid;
! 			}
! 			else if (OidIsValid(*funcid))
  				result = COERCION_PATH_FUNC;
  			else
  				result = COERCION_PATH_RELABELTYPE;
Index: src/include/catalog/pg_cast.h
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/catalog/pg_cast.h,v
retrieving revision 1.39
diff -c -r1.39 pg_cast.h
*** src/include/catalog/pg_cast.h	27 Mar 2008 03:57:34 -0000	1.39
--- src/include/catalog/pg_cast.h	29 Aug 2008 09:14:15 -0000
***************
*** 56,61 ****
--- 56,63 ----
  	COERCION_CODE_EXPLICIT = 'e'	/* explicit cast operation */
  } CoercionCodes;
  
+ #define IOCOERCE_FUNCOID 1
+ 
  
  /* ----------------
   *		compiler constants for pg_cast
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.371
diff -c -r1.371 parsenodes.h
*** src/include/nodes/parsenodes.h	7 Aug 2008 01:11:51 -0000	1.371
--- src/include/nodes/parsenodes.h	29 Aug 2008 09:21:08 -0000
***************
*** 1989,1994 ****
--- 1989,1995 ----
  	TypeName   *targettype;
  	FuncWithArgs *func;
  	CoercionContext context;
+ 	bool		coerceviaio;
  } CreateCastStmt;
  
  /* ----------------------
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to