Projekt

Allgemein

Profil

Herunterladen (55,2 KB) Statistiken
| Zweig: | Markierung: | Revision:
/****************************************************************************
* 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;
}





(16-16/18)