ECPG support for string pseudo-type

Started by Boszormenyi Zoltanover 16 years ago7 messages
#1Boszormenyi Zoltan
zb@cybertec.at
1 attachment(s)

Hi,

in a continued effort for better Informix ESQL/C compatibility,
we added the "string" pseudo-type handling to ECPG.
This type in ESQL/C is documented as:

--------------------------------------------------
The string Data Type

The string data type is an ESQL/C data type that holds character data
that is
null terminated and does not contain trailing blanks. When an application
reads a value from a CHAR column into a host variable of data type
string, it
strips the value of any trailing blanks and appends a null terminator. The
behavior is the same if an application reads a value from a VARCHAR column
into a host variable of data type string.
Declare the string data type with a length of [n+1] (where n is the size
of the
column with values that you want read) to allow for the null terminator. Use
the following syntax to declare a host variable of the string data type:
EXEC SQL BEGIN DECLARE SECTION;
string str_name[n + 1];
EXEC SQL END DECLARE SECTION;
--------------------------------------------------

So, we added it accordingly. This means the following:
- "string" has become a type name, reserved word in ECPG.
- When ECPG encounters "string", it will be transparently replaced by
"char" in the generated C source, but ECPGt_string will be passed
to ECPGdo()
- ecpg_get_data() right-trims the string value if ECPGt_string was passed.

Two regression tests had to be modified because "string" is now
a type name: preproc/define.pgc and preproc/type.pgc.

The attached patch is built upon our previous patch supporting
dynamic cursor and SQLDA.

Best regards,
Zolt�n B�sz�rm�nyi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

Attachments:

