mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	bpo-39652: Truncate the column name after '[' only if PARSE_COLNAMES is set. (GH-18942)
This commit is contained in:
		
							parent
							
								
									684d2b9a07
								
							
						
					
					
						commit
						b146568dfc
					
				
					 5 changed files with 32 additions and 14 deletions
				
			
		|  | @ -165,9 +165,10 @@ Module functions and constants | |||
|    that 'mytype' is the type of the column. It will try to find an entry of | ||||
|    'mytype' in the converters dictionary and then use the converter function found | ||||
|    there to return the value. The column name found in :attr:`Cursor.description` | ||||
|    is only the first word of the column name, i.  e. if you use something like | ||||
|    ``'as "x [datetime]"'`` in your SQL, then we will parse out everything until the | ||||
|    first blank for the column name: the column name would simply be "x". | ||||
|    does not include the type, i. e. if you use something like | ||||
|    ``'as "Expiration date [datetime]"'`` in your SQL, then we will parse out | ||||
|    everything until the first ``'['`` for the column name and strip | ||||
|    the preceeding space: the column name would simply be "Expiration date". | ||||
| 
 | ||||
| 
 | ||||
| .. function:: connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri]) | ||||
|  |  | |||
|  | @ -68,7 +68,7 @@ def CheckStatementReset(self): | |||
|     def CheckColumnNameWithSpaces(self): | ||||
|         cur = self.con.cursor() | ||||
|         cur.execute('select 1 as "foo bar [datetime]"') | ||||
|         self.assertEqual(cur.description[0][0], "foo bar") | ||||
|         self.assertEqual(cur.description[0][0], "foo bar [datetime]") | ||||
| 
 | ||||
|         cur.execute('select 1 as "foo baz"') | ||||
|         self.assertEqual(cur.description[0][0], "foo baz") | ||||
|  |  | |||
|  | @ -275,13 +275,13 @@ def CheckNone(self): | |||
| 
 | ||||
|     def CheckColName(self): | ||||
|         self.cur.execute("insert into test(x) values (?)", ("xxx",)) | ||||
|         self.cur.execute('select x as "x [bar]" from test') | ||||
|         self.cur.execute('select x as "x y [bar]" from test') | ||||
|         val = self.cur.fetchone()[0] | ||||
|         self.assertEqual(val, "<xxx>") | ||||
| 
 | ||||
|         # Check if the stripping of colnames works. Everything after the first | ||||
|         # whitespace should be stripped. | ||||
|         self.assertEqual(self.cur.description[0][0], "x") | ||||
|         # '[' (and the preceeding space) should be stripped. | ||||
|         self.assertEqual(self.cur.description[0][0], "x y") | ||||
| 
 | ||||
|     def CheckCaseInConverterName(self): | ||||
|         self.cur.execute("select 'other' as \"x [b1b1]\"") | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| The column name found in ``sqlite3.Cursor.description`` is now truncated on | ||||
| the first '[' only if the PARSE_COLNAMES option is set. | ||||
|  | @ -193,22 +193,30 @@ pysqlite_build_row_cast_map(pysqlite_Cursor* self) | |||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| _pysqlite_build_column_name(const char* colname) | ||||
| _pysqlite_build_column_name(pysqlite_Cursor *self, const char *colname) | ||||
| { | ||||
|     const char* pos; | ||||
|     Py_ssize_t len; | ||||
| 
 | ||||
|     if (!colname) { | ||||
|         Py_RETURN_NONE; | ||||
|     } | ||||
| 
 | ||||
|     for (pos = colname;; pos++) { | ||||
|         if (*pos == 0 || *pos == '[') { | ||||
|             if ((*pos == '[') && (pos > colname) && (*(pos-1) == ' ')) { | ||||
|                 pos--; | ||||
|     if (self->connection->detect_types & PARSE_COLNAMES) { | ||||
|         for (pos = colname; *pos; pos++) { | ||||
|             if (*pos == '[') { | ||||
|                 if ((pos != colname) && (*(pos-1) == ' ')) { | ||||
|                     pos--; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|             return PyUnicode_FromStringAndSize(colname, pos - colname); | ||||
|         } | ||||
|         len = pos - colname; | ||||
|     } | ||||
|     else { | ||||
|         len = strlen(colname); | ||||
|     } | ||||
|     return PyUnicode_FromStringAndSize(colname, len); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -370,6 +378,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) | |||
|     PyObject* result; | ||||
|     int numcols; | ||||
|     PyObject* descriptor; | ||||
|     PyObject* column_name; | ||||
|     PyObject* second_argument = NULL; | ||||
|     sqlite_int64 lastrowid; | ||||
| 
 | ||||
|  | @ -536,7 +545,13 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) | |||
|                 if (!descriptor) { | ||||
|                     goto error; | ||||
|                 } | ||||
|                 PyTuple_SetItem(descriptor, 0, _pysqlite_build_column_name(sqlite3_column_name(self->statement->st, i))); | ||||
|                 column_name = _pysqlite_build_column_name(self, | ||||
|                                 sqlite3_column_name(self->statement->st, i)); | ||||
|                 if (!column_name) { | ||||
|                     Py_DECREF(descriptor); | ||||
|                     goto error; | ||||
|                 } | ||||
|                 PyTuple_SetItem(descriptor, 0, column_name); | ||||
|                 Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 1, Py_None); | ||||
|                 Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 2, Py_None); | ||||
|                 Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 3, Py_None); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Serhiy Storchaka
						Serhiy Storchaka