Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sqlite3 column table alias #3

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion manifest.uuid
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9ea2d3dcf798393a7fd231e199c0e2c6302949fe2a7f2573178fb0e50c78a2f4
9ea2d3dcf798393a7fd231e199c0e2c6302949fe2a7f2573178fb0e50c78a2f4
9 changes: 8 additions & 1 deletion src/loadext.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
# define sqlite3_column_database_name16 0
# define sqlite3_column_table_name 0
# define sqlite3_column_table_name16 0
# define sqlite3_column_table_alias 0
# define sqlite3_column_table_alias16 0
# define sqlite3_column_origin_name 0
# define sqlite3_column_origin_name16 0
#endif
Expand Down Expand Up @@ -61,6 +63,7 @@
# define sqlite3_value_text16le 0
# define sqlite3_column_database_name16 0
# define sqlite3_column_table_name16 0
# define sqlite3_column_table_alias16 0
# define sqlite3_column_origin_name16 0
#endif

Expand Down Expand Up @@ -510,7 +513,11 @@ static const sqlite3_api_routines sqlite3Apis = {
#endif
sqlite3_db_name,
/* Version 3.40.0 and later */
sqlite3_value_encoding
sqlite3_value_encoding,
/* Version 3.40.1 and later */
sqlite3_column_table_alias,
sqlite3_column_table_alias16,

};

