aboutsummaryrefslogtreecommitdiff
path: root/ext/misc
diff options
context:
space:
mode:
Diffstat (limited to 'ext/misc')
-rw-r--r--ext/misc/fileio.c22
-rw-r--r--ext/misc/vtablog.c55
-rw-r--r--ext/misc/windirent.h163
3 files changed, 225 insertions, 15 deletions
diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c
index c67fa9600..22d61df61 100644
--- a/ext/misc/fileio.c
+++ b/ext/misc/fileio.c
@@ -93,13 +93,11 @@ SQLITE_EXTENSION_INIT1
# include <dirent.h>
# include <utime.h>
# include <sys/time.h>
+# define STRUCT_STAT struct stat
#else
-# include "windows.h"
-# include <io.h>
+# include "windirent.h"
# include <direct.h>
-# include "test_windirent.h"
-# define dirent DIRENT
-# define stat _stat
+# define STRUCT_STAT struct _stat
# define chmod(path,mode) fileio_chmod(path,mode)
# define mkdir(path,mode) fileio_mkdir(path)
#endif
@@ -292,7 +290,7 @@ LPWSTR utf8_to_utf16(const char *z){
*/
static void statTimesToUtc(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
HANDLE hFindFile;
WIN32_FIND_DATAW fd;
@@ -320,7 +318,7 @@ static void statTimesToUtc(
*/
static int fileStat(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
#if defined(_WIN32)
sqlite3_int64 sz = strlen(zPath);
@@ -344,7 +342,7 @@ static int fileStat(
*/
static int fileLinkStat(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
#if defined(_WIN32)
return fileStat(zPath, pStatBuf);
@@ -377,7 +375,7 @@ static int makeDirectory(
int i = 1;
while( rc==SQLITE_OK ){
- struct stat sStat;
+ STRUCT_STAT sStat;
int rc2;
for(; zCopy[i]!='/' && i<nCopy; i++);
@@ -427,7 +425,7 @@ static int writeFile(
** be an error though - if there is already a directory at the same
** path and either the permissions already match or can be changed
** to do so using chmod(), it is not an error. */
- struct stat sStat;
+ STRUCT_STAT sStat;
if( errno!=EEXIST
|| 0!=fileStat(zFile, &sStat)
|| !S_ISDIR(sStat.st_mode)
@@ -630,7 +628,7 @@ struct fsdir_cursor {
const char *zBase;
int nBase;
- struct stat sStat; /* Current lstat() results */
+ STRUCT_STAT sStat; /* Current lstat() results */
char *zPath; /* Path to current entry */
sqlite3_int64 iRowid; /* Current rowid */
};
@@ -901,9 +899,9 @@ static int fsdirFilter(
){
const char *zDir = 0;
fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ int i;
(void)idxStr;
fsdirResetCursor(pCur);
- int i;
if( idxNum==0 ){
fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
diff --git a/ext/misc/vtablog.c b/ext/misc/vtablog.c
index e8f084e1b..44acc32e6 100644
--- a/ext/misc/vtablog.c
+++ b/ext/misc/vtablog.c
@@ -14,6 +14,13 @@
** on stdout when its key interfaces are called. This is intended for
** interactive analysis and debugging of virtual table interfaces.
**
+** To build this extension as a separately loaded shared library or
+** DLL, use compiler command-lines similar to the following:
+**
+** (linux) gcc -fPIC -shared vtablog.c -o vtablog.so
+** (mac) clang -fPIC -dynamiclib vtablog.c -o vtablog.dylib
+** (windows) cl vtablog.c -link -dll -out:vtablog.dll
+**
** Usage example:
**
** .load ./vtablog
@@ -436,6 +443,39 @@ static int vtablogFilter(
}
/*
+** Return an sqlite3_index_info operator name in static space.
+** The name is possibly overwritten on subsequent calls.
+*/
+static char *vtablogOpName(unsigned char op){
+ static char zUnknown[30];
+ char *zOut;
+ switch( op ){
+ case SQLITE_INDEX_CONSTRAINT_EQ: zOut = "EQ"; break;
+ case SQLITE_INDEX_CONSTRAINT_GT: zOut = "GT"; break;
+ case SQLITE_INDEX_CONSTRAINT_LE: zOut = "LE"; break;
+ case SQLITE_INDEX_CONSTRAINT_LT: zOut = "LT"; break;
+ case SQLITE_INDEX_CONSTRAINT_GE: zOut = "GE"; break;
+ case SQLITE_INDEX_CONSTRAINT_MATCH: zOut = "MATCH"; break;
+ case SQLITE_INDEX_CONSTRAINT_LIKE: zOut = "LIKE"; break;
+ case SQLITE_INDEX_CONSTRAINT_GLOB: zOut = "GLOB"; break;
+ case SQLITE_INDEX_CONSTRAINT_REGEXP: zOut = "REGEXP"; break;
+ case SQLITE_INDEX_CONSTRAINT_NE: zOut = "NE"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNOT: zOut = "ISNOT"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: zOut = "ISNOTNULL"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNULL: zOut = "ISNULL"; break;
+ case SQLITE_INDEX_CONSTRAINT_IS: zOut = "IS"; break;
+ case SQLITE_INDEX_CONSTRAINT_LIMIT: zOut = "LIMIT"; break;
+ case SQLITE_INDEX_CONSTRAINT_OFFSET: zOut = "OFFSET"; break;
+ case SQLITE_INDEX_CONSTRAINT_FUNCTION: zOut = "FUNCTION"; break;
+ default:
+ sqlite3_snprintf(sizeof(zUnknown),zUnknown,"%d",op);
+ zOut = zUnknown;
+ break;
+ }
+ return zOut;
+}
+
+/*
** SQLite will invoke this method one or more times while planning a query
** that uses the vtablog virtual table. This routine needs to create
** a query plan for each invocation and compute an estimated cost for that
@@ -451,14 +491,23 @@ static int vtablogBestIndex(
printf(" colUsed: 0x%016llx\n", p->colUsed);
printf(" nConstraint: %d\n", p->nConstraint);
for(i=0; i<p->nConstraint; i++){
+ sqlite3_value *pVal = 0;
+ int rc = sqlite3_vtab_rhs_value(p, i, &pVal);
printf(
- " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n",
+ " constraint[%d]: col=%d termid=%d op=%s usabled=%d coll=%s rhs=",
i,
p->aConstraint[i].iColumn,
p->aConstraint[i].iTermOffset,
- p->aConstraint[i].op,
+ vtablogOpName(p->aConstraint[i].op),
p->aConstraint[i].usable,
- sqlite3_vtab_collation(p,i));
+ sqlite3_vtab_collation(p,i)
+ );
+ if( rc==SQLITE_OK ){
+ vtablogQuote(pVal);
+ printf("\n");
+ }else{
+ printf("N/A\n");
+ }
}
printf(" nOrderBy: %d\n", p->nOrderBy);
for(i=0; i<p->nOrderBy; i++){
diff --git a/ext/misc/windirent.h b/ext/misc/windirent.h
new file mode 100644
index 000000000..f84491e46
--- /dev/null
+++ b/ext/misc/windirent.h
@@ -0,0 +1,163 @@
+/*
+** 2025-06-05
+**
+** 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.
+**
+*************************************************************************
+**
+** An implementation of opendir(), readdir(), and closedir() for Windows,
+** based on the FindFirstFile(), FindNextFile(), and FindClose() APIs
+** of Win32.
+**
+** #include this file inside any C-code module that needs to use
+** opendir()/readdir()/closedir(). This file is a no-op on non-Windows
+** machines. On Windows, static functions are defined that implement
+** those standard interfaces.
+*/
+#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
+#define SQLITE_WINDIRENT_H
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#ifndef FILENAME_MAX
+# define FILENAME_MAX (260)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISLNK
+#define S_ISLNK(m) (0)
+#endif
+typedef unsigned short mode_t;
+
+/* The dirent object for Windows is abbreviated. The only field really
+** usable by applications is d_name[].
+*/
+struct dirent {
+ int d_ino; /* Inode number (synthesized) */
+ unsigned d_attributes; /* File attributes */
+ char d_name[FILENAME_MAX]; /* Null-terminated filename */
+};
+
+/* The internals of DIR are opaque according to standards. So it
+** does not matter what we put here. */
+typedef struct DIR DIR;
+struct DIR {
+ intptr_t d_handle; /* Handle for findfirst()/findnext() */
+ struct dirent cur; /* Current entry */
+};
+
+/* Ignore hidden and system files */
+#define WindowsFileToIgnore(a) \
+ ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM))
+
+/*
+** Close a previously opened directory
+*/
+static int closedir(DIR *pDir){
+ int rc = 0;
+ if( pDir==0 ){
+ return EINVAL;
+ }
+ if( pDir->d_handle!=0 && pDir->d_handle!=(-1) ){
+ rc = _findclose(pDir->d_handle);
+ }
+ sqlite3_free(pDir);
+ return rc;
+}
+
+/*
+** Open a new directory. The directory name should be UTF-8 encoded.
+** appropriate translations happen automatically.
+*/
+static DIR *opendir(const char *zDirName){
+ DIR *pDir;
+ wchar_t *b1;
+ sqlite3_int64 sz;
+ struct _wfinddata_t data;
+
+ pDir = sqlite3_malloc64( sizeof(DIR) );
+ if( pDir==0 ) return 0;
+ memset(pDir, 0, sizeof(DIR));
+ memset(&data, 0, sizeof(data));
+ sz = strlen(zDirName);
+ b1 = sqlite3_malloc64( (sz+3)*sizeof(b1[0]) );
+ if( b1==0 ){
+ closedir(pDir);
+ return NULL;
+ }
+ sz = MultiByteToWideChar(CP_UTF8, 0, zDirName, sz, b1, sz);
+ b1[sz++] = '\\';
+ b1[sz++] = '*';
+ b1[sz] = 0;
+ if( sz+1>sizeof(data.name)/sizeof(data.name[0]) ){
+ closedir(pDir);
+ sqlite3_free(b1);
+ return NULL;
+ }
+ memcpy(data.name, b1, (sz+1)*sizeof(b1[0]));
+ sqlite3_free(b1);
+ pDir->d_handle = _wfindfirst(data.name, &data);
+ if( pDir->d_handle<0 ){
+ closedir(pDir);
+ return NULL;
+ }
+ while( WindowsFileToIgnore(data) ){
+ memset(&data, 0, sizeof(data));
+ if( _wfindnext(pDir->d_handle, &data)==-1 ){
+ closedir(pDir);
+ return NULL;
+ }
+ }
+ pDir->cur.d_ino = 0;
+ pDir->cur.d_attributes = data.attrib;
+ WideCharToMultiByte(CP_UTF8, 0, data.name, -1,
+ pDir->cur.d_name, FILENAME_MAX, 0, 0);
+ return pDir;
+}
+
+/*
+** Read the next entry from a directory.
+**
+** The returned struct-dirent object is managed by DIR. It is only
+** valid until the next readdir() or closedir() call. Only the
+** d_name[] field is meaningful. The d_name[] value has been
+** translated into UTF8.
+*/
+static struct dirent *readdir(DIR *pDir){
+ struct _wfinddata_t data;
+ if( pDir==0 ) return 0;
+ if( (pDir->cur.d_ino++)==0 ){
+ return &pDir->cur;
+ }
+ do{
+ memset(&data, 0, sizeof(data));
+ if( _wfindnext(pDir->d_handle, &data)==-1 ){
+ return NULL;
+ }
+ }while( WindowsFileToIgnore(data) );
+ pDir->cur.d_attributes = data.attrib;
+ WideCharToMultiByte(CP_UTF8, 0, data.name, -1,
+ pDir->cur.d_name, FILENAME_MAX, 0, 0);
+ return &pDir->cur;
+}
+
+#endif /* defined(_WIN32) && defined(_MSC_VER) */