ecpg-string-8.4-1-ctxdiff.patchtext/x-patch; name=ecpg-string-8.4-1-ctxdiff.patchDownload
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/data.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/data.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/data.c	2009-01-15 12:52:55.000000000 +0100
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/data.c	2009-07-04 12:27:57.000000000 +0200
*************** ecpg_get_data(const PGresult *results, i
*** 138,143 ****
--- 138,144 ----
  			case ECPGt_char:
  			case ECPGt_unsigned_char:
  			case ECPGt_varchar:
+ 			case ECPGt_string:
  				break;
  
  			default:
*************** ecpg_get_data(const PGresult *results, i
*** 389,394 ****
--- 390,396 ----
  
  				case ECPGt_char:
  				case ECPGt_unsigned_char:
+ 				case ECPGt_string:
  					if (pval)
  					{
  						if (varcharsize == 0 || varcharsize > size)
*************** ecpg_get_data(const PGresult *results, i
*** 426,431 ****
--- 428,454 ----
  								sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
  							}
  						}
+ 						/* Do the rtrim() */
+ 						if (type == ECPGt_string)
+ 						{
+ 							char	*str = (char *) ((long) var + offset * act_tuple);
+ 							char	*last;
+ 							int	len = strlen(str);
+ 
+ 							last = str + len;
+ 							while (last > str)
+ 							{
+ 								if (*last == '\0')
+ 									last--;
+ 								else if (*last == ' ')
+ 								{
+ 									*last = '\0';
+ 									last--;
+ 								}
+ 								else
+ 									break;
+ 							}
+ 						}
  						pval += size;
  					}
  					break;
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/descriptor.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/descriptor.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/descriptor.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/descriptor.c	2009-07-04 12:12:02.000000000 +0200
*************** get_char_item(int lineno, void *var, enu
*** 201,206 ****
--- 201,207 ----
  	{
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			strncpy((char *) var, value, varcharsize);
  			break;
  		case ECPGt_varchar:
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/execute.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/execute.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/execute.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/execute.c	2009-07-04 12:12:02.000000000 +0200
*************** ecpg_store_result(const PGresult *result
*** 360,365 ****
--- 360,366 ----
  			{
  				case ECPGt_char:
  				case ECPGt_unsigned_char:
+ 				case ECPGt_string:
  					if (!var->varcharsize && !var->arrsize)
  					{
  						/* special mode for handling char**foo=0 */
*************** ecpg_store_result(const PGresult *result
*** 419,425 ****
  
  	/* fill the variable with the tuple(s) */
  	if (!var->varcharsize && !var->arrsize &&
! 		(var->type == ECPGt_char || var->type == ECPGt_unsigned_char))
  	{
  		/* special mode for handling char**foo=0 */
  
--- 420,426 ----
  
  	/* fill the variable with the tuple(s) */
  	if (!var->varcharsize && !var->arrsize &&
! 		(var->type == ECPGt_char || var->type == ECPGt_unsigned_char || var->type == ECPGt_string))
  	{
  		/* special mode for handling char**foo=0 */
  
*************** ecpg_store_input(const int lineno, const
*** 758,763 ****
--- 759,765 ----
  
  			case ECPGt_char:
  			case ECPGt_unsigned_char:
+ 			case ECPGt_string:
  				{
  					/* set slen to string length if type is char * */
  					int			slen = (var->varcharsize == 0) ? strlen((char *) var->value) : (unsigned int) var->varcharsize;
*************** ecpg_execute(struct statement * stmt)
*** 1196,1201 ****
--- 1198,1204 ----
  					{
  						case ECPGt_char:
  						case ECPGt_varchar:
+ 						case ECPGt_string:
  							desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
  							break;
  						default:
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/misc.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/misc.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/misc.c	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/misc.c	2009-07-04 12:12:02.000000000 +0200
*************** ECPGset_noind_null(enum ECPGttype type, 
*** 295,300 ****
--- 295,301 ----
  	{
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			*((char *) ptr) = '\0';
  			break;
  		case ECPGt_short:
*************** ECPGis_noind_null(enum ECPGttype type, v
*** 361,366 ****
--- 362,368 ----
  	{
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			if (*((char *) ptr) == '\0')
  				return true;
  			break;
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/typename.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/typename.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/typename.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/typename.c	2009-07-04 12:12:02.000000000 +0200
*************** ecpg_type_name(enum ECPGttype typ)
*** 20,25 ****
--- 20,26 ----
  	switch (typ)
  	{
  		case ECPGt_char:
+ 		case ECPGt_string:
  			return "char";
  		case ECPGt_unsigned_char:
  			return "unsigned char";
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/include/ecpgtype.h postgresql-8.4.0-string/src/interfaces/ecpg/include/ecpgtype.h
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/include/ecpgtype.h	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/include/ecpgtype.h	2009-07-04 12:06:05.000000000 +0200
*************** enum ECPGttype
*** 62,68 ****
  	ECPGt_EOIT,					/* End of insert types. */
  	ECPGt_EORT,					/* End of result types. */
  	ECPGt_NO_INDICATOR,			/* no indicator */
! 	ECPGt_sqlda				/* INFORMIX-compatible sqlda_t descriptor */
  };
  
   /* descriptor items */
--- 62,69 ----
  	ECPGt_EOIT,					/* End of insert types. */
  	ECPGt_EORT,					/* End of result types. */
  	ECPGt_NO_INDICATOR,			/* no indicator */
! 	ECPGt_sqlda,				/* INFORMIX-compatible sqlda_t descriptor */
! 	ECPGt_string				/* trimmed (char *) type */
  };
  
   /* descriptor items */
*************** enum ECPGdtype
*** 87,93 ****
  	ECPGd_cardinality
  };
  
! #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_interval)
  
  /* we also have to handle different statement types */
  enum ECPG_statement_type
--- 88,94 ----
  	ECPGd_cardinality
  };
  
! #define IS_SIMPLE_TYPE(type) (((type) >= ECPGt_char && (type) <= ECPGt_interval) || ((type) == ECPGt_string))
  
  /* we also have to handle different statement types */
  enum ECPG_statement_type
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/c_keywords.c postgresql-8.4.0-string/src/interfaces/ecpg/preproc/c_keywords.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/c_keywords.c	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/c_keywords.c	2009-07-04 13:40:14.000000000 +0200
*************** static const ScanKeyword ScanCKeywords[]
*** 45,50 ****
--- 45,51 ----
  	{"short", SQL_SHORT, 0},
  	{"signed", SQL_SIGNED, 0},
  	{"static", S_STATIC, 0},
+ 	{"string", STRING_P, 0},
  	{"struct", SQL_STRUCT, 0},
  	{"to", TO, 0},
  	{"typedef", S_TYPEDEF, 0},
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.addons postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.addons
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.addons	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.addons	2009-07-04 14:26:02.000000000 +0200
*************** ECPG: ColIdcol_name_keyword rule
*** 331,336 ****
--- 331,337 ----
  	| ECPGKeywords                  { $$ = $1; }
  	| ECPGCKeywords                 { $$ = $1; }
  	| CHAR_P                        { $$ = make_str("char"); }
+ 	| STRING_P                      { $$ = make_str("char"); }
  	| VALUES                        { $$ = make_str("values"); }
  ECPG: type_function_nametype_func_name_keyword rule
  	| ECPGKeywords                          { $$ = $1; }
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.header postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.header
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.header	2009-06-11 01:11:52.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.header	2009-07-04 11:49:50.000000000 +0200
*************** adjust_informix(struct arguments *list)
*** 256,267 ****
  		original_var = ptr->variable->name;
  		sprintf(temp, "%d))", ecpg_informix_var);
  
! 		if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
  		}
! 		else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
--- 256,267 ----
  		original_var = ptr->variable->name;
  		sprintf(temp, "%d))", ecpg_informix_var);
  
! 		if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char && ptr->variable->type->type != ECPGt_string) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
  		}
! 		else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char || ptr->variable->type->type != ECPGt_string) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
*************** add_typedef(char *name, char * dimension
*** 371,376 ****
--- 371,377 ----
  		if (type_enum != ECPGt_varchar &&
  			type_enum != ECPGt_char &&
  			type_enum != ECPGt_unsigned_char &&
+ 			type_enum != ECPGt_string &&
  			atoi(this->type->type_index) >= 0)
  			mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported");
  
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.tokens postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.tokens
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.tokens	2008-11-14 11:03:33.000000000 +0100
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.tokens	2009-07-04 10:59:43.000000000 +0200
***************
*** 25,28 ****
  %token TYPECAST
  %token CSTRING CVARIABLE CPP_LINE IP 
  %token DOLCONST ECONST NCONST UCONST UIDENT
! 
--- 25,28 ----
  %token TYPECAST
  %token CSTRING CVARIABLE CPP_LINE IP 
  %token DOLCONST ECONST NCONST UCONST UIDENT
! %token STRING_P
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.trailer postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.trailer
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.trailer	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.trailer	2009-07-04 11:51:06.000000000 +0200
*************** char_variable: cvariable
*** 213,218 ****
--- 213,219 ----
  				{
  					case ECPGt_char:
  					case ECPGt_unsigned_char:
+ 					case ECPGt_string:
  						$$ = $1;
  						break;
  					case ECPGt_varchar:
*************** signed_type: SQL_SHORT				{ $$ = ECPGt_s
*** 795,800 ****
--- 796,802 ----
  		}
  		| SQL_BOOL					{ $$ = ECPGt_bool; }
  		| CHAR_P					{ $$ = ECPGt_char; }
+ 		| STRING_P					{ $$ = ECPGt_string; }
  		| DOUBLE_P					{ $$ = ECPGt_double; }
  		;
  
*************** variable: opt_pointer ECPGColLabel opt_a
*** 855,860 ****
--- 857,863 ----
  
  				case ECPGt_char:
  				case ECPGt_unsigned_char:
+ 				case ECPGt_string:
  					if (atoi(dimension) == -1)
  					{
  						int i = strlen($5);
*************** ECPGVar: SQL_VAR
*** 1331,1336 ****
--- 1334,1340 ----
  
  					case ECPGt_char:
  					case ECPGt_unsigned_char:
+ 					case ECPGt_string:
  						if (atoi(dimension) == -1)
  							type = ECPGmake_simple_type($5.type_enum, length, 0);
  						else
*************** c_anything:  ecpg_ident				{ $$ = $1; }
*** 2017,2022 ****
--- 2021,2027 ----
  		| SQL_UNSIGNED			{ $$ = make_str("unsigned"); }
  		| YEAR_P			{ $$ = make_str("year"); }
  		| CHAR_P			{ $$ = make_str("char"); }
+ 		| STRING_P			{ $$ = make_str("char"); }
  		| FLOAT_P			{ $$ = make_str("float"); }
  		| TO				{ $$ = make_str("to"); }
  		| UNION				{ $$ = make_str("union"); }
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/type.c postgresql-8.4.0-string/src/interfaces/ecpg/preproc/type.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/type.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/type.c	2009-07-04 14:12:07.000000000 +0200
*************** get_type(enum ECPGttype type)
*** 200,205 ****
--- 200,208 ----
  		case ECPGt_timestamp:
  			return ("ECPGt_timestamp");
  			break;
+ 		case ECPGt_string:
+ 			return ("ECPGt_string");
+ 			break;
  		default:
  			mmerror(PARSE_ERROR, ET_ERROR, "unrecognized variable type code %d", type);
  	}
*************** ECPGdump_a_simple(FILE *o, const char *n
*** 368,373 ****
--- 371,377 ----
  			case ECPGt_char:
  			case ECPGt_unsigned_char:
  			case ECPGt_char_variable:
+ 			case ECPGt_string:
  
  				/*
  				 * we have to use the pointer except for arrays with given
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/variable.c postgresql-8.4.0-string/src/interfaces/ecpg/preproc/variable.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/variable.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/variable.c	2009-07-04 11:45:25.000000000 +0200
*************** adjust_array(enum ECPGttype type_enum, c
*** 524,530 ****
  												"multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
  				pointer_len);
  
! 	if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char)
  		mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type");
  
  	if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
--- 524,530 ----
  												"multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
  				pointer_len);
  
! 	if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
  		mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type");
  
  	if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
*************** adjust_array(enum ECPGttype type_enum, c
*** 563,568 ****
--- 563,569 ----
  			break;
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			/* char ** */
  			if (pointer_len == 2)
  			{
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-define.c postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-define.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-define.c	2008-12-29 18:07:06.000000000 +0100
--- postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-define.c	2009-07-04 14:41:02.000000000 +0200
*************** main(void)
*** 40,46 ****
  {
  /* exec sql begin declare section */
  
! 	   typedef char  string [ 8 ];
  
  #line 21 "define.pgc"
  
--- 40,46 ----
  {
  /* exec sql begin declare section */
  
! 	   typedef char  str [ 8 ];
  
  #line 21 "define.pgc"
  
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-type.c postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-type.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-type.c	2008-12-29 18:07:06.000000000 +0100
--- postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-type.c	2009-07-04 14:42:08.000000000 +0200
*************** typedef short  mmSmallInt ;
*** 40,52 ****
  #line 8 "type.pgc"
  
  
- /* exec sql type string is char [ 11 ] */
- #line 10 "type.pgc"
- 
- typedef char string[11];
- 
  /* exec sql type c is char reference */
! #line 13 "type.pgc"
  
  typedef char* c;
  
--- 40,47 ----
  #line 8 "type.pgc"
  
  
  /* exec sql type c is char reference */
! #line 10 "type.pgc"
  
  typedef char* c;
  
*************** typedef char* c;
*** 58,73 ****
     
  
  struct TBempl { 
! #line 19 "type.pgc"
   mmInteger idnum ;
   
! #line 20 "type.pgc"
   mmChar name [ 21 ] ;
   
! #line 21 "type.pgc"
   mmSmallInt accs ;
   } ;/* exec sql end declare section */
! #line 23 "type.pgc"
  
  
  int
--- 53,68 ----
     
  
  struct TBempl { 
! #line 16 "type.pgc"
   mmInteger idnum ;
   
! #line 17 "type.pgc"
   mmChar name [ 21 ] ;
   
! #line 18 "type.pgc"
   mmSmallInt accs ;
   } ;/* exec sql end declare section */
! #line 20 "type.pgc"
  
  
  int
*************** main (void)
*** 83,117 ****
  	 
     
    
! #line 29 "type.pgc"
   struct TBempl empl ;
   
! #line 30 "type.pgc"
!  string str ;
   
! #line 31 "type.pgc"
   c ptr = NULL ;
   
! #line 36 "type.pgc"
   struct varchar_vc { 
! #line 34 "type.pgc"
   int len ;
   
! #line 35 "type.pgc"
   char text [ 10 ] ;
   } vc ;
  /* exec sql end declare section */
! #line 37 "type.pgc"
  
  
    /* exec sql var vc is [ 10 ] */
! #line 39 "type.pgc"
  
    ECPGdebug (1, stderr);
  
    empl.idnum = 1;
    { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); }
! #line 43 "type.pgc"
  
    if (sqlca.sqlcode)
      {
--- 78,112 ----
  	 
     
    
! #line 26 "type.pgc"
   struct TBempl empl ;
   
! #line 27 "type.pgc"
!  char str [ 11 ] ;
   
! #line 28 "type.pgc"
   c ptr = NULL ;
   
! #line 33 "type.pgc"
   struct varchar_vc { 
! #line 31 "type.pgc"
   int len ;
   
! #line 32 "type.pgc"
   char text [ 10 ] ;
   } vc ;
  /* exec sql end declare section */
! #line 34 "type.pgc"
  
  
    /* exec sql var vc is [ 10 ] */
! #line 36 "type.pgc"
  
    ECPGdebug (1, stderr);
  
    empl.idnum = 1;
    { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); }
! #line 40 "type.pgc"
  
    if (sqlca.sqlcode)
      {
*************** main (void)
*** 120,126 ****
      }
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT);}
! #line 51 "type.pgc"
  
    if (sqlca.sqlcode)
      {
--- 115,121 ----
      }
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT);}
! #line 48 "type.pgc"
  
    if (sqlca.sqlcode)
      {
*************** main (void)
*** 129,135 ****
      }
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' )", ECPGt_EOIT, ECPGt_EORT);}
! #line 58 "type.pgc"
  
    if (sqlca.sqlcode)
      {
--- 124,130 ----
      }
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' )", ECPGt_EOIT, ECPGt_EORT);}
! #line 55 "type.pgc"
  
    if (sqlca.sqlcode)
      {
*************** main (void)
*** 146,158 ****
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
  	ECPGt_short,&(empl.accs),(long)1,(long)1,sizeof(short), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
! 	ECPGt_char,(str),(long)11,(long)1,(11)*sizeof(char), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
  	ECPGt_char,&(ptr),(long)0,(long)1,(1)*sizeof(char), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
  	ECPGt_varchar,&(vc),(long)10,(long)1,sizeof(struct varchar_vc), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
! #line 68 "type.pgc"
  
    if (sqlca.sqlcode)
      {
--- 141,153 ----
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
  	ECPGt_short,&(empl.accs),(long)1,(long)1,sizeof(short), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
! 	ECPGt_string,&(str),(long)11,(long)1,sizeof(char), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
  	ECPGt_char,&(ptr),(long)0,(long)1,(1)*sizeof(char), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
  	ECPGt_varchar,&(vc),(long)10,(long)1,sizeof(struct varchar_vc), 
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
! #line 65 "type.pgc"
  
    if (sqlca.sqlcode)
      {
*************** main (void)
*** 162,168 ****
    printf ("id=%ld name='%s' accs=%d str='%s' ptr='%s' vc='%10.10s'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text);
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
! #line 76 "type.pgc"
  
  
    free(ptr);
--- 157,163 ----
    printf ("id=%ld name='%s' accs=%d str='%s' ptr='%s' vc='%10.10s'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text);
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
! #line 73 "type.pgc"
  
  
    free(ptr);
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-type.stderr postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-type.stderr
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-type.stderr	2008-12-29 18:07:06.000000000 +0100
--- postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-type.stderr	2009-07-04 14:42:09.000000000 +0200
***************
*** 2,40 ****
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>  
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 50: query: create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) ); with 0 parameter(s) on connection regress1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 50: using PQexec
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 50: OK: CREATE TABLE
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 58: query: insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' ); with 0 parameter(s) on connection regress1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 58: using PQexec
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 58: OK: INSERT 0 1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 65: query: select idnum , name , accs , string1 , string2 , string3 from empl where idnum = $1 ; with 1 parameter(s) on connection regress1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 65: using PQexecParams
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 65: parameter 1 = 1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 65: correctly got 1 tuples with 6 fields
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 65: RESULT: 1 offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 65: RESULT: user name            offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 65: RESULT: 320 offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 65: RESULT: first str  offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_store_result on line 65: allocating memory for 1 tuples
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 65: RESULT: second str offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 65: RESULT: third str  offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
--- 2,40 ----
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>  
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 47: query: create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) ); with 0 parameter(s) on connection regress1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 47: using PQexec
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 47: OK: CREATE TABLE
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 55: query: insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' ); with 0 parameter(s) on connection regress1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 55: using PQexec
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 55: OK: INSERT 0 1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 62: query: select idnum , name , accs , string1 , string2 , string3 from empl where idnum = $1 ; with 1 parameter(s) on connection regress1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 62: using PQexecParams
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 62: parameter 1 = 1
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 62: correctly got 1 tuples with 6 fields
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 62: RESULT: 1 offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 62: RESULT: user name            offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 62: RESULT: 320 offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 62: RESULT: first str  offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_store_result on line 62: allocating memory for 1 tuples
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 62: RESULT: second str offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_get_data on line 62: RESULT: third str  offset: -1; array: yes
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-type.stdout postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-type.stdout
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/expected/preproc-type.stdout	2006-09-08 11:03:40.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/test/expected/preproc-type.stdout	2009-07-04 14:42:10.000000000 +0200
***************
*** 1 ****
! id=1 name='user name           ' accs=320 str='first str ' ptr='second str' vc='third str '
--- 1 ----
! id=1 name='user name           ' accs=320 str='first str' ptr='second str' vc='third str '
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/preproc/define.pgc postgresql-8.4.0-string/src/interfaces/ecpg/test/preproc/define.pgc
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/preproc/define.pgc	2006-09-08 11:03:40.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/test/preproc/define.pgc	2009-07-04 14:03:18.000000000 +0200
*************** main(void)
*** 18,24 ****
  {
  exec sql begin declare section;
  exec sql ifdef NAMELEN;
! 	typedef char string[NAMELEN];
  	intarray amount;
  	char name[AMOUNT][NAMELEN];
  	char letter[AMOUNT][1];
--- 18,24 ----
  {
  exec sql begin declare section;
  exec sql ifdef NAMELEN;
! 	typedef char str[NAMELEN];
  	intarray amount;
  	char name[AMOUNT][NAMELEN];
  	char letter[AMOUNT][1];
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/preproc/type.pgc postgresql-8.4.0-string/src/interfaces/ecpg/test/preproc/type.pgc
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/test/preproc/type.pgc	2006-09-08 15:32:29.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/test/preproc/type.pgc	2009-07-04 14:04:29.000000000 +0200
*************** EXEC SQL typedef long mmInteger;
*** 7,15 ****
  EXEC SQL typedef char mmChar;
  EXEC SQL typedef short mmSmallInt;
  
- exec sql type string is char[11];
- typedef char string[11];
- 
  exec sql type c is char reference;
  typedef char* c;
  
--- 7,12 ----
*************** main (void)
*** 27,33 ****
  {
    EXEC SQL BEGIN DECLARE SECTION;
    struct TBempl empl;
!   string str;
    c ptr = NULL;
    struct varchar_vc
    {
--- 24,30 ----
  {
    EXEC SQL BEGIN DECLARE SECTION;
    struct TBempl empl;
!   string str[11];
    c ptr = NULL;
    struct varchar_vc
    {
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Boszormenyi Zoltan (#1)
Re: ECPG support for string pseudo-type

Boszormenyi Zoltan <zb@cybertec.at> writes:

in a continued effort for better Informix ESQL/C compatibility,
we added the "string" pseudo-type handling to ECPG.
...
- "string" has become a type name, reserved word in ECPG.

This seems like a sufficient reason to reject the patch. Who knows
what that will break? (I observe that it already broke a few of the
ecpg regression tests, suggesting that using "string" as a variable
name is hardly uncommon.)

regards, tom lane

#3Boszormenyi Zoltan
zb@cybertec.at
In reply to: Tom Lane (#2)
1 attachment(s)
Re: ECPG support for string pseudo-type

Hi,

Tom Lane �rta:

Boszormenyi Zoltan <zb@cybertec.at> writes:

in a continued effort for better Informix ESQL/C compatibility,
we added the "string" pseudo-type handling to ECPG.
...
- "string" has become a type name, reserved word in ECPG.

This seems like a sufficient reason to reject the patch. Who knows
what that will break? (I observe that it already broke a few of the
ecpg regression tests, suggesting that using "string" as a variable
name is hardly uncommon.)

regards, tom lane

OK, let me retry. This version treats "string" as a non-reserved word,
and also discovers whether the PGC contains this construct below,
as in ecpg/tests/preproc/type.pgc:

exec sql type string is char[11];
typedef char string[11];

Now all regression tests pass unchanged and ECPG also accepts
string *string;
and
string string[N];
without typedef, replacing "string" with "char".

I think it's acceptable.

Thanks in advance,
Zolt�n B�sz�rm�nyi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

Attachments:

ecpg-string-8.4-2-ctxdiff.patchtext/x-patch; name=ecpg-string-8.4-2-ctxdiff.patchDownload
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/data.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/data.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/data.c	2009-01-15 12:52:55.000000000 +0100
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/data.c	2009-07-04 12:27:57.000000000 +0200
*************** ecpg_get_data(const PGresult *results, i
*** 138,143 ****
--- 138,144 ----
  			case ECPGt_char:
  			case ECPGt_unsigned_char:
  			case ECPGt_varchar:
+ 			case ECPGt_string:
  				break;
  
  			default:
*************** ecpg_get_data(const PGresult *results, i
*** 389,394 ****
--- 390,396 ----
  
  				case ECPGt_char:
  				case ECPGt_unsigned_char:
+ 				case ECPGt_string:
  					if (pval)
  					{
  						if (varcharsize == 0 || varcharsize > size)
*************** ecpg_get_data(const PGresult *results, i
*** 426,431 ****
--- 428,454 ----
  								sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
  							}
  						}
+ 						/* Do the rtrim() */
+ 						if (type == ECPGt_string)
+ 						{
+ 							char	*str = (char *) ((long) var + offset * act_tuple);
+ 							char	*last;
+ 							int	len = strlen(str);
+ 
+ 							last = str + len;
+ 							while (last > str)
+ 							{
+ 								if (*last == '\0')
+ 									last--;
+ 								else if (*last == ' ')
+ 								{
+ 									*last = '\0';
+ 									last--;
+ 								}
+ 								else
+ 									break;
+ 							}
+ 						}
  						pval += size;
  					}
  					break;
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/descriptor.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/descriptor.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/descriptor.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/descriptor.c	2009-07-04 12:12:02.000000000 +0200
*************** get_char_item(int lineno, void *var, enu
*** 201,206 ****
--- 201,207 ----
  	{
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			strncpy((char *) var, value, varcharsize);
  			break;
  		case ECPGt_varchar:
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/execute.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/execute.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/execute.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/execute.c	2009-07-04 12:12:02.000000000 +0200
*************** ecpg_store_result(const PGresult *result
*** 360,365 ****
--- 360,366 ----
  			{
  				case ECPGt_char:
  				case ECPGt_unsigned_char:
+ 				case ECPGt_string:
  					if (!var->varcharsize && !var->arrsize)
  					{
  						/* special mode for handling char**foo=0 */
*************** ecpg_store_result(const PGresult *result
*** 419,425 ****
  
  	/* fill the variable with the tuple(s) */
  	if (!var->varcharsize && !var->arrsize &&
! 		(var->type == ECPGt_char || var->type == ECPGt_unsigned_char))
  	{
  		/* special mode for handling char**foo=0 */
  
--- 420,426 ----
  
  	/* fill the variable with the tuple(s) */
  	if (!var->varcharsize && !var->arrsize &&
! 		(var->type == ECPGt_char || var->type == ECPGt_unsigned_char || var->type == ECPGt_string))
  	{
  		/* special mode for handling char**foo=0 */
  
*************** ecpg_store_input(const int lineno, const
*** 758,763 ****
--- 759,765 ----
  
  			case ECPGt_char:
  			case ECPGt_unsigned_char:
+ 			case ECPGt_string:
  				{
  					/* set slen to string length if type is char * */
  					int			slen = (var->varcharsize == 0) ? strlen((char *) var->value) : (unsigned int) var->varcharsize;
*************** ecpg_execute(struct statement * stmt)
*** 1196,1201 ****
--- 1198,1204 ----
  					{
  						case ECPGt_char:
  						case ECPGt_varchar:
+ 						case ECPGt_string:
  							desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
  							break;
  						default:
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/misc.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/misc.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/misc.c	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/misc.c	2009-07-04 12:12:02.000000000 +0200
*************** ECPGset_noind_null(enum ECPGttype type, 
*** 295,300 ****
--- 295,301 ----
  	{
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			*((char *) ptr) = '\0';
  			break;
  		case ECPGt_short:
*************** ECPGis_noind_null(enum ECPGttype type, v
*** 361,366 ****
--- 362,368 ----
  	{
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			if (*((char *) ptr) == '\0')
  				return true;
  			break;
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/typename.c postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/typename.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/ecpglib/typename.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/ecpglib/typename.c	2009-07-04 12:12:02.000000000 +0200
*************** ecpg_type_name(enum ECPGttype typ)
*** 20,25 ****
--- 20,26 ----
  	switch (typ)
  	{
  		case ECPGt_char:
+ 		case ECPGt_string:
  			return "char";
  		case ECPGt_unsigned_char:
  			return "unsigned char";
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/include/ecpgtype.h postgresql-8.4.0-string/src/interfaces/ecpg/include/ecpgtype.h
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/include/ecpgtype.h	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/include/ecpgtype.h	2009-07-04 12:06:05.000000000 +0200
*************** enum ECPGttype
*** 62,68 ****
  	ECPGt_EOIT,					/* End of insert types. */
  	ECPGt_EORT,					/* End of result types. */
  	ECPGt_NO_INDICATOR,			/* no indicator */
! 	ECPGt_sqlda				/* INFORMIX-compatible sqlda_t descriptor */
  };
  
   /* descriptor items */
--- 62,69 ----
  	ECPGt_EOIT,					/* End of insert types. */
  	ECPGt_EORT,					/* End of result types. */
  	ECPGt_NO_INDICATOR,			/* no indicator */
! 	ECPGt_sqlda,				/* INFORMIX-compatible sqlda_t descriptor */
! 	ECPGt_string				/* trimmed (char *) type */
  };
  
   /* descriptor items */
*************** enum ECPGdtype
*** 87,93 ****
  	ECPGd_cardinality
  };
  
! #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_interval)
  
  /* we also have to handle different statement types */
  enum ECPG_statement_type
--- 88,94 ----
  	ECPGd_cardinality
  };
  
! #define IS_SIMPLE_TYPE(type) (((type) >= ECPGt_char && (type) <= ECPGt_interval) || ((type) == ECPGt_string))
  
  /* we also have to handle different statement types */
  enum ECPG_statement_type
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.addons postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.addons
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.addons	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.addons	2009-07-04 16:49:28.000000000 +0200
*************** ECPG: ColIdcol_name_keyword rule
*** 331,336 ****
--- 331,344 ----
  	| ECPGKeywords                  { $$ = $1; }
  	| ECPGCKeywords                 { $$ = $1; }
  	| CHAR_P                        { $$ = make_str("char"); }
+ 	| STRING_P
+ 	{
+ 		struct typedefs *this = get_typedef("string");
+ 		if (this)
+ 			$$ = make_str("string");
+ 		else
+ 			$$ = make_str("char");
+ 	}
  	| VALUES                        { $$ = make_str("values"); }
  ECPG: type_function_nametype_func_name_keyword rule
  	| ECPGKeywords                          { $$ = $1; }
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.header postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.header
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.header	2009-06-11 01:11:52.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.header	2009-07-04 11:49:50.000000000 +0200
*************** adjust_informix(struct arguments *list)
*** 256,267 ****
  		original_var = ptr->variable->name;
  		sprintf(temp, "%d))", ecpg_informix_var);
  
! 		if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
  		}
! 		else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
--- 256,267 ----
  		original_var = ptr->variable->name;
  		sprintf(temp, "%d))", ecpg_informix_var);
  
! 		if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char && ptr->variable->type->type != ECPGt_string) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
  		}
! 		else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char || ptr->variable->type->type != ECPGt_string) && atoi(ptr->variable->type->size) > 1)
  		{
  			ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0);
  			sprintf(temp, "%d, (", ecpg_informix_var++);
*************** add_typedef(char *name, char * dimension
*** 371,376 ****
--- 371,377 ----
  		if (type_enum != ECPGt_varchar &&
  			type_enum != ECPGt_char &&
  			type_enum != ECPGt_unsigned_char &&
+ 			type_enum != ECPGt_string &&
  			atoi(this->type->type_index) >= 0)
  			mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported");
  
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.tokens postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.tokens
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.tokens	2008-11-14 11:03:33.000000000 +0100
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.tokens	2009-07-04 10:59:43.000000000 +0200
***************
*** 25,28 ****
  %token TYPECAST
  %token CSTRING CVARIABLE CPP_LINE IP 
  %token DOLCONST ECONST NCONST UCONST UIDENT
! 
--- 25,28 ----
  %token TYPECAST
  %token CSTRING CVARIABLE CPP_LINE IP 
  %token DOLCONST ECONST NCONST UCONST UIDENT
! %token STRING_P
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.trailer postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.trailer
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/ecpg.trailer	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/ecpg.trailer	2009-07-04 17:02:20.000000000 +0200
*************** char_variable: cvariable
*** 213,218 ****
--- 213,219 ----
  				{
  					case ECPGt_char:
  					case ECPGt_unsigned_char:
+ 					case ECPGt_string:
  						$$ = $1;
  						break;
  					case ECPGt_varchar:
*************** var_type:	simple_type
*** 529,534 ****
--- 530,560 ----
  				$$.type_index = make_str("-1");
  				$$.type_sizeof = NULL;
  			}
+ 			else if (strcmp($1, "string") == 0)
+ 			{
+ 				struct typedefs *this = get_typedef($1);
+ 				if (this == NULL)
+ 				{
+ 					$$.type_enum = ECPGt_string;
+ 					$$.type_str = make_str("char");
+ 					$$.type_dimension = make_str("-1");
+ 					$$.type_index = make_str("-1");
+ 					$$.type_sizeof = NULL;
+ 				}
+ 				else
+ 				{
+ 					$$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name);
+ 					$$.type_enum = this->type->type_enum;
+ 					$$.type_dimension = this->type->type_dimension;
+ 					$$.type_index = this->type->type_index;
+ 					if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
+ 						$$.type_sizeof = this->type->type_sizeof;
+ 					else 
+ 						$$.type_sizeof = cat_str(3, make_str("sizeof("), mm_strdup(this->name), make_str(")"));
+ 
+ 					struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
+ 				}
+ 			}
  			else if (strcmp($1, "float") == 0)
  			{
  				$$.type_enum = ECPGt_float;
*************** signed_type: SQL_SHORT				{ $$ = ECPGt_s
*** 795,800 ****
--- 821,827 ----
  		}
  		| SQL_BOOL					{ $$ = ECPGt_bool; }
  		| CHAR_P					{ $$ = ECPGt_char; }
+ 		| STRING_P					{ $$ = ECPGt_string; }
  		| DOUBLE_P					{ $$ = ECPGt_double; }
  		;
  
*************** variable: opt_pointer ECPGColLabel opt_a
*** 855,860 ****
--- 882,888 ----
  
  				case ECPGt_char:
  				case ECPGt_unsigned_char:
+ 				case ECPGt_string:
  					if (atoi(dimension) == -1)
  					{
  						int i = strlen($5);
*************** ECPGVar: SQL_VAR
*** 1331,1336 ****
--- 1359,1365 ----
  
  					case ECPGt_char:
  					case ECPGt_unsigned_char:
+ 					case ECPGt_string:
  						if (atoi(dimension) == -1)
  							type = ECPGmake_simple_type($5.type_enum, length, 0);
  						else
*************** c_anything:  ecpg_ident				{ $$ = $1; }
*** 2017,2022 ****
--- 2046,2052 ----
  		| SQL_UNSIGNED			{ $$ = make_str("unsigned"); }
  		| YEAR_P			{ $$ = make_str("year"); }
  		| CHAR_P			{ $$ = make_str("char"); }
+ 		| STRING_P			{ $$ = make_str("string"); }
  		| FLOAT_P			{ $$ = make_str("float"); }
  		| TO				{ $$ = make_str("to"); }
  		| UNION				{ $$ = make_str("union"); }
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/type.c postgresql-8.4.0-string/src/interfaces/ecpg/preproc/type.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/type.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/type.c	2009-07-04 14:12:07.000000000 +0200
*************** get_type(enum ECPGttype type)
*** 200,205 ****
--- 200,208 ----
  		case ECPGt_timestamp:
  			return ("ECPGt_timestamp");
  			break;
+ 		case ECPGt_string:
+ 			return ("ECPGt_string");
+ 			break;
  		default:
  			mmerror(PARSE_ERROR, ET_ERROR, "unrecognized variable type code %d", type);
  	}
*************** ECPGdump_a_simple(FILE *o, const char *n
*** 368,373 ****
--- 371,377 ----
  			case ECPGt_char:
  			case ECPGt_unsigned_char:
  			case ECPGt_char_variable:
+ 			case ECPGt_string:
  
  				/*
  				 * we have to use the pointer except for arrays with given
diff -dcrpN postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/variable.c postgresql-8.4.0-string/src/interfaces/ecpg/preproc/variable.c
*** postgresql-8.4.0-sqlda/src/interfaces/ecpg/preproc/variable.c	2009-07-04 10:42:50.000000000 +0200
--- postgresql-8.4.0-string/src/interfaces/ecpg/preproc/variable.c	2009-07-04 11:45:25.000000000 +0200
*************** adjust_array(enum ECPGttype type_enum, c
*** 524,530 ****
  												"multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
  				pointer_len);
  
! 	if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char)
  		mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type");
  
  	if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
--- 524,530 ----
  												"multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
  				pointer_len);
  
! 	if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
  		mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type");
  
  	if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
*************** adjust_array(enum ECPGttype type_enum, c
*** 563,568 ****
--- 563,569 ----
  			break;
  		case ECPGt_char:
  		case ECPGt_unsigned_char:
+ 		case ECPGt_string:
  			/* char ** */
  			if (pointer_len == 2)
  			{
#4Michael Meskes
meskes@postgresql.org
In reply to: Boszormenyi Zoltan (#1)
Re: ECPG support for string pseudo-type

On Sat, Jul 04, 2009 at 03:39:14PM +0200, Boszormenyi Zoltan wrote:

The attached patch is built upon our previous patch supporting
dynamic cursor and SQLDA.

Please don't do this unless the new patch relies on some changes made in the
older one.

Michael
--
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!

#5Michael Meskes
meskes@postgresql.org
In reply to: Boszormenyi Zoltan (#3)
Re: ECPG support for string pseudo-type

On Sat, Jul 04, 2009 at 05:09:04PM +0200, Boszormenyi Zoltan wrote:

OK, let me retry. This version treats "string" as a non-reserved word,
and also discovers whether the PGC contains this construct below,
as in ecpg/tests/preproc/type.pgc:

exec sql type string is char[11];
typedef char string[11];

I don't like this because it means a datatype can change its meaning in the
middle of a source file. Your new datatype is only needed for Informix
compatibility, so why not only defining it when running in compatibility mode?
An Informix file will not have such a typedef because it wouldn't/shouldn't
work there either.

Also the new datatype needs some documentation.

Michael
--
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!

#6Boszormenyi Zoltan
zb@cybertec.at
In reply to: Michael Meskes (#4)
Re: ECPG support for string pseudo-type

Michael Meskes �rta:

On Sat, Jul 04, 2009 at 03:39:14PM +0200, Boszormenyi Zoltan wrote:

The attached patch is built upon our previous patch supporting
dynamic cursor and SQLDA.

Please don't do this unless the new patch relies on some changes made in the
older one.

Michael

AFAICS the only dependence is one small reject in ecpgtypes.h
because both patches add one new ECPGt_XXX constant.

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

#7Boszormenyi Zoltan
zb@cybertec.at
In reply to: Michael Meskes (#5)
Re: ECPG support for string pseudo-type

Michael Meskes �rta:

On Sat, Jul 04, 2009 at 05:09:04PM +0200, Boszormenyi Zoltan wrote:

OK, let me retry. This version treats "string" as a non-reserved word,
and also discovers whether the PGC contains this construct below,
as in ecpg/tests/preproc/type.pgc:

exec sql type string is char[11];
typedef char string[11];

I don't like this because it means a datatype can change its meaning in the
middle of a source file. Your new datatype is only needed for Informix
compatibility, so why not only defining it when running in compatibility mode?
An Informix file will not have such a typedef because it wouldn't/shouldn't
work there either.

Also the new datatype needs some documentation.

Michael

Okay, I modified it so in Informix mode ECPG refuses
redefining the "string" type. I will add documentation and
also port it to 8.5devel, get_typedef() has changed since 8.4RC2
and it errors out now if asking for a non-typedef'd type name.

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/