/* True if x is the directory separator character
Expand Down
25 changes: 17 additions & 8 deletions src/select.c
Original file line number Diff line number Diff line change
Expand Up @@ -1846,9 +1846,9 @@ static void generateSortTail(
** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
*/
#ifdef SQLITE_ENABLE_COLUMN_METADATA
# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E)
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
# define columnType(A,B,C,D,E) columnTypeImpl(A,B)
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B)
#endif
static const char *columnTypeImpl(
NameContext *pNC,
Expand All @@ -1858,7 +1858,8 @@ static const char *columnTypeImpl(
Expr *pExpr,
const char **pzOrigDb,
const char **pzOrigTab,
const char **pzOrigCol
const char **pzOrigCol,
const char **pzOrigTabAlias
#endif
){
char const *zType = 0;
Expand All @@ -1867,6 +1868,7 @@ static const char *columnTypeImpl(
char const *zOrigDb = 0;
char const *zOrigTab = 0;
char const *zOrigCol = 0;
char const *zOrigTabAlias = 0;
#endif

assert( pExpr!=0 );
Expand All @@ -1886,6 +1888,10 @@ static const char *columnTypeImpl(
if( j<pTabList->nSrc ){
pTab = pTabList->a[j].pTab;
pS = pTabList->a[j].pSelect;
#ifdef SQLITE_ENABLE_COLUMN_METADATA
zOrigTabAlias =
pTabList->a[j].zAlias?pTabList->a[j].zAlias:pTabList->a[j].zName;
#endif
}else{
pNC = pNC->pNext;
}
Expand Down Expand Up @@ -1934,7 +1940,7 @@ static const char *columnTypeImpl(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol);
zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol,&zOrigTabAlias);
}
}else{
/* A real table or a CTE table */
Expand Down Expand Up @@ -1980,7 +1986,7 @@ static const char *columnTypeImpl(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &zOrigTabAlias);
break;
}
#endif
Expand All @@ -1992,6 +1998,7 @@ static const char *columnTypeImpl(
*pzOrigDb = zOrigDb;
*pzOrigTab = zOrigTab;
*pzOrigCol = zOrigCol;
*pzOrigTabAlias = zOrigTabAlias;
}
#endif
return zType;
Expand Down Expand Up @@ -2020,7 +2027,8 @@ static void generateColumnTypes(
const char *zOrigDb = 0;
const char *zOrigTab = 0;
const char *zOrigCol = 0;
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
const char *zOrigTabAlias = 0;
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &zOrigTabAlias);

/* The vdbe must make its own copy of the column-type and other
** column specific strings, in case the schema is reset before this
Expand All @@ -2029,8 +2037,9 @@ static void generateColumnTypes(
sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT);
sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
sqlite3VdbeSetColName(v, i, COLNAME_TABLE_ALIAS, zOrigTabAlias, SQLITE_TRANSIENT);
#else
zType = columnType(&sNC, p, 0, 0, 0);
zType = columnType(&sNC, p, 0, 0, 0, 0);
#endif
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
}
Expand Down Expand Up @@ -2303,7 +2312,7 @@ void sqlite3SelectAddColumnTypeAndCollation(
i64 n, m;
pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT);
p = a[i].pExpr;
zType = columnType(&sNC, p, 0, 0, 0);
zType = columnType(&sNC, p, 0, 0, 0, 0);
/* pCol->szEst = ... // Column size est for SELECT tables never used */
pCol->affinity = sqlite3ExprAffinity(p);
if( zType ){
Expand Down
7 changes: 6 additions & 1 deletion src/sqlite.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -4712,7 +4712,10 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** ^The name of the database or table or column can be returned as
** either a UTF-8 or UTF-16 string. ^The _database_ routines return
** the database name, the _table_ routines return the table name, and
** the origin_ routines return the column name.
** the origin_ routines return the column name. _table_alias_ results
** with the alias(if any) of the table associated with the column;
** _table_ always returns the source table name, even if it has been
** aliased, this returns the original table name if there is no alias.
** ^The returned string is valid until the [prepared statement] is destroyed
** using [sqlite3_finalize()] or until the statement is automatically
** reprepared by the first call to [sqlite3_step()] for a particular run
Expand Down Expand Up @@ -4750,6 +4753,8 @@ const char *sqlite3_column_table_name(sqlite3_stmt*,int);
const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
const char *sqlite3_column_table_alias(sqlite3_stmt*,int);
const void *sqlite3_column_table_alias16(sqlite3_stmt*,int);

/*
** CAPI3REF: Declared Datatype Of A Query Result
Expand Down
6 changes: 6 additions & 0 deletions src/sqlite3ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ struct sqlite3_api_routines {
const char *(*db_name)(sqlite3*,int);
/* Version 3.40.0 and later */
int (*value_encoding)(sqlite3_value*);
/* Version 3.40.1 and later */
const char * (*column_table_alias)(sqlite3_stmt*,int);
const void * (*column_table_alias16)(sqlite3_stmt*,int);
};

/*
Expand Down Expand Up @@ -685,6 +688,9 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_db_name sqlite3_api->db_name
/* Version 3.40.0 and later */
#define sqlite3_value_encoding sqlite3_api->value_encoding
/* Version 3.40.1 and later */
#define sqlite3_column_table_alias sqlite3_api->column_table_alias
#define sqlite3_column_table_alias16 sqlite3_api->column_table_alias16
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */

#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
Expand Down
2 changes: 2 additions & 0 deletions src/test1.c
Original file line number Diff line number Diff line change
Expand Up @@ -8697,6 +8697,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#ifdef SQLITE_ENABLE_COLUMN_METADATA
{ "sqlite3_column_database_name",test_stmt_utf8,(void*)sqlite3_column_database_name},
{ "sqlite3_column_table_name",test_stmt_utf8,(void*)sqlite3_column_table_name},
{ "sqlite3_column_table_alias",test_stmt_utf8,(void*)sqlite3_column_table_alias},
{ "sqlite3_column_origin_name",test_stmt_utf8,(void*)sqlite3_column_origin_name},
#endif

Expand All @@ -8712,6 +8713,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{"sqlite3_column_database_name16",
test_stmt_utf16, (void*)sqlite3_column_database_name16},
{"sqlite3_column_table_name16", test_stmt_utf16, (void*)sqlite3_column_table_name16},
{"sqlite3_column_table_alias16", test_stmt_utf16, (void*)sqlite3_column_table_alias16},
{"sqlite3_column_origin_name16", test_stmt_utf16, (void*)sqlite3_column_origin_name16},
#endif
#endif
Expand Down
13 changes: 7 additions & 6 deletions src/vdbe.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,14 @@ typedef struct VdbeOpList VdbeOpList;
** The Vdbe.aColName array contains 5n Mem structures, where n is the
** number of columns of data returned by the statement.
*/
#define COLNAME_NAME 0
#define COLNAME_DECLTYPE 1
#define COLNAME_DATABASE 2
#define COLNAME_TABLE 3
#define COLNAME_COLUMN 4
#define COLNAME_NAME 0
#define COLNAME_DECLTYPE 1
#define COLNAME_DATABASE 2
#define COLNAME_TABLE 3
#define COLNAME_COLUMN 4
#define COLNAME_TABLE_ALIAS 5
#ifdef SQLITE_ENABLE_COLUMN_METADATA
# define COLNAME_N 5 /* Number of COLNAME_xxx symbols */
# define COLNAME_N 6 /* Number of COLNAME_xxx symbols */
#else
# ifdef SQLITE_OMIT_DECLTYPE
# define COLNAME_N 1 /* Store only the name */
Expand Down
17 changes: 17 additions & 0 deletions src/vdbeapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1417,6 +1417,23 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
return columnName(pStmt, N, 1, COLNAME_COLUMN);
}
#endif /* SQLITE_OMIT_UTF16 */

