mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	Fix off-by-one error in PGTYPEStimestamp_fmt_asc
When using %b or %B patterns to format a date, the code was simply using tm_mon as an index into array of month names. But that is wrong, because tm_mon is 1-based, while array indexes are 0-based. The result is we either use name of the next month, or a segfault (for December). Fix by subtracting 1 from tm_mon for both patterns, and add a regression test triggering the issue. Backpatch to all supported versions (the bug is there far longer, since at least 2003). Reported-by: Paul Spencer Backpatch-through: 9.4 Discussion: https://postgr.es/m/16143-0d861eb8688d3fef%40postgresql.org
This commit is contained in:
		| @@ -334,13 +334,13 @@ dttofmtasc_replace(timestamp * ts, date dDate, int dow, struct tm *tm, | ||||
| 					/* XXX should be locale aware */ | ||||
| 				case 'b': | ||||
| 				case 'h': | ||||
| 					replace_val.str_val = months[tm->tm_mon]; | ||||
| 					replace_val.str_val = months[tm->tm_mon - 1]; | ||||
| 					replace_type = PGTYPES_TYPE_STRING_CONSTANT; | ||||
| 					break; | ||||
| 					/* the full name of the month */ | ||||
| 					/* XXX should be locale aware */ | ||||
| 				case 'B': | ||||
| 					replace_val.str_val = pgtypes_date_months[tm->tm_mon]; | ||||
| 					replace_val.str_val = pgtypes_date_months[tm->tm_mon - 1]; | ||||
| 					replace_type = PGTYPES_TYPE_STRING_CONSTANT; | ||||
| 					break; | ||||
|  | ||||
|   | ||||
| @@ -436,17 +436,33 @@ if (sqlca.sqlcode < 0) sqlprint ( );} | ||||
| 	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); | ||||
| 	PGTYPESchar_free(text); | ||||
|  | ||||
| 	out = (char*) malloc(64); | ||||
| 	fmt = "%a %b %d %H:%M:%S %Y"; | ||||
| 	in =  "Mon Dec 30 17:28:44 2019"; | ||||
| 	i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); | ||||
| 	i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt); | ||||
| 	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i); | ||||
| 	free(out); | ||||
|  | ||||
| 	out = (char*) malloc(64); | ||||
| 	fmt = "%a %b %d %H:%M:%S %Y"; | ||||
| 	in =  "Mon December 30 17:28:44 2019"; | ||||
| 	i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); | ||||
| 	i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt); | ||||
| 	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i); | ||||
| 	free(out); | ||||
|  | ||||
| 	{ ECPGtrans(__LINE__, NULL, "rollback"); | ||||
| #line 365 "dt_test.pgc" | ||||
| #line 381 "dt_test.pgc" | ||||
|  | ||||
| if (sqlca.sqlcode < 0) sqlprint ( );} | ||||
| #line 365 "dt_test.pgc" | ||||
| #line 381 "dt_test.pgc" | ||||
|  | ||||
|         { ECPGdisconnect(__LINE__, "CURRENT"); | ||||
| #line 366 "dt_test.pgc" | ||||
| #line 382 "dt_test.pgc" | ||||
|  | ||||
| if (sqlca.sqlcode < 0) sqlprint ( );} | ||||
| #line 366 "dt_test.pgc" | ||||
| #line 382 "dt_test.pgc" | ||||
|  | ||||
|  | ||||
| 	return 0; | ||||
|   | ||||
| @@ -42,7 +42,7 @@ | ||||
| [NO_PID]: sqlca: code: 0, state: 00000 | ||||
| [NO_PID]: ecpg_get_data on line 38: RESULT: 2000-07-12 17:34:29 offset: -1; array: no | ||||
| [NO_PID]: sqlca: code: 0, state: 00000 | ||||
| [NO_PID]: ECPGtrans on line 365: action "rollback"; connection "ecpg1_regression" | ||||
| [NO_PID]: ECPGtrans on line 381: action "rollback"; connection "ecpg1_regression" | ||||
| [NO_PID]: sqlca: code: 0, state: 00000 | ||||
| [NO_PID]: ecpg_finish: connection ecpg1_regression closed | ||||
| [NO_PID]: sqlca: code: 0, state: 00000 | ||||
|   | ||||
| @@ -48,3 +48,5 @@ timestamp_defmt_asc(  1976, July 14. Time: 9:15am, %Y,   %B %d. Time: %I:%M %p) | ||||
| timestamp_defmt_asc(  1976, July 14. Time: 9:15 am, %Y,   %B %d. Time: %I:%M%p) = 1976-07-14 09:15:00, error: 0 | ||||
| timestamp_defmt_asc(  1976, P.M. July 14. Time: 9:15, %Y, %P  %B %d. Time: %I:%M) = 1976-07-14 21:15:00, error: 0 | ||||
| timestamp_defmt_asc(1234567890, %s) = 2009-02-13 23:31:30, error: 0 | ||||
| timestamp_defmt_asc(Mon Dec 30 17:28:44 2019, %a %b %d %H:%M:%S %Y) = Mon Dec 30 17:28:44 2019, error: 0 | ||||
| timestamp_defmt_asc(Mon December 30 17:28:44 2019, %a %b %d %H:%M:%S %Y) = Mon Dec 30 17:28:44 2019, error: 0 | ||||
|   | ||||
| @@ -362,6 +362,22 @@ main(void) | ||||
| 	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i); | ||||
| 	PGTYPESchar_free(text); | ||||
|  | ||||
| 	out = (char*) malloc(64); | ||||
| 	fmt = "%a %b %d %H:%M:%S %Y"; | ||||
| 	in =  "Mon Dec 30 17:28:44 2019"; | ||||
| 	i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); | ||||
| 	i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt); | ||||
| 	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i); | ||||
| 	free(out); | ||||
|  | ||||
| 	out = (char*) malloc(64); | ||||
| 	fmt = "%a %b %d %H:%M:%S %Y"; | ||||
| 	in =  "Mon December 30 17:28:44 2019"; | ||||
| 	i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1); | ||||
| 	i = PGTYPEStimestamp_fmt_asc(&ts1, out, 63, fmt); | ||||
| 	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, out, i); | ||||
| 	free(out); | ||||
|  | ||||
| 	exec sql rollback; | ||||
|         exec sql disconnect; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user