mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Avoid code duplication in \crosstabview.
In commit 6f0d6a507 I added a duplicate copy of psqlscanslash's identifier downcasing code, but actually it's not hard to split that out as a callable subroutine and avoid the duplication.
This commit is contained in:
		
							parent
							
								
									4039c736eb
								
							
						
					
					
						commit
						9603a32594
					
				| @ -12,6 +12,7 @@ | ||||
| #include "common.h" | ||||
| #include "crosstabview.h" | ||||
| #include "pqexpbuffer.h" | ||||
| #include "psqlscanslash.h" | ||||
| #include "settings.h" | ||||
| 
 | ||||
| 
 | ||||
| @ -648,39 +649,14 @@ indexOfColumn(char *arg, const PGresult *res) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		bool		inquotes = false; | ||||
| 		char	   *cp = arg; | ||||
| 		int			i; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Dequote and downcase the column name.  By checking for all-digits | ||||
| 		 * before doing this, we can ensure that a quoted name is treated as a | ||||
| 		 * name even if it's all digits.  This transformation should match | ||||
| 		 * what psqlscanslash.l does in OT_SQLID mode.  (XXX ideally we would | ||||
| 		 * let the lexer do this, but then we couldn't tell if the name was | ||||
| 		 * quoted.) | ||||
| 		 * name even if it's all digits. | ||||
| 		 */ | ||||
| 		while (*cp) | ||||
| 		{ | ||||
| 			if (*cp == '"') | ||||
| 			{ | ||||
| 				if (inquotes && cp[1] == '"') | ||||
| 				{ | ||||
| 					/* Keep the first quote, remove the second */ | ||||
| 					cp++; | ||||
| 				} | ||||
| 				inquotes = !inquotes; | ||||
| 				/* Collapse out quote at *cp */ | ||||
| 				memmove(cp, cp + 1, strlen(cp)); | ||||
| 				/* do not advance cp */ | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if (!inquotes) | ||||
| 					*cp = pg_tolower((unsigned char) *cp); | ||||
| 				cp += PQmblen(cp, pset.encoding); | ||||
| 			} | ||||
| 		} | ||||
| 		dequote_downcase_identifier(arg, true, pset.encoding); | ||||
| 
 | ||||
| 		/* Now look for match(es) among res' column names */ | ||||
| 		idx = -1; | ||||
|  | ||||
| @ -32,4 +32,6 @@ extern char *psql_scan_slash_option(PsqlScanState state, | ||||
| 
 | ||||
| extern void psql_scan_slash_command_end(PsqlScanState state); | ||||
| 
 | ||||
| extern void dequote_downcase_identifier(char *str, bool downcase, int encoding); | ||||
| 
 | ||||
| #endif   /* PSQLSCANSLASH_H */ | ||||
|  | ||||
| @ -566,42 +566,15 @@ psql_scan_slash_option(PsqlScanState state, | ||||
| 
 | ||||
| 			/* | ||||
| 			 * If SQL identifier processing was requested, then we strip out | ||||
| 			 * excess double quotes and downcase unquoted letters. | ||||
| 			 * Doubled double-quotes become output double-quotes, per spec. | ||||
| 			 * | ||||
| 			 * Note that a string like FOO"BAR"BAZ will be converted to | ||||
| 			 * fooBARbaz; this is somewhat inconsistent with the SQL spec, | ||||
| 			 * which would have us parse it as several identifiers.  But | ||||
| 			 * for psql's purposes, we want a string like "foo"."bar" to | ||||
| 			 * be treated as one option, so there's little choice. | ||||
| 			 * excess double quotes and optionally downcase unquoted letters. | ||||
| 			 */ | ||||
| 			if (type == OT_SQLID || type == OT_SQLIDHACK) | ||||
| 			{ | ||||
| 				bool		inquotes = false; | ||||
| 				char	   *cp = mybuf.data; | ||||
| 
 | ||||
| 				while (*cp) | ||||
| 				{ | ||||
| 					if (*cp == '"') | ||||
| 					{ | ||||
| 						if (inquotes && cp[1] == '"') | ||||
| 						{ | ||||
| 							/* Keep the first quote, remove the second */ | ||||
| 							cp++; | ||||
| 						} | ||||
| 						inquotes = !inquotes; | ||||
| 						/* Collapse out quote at *cp */ | ||||
| 						memmove(cp, cp + 1, strlen(cp)); | ||||
| 						mybuf.len--; | ||||
| 						/* do not advance cp */ | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						if (!inquotes && type == OT_SQLID) | ||||
| 							*cp = pg_tolower((unsigned char) *cp); | ||||
| 						cp += PQmblen(cp, state->encoding); | ||||
| 					} | ||||
| 				} | ||||
| 				dequote_downcase_identifier(mybuf.data, | ||||
| 											(type != OT_SQLIDHACK), | ||||
| 											state->encoding); | ||||
| 				/* update mybuf.len for possible shortening */ | ||||
| 				mybuf.len = strlen(mybuf.data); | ||||
| 			} | ||||
| 			break; | ||||
| 		case xslashquote: | ||||
| @ -667,6 +640,51 @@ psql_scan_slash_command_end(PsqlScanState state) | ||||
| 	psql_scan_reselect_sql_lexer(state); | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * De-quote and optionally downcase a SQL identifier. | ||||
|  * | ||||
|  * The string at *str is modified in-place; it can become shorter, | ||||
|  * but not longer. | ||||
|  * | ||||
|  * If downcase is true then non-quoted letters are folded to lower case. | ||||
|  * Ideally this behavior will match the backend's downcase_identifier(); | ||||
|  * but note that it could differ if LC_CTYPE is different in the frontend. | ||||
|  * | ||||
|  * Note that a string like FOO"BAR"BAZ will be converted to fooBARbaz; | ||||
|  * this is somewhat inconsistent with the SQL spec, which would have us | ||||
|  * parse it as several identifiers.  But for psql's purposes, we want a | ||||
|  * string like "foo"."bar" to be treated as one option, so there's little | ||||
|  * choice; this routine doesn't get to change the token boundaries. | ||||
|  */ | ||||
| void | ||||
| dequote_downcase_identifier(char *str, bool downcase, int encoding) | ||||
| { | ||||
| 	bool		inquotes = false; | ||||
| 	char	   *cp = str; | ||||
| 
 | ||||
| 	while (*cp) | ||||
| 	{ | ||||
| 		if (*cp == '"') | ||||
| 		{ | ||||
| 			if (inquotes && cp[1] == '"') | ||||
| 			{ | ||||
| 				/* Keep the first quote, remove the second */ | ||||
| 				cp++; | ||||
| 			} | ||||
| 			inquotes = !inquotes; | ||||
| 			/* Collapse out quote at *cp */ | ||||
| 			memmove(cp, cp + 1, strlen(cp)); | ||||
| 			/* do not advance cp */ | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (downcase && !inquotes) | ||||
| 				*cp = pg_tolower((unsigned char) *cp); | ||||
| 			cp += PQmblen(cp, encoding); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Evaluate a backticked substring of a slash command's argument. | ||||
|  * | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user