/*
** Return the alias or, if no alias specified, the name of the table from
** which a result column derives. NULL is returned if the result name is
** an expression or constant or anything else which is not an unambiguous
** reference to a database table.
*/
const char *sqlite3_column_table_alias(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, 0, COLNAME_TABLE_ALIAS);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_table_alias16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, 1, COLNAME_TABLE_ALIAS);
}
#endif /* SQLITE_OMIT_UTF16 */
#endif /* SQLITE_ENABLE_COLUMN_METADATA */


Expand Down
121 changes: 121 additions & 0 deletions test/capi3f.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# 2021 January 22
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi3f.test,v 1.70 2009/01/09 02:49:32 d3x0r Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix capi3f

# Do not use a codec for tests in this file, as the database file is
# manipulated directly using tcl scripts (using the [hexio_write] command).
#
do_not_use_codec


# Return the UTF-16 representation of the supplied UTF-8 string $str.
# If $nt is true, append two 0x00 bytes as a nul terminator.
proc utf16 {str {nt 1}} {
set r [encoding convertto unicode $str]
if {$nt} {
append r "\x00\x00"
}
return $r
}

# Return the UTF-8 representation of the supplied UTF-16 string $str.
proc utf8 {str} {
# If $str ends in two 0x00 0x00 bytes, knock these off before
# converting to UTF-8 using TCL.
binary scan $str \c* vals
if {[lindex $vals end]==0 && [lindex $vals end-1]==0} {
set str [binary format \c* [lrange $vals 0 end-2]]
}

set r [encoding convertfrom unicode $str]
return $r
}


# This proc is used to test the following API calls:
#
# sqlite3_column_table_alias
# sqlite3_column_table_alias16

#
# $STMT is a compiled SQL statement. $test is a prefix
# to use for test names within this proc. $names is a list
# of the column names that should be returned by $STMT.
# $decltypes is a list of column declaration types for $STMT.
#
# Example:
#
# set STMT [sqlite3_prepare "SELECT 1, 2, 2;" -1 DUMMY]
# check_header test1.1 {1 2 3} {"" "" ""}
#
proc check_origin_header2 {STMT test als } {
# If sqlite3_column_origin_name() and friends are not compiled into
# this build, this proc is a no-op.
ifcapable columnmetadata {

# Use the return value of sqlite3_column_count() to build
# a list of column indexes. i.e. If sqlite3_column_count
# is 3, build the list {0 1 2}.
set ::idxlist [list]
set ::numcols [sqlite3_column_count $STMT]
for {set i 0} {$i < $::numcols} {incr i} {lappend ::idxlist $i}

# Table alias in UTF-8
do_test $test.3 {
set caliaslist [list]
foreach i $idxlist {
lappend caliaslist [sqlite3_column_table_alias $STMT $i]
}
set caliaslist
} $als

# Table alias in UTF-16
ifcapable {utf16} {
do_test $test.4 {
set caliaslist [list]
foreach i $idxlist {
lappend caliaslist [utf8 [sqlite3_column_table_alias16 $STMT $i]]
}
set caliaslist
} $als
}

}
}

sqlite3 db test.db
set DB [sqlite3_connection_pointer db]

do_test capi3f-1 {
execsql {
CREATE TABLE t1(a VARINT, b BLOB, c VARCHAR(16));
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES('one', 'two', NULL);
INSERT INTO t1 VALUES(1.2, 1.3, 1.4);
}
set sql "SELECT * FROM t1 tz"
set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
sqlite3_column_count $STMT
} 3

check_origin_header2 $STMT capi3f-1 {tz tz tz}

db close

finish_test