📄 main.cpp
字号:
/*************************************************************************** main.c SQLite driver iHacked by N.Gerrard from code originally provided by (c) 2000-2003 Beno� Minisini <gambas@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define __MAIN_C#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <libgen.h> /* For basename function */#include <pwd.h> /* For passwd file functions */#include <grp.h> /* For group file functions */#include <sys/types.h>#include <sys/stat.h>#include <dirent.h>#include <unistd.h>#include "sqlitedataset.h"#include "main.h"extern "C" {GB_INTERFACE GB;DB_INTERFACE DB;} //end extern "C"static char _buffer[32];static int _print_query = FALSE;/***************************************************************************** The driver interface*****************************************************************************/static DB_DRIVER _driver ={ "sqlite", open_database, close_database, format_value, exec_query, begin_transaction, commit_transaction, rollback_transaction, get_quote, { query_init, query_fill, query_release, { field_type, field_name, field_index, field_length, }, }, { field_exist, field_list, field_info, }, { table_init, table_index, table_release, table_exist, table_list, table_primary_key, table_is_system, table_type, table_delete, table_create, }, { index_exist, index_list, index_info, index_delete, index_create, }, { database_exist, database_list, database_is_system, database_delete, database_create, }, { user_exist, user_list, user_info, user_delete, user_create, user_set_password }};/* Internal function to convert a database type into a Gambas type */static GB_TYPE conv_type(int type){ switch(type) { case ft_Boolean: return GB_T_BOOLEAN; case ft_Short: case ft_UShort: case ft_Long: case ft_ULong: return GB_T_INTEGER; case ft_Float: case ft_Double: case ft_LongDouble: return GB_T_FLOAT; case ft_Date: return GB_T_DATE; case ft_String: case ft_WideString: case ft_Char: case ft_WChar: return GB_T_STRING; default: return GB_T_STRING; }}/* Internal function to convert a database value into a Gambas variant value */static void conv_data(char *data, GB_VARIANT_VALUE *val, fType type){ GB_VALUE conv; GB_DATE_SERIAL date; double sec; switch (type) { case ft_Boolean: val->_boolean.type = GB_T_BOOLEAN; /*GB.NumberFromString(GB_NB_READ_INTEGER, data, strlen(data), &conv);*/ if (data[0] == 't' || data[0] == 'T'){ val->_boolean.value = 1; } else { val->_boolean.value = atoi(data);// != 0; } break; case ft_Short: case ft_UShort: case ft_Long: case ft_ULong: GB.NumberFromString(GB_NB_READ_INTEGER, data, strlen(data), &conv); val->_integer.type = GB_T_INTEGER; val->_integer.value = ((GB_INTEGER *)&conv)->value; break; case ft_Float: case ft_Double: case ft_LongDouble: GB.NumberFromString(GB_NB_READ_FLOAT, data, strlen(data), &conv); val->_float.type = GB_T_FLOAT; val->_float.value = ((GB_FLOAT *)&conv)->value; break; case ft_Date: memset(&date, 0, sizeof(date)); switch(strlen(data)) { case 14: sscanf(data, "%4hu%2hu%2hu%2hu%2hu%lf", &date.year, &date.month, &date.day, &date.hour, &date.min, &sec); date.sec = (short)sec; date.msec = (short)((sec - date.sec) * 1000 + 0.5); break; case 12: sscanf(data, "%2hu%2hu%2hu%2hu%2hu%lf", &date.year, &date.month, &date.day, &date.hour, &date.min, &sec); date.sec = (short)sec; date.msec = (short)((sec - date.sec) * 1000 + 0.5); break; case 10: if (sscanf(data, "%4hu-%2hu-%2hu", &date.year, &date.month, &date.day) != 3){ if (sscanf(data, "%4hu/%2hu/%2hu", &date.year, &date.month, &date.day) != 3){ if (sscanf(data, "%4hu:%2hu:%lf", &date.hour, &date.min, &sec) == 3){ date.sec = (short)sec; date.msec = (short)((sec - date.sec) * 1000 + 0.5); } else { sscanf(data, "%2hu%2hu%2hu%2hu%2hu", &date.year, &date.month, &date.day, &date.hour, &date.min ); } } } break; case 8: if (sscanf(data, "%4hu%2hu%2hu", &date.year, &date.month, &date.day) != 3){ sscanf(data, "%2hu/%2hu/%2hu", &date.year, &date.month, &date.day); } break; case 6: sscanf(data, "%2hu%2hu%2hu", &date.year, &date.month, &date.day); break; case 4: sscanf(data, "%2hu%2hu", &date.year, &date.month); break; case 2: sscanf(data, "%2hu", &date.year); break; default: sscanf(data, "%4hu-%2hu-%2hu %2hu:%2hu:%lf", &date.year, &date.month, &date.day, &date.hour, &date.min, &sec); date.sec = (short)sec; date.msec = (short)((sec - date.sec) * 1000 + 0.5); } if (date.year < 100) date.year=+1900; GB.MakeDate(&date, (GB_DATE *)&conv); val->_date.type = GB_T_DATE; val->_date.date = ((GB_DATE *)&conv)->value.date; val->_date.time = ((GB_DATE *)&conv)->value.time; break; case ft_String: case ft_WideString: case ft_Char: case ft_WChar: default: val->_string.type = GB_T_CSTRING; val->_string.value = data; /*GB.NewString(&val->_string.value, data, strlen(data));*/ break; }}/* Internal function to substitute the table name into a query */static char *query_param[3];static void query_get_param(int index, char **str, long *len){ if (index > 3) return; index--; *str = query_param[index]; *len = strlen(*str);}/* Internal function to run a query */static int do_query(SqliteDatabase *conn, const char *error, Dataset **pres, const char *qtemp, int nsubst, ...){ va_list args; int i; const char *query; Dataset *res = conn->CreateDataset(); int ret; if (nsubst) { va_start(args, nsubst); if (nsubst > 3) nsubst = 3; for (i = 0; i < nsubst; i++) query_param[i] = va_arg(args, char *); query = GB.SubstString(qtemp, 0, query_get_param); } else query = qtemp; if (_print_query) { _print_query = FALSE; } if (DB.IsDebug()) fprintf(stderr, "sqlite: %p: %s\n", conn, query); if (strncasecmp("select",query,6) == 0){ if(res->query(query)){ ret = FALSE; if (pres){ *pres = res; } } else { ret = TRUE; GB.Error(error, conn->getErrorMsg()); } } else { if(res->exec(query)){ ret = FALSE; if (pres){ *pres = res; } } else { ret = TRUE; GB.Error(error, conn->getErrorMsg()); } } return ret;}/* Internal function to check whether a file is a sqlite database file */bool IsDatabaseFile ( char *filename ){ /* SQLite databases start with the string: * ** This file contains an SQLite 2.1 database ** * */ FILE* fp; bool res; char magic_text[48]; fp = fopen(filename, "r"); if (!fp) return false; res = fread(magic_text, 1, 47, fp) == 47; fclose(fp); if (!res) return false; magic_text[47] = '\0'; if (strcmp(magic_text, "** This file contains an SQLite 2.1 database **")) return false; return true;}/* Internal function to locate database and return full qualified *//* path. */char *FindDatabase ( char *name, char *hostName){ char *dbhome = NULL; char *fullpath = NULL; /* Does Name includes fullpath */ if (strcmp(basename(name), name)) { if (IsDatabaseFile(name)) GB.NewString(&fullpath, name, 0); return fullpath; } /* Hostname contains home area */ GB.NewString(&fullpath, hostName, 0); GB.AddString(&fullpath, "/", 0); GB.AddString(&fullpath, name, 0); if (IsDatabaseFile(fullpath)){ return fullpath; } GB.FreeString(&fullpath); /* Check the GAMBAS_SQLITE_DBHOME setting */ dbhome = getenv("GAMBAS_SQLITE_DBHOME"); if (dbhome != NULL ){ GB.NewString(&fullpath, dbhome, 0); GB.AddString(&fullpath, "/", 0); GB.AddString(&fullpath, name, 0); if (IsDatabaseFile(fullpath)){ return fullpath; } } #if 0 /* Now check for database in current working directory */ if (getcwd(cwd, MAX_PATH) == NULL){ GB.Error("Unable to get databases: &1", "Can't find current directory"); return NULL; } #endif GB.NewString(&fullpath, GB.GetTempDir(), 0); GB.AddString(&fullpath, "/sqlite/", 0); GB.AddString(&fullpath, name, 0); if (IsDatabaseFile(fullpath)){ return fullpath; } GB.FreeString(&fullpath); return NULL;}/* Internal function to return database home directory *//* - GAMBAS_SQLITE_HOMEDB if set or temporary directory /tmp/gambas.%pid%/ */char *GetDatabaseHome(){ char *env = NULL; char *dbhome = NULL; GB.Alloc((void **)&dbhome, MAX_PATH); /* Check for Environment variable */ env = getenv("GAMBAS_SQLITE_DBHOME"); /* if not set then set to current working directory */ if (env == NULL){ /* if (getcwd(dbhome, MAX_PATH) == NULL){ GB.Error("Unable to get databases: &1", "Can't find current directory"); GB.Free((void **)&dbhome); return NULL; } */ sprintf(dbhome, "%s/sqlite", GB.GetTempDir()); } else { strcpy(dbhome, env); } return dbhome;}// BM: not used anymore#if 0/* Return Fullpath for database */char *FullPath( char *name ){ char *db_fullpath = NULL; char *dbhome = NULL; dbhome = GetDatabaseHome(); if (!dbhome) return NULL; GB.Alloc ((void **)&db_fullpath, strlen(name)+strlen(dbhome)+2); /* leave room for \0 and / */ /* start with an empty string */ db_fullpath[0] = '\0'; strcpy(db_fullpath, dbhome); if (db_fullpath[strlen(db_fullpath)-1] != '/') { strcat(db_fullpath, "/"); } strcat(db_fullpath, name); GB.Free((void **)&dbhome); return db_fullpath;}#endif/* Internal function to walk a dirctory and list files *//* Used by database_list */int WalkDirectory( char *dir, char ***databases ){ DIR *dp; struct dirent *entry; struct stat statbuf; char cwd[MAX_PATH]; if ((dp = opendir(dir)) == NULL) { return -1; } getcwd(cwd, MAX_PATH); chdir(dir); while ((entry = readdir(dp)) != NULL) { stat(entry->d_name, &statbuf); if (S_ISREG(statbuf.st_mode)) { if (IsDatabaseFile(entry->d_name)){ GB.NewString((char **)GB.Add(databases), entry->d_name, 0); } } } chdir(cwd); // BM: you must call closedir() closedir(dp); return GB.Count(databases);}/* Internal function to check database version number */long db_version(){ //Check db version long dbversion =0; unsigned int verMain, verMajor, verMinor; sscanf(sqlite_version,"%2u.%2u.%2u", &verMain, &verMajor, &verMinor); dbversion = ((verMain * 10000) + (verMajor * 100) + verMinor); return dbversion;}/***************************************************************************** get_quote() Returns the character used for quoting object names.*****************************************************************************/static char *get_quote(void){ return QUOTE_STRING;}/***************************************************************************** open_database() Connect to a database. <desc> points at a structure describing each connection parameter. In Sqlite, there is no such thing as a host. If this is set then check to see whether this is actually a path to a home area. NG 01/04/04 This function must return a database handle, or NULL if the connection has failed.*****************************************************************************/static DB_DATABASE open_database(DB_DESC *desc, char **charset){ SqliteDatabase *conn = new SqliteDatabase(); char *name = NULL; char *db_fullpath = NULL; bool memory; /* connect by default to memory database */ if (desc->name) { GB.NewString(&name, desc->name, 0); memory = false; } else { GB.NewString(&name, ":memory:", 0); memory = true; } if (desc->host) conn->setHostName(desc->host); if (memory) { conn->setDatabase(name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -