|
/****************************************************************************
|
|
* This file is part of the project AqFinance.
|
|
* AqFinance (c) by 2007 Martin Preuss, all rights reserved.
|
|
*
|
|
* The license for this file can be found in the file COPYING which you
|
|
* should have received along with this file.
|
|
****************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
|
|
#include "table_p.h"
|
|
#include "dbdir_l.h"
|
|
#include "query_object_l.h"
|
|
|
|
#include <aqdatabase/aqdb_db_be.h>
|
|
#include <aqdatabase/aqdb_object_be.h>
|
|
#include <aqdatabase/aqdb_query_be.h>
|
|
|
|
#include <gwenhywfar/buffer.h>
|
|
#include <gwenhywfar/text.h>
|
|
#include <gwenhywfar/debug.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
GWEN_LIST_FUNCTIONS(AQDB_DBDIR_TABLE, AQDB_DbDir_Table)
|
|
|
|
|
|
|
|
#ifdef OS_WIN32
|
|
|
|
|
|
int AQDB_DbDir_Table_open(AQDB_DBDIR_TABLE *table, int rw) {
|
|
DWORD flags=0;
|
|
HANDLE fh;
|
|
|
|
if (rw)
|
|
flags=GENERIC_READ | GENERIC_WRITE;
|
|
else
|
|
flags=GENERIC_READ;
|
|
|
|
fh=CreateFile(table->dataFileName,
|
|
flags, /* dwDesiredAccess */
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
|
|
NULL, /* pSecurityAttributes */
|
|
OPEN_EXISTING, /* dwCreationDistribution */
|
|
FILE_FLAG_RANDOM_ACCESS, /* dwFlagsAndAttrs */
|
|
NULL); /* hTemplateFile */
|
|
if (fh==INVALID_HANDLE_VALUE) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error opening file[%s]: %d",
|
|
table->dataFileName,
|
|
(int)GetLastError());
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
table->fh=fh;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_creat(AQDB_DBDIR_TABLE *table) {
|
|
HANDLE fh;
|
|
|
|
fh=CreateFile(table->dataFileName,
|
|
GENERIC_READ | GENERIC_WRITE, /* dwDesiredAccess */
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
|
|
NULL, /* pSecurityAttributes */
|
|
CREATE_NEW, /* dwCreationDistribution */
|
|
FILE_FLAG_RANDOM_ACCESS | /* dwFlagsAndAttrs */
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL); /* hTemplateFile */
|
|
if (fh==INVALID_HANDLE_VALUE) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error creating file[%s]: %d",
|
|
table->dataFileName,
|
|
(int)GetLastError());
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
table->fh=fh;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_close(AQDB_DBDIR_TABLE *table) {
|
|
if (!CloseHandle(table->fh)) {
|
|
table->fh=NULL;
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error closing file[%s]: %d",
|
|
table->dataFileName,
|
|
(int)GetLastError());
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
table->fh=NULL;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_seek(AQDB_DBDIR_TABLE *table, uint64_t offs) {
|
|
LARGE_INTEGER li;
|
|
|
|
li.QuadPart = offs;
|
|
li.LowPart=SetFilePointer(table->fh,
|
|
li.LowPart,
|
|
&li.HighPart,
|
|
FILE_BEGIN);
|
|
if (li.LowPart==INVALID_SET_FILE_POINTER) {
|
|
DWORD rv;
|
|
|
|
rv=GetLastError();
|
|
if (rv!=NO_ERROR) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking in file[%s] at %llu: %d",
|
|
table->dataFileName,
|
|
(unsigned long long) offs,
|
|
(int)rv);
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
size_t AQDB_DbDir_Table_read(AQDB_DBDIR_TABLE *table, uint8_t *ptr, size_t size, size_t nmember) {
|
|
size_t r=size*nmember;
|
|
|
|
while(r) {
|
|
DWORD bytesRead=0;
|
|
|
|
if (!ReadFile(table->fh, ptr, r, &bytesRead, NULL)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Error on ReadFile(%s): %d",
|
|
table->dataFileName,
|
|
(int)GetLastError());
|
|
return -1;
|
|
}
|
|
|
|
if (bytesRead==0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "EOF met on read(%s)",
|
|
table->dataFileName);
|
|
return 0;
|
|
}
|
|
else {
|
|
ptr+=bytesRead;
|
|
r-=bytesRead;
|
|
}
|
|
}
|
|
|
|
return nmember;
|
|
}
|
|
|
|
|
|
|
|
size_t AQDB_DbDir_Table_write(AQDB_DBDIR_TABLE *table, const uint8_t *ptr, size_t size, size_t nmember) {
|
|
size_t r=size*nmember;
|
|
|
|
while(r) {
|
|
DWORD bytesWritten=0;
|
|
|
|
if (!WriteFile(table->fh, ptr, r, &bytesWritten, NULL)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Error on WriteFile(%s): %d",
|
|
table->dataFileName,
|
|
(int)GetLastError());
|
|
return -1;
|
|
}
|
|
|
|
if (bytesWritten==0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Broken pipe on WriteFile(%s)",
|
|
table->dataFileName);
|
|
return 0;
|
|
}
|
|
else {
|
|
ptr+=bytesWritten;
|
|
r-=bytesWritten;
|
|
}
|
|
}
|
|
|
|
return nmember;
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
int AQDB_DbDir_Table_seek(AQDB_DBDIR_TABLE *table, uint64_t offs) {
|
|
if (lseek(table->fd, offs, SEEK_SET)==-1)
|
|
return GWEN_ERROR_IO;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_open(AQDB_DBDIR_TABLE *table, int rw) {
|
|
int flags=0;
|
|
int fd;
|
|
|
|
if (rw)
|
|
flags=O_RDWR;
|
|
else
|
|
flags=O_RDONLY;
|
|
#ifdef O_BINARY
|
|
flags|=O_BINARY;
|
|
#endif
|
|
|
|
fd=open(table->dataFileName, flags);
|
|
if (fd==-1) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error opening file[%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
table->fd=fd;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_creat(AQDB_DBDIR_TABLE *table) {
|
|
int fd;
|
|
|
|
fd=open(table->dataFileName,
|
|
#ifdef O_BINARY
|
|
O_BINARY |
|
|
#endif
|
|
O_RDWR | O_CREAT | O_EXCL,
|
|
S_IRUSR | S_IWUSR
|
|
#ifdef S_IRGRP
|
|
| S_IRGRP
|
|
#endif
|
|
#ifdef S_IWGRP
|
|
| S_IWGRP
|
|
#endif
|
|
);
|
|
if (fd==-1) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error creating file[%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
table->fd=fd;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_close(AQDB_DBDIR_TABLE *table) {
|
|
int rv;
|
|
|
|
rv=close(table->fd);
|
|
table->fd=-1;
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
size_t AQDB_DbDir_Table_read(AQDB_DBDIR_TABLE *table, uint8_t *ptr, size_t size, size_t nmember) {
|
|
size_t total=size*nmember;
|
|
size_t r=total;
|
|
|
|
while(r) {
|
|
ssize_t t;
|
|
|
|
t=read(table->fd, ptr, r);
|
|
if (t<0) {
|
|
if (errno!=EINTR) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Error on read(%s): %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
else if (t==0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "EOF met on read(%s)",
|
|
table->dataFileName);
|
|
return 0;
|
|
}
|
|
else {
|
|
ptr+=t;
|
|
r-=t;
|
|
}
|
|
}
|
|
|
|
return nmember;
|
|
}
|
|
|
|
|
|
|
|
size_t AQDB_DbDir_Table_write(AQDB_DBDIR_TABLE *table, const uint8_t *ptr, size_t size, size_t nmember) {
|
|
size_t total=size*nmember;
|
|
size_t r=total;
|
|
|
|
while(r) {
|
|
ssize_t t;
|
|
|
|
t=write(table->fd, ptr, r);
|
|
if (t<0) {
|
|
if (errno!=EINTR) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Error on write(%s): %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
else if (t==0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Pipe broken on write(%s)",
|
|
table->dataFileName);
|
|
return 0;
|
|
}
|
|
else {
|
|
ptr+=t;
|
|
r-=t;
|
|
}
|
|
}
|
|
|
|
return nmember;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
AQDB_DBDIR_TABLE *AQDB_DbDir_Table_new(AQDB_DB *db, const char *tname, AQDB_ID id) {
|
|
AQDB_DBDIR_TABLE *table;
|
|
const GWEN_URL *url;
|
|
|
|
GWEN_NEW_OBJECT(AQDB_DBDIR_TABLE, table);
|
|
GWEN_LIST_INIT(AQDB_DBDIR_TABLE, table);
|
|
table->db=db;
|
|
table->name=strdup(tname);
|
|
table->tableId=id;
|
|
table->lastId=0;
|
|
#ifdef OS_WIN32
|
|
table->fh=NULL;
|
|
#else
|
|
table->fd=-1;
|
|
#endif
|
|
|
|
url=AQDB_DB_GetUrl(db);
|
|
if (url) {
|
|
GWEN_BUFFER *pbuf;
|
|
const char *s;
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
s=GWEN_Url_GetServer(url);
|
|
if (s)
|
|
GWEN_Buffer_AppendString(pbuf, s);
|
|
s=GWEN_Url_GetPath(url);
|
|
if (s) {
|
|
if (GWEN_Buffer_GetUsedBytes(pbuf))
|
|
GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S);
|
|
GWEN_Buffer_AppendString(pbuf, s);
|
|
}
|
|
GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S);
|
|
GWEN_Text_EscapeToBufferTolerant(tname, pbuf);
|
|
GWEN_Buffer_AppendString(pbuf, ".table");
|
|
table->dataFileName=strdup(GWEN_Buffer_GetStart(pbuf));
|
|
GWEN_Buffer_free(pbuf);
|
|
}
|
|
|
|
table->columnList=AQDB_Column_List_new();
|
|
|
|
table->sessionObjectMap=AQDB_DbDir_ObjectDescr_IdMap_new(GWEN_IdMapAlgo_Hex4);
|
|
table->sessionObjectList=AQDB_DbDir_ObjectDescr_List_new();
|
|
|
|
return table;
|
|
}
|
|
|
|
|
|
|
|
void AQDB_DbDir_Table_free(AQDB_DBDIR_TABLE *table) {
|
|
if (table) {
|
|
#ifdef OS_WIN32
|
|
if (table->fh!=NULL)
|
|
AQDB_DbDir_Table_close(table);
|
|
table->fh=NULL;
|
|
#else
|
|
if (table->fd!=-1)
|
|
AQDB_DbDir_Table_close(table);
|
|
table->fd=-1;
|
|
#endif
|
|
|
|
if (table->dataFileName)
|
|
free(table->dataFileName);
|
|
if (table->name)
|
|
free(table->name);
|
|
AQDB_Column_List_free(table->columnList);
|
|
GWEN_IdList64_free(table->editObjectsAdded);
|
|
GWEN_IdList64_free(table->editObjectsDeleted);
|
|
GWEN_IdList64_free(table->objectPositions);
|
|
GWEN_LIST_FINI(AQDB_DBDIR_TABLE, table);
|
|
AQDB_DbDir_ObjectDescr_IdMap_free(table->sessionObjectMap);
|
|
AQDB_DbDir_ObjectDescr_List_free(table->sessionObjectList);
|
|
|
|
GWEN_FREE_OBJECT(table);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const char *AQDB_DbDir_Table_GetName(const AQDB_DBDIR_TABLE *table) {
|
|
return table->name;
|
|
}
|
|
|
|
|
|
|
|
AQDB_ID AQDB_DbDir_Table_GetId(const AQDB_DBDIR_TABLE *table) {
|
|
return table->tableId;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_IsOpen(const AQDB_DBDIR_TABLE *table) {
|
|
return (!(table->openFlags & AQDB_ACTION_FLAGS_WRITE) &&
|
|
!(table->openFlags & AQDB_ACTION_FLAGS_READ));
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_ReadHeader(AQDB_DBDIR_TABLE *table) {
|
|
uint32_t v32;
|
|
uint8_t header[AQDB_DBDIR_TABLE_HEADER_SIZE];
|
|
|
|
/* seek position of header */
|
|
if (AQDB_DbDir_Table_seek(table, 0)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking on file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* read header */
|
|
if (1!=AQDB_DbDir_Table_read(table, header, AQDB_DBDIR_TABLE_HEADER_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error reading from file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* read version */
|
|
table->vMajor=header[AQDB_DBDIR_TABLE_HEADER_VERSION_MAJOR];
|
|
table->vMinor=header[AQDB_DBDIR_TABLE_HEADER_VERSION_MINOR];
|
|
table->vMicro=header[AQDB_DBDIR_TABLE_HEADER_VERSION_MICRO];
|
|
|
|
/* read flags */
|
|
table->flags=
|
|
(header[AQDB_DBDIR_TABLE_HEADER_FLAGS+0]<<24)+
|
|
(header[AQDB_DBDIR_TABLE_HEADER_FLAGS+1]<<16)+
|
|
(header[AQDB_DBDIR_TABLE_HEADER_FLAGS+2]<<8)+
|
|
header[AQDB_DBDIR_TABLE_HEADER_FLAGS+3];
|
|
|
|
/* read object size */
|
|
v32=
|
|
(header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+0]<<24)+
|
|
(header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+1]<<16)+
|
|
(header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+2]<<8)+
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+3];
|
|
table->objectSize=v32;
|
|
|
|
/* read number of object fields */
|
|
v32=
|
|
(header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+0]<<24)+
|
|
(header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+1]<<16)+
|
|
(header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+2]<<8)+
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+3];
|
|
table->objectColumns=v32;
|
|
|
|
/* read last id */
|
|
table->lastId=
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+0])<<56)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+1])<<48)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+2])<<40)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+3])<<32)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+4])<<24)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+5])<<16)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+6])<<8)+
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+7];
|
|
|
|
/* read types offset */
|
|
table->typesOffset=
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+0])<<56)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+1])<<48)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+2])<<40)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+3])<<32)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+4])<<24)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+5])<<16)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+6])<<8)+
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+7];
|
|
|
|
table->dataOffset=
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_DATA_START+0])<<56)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_DATA_START+1])<<48)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_DATA_START+2])<<40)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_DATA_START+3])<<32)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_DATA_START+4])<<24)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_DATA_START+5])<<16)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_DATA_START+6])<<8)+
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+7];
|
|
|
|
/* read max objects */
|
|
table->maxObjects=
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+0])<<56)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+1])<<48)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+2])<<40)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+3])<<32)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+4])<<24)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+5])<<16)+
|
|
(((uint64_t)header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+6])<<8)+
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+7];
|
|
|
|
if (table->maxObjects==0) {
|
|
if (table->lastId>0) {
|
|
DBG_WARN(AQDB_LOGDOMAIN, "Updating maxObjects");
|
|
table->maxObjects=table->lastId+1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_WriteHeader(AQDB_DBDIR_TABLE *table) {
|
|
uint8_t header[AQDB_DBDIR_TABLE_HEADER_SIZE];
|
|
uint64_t v64;
|
|
uint32_t v32;
|
|
|
|
memset(header, 0, AQDB_DBDIR_TABLE_HEADER_SIZE);
|
|
|
|
/* write version */
|
|
header[AQDB_DBDIR_TABLE_HEADER_VERSION_MAJOR]=table->vMajor;
|
|
header[AQDB_DBDIR_TABLE_HEADER_VERSION_MINOR]=table->vMinor;
|
|
header[AQDB_DBDIR_TABLE_HEADER_VERSION_MICRO]=table->vMicro;
|
|
|
|
/* write flags */
|
|
v32=table->flags;
|
|
header[AQDB_DBDIR_TABLE_HEADER_FLAGS+3]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_FLAGS+2]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_FLAGS+1]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_FLAGS+0]=v32 & 0xff;
|
|
|
|
/* write object size */
|
|
v32=table->objectSize;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+3]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+2]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+1]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_SIZE+0]=v32 & 0xff;
|
|
|
|
/* write number of object fields */
|
|
v32=table->objectColumns;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+3]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+2]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+1]=v32 & 0xff;
|
|
v32>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_OBJECT_FIELDS+0]=v32 & 0xff;
|
|
|
|
/* write last id */
|
|
v64=table->lastId;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+7]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+6]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+5]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+4]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+3]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+2]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+1]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_HIGHEST_ID+0]=v64 & 0xff;
|
|
|
|
/* write types offset */
|
|
v64=table->typesOffset;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+7]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+6]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+5]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+4]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+3]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+2]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+1]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_TYPES_START+0]=v64 & 0xff;
|
|
|
|
/* write data offset */
|
|
v64=table->dataOffset;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+7]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+6]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+5]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+4]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+3]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+2]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+1]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_DATA_START+0]=v64 & 0xff;
|
|
|
|
/* write last id */
|
|
v64=table->maxObjects;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+7]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+6]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+5]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+4]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+3]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+2]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+1]=v64 & 0xff;
|
|
v64>>=8;
|
|
header[AQDB_DBDIR_TABLE_HEADER_MAX_OBJECTS+0]=v64 & 0xff;
|
|
|
|
/* seek position of header */
|
|
if (AQDB_DbDir_Table_seek(table, 0)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking on file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* write header */
|
|
if (1!=AQDB_DbDir_Table_write(table, header, AQDB_DBDIR_TABLE_HEADER_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error writing to file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableReadObjectAt(AQDB_DBDIR_TABLE *table,
|
|
uint64_t filePos,
|
|
AQDB_ID objectId,
|
|
int objLen,
|
|
int maxColumns,
|
|
AQDB_OBJECT **pObject) {
|
|
uint8_t oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE];
|
|
uint32_t v32;
|
|
|
|
assert(table);
|
|
assert(maxColumns);
|
|
|
|
if (AQDB_DbDir_Table_seek(table, filePos)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking position %llu on file [%s]: %s",
|
|
(long long int)filePos,
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* read object header */
|
|
if (1!=AQDB_DbDir_Table_read(table, oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error reading from file [%s] at %llu: %s (%d)",
|
|
table->dataFileName,
|
|
(long long int)filePos,
|
|
strerror(errno),
|
|
errno);
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
v32=((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS]);
|
|
if (v32!=AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Object [%lx] of table [%s] is not active (%d)",
|
|
(unsigned long)objectId, table->name, v32);
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
v32=
|
|
(((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+0])<<24)+
|
|
(((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+1])<<16)+
|
|
(((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+2])<<8)+
|
|
((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+3]);
|
|
if (!(table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH) &&
|
|
(v32>(objLen-AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE))) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Internal error: Object of table [%s] too big [%ld>%ld]",
|
|
table->name, (unsigned long)v32, (unsigned long) (objLen-AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE));
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
else {
|
|
GWEN_BUFFER *buf;
|
|
uint8_t *p;
|
|
AQDB_OBJECT *o;
|
|
int i;
|
|
int len;
|
|
const uint8_t *t;
|
|
uint8_t x=0;
|
|
|
|
buf=GWEN_Buffer_new(0, v32, 0, 1);
|
|
p=(uint8_t*) GWEN_Buffer_GetStart(buf);
|
|
while(v32) {
|
|
size_t l;
|
|
|
|
l=1024;
|
|
if (l>v32)
|
|
l=v32;
|
|
l=AQDB_DbDir_Table_read(table, p, 1, l);
|
|
if (l<0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error reading from file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
GWEN_Buffer_free(buf);
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
GWEN_Buffer_IncrementPos(buf, l);
|
|
v32-=l;
|
|
p+=l;
|
|
}
|
|
GWEN_Buffer_AdjustUsedBytes(buf);
|
|
|
|
/* create checksum, start with header */
|
|
t=oheader;
|
|
len=AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH;
|
|
for (i=0; i<len; i++)
|
|
x=x^(*(t++));
|
|
|
|
/* continue with data */
|
|
t=(const uint8_t*)GWEN_Buffer_GetStart(buf);
|
|
len=GWEN_Buffer_GetUsedBytes(buf);
|
|
for (i=0; i<len; i++)
|
|
x=x^(*(t++));
|
|
if (x!=0) {
|
|
if (oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_CHECKSUM]!=0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Bad checksum in object %d at %08x of table [%s]",
|
|
objectId,
|
|
(unsigned int) filePos,
|
|
table->name);
|
|
GWEN_Text_LogString((const char*) oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE,
|
|
AQDB_LOGDOMAIN, GWEN_LoggerLevel_Error);
|
|
GWEN_Text_LogString(GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf),
|
|
AQDB_LOGDOMAIN, GWEN_LoggerLevel_Error);
|
|
GWEN_Buffer_free(buf);
|
|
return GWEN_ERROR_BAD_DATA;
|
|
}
|
|
}
|
|
|
|
o=AQDB_DbDir_Object_fromBuffer(table->tableId,
|
|
objectId,
|
|
maxColumns,
|
|
(const uint8_t*)GWEN_Buffer_GetStart(buf),
|
|
GWEN_Buffer_GetUsedBytes(buf));
|
|
if (o==NULL) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Could not create object from buffer");
|
|
GWEN_Buffer_free(buf);
|
|
return GWEN_ERROR_INTERNAL;
|
|
}
|
|
GWEN_Buffer_free(buf);
|
|
*pObject=o;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableWriteObjectAt(AQDB_DBDIR_TABLE *table,
|
|
uint64_t filePos,
|
|
AQDB_ID objectId,
|
|
int objLen,
|
|
int maxColumns,
|
|
const AQDB_OBJECT *object,
|
|
uint32_t status) {
|
|
uint8_t oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE];
|
|
uint32_t v32;
|
|
GWEN_BUFFER *obuffer;
|
|
int i;
|
|
int len;
|
|
const uint8_t *p;
|
|
uint8_t x=0;
|
|
int rv;
|
|
|
|
if (AQDB_DbDir_Table_seek(table, filePos)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking position %llu on file [%s]: %s",
|
|
(long long int)filePos,
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
obuffer=GWEN_Buffer_new(0, 256, 0, 1);
|
|
rv=AQDB_DbDir_Object_toBuffer(object, obuffer);
|
|
if (rv<0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error storing object %08x to buffer for table [%s]: %d",
|
|
(unsigned int) objectId,
|
|
table->dataFileName,
|
|
rv);
|
|
return rv;
|
|
}
|
|
|
|
/* prepare object header */
|
|
memset(oheader, 0, AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE);
|
|
|
|
/* write status */
|
|
v32=status;
|
|
oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS]=v32 & 0xff;
|
|
|
|
/* write object length */
|
|
v32=GWEN_Buffer_GetUsedBytes(obuffer);
|
|
oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+3]=v32 & 0xff;
|
|
v32>>=8;
|
|
oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+2]=v32 & 0xff;
|
|
v32>>=8;
|
|
oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+1]=v32 & 0xff;
|
|
v32>>=8;
|
|
oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+0]=v32 & 0xff;
|
|
|
|
/* create checksum over header */
|
|
p=oheader;
|
|
len=AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH;
|
|
for (i=0; i<len; i++)
|
|
x=x^(*(p++));
|
|
|
|
/* continue with data */
|
|
p=(const uint8_t*)GWEN_Buffer_GetStart(obuffer);
|
|
len=GWEN_Buffer_GetUsedBytes(obuffer);
|
|
for (i=0; i<len; i++)
|
|
x=x^(*(p++));
|
|
|
|
/* store checksum */
|
|
oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_CHECKSUM]=x & 0xff;
|
|
|
|
/* write object header */
|
|
if (1!=AQDB_DbDir_Table_write(table, oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error writing to file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
GWEN_Buffer_free(obuffer);
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
else {
|
|
const uint8_t *p;
|
|
|
|
/* write object data */
|
|
p=(const uint8_t*)GWEN_Buffer_GetStart(obuffer);
|
|
v32=GWEN_Buffer_GetUsedBytes(obuffer);
|
|
while(v32) {
|
|
size_t l;
|
|
|
|
l=1024;
|
|
if (l>v32)
|
|
l=v32;
|
|
if (1!=AQDB_DbDir_Table_write(table, p, l, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error writing to file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
GWEN_Buffer_free(obuffer);
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
v32-=l;
|
|
p+=l;
|
|
}
|
|
GWEN_Buffer_free(obuffer);
|
|
|
|
return (int) len;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_ColumnFromObject(AQDB_DBDIR_TABLE *table,
|
|
const AQDB_OBJECT *o,
|
|
AQDB_COLUMN **pCol) {
|
|
return AQDB_Column_fromObject(o, pCol);
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_ColumnToObject(AQDB_DBDIR_TABLE *table,
|
|
const AQDB_COLUMN *col,
|
|
AQDB_OBJECT *o) {
|
|
return AQDB_Column_toObject(col, o);
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_WriteColumns(AQDB_DBDIR_TABLE *table) {
|
|
AQDB_COLUMN *col;
|
|
AQDB_ID id=1;
|
|
int rv;
|
|
|
|
col=AQDB_Column_List_First(table->columnList);
|
|
while(col) {
|
|
AQDB_OBJECT *o;
|
|
uint64_t filePos;
|
|
|
|
o=AQDB_Object_new(table->tableId, id, AQDB_COLUMN_FIELD_COUNT);
|
|
rv=AQDB_Column_toObject(col, o);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_Object_free(o);
|
|
return rv;
|
|
}
|
|
|
|
filePos=table->typesOffset+((id-1)*AQDB_COLUMN_OBJECT_SIZE);
|
|
rv=AQDB_DbDir_TableWriteObjectAt(table,
|
|
filePos,
|
|
id,
|
|
AQDB_COLUMN_OBJECT_SIZE,
|
|
AQDB_COLUMN_FIELD_COUNT,
|
|
o,
|
|
AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_Object_free(o);
|
|
return rv;
|
|
}
|
|
AQDB_Object_free(o);
|
|
|
|
id++;
|
|
col=AQDB_Column_List_Next(col);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_ReadColumns(AQDB_DBDIR_TABLE *table) {
|
|
int i;
|
|
|
|
for (i=0; i<table->objectColumns; i++) {
|
|
int rv;
|
|
AQDB_OBJECT *o=NULL;
|
|
AQDB_COLUMN *col=NULL;
|
|
AQDB_ID id=i+1;
|
|
uint64_t filePos;
|
|
|
|
filePos=table->typesOffset+((id-1)*AQDB_COLUMN_OBJECT_SIZE);
|
|
rv=AQDB_DbDir_TableReadObjectAt(table,
|
|
filePos,
|
|
id,
|
|
AQDB_COLUMN_OBJECT_SIZE,
|
|
AQDB_COLUMN_FIELD_COUNT,
|
|
&o);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
rv=AQDB_DbDir_Table_ColumnFromObject(table, o, &col);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_Object_free(o);
|
|
return rv;
|
|
}
|
|
|
|
AQDB_Column_List_Add(col, table->columnList);
|
|
AQDB_Object_free(o);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableOpen(AQDB_DBDIR_TABLE *table,
|
|
uint32_t flags) {
|
|
if (table->openFlags) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table already open");
|
|
return GWEN_ERROR_OPEN;
|
|
}
|
|
else {
|
|
int rv;
|
|
struct stat st;
|
|
|
|
/* check whether file exists */
|
|
rv=stat(table->dataFileName, &st);
|
|
if (rv<0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error opening file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
table->openFlags=0;
|
|
return GWEN_ERROR_NOT_FOUND;
|
|
}
|
|
|
|
flags&=~AQDB_ACTION_FLAGS_CREATE;
|
|
|
|
AQDB_Column_List_Clear(table->columnList);
|
|
table->openFlags=flags;
|
|
table->lastId=0;
|
|
|
|
rv=AQDB_DbDir_Table_open(table, (flags & AQDB_ACTION_FLAGS_WRITE)?1:0);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
table->openFlags=0;
|
|
return rv;
|
|
}
|
|
|
|
rv=AQDB_DbDir_Table_ReadHeader(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_DbDir_Table_close(table);
|
|
table->openFlags=0;
|
|
return rv;
|
|
}
|
|
|
|
rv=AQDB_DbDir_Table_ReadColumns(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_DbDir_Table_close(table);
|
|
table->openFlags=0;
|
|
return rv;
|
|
}
|
|
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH) {
|
|
GWEN_IDLIST64 *poslist;
|
|
|
|
/* this table uses variable object length, scan positions */
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Scanning object positions");
|
|
poslist=GWEN_IdList64_new();
|
|
rv=AQDB_DbDir__TableScanObjects(table, poslist);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_IdList64_free(poslist);
|
|
AQDB_DbDir_Table_close(table);
|
|
table->openFlags=0;
|
|
return rv;
|
|
}
|
|
GWEN_IdList64_free(table->objectPositions);
|
|
table->objectPositions=poslist;
|
|
}
|
|
|
|
table->openFlags=flags;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableCreate(AQDB_DBDIR_TABLE *table,
|
|
uint32_t flags,
|
|
const AQDB_COLUMN_LIST *columns) {
|
|
AQDB_COLUMN *col;
|
|
int maxLen=0;
|
|
int rv;
|
|
|
|
assert(table);
|
|
AQDB_Column_List_free(table->columnList);
|
|
table->columnList=AQDB_Column_List_dup(columns);
|
|
table->openFlags=flags;
|
|
table->flags=flags & ~AQDB_ACTION_FLAGS_MASK;
|
|
table->lastId=0;
|
|
|
|
table->objectColumns=AQDB_Column_List_GetCount(table->columnList);
|
|
|
|
/* get max object size */
|
|
col=AQDB_Column_List_First(table->columnList);
|
|
while(col) {
|
|
maxLen+=AQDB_Column_GetMaxLen(col)+AQDB_DBDIR_TABLE_COLUMN_HEADER_SIZE;
|
|
col=AQDB_Column_List_Next(col);
|
|
}
|
|
|
|
/* add header length to object size */
|
|
maxLen+=AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE;
|
|
|
|
/* align to 16 bytes */
|
|
maxLen+=15;
|
|
maxLen&=~15;
|
|
|
|
table->objectSize=maxLen;
|
|
|
|
/* set type offset */
|
|
table->typesOffset=AQDB_DBDIR_TABLE_HEADER_SIZE;
|
|
|
|
/* set data offset */
|
|
table->dataOffset=table->typesOffset+(table->objectColumns*AQDB_COLUMN_OBJECT_SIZE);
|
|
/* align to 256 */
|
|
table->dataOffset+=255;
|
|
table->dataOffset&=~255;
|
|
|
|
/* set version */
|
|
table->vMajor=AQDB_DBDIR_TABLE_VERSION_MAJOR;
|
|
table->vMinor=AQDB_DBDIR_TABLE_VERSION_MINOR;
|
|
table->vMicro=AQDB_DBDIR_TABLE_VERSION_MICRO;
|
|
|
|
rv=AQDB_DbDir_Table_creat(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
table->openFlags=0;
|
|
return rv;
|
|
}
|
|
|
|
/* write header */
|
|
rv=AQDB_DbDir_Table_WriteHeader(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_DbDir_Table_close(table);
|
|
unlink(table->dataFileName);
|
|
table->openFlags=0;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* write columns */
|
|
rv=AQDB_DbDir_Table_WriteColumns(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_DbDir_Table_close(table);
|
|
unlink(table->dataFileName);
|
|
table->openFlags=0;
|
|
return rv;
|
|
}
|
|
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH)
|
|
table->objectPositions=GWEN_IdList64_new();
|
|
|
|
/* done */
|
|
table->openFlags=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableClose(AQDB_DBDIR_TABLE *table,
|
|
uint32_t flags) {
|
|
int rv;
|
|
|
|
/* write header if in write mode */
|
|
if (table->openFlags & AQDB_ACTION_FLAGS_WRITE) {
|
|
rv=AQDB_DbDir_Table_WriteHeader(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
AQDB_DbDir_Table_close(table);
|
|
table->openFlags=0;
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
if (AQDB_DbDir_Table_close(table)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error closing file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
table->openFlags=0;
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
table->openFlags=0;
|
|
#ifdef OS_WIN32
|
|
table->fh=NULL;
|
|
#else
|
|
table->fd=-1;
|
|
#endif
|
|
GWEN_IdList64_free(table->objectPositions);
|
|
table->objectPositions=NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableReset(AQDB_DBDIR_TABLE *table) {
|
|
int rv;
|
|
|
|
if (!(table->openFlags & AQDB_ACTION_FLAGS_WRITE)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table not in write mode");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
|
|
/* reset */
|
|
table->lastId=0;
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH) {
|
|
GWEN_IdList64_free(table->objectPositions);
|
|
table->objectPositions=GWEN_IdList64_new();
|
|
table->fileSize=table->dataOffset;
|
|
}
|
|
|
|
rv=AQDB_DbDir_Table_WriteHeader(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableDelete(AQDB_DBDIR_TABLE *table) {
|
|
if (table->openFlags) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table still open");
|
|
return GWEN_ERROR_OPEN;
|
|
}
|
|
else {
|
|
int rv;
|
|
struct stat st;
|
|
|
|
/* check whether file exists */
|
|
rv=stat(table->dataFileName, &st);
|
|
if (rv<0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Table not found [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_NOT_FOUND;
|
|
}
|
|
|
|
if (unlink(table->dataFileName)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error deleting file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableReadObject(AQDB_DBDIR_TABLE *table,
|
|
AQDB_ID objectId,
|
|
AQDB_OBJECT **pObject) {
|
|
assert(table);
|
|
if (!(table->openFlags & AQDB_ACTION_FLAGS_READ)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table not open for reading");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
else {
|
|
if (objectId==0 || objectId>table->lastId) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Object id in table [%s] is invalid (%d>%d)",
|
|
table->name, objectId, table->lastId);
|
|
abort();
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
else {
|
|
int rv;
|
|
AQDB_OBJECT *o=NULL;
|
|
|
|
if (table->tableId!=AQDB_DB_DIR_TID_SESSIONLOG &&
|
|
table->tableId!=AQDB_DB_DIR_TID_ROLLBACKLOG)
|
|
rv=AQDB_DB_CacheGetObject(table->db, table->tableId, objectId, &o);
|
|
else
|
|
rv=GWEN_ERROR_NOT_FOUND;
|
|
|
|
if (rv<0) {
|
|
if (rv==GWEN_ERROR_NOT_FOUND) {
|
|
uint64_t filePos;
|
|
|
|
/* not in cache, read from disk */
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH)
|
|
filePos=GWEN_IdList64_GetIdAt(table->objectPositions, objectId-1);
|
|
else
|
|
filePos=table->dataOffset+((objectId-1)*table->objectSize);
|
|
|
|
rv=AQDB_DbDir_TableReadObjectAt(table,
|
|
filePos,
|
|
objectId,
|
|
table->objectSize,
|
|
table->objectColumns,
|
|
&o);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
if (table->tableId!=AQDB_DB_DIR_TID_SESSIONLOG &&
|
|
table->tableId!=AQDB_DB_DIR_TID_ROLLBACKLOG) {
|
|
/* store in cache */
|
|
rv=AQDB_DB_CacheSetObject(table->db, o, table->objectSize);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
*pObject=o;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableWriteObject(AQDB_DBDIR_TABLE *table,
|
|
const AQDB_OBJECT *object) {
|
|
if (!(table->openFlags & AQDB_ACTION_FLAGS_WRITE)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table not open for writing");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
else {
|
|
if (AQDB_Object_GetObjectId(object)==0 ||
|
|
AQDB_Object_GetObjectId(object)>table->lastId) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Object id in table [%s] is invalid (%d>%d)",
|
|
table->name, AQDB_Object_GetObjectId(object), table->lastId);
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
else {
|
|
int rv;
|
|
AQDB_ID objectId;
|
|
uint64_t filePos;
|
|
|
|
objectId=AQDB_Object_GetObjectId(object);
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH) {
|
|
/*filePos=GWEN_IdList64_GetIdAt(table->objectPositions, objectId-1);*/
|
|
|
|
/* TODO: check for same size, for now just reject this request */
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Writing of objects with variable size not allowed for now");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
else
|
|
filePos=table->dataOffset+((objectId-1)*table->objectSize);
|
|
|
|
rv=AQDB_DbDir_TableWriteObjectAt(table,
|
|
filePos,
|
|
objectId,
|
|
table->objectSize,
|
|
table->objectColumns,
|
|
object,
|
|
AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
table->modified=1;
|
|
|
|
if (table->tableId!=AQDB_DB_DIR_TID_SESSIONLOG &&
|
|
table->tableId!=AQDB_DB_DIR_TID_ROLLBACKLOG) {
|
|
/* remove from cache */
|
|
AQDB_DB_CachePurgeObject(table->db, table->tableId, objectId);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableDeleteObject(AQDB_DBDIR_TABLE *table,
|
|
AQDB_ID objectId) {
|
|
if (!(table->openFlags & AQDB_ACTION_FLAGS_WRITE)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table not open for writing");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
else {
|
|
uint8_t oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE];
|
|
uint32_t v32;
|
|
uint64_t filePos;
|
|
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH)
|
|
filePos=GWEN_IdList64_GetIdAt(table->objectPositions, objectId-1);
|
|
else
|
|
filePos=table->dataOffset+((objectId-1)*table->objectSize);
|
|
|
|
if (AQDB_DbDir_Table_seek(table, filePos)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking position %llu on file [%s]: %s",
|
|
(long long int)filePos,
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* read object header */
|
|
if (1!=AQDB_DbDir_Table_read(table, oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error reading from file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
v32=((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS]);
|
|
if (v32!=AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Object [%lx] is not active (%08x)",
|
|
(unsigned long)objectId, v32);
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
/* change status (only status!) */
|
|
v32=AQDB_DBDIR_TABLE_OBJECT_STATUS_DELETED;
|
|
oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS]=v32 & 0xff;
|
|
|
|
/* seek */
|
|
if (AQDB_DbDir_Table_seek(table, filePos)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking position %llu on file [%s]: %s",
|
|
(long long int)filePos,
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* write object header */
|
|
if (1!=AQDB_DbDir_Table_write(table, oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error writing to file [%s]: %s",
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
if ((table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH)) {
|
|
if (objectId==table->lastId) {
|
|
GWEN_IdList64_DelId(table->objectPositions, filePos);
|
|
table->lastId--;
|
|
table->fileSize=filePos;
|
|
}
|
|
}
|
|
|
|
table->modified=1;
|
|
|
|
if (table->tableId!=AQDB_DB_DIR_TID_SESSIONLOG &&
|
|
table->tableId!=AQDB_DB_DIR_TID_ROLLBACKLOG) {
|
|
/* remove from cache */
|
|
AQDB_DB_CachePurgeObject(table->db, table->tableId, objectId);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableAddObject(AQDB_DBDIR_TABLE *table,
|
|
AQDB_OBJECT *object) {
|
|
if (!(table->openFlags & AQDB_ACTION_FLAGS_WRITE)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table not open for writing");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
else {
|
|
int rv;
|
|
AQDB_ID id;
|
|
|
|
id=++(table->lastId);
|
|
if (id>=table->maxObjects)
|
|
table->maxObjects=id+1;
|
|
table->modified=1;
|
|
AQDB_Object_SetObjectId(object, id);
|
|
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH) {
|
|
uint64_t filePos;
|
|
|
|
filePos=table->fileSize;
|
|
|
|
#if 0
|
|
DBG_ERROR(0, "Writing object at %lu (%lu bytes)",
|
|
(unsigned long int) filePos,
|
|
(unsigned long int) GWEN_Buffer_GetUsedBytes(AQDB_Object_GetBuffer(object)));
|
|
#endif
|
|
|
|
rv=AQDB_DbDir_TableWriteObjectAt(table,
|
|
filePos,
|
|
id,
|
|
table->objectSize,
|
|
table->objectColumns,
|
|
object,
|
|
AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
/* add pointer, adjust filesize */
|
|
#if 0
|
|
DBG_ERROR(0, "Adding variable object %lu at %lu in %s",
|
|
(unsigned long int) id,
|
|
(unsigned long int) filePos,
|
|
table->dataFileName);
|
|
#endif
|
|
GWEN_IdList64_AppendId(table->objectPositions, filePos);
|
|
table->fileSize+=rv+AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE;
|
|
}
|
|
else {
|
|
uint64_t filePos;
|
|
|
|
filePos=table->dataOffset+((id-1)*table->objectSize);
|
|
|
|
rv=AQDB_DbDir_TableWriteObjectAt(table,
|
|
filePos,
|
|
id,
|
|
table->objectSize,
|
|
table->objectColumns,
|
|
object,
|
|
AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
/* update number of objects */
|
|
if (id>=table->maxObjects)
|
|
table->maxObjects=id+1;
|
|
|
|
rv=AQDB_DbDir_Table_WriteHeader(table);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableReserveObject(AQDB_DBDIR_TABLE *table, AQDB_OBJECT *object) {
|
|
if (!(table->openFlags & AQDB_ACTION_FLAGS_WRITE)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN, "Table not open for writing");
|
|
return GWEN_ERROR_NOT_OPEN;
|
|
}
|
|
else {
|
|
int rv;
|
|
AQDB_ID id;
|
|
|
|
id=++(table->lastId);
|
|
if (id>=table->maxObjects)
|
|
table->maxObjects=id+1;
|
|
table->modified=1;
|
|
AQDB_Object_SetObjectId(object, id);
|
|
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH) {
|
|
uint64_t filePos;
|
|
|
|
filePos=table->fileSize;
|
|
|
|
rv=AQDB_DbDir_TableWriteObjectAt(table,
|
|
filePos,
|
|
id,
|
|
table->objectSize,
|
|
table->objectColumns,
|
|
object,
|
|
/* write as "unused"; this status will be overwritten
|
|
* when writing the new object */
|
|
AQDB_DBDIR_TABLE_OBJECT_STATUS_UNUSED);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
/* add pointer, adjust filesize */
|
|
#if 0
|
|
DBG_ERROR(0, "Adding variable object %lu at %lu in %s",
|
|
(unsigned long int) id,
|
|
(unsigned long int) filePos,
|
|
table->dataFileName);
|
|
#endif
|
|
GWEN_IdList64_AppendId(table->objectPositions, filePos);
|
|
table->fileSize+=rv+AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE;
|
|
}
|
|
else {
|
|
uint64_t filePos;
|
|
|
|
filePos=table->dataOffset+((id-1)*table->objectSize);
|
|
|
|
rv=AQDB_DbDir_TableWriteObjectAt(table,
|
|
filePos,
|
|
id,
|
|
table->objectSize,
|
|
table->objectColumns,
|
|
object,
|
|
/* write as "unused"; this status will be overwritten
|
|
* when writing the new object */
|
|
AQDB_DBDIR_TABLE_OBJECT_STATUS_UNUSED);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir__TableListObjects(AQDB_DBDIR_TABLE *table, GWEN_IDLIST64 *idList) {
|
|
int64_t i;
|
|
uint64_t filePos;
|
|
|
|
filePos=table->dataOffset;
|
|
for (i=0; i<table->lastId; i++) {
|
|
uint8_t oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS_SIZE];
|
|
uint32_t v32;
|
|
|
|
if (AQDB_DbDir_Table_seek(table, filePos)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking position %llu on file [%s]: %s",
|
|
(long long int)filePos,
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* read object status */
|
|
if (1!=AQDB_DbDir_Table_read(table, oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error reading object %lu from file [%s] at %llu: %s",
|
|
(unsigned long int) i,
|
|
table->dataFileName,
|
|
(long long int)filePos,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
v32=((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS]);
|
|
if (v32==AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE) {
|
|
GWEN_IdList64_AppendId(idList, (i+1));
|
|
}
|
|
filePos+=table->objectSize;
|
|
}
|
|
|
|
if (AQDB_DbDir_IsInEditMode(table->db)) {
|
|
/* DBG_ERROR(0, "Adjusting id list"); */
|
|
AQDB_DbDir_AdjustIdList(table->db, table->tableId, idList);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir__TableListObjectsV(AQDB_DBDIR_TABLE *table, GWEN_IDLIST64 *idList) {
|
|
int64_t i;
|
|
|
|
for (i=0; i<table->lastId; i++) {
|
|
uint8_t oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS_SIZE];
|
|
uint32_t v32;
|
|
uint64_t filePos;
|
|
|
|
filePos=GWEN_IdList64_GetIdAt(table->objectPositions, i);
|
|
if (filePos==0) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"No position for object %lu in file [%s] (max id=%lu)",
|
|
(unsigned long int) i,
|
|
table->dataFileName,
|
|
(unsigned long int) (table->lastId));
|
|
return GWEN_ERROR_GENERIC;
|
|
}
|
|
|
|
if (AQDB_DbDir_Table_seek(table, filePos)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking position %llu on file [%s]: %s",
|
|
(long long int)filePos,
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* read object status */
|
|
if (1!=AQDB_DbDir_Table_read(table, oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error reading object %lu from file [%s] at %llu: %s",
|
|
(unsigned long int) i,
|
|
table->dataFileName,
|
|
(long long int)filePos,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
v32=((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_STATUS]);
|
|
if (v32==AQDB_DBDIR_TABLE_OBJECT_STATUS_ACTIVE)
|
|
GWEN_IdList64_AppendId(idList, (i+1));
|
|
}
|
|
|
|
if (AQDB_DbDir_IsInEditMode(table->db)) {
|
|
/* DBG_ERROR(0, "Adjusting id list"); */
|
|
AQDB_DbDir_AdjustIdList(table->db, table->tableId, idList);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir__TableScanObjects(AQDB_DBDIR_TABLE *table, GWEN_IDLIST64 *posList) {
|
|
int64_t i;
|
|
uint64_t filePos;
|
|
|
|
filePos=table->dataOffset;
|
|
for (i=0; i<table->lastId; i++) {
|
|
uint8_t oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE];
|
|
uint32_t v32;
|
|
|
|
if (AQDB_DbDir_Table_seek(table, filePos)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error seeking position %llu on file [%s]: %s",
|
|
(long long int)filePos,
|
|
table->dataFileName,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/* read object status */
|
|
if (1!=AQDB_DbDir_Table_read(table, oheader, AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE, 1)) {
|
|
DBG_ERROR(AQDB_LOGDOMAIN,
|
|
"Error reading from file [%s] at %lu (%lu): %s",
|
|
table->dataFileName,
|
|
(unsigned long int) filePos,
|
|
(unsigned long int) i,
|
|
strerror(errno));
|
|
return GWEN_ERROR_IO;
|
|
}
|
|
|
|
/*
|
|
DBG_ERROR(0,
|
|
"Adding position from file [%s] at %lu (%lu)",
|
|
table->dataFileName,
|
|
(unsigned long int) filePos,
|
|
(unsigned long int) i);
|
|
*/
|
|
GWEN_IdList64_AppendId(posList, filePos);
|
|
|
|
/* advance */
|
|
v32=
|
|
(((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+0])<<24)+
|
|
(((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+1])<<16)+
|
|
(((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+2])<<8)+
|
|
((uint32_t)oheader[AQDB_DBDIR_TABLE_OBJECT_HEADER_LENGTH+3]);
|
|
|
|
filePos+=v32+AQDB_DBDIR_TABLE_OBJECT_HEADER_SIZE;
|
|
}
|
|
|
|
/* store filesize */
|
|
table->fileSize=filePos;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableQuerySubmit(AQDB_DBDIR_TABLE *table,
|
|
AQDB_ID refQueryId,
|
|
const char *queryExpression,
|
|
uint32_t flags,
|
|
AQDB_ID *pQueryId) {
|
|
QUERY *q;
|
|
int rv;
|
|
int i;
|
|
GWEN_IDLIST64 *idl;
|
|
GWEN_IDLIST64_ITERATOR *it;
|
|
uint64_t id;
|
|
AQDB_QUERY *dbq=NULL;
|
|
|
|
/* check reference query */
|
|
if (refQueryId) {
|
|
if (refQueryId>AQDB_DBDIR_MAX_QUERY) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Invalid query reference");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
if (table->queryList[refQueryId-1]==NULL) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Reference query not in use");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
}
|
|
|
|
if (queryExpression) {
|
|
/* parse expression */
|
|
dbq=ObjectQuery_new(queryExpression, table);
|
|
if (dbq==NULL) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "No query generated");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
}
|
|
|
|
/* find free query position */
|
|
for (i=0; i<AQDB_DBDIR_MAX_QUERY; i++) {
|
|
if (table->queryList[i]==NULL)
|
|
break;
|
|
}
|
|
if (i>=AQDB_DBDIR_MAX_QUERY) {
|
|
/* all positions used */
|
|
DBG_INFO(AQDB_LOGDOMAIN, "All queries in use");
|
|
AQDB_Query_free(dbq);
|
|
return GWEN_ERROR_TRY_AGAIN;
|
|
}
|
|
|
|
if (dbq==NULL && refQueryId==0) {
|
|
/* no expression given, just sample all currently available ids */
|
|
q=Query_new(i+1, table);
|
|
assert(q);
|
|
table->queryList[i]=q;
|
|
|
|
idl=Query_GetIdList(q);
|
|
assert(idl);
|
|
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH)
|
|
rv=AQDB_DbDir__TableListObjectsV(table, idl);
|
|
else
|
|
rv=AQDB_DbDir__TableListObjects(table, idl);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
table->queryList[i]=NULL;
|
|
Query_free(q);
|
|
AQDB_Query_free(dbq);
|
|
return rv;
|
|
}
|
|
}
|
|
else {
|
|
/* get data base */
|
|
if (refQueryId) {
|
|
/* referenced another query, use the data from there */
|
|
idl=Query_GetIdList(table->queryList[refQueryId-1]);
|
|
assert(idl);
|
|
GWEN_IdList64_Attach(idl);
|
|
}
|
|
else {
|
|
idl=GWEN_IdList64_new();
|
|
if (table->flags & AQDB_DBDIR_TABLE_FLAGS_VARIABLE_LENGTH)
|
|
rv=AQDB_DbDir__TableListObjectsV(table, idl);
|
|
else
|
|
rv=AQDB_DbDir__TableListObjects(table, idl);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
GWEN_IdList64_free(idl);
|
|
AQDB_Query_free(dbq);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
/* create query, store it */
|
|
q=Query_new(i+1, table);
|
|
assert(q);
|
|
table->queryList[i]=q;
|
|
|
|
if (dbq) {
|
|
/* scan for matching objects */
|
|
it=GWEN_IdList64_Iterator_new(idl);
|
|
id=GWEN_IdList64_Iterator_GetFirstId(it);
|
|
while(id) {
|
|
AQDB_OBJECT *o=NULL;
|
|
|
|
if (AQDB_DbDir_IsInEditMode(table->db) &&
|
|
!(AQDB_DbDir_GetSessionFlags(table->db) & AQDB_DB_DIR_SESSION_FLAGS_ROLLBACK)) {
|
|
rv=AQDB_DbDir_ReadObjectFromSessionLog(table->db, table->tableId, id, &o);
|
|
if (rv==GWEN_ERROR_NO_DATA)
|
|
rv=AQDB_DbDir_TableReadObject(table, id, &o);
|
|
}
|
|
else {
|
|
rv=AQDB_DbDir_TableReadObject(table, id, &o);
|
|
}
|
|
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
}
|
|
else {
|
|
rv=ObjectQuery_Check(dbq, o);
|
|
AQDB_Object_free(o);
|
|
if (rv) {
|
|
#if 0
|
|
DBG_ERROR(0, "Entry matches for query %08x [%s] (ref: %08x)", i+1,
|
|
queryExpression, refQueryId);
|
|
#endif
|
|
Query_AddId(q, id);
|
|
if (flags & AQDB_QUERY_FLAGS_STOPATFIRST)
|
|
break;
|
|
}
|
|
#if 0
|
|
else {
|
|
DBG_ERROR(0, "Entry %d does not match for query %08x [%s] (ref: %08x)",
|
|
(int) id,
|
|
i+1,
|
|
queryExpression, refQueryId);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
id=GWEN_IdList64_Iterator_GetNextId(it);
|
|
}
|
|
GWEN_IdList64_Iterator_free(it);
|
|
GWEN_IdList64_free(idl);
|
|
}
|
|
else {
|
|
/* scan for matching objects */
|
|
it=GWEN_IdList64_Iterator_new(idl);
|
|
id=GWEN_IdList64_Iterator_GetFirstId(it);
|
|
while(id) {
|
|
Query_AddId(q, id);
|
|
if (flags & AQDB_QUERY_FLAGS_STOPATFIRST)
|
|
break;
|
|
|
|
id=GWEN_IdList64_Iterator_GetNextId(it);
|
|
}
|
|
GWEN_IdList64_Iterator_free(it);
|
|
GWEN_IdList64_free(idl);
|
|
}
|
|
|
|
/* cleanup */
|
|
AQDB_Query_free(dbq);
|
|
}
|
|
|
|
*pQueryId=i+1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableQueryGetFirst(AQDB_DBDIR_TABLE *table,
|
|
AQDB_ID queryId,
|
|
AQDB_ID *pIdListPtr,
|
|
int *pIdListLen) {
|
|
int rv;
|
|
|
|
if (queryId==0 || queryId>AQDB_DBDIR_MAX_QUERY) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Invalid query id %d", queryId);
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
if (table->queryList[queryId-1]==NULL) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Query not in use");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
rv=Query_GetFirstIds(table->queryList[queryId-1],
|
|
pIdListPtr,
|
|
pIdListLen);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Error getting first ids for table [%s] (%d)",
|
|
table->dataFileName, rv);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableQueryGetNext(AQDB_DBDIR_TABLE *table,
|
|
AQDB_ID queryId,
|
|
AQDB_ID *pIdListPtr,
|
|
int *pIdListLen) {
|
|
int rv;
|
|
|
|
if (queryId==0 || queryId>AQDB_DBDIR_MAX_QUERY) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Invalid query id %08x", queryId);
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
if (table->queryList[queryId-1]==NULL) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Query not in use");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
rv=Query_GetNextIds(table->queryList[queryId-1],
|
|
pIdListPtr,
|
|
pIdListLen);
|
|
if (rv<0) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableQueryClose(AQDB_DBDIR_TABLE *table, AQDB_ID queryId) {
|
|
QUERY *q;
|
|
|
|
if (queryId==0 || queryId>AQDB_DBDIR_MAX_QUERY) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Invalid query id %d", queryId);
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
if (table->queryList[queryId-1]==NULL) {
|
|
DBG_INFO(AQDB_LOGDOMAIN, "Query not in use");
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
q=table->queryList[queryId-1];
|
|
table->queryList[queryId-1]=NULL;
|
|
Query_free(q);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
AQDB_COLUMN_LIST *AQDB_DbDir_TableGetColumnList(const AQDB_DBDIR_TABLE *table) {
|
|
return table->columnList;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_TableGetColumnCount(const AQDB_DBDIR_TABLE *table) {
|
|
return AQDB_Column_List_GetCount(table->columnList);
|
|
}
|
|
|
|
|
|
|
|
AQDB_COLUMN *AQDB_DbDir_TableGetColumnByName(const AQDB_DBDIR_TABLE *table,
|
|
const char *name,
|
|
int *pIdx){
|
|
AQDB_COLUMN *col;
|
|
int idx=0;
|
|
|
|
col=AQDB_Column_List_First(table->columnList);
|
|
while(col) {
|
|
if (strcasecmp(AQDB_Column_GetName(col), name)==0) {
|
|
if (pIdx)
|
|
*pIdx=idx;
|
|
return col;
|
|
}
|
|
idx++;
|
|
col=AQDB_Column_List_Next(col);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
AQDB_COLUMN *AQDB_DbDir_TableGetColumnByIndex(const AQDB_DBDIR_TABLE *table, int idx){
|
|
AQDB_COLUMN *col;
|
|
|
|
col=AQDB_Column_List_First(table->columnList);
|
|
while(col) {
|
|
if (idx==0)
|
|
return col;
|
|
idx--;
|
|
col=AQDB_Column_List_Next(col);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_Flush(AQDB_DBDIR_TABLE *table) {
|
|
return AQDB_DbDir_Table_WriteHeader(table);
|
|
}
|
|
|
|
|
|
|
|
|
|
void AQDB_DbDir_Table_EditObjectAdded(AQDB_DBDIR_TABLE *table, AQDB_ID id) {
|
|
assert(table);
|
|
assert(id);
|
|
if (table->editObjectsAdded==NULL)
|
|
table->editObjectsAdded=GWEN_IdList64_new();
|
|
GWEN_IdList64_AppendId(table->editObjectsAdded, id);
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_EditIsObjectAdded(AQDB_DBDIR_TABLE *table, AQDB_ID id) {
|
|
assert(table);
|
|
if (table->editObjectsAdded==NULL)
|
|
return 0;
|
|
else
|
|
return GWEN_IdList64_HasId(table->editObjectsAdded, id);
|
|
}
|
|
|
|
|
|
|
|
void AQDB_DbDir_Table_EditObjectDeleted(AQDB_DBDIR_TABLE *table, AQDB_ID id) {
|
|
assert(table);
|
|
assert(id);
|
|
if (table->editObjectsDeleted==NULL)
|
|
table->editObjectsDeleted=GWEN_IdList64_new();
|
|
GWEN_IdList64_AppendId(table->editObjectsDeleted, id);
|
|
}
|
|
|
|
|
|
|
|
int AQDB_DbDir_Table_EditIsObjectDeleted(AQDB_DBDIR_TABLE *table, AQDB_ID id) {
|
|
assert(table);
|
|
if (table->editObjectsDeleted==NULL)
|
|
return 0;
|
|
else
|
|
return GWEN_IdList64_HasId(table->editObjectsDeleted, id);
|
|
}
|
|
|
|
|
|
|
|
void AQDB_DbDir_Table_EditEnd(AQDB_DBDIR_TABLE *table) {
|
|
assert(table);
|
|
if (table->editObjectsAdded)
|
|
GWEN_IdList64_Clear(table->editObjectsAdded);
|
|
if (table->editObjectsDeleted)
|
|
GWEN_IdList64_Clear(table->editObjectsDeleted);
|
|
|
|
AQDB_DbDir_ObjectDescr_IdMap_Clear(table->sessionObjectMap);
|
|
AQDB_DbDir_ObjectDescr_List_Clear(table->sessionObjectList);
|
|
}
|
|
|
|
|
|
|
|
void AQDB_DbDir_Table_AddSessionObjectDescr(AQDB_DBDIR_TABLE *table, AQDB_DBDIR_OBJDESCR *od) {
|
|
AQDB_DBDIR_OBJDESCR *oldOd;
|
|
AQDB_ID objId;
|
|
|
|
assert(table);
|
|
|
|
/* remove previous object from list */
|
|
objId=AQDB_DbDir_ObjectDescr_GetObjectId(od);
|
|
oldOd=AQDB_DbDir_ObjectDescr_IdMap_Find(table->sessionObjectMap, objId);
|
|
if (oldOd) {
|
|
AQDB_DbDir_ObjectDescr_List_Del(oldOd);
|
|
AQDB_DbDir_ObjectDescr_free(oldOd);
|
|
}
|
|
|
|
/* add new entry */
|
|
AQDB_DbDir_ObjectDescr_List_Add(od, table->sessionObjectList);
|
|
AQDB_DbDir_ObjectDescr_IdMap_Insert(table->sessionObjectMap, objId, od);
|
|
}
|
|
|
|
|
|
|
|
AQDB_ID AQDB_DbDir_Table_GetSessionObjectId(const AQDB_DBDIR_TABLE *table, AQDB_ID objId) {
|
|
AQDB_DBDIR_OBJDESCR *od;
|
|
|
|
od=AQDB_DbDir_ObjectDescr_IdMap_Find(table->sessionObjectMap, objId);
|
|
if (od)
|
|
return AQDB_DbDir_ObjectDescr_GetSessionLogId(od);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
AQDB_DBDIR_OBJDESCR_LIST *AQDB_DbDir_Table_GetSessionObjectList(const AQDB_DBDIR_TABLE *table) {
|
|
assert(table);
|
|
return table->sessionObjectList;
|
|
}
|
|
|
|
|
|
|
|
|
|
|