📄 dbobject.c
字号:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <glib.h>#include "db.h"#include "dbobject.h"#include "debug.h"#include "dbwrapper.h"#include "dbgather.h"#include "dbconstraint.h"#include "dbmapme.h"#include "dbsqlparse.h"#include "dbobjectvalid.h"#include "dbbureaucrat.h"#include "dbtoliet.h"#include "dbuniqueid.h"#include "dbobjectnav.h"#include "dbfield.h"#include "dbbirth.h"#include "dbcache.h"/* Not part of hte main db_API. But a side function If a record is new, and hasn't been in database then this function will go and blonk it into the database *//* Write ahead cache flush out all writes to db and free cache. This function has been re-written way to much and is such a fundemental one to the whole project. Recode with caution, many a dead programme scatter this lines of code.... . *//** * db_obj_addwrite: * @obj: database object * @field: fieldname to write to * @value: value to write to that field * @mark: whether or not to leave a mark on the object that you wrote. Set to TRUE normally. * * For the given @obj add a write to the @field at the current row the object is on. The record * must have a table name supplied to it on creation in order to write back. This is a low level * function, you should generally use db_setvalue(). Also note this wont write back straight away but * at some time when it thinks it appropriate. The @mark is for things like default values where you * want to save a value but you want to wait till you get some real data before writing back and this is just * one of those optional extra values to have. * * Returns: non-zero on failure. */gintdb_obj_addwrite(Object * obj, gchar * field, gchar * table, gchar * value, gboolean mark) { DbCache *cache; g_assert(obj); g_assert(field); if (value != NULL && strlen(value) == 0) value = NULL; /* debugmsg("Write to cache of %s.%s of value %s", obj->name, field, value); */ cache = db_cache_isincache(obj); if (cache == NULL) { /* This is the first write to this object so create a cache for it. */ cache = db_cache_moveto(obj); /* m.essage("%s.%s: Adding writeid of %d",obj->name,field,obj->id->pg_oid); */ /* State the object is new, or edited or whatever */ if (db_id_isnewrecord(obj->id) == TRUE) cache->state = OBJ_NEW; else cache->state = OBJ_EDITREAD; } /* hmm mark. If its set to mark it then mark it. */ if (mark == TRUE) { /* record that you did some write... so if you have an object previously in cache you dump it. */ db_bureaucrat_recordwrite(obj->objectinstance); /* debugmsg("Marking object %s with a write", obj->name); */ obj->changed = TRUE; cache->changed = TRUE; } /* now we actually going to do it.. */ db_cache_setvalue(obj, cache, field, table, value); return 0; }/** * db_obj_doread: * @obj: Database object * @field: name of field to read * @value: value to return * * This shoulnd't be called directly, but what it does is check to see if a value is in cache, * and when and if its not then it will read it from the database. This is done on your currently * selected row in the database, use db_moveto() to navigate the recordset. Don't free @value when * your done. * * Returns: non-zero on failure */gintdb_obj_doread(Object * obj, gchar * field, gchar * table, gchar ** value) { gint retval, fieldpos; DbCache *cache; DbField *fielddef; g_assert(obj); g_assert(field); *value = NULL; /* check cache */ cache = db_cache_isincache(obj); /* db_obj_debug(obj); */ /* check if we have the record cached */ if (cache != NULL) { /* m.essage("checking in cache. hmm. row is %d, orig row is %d", obj->row, cache->origrow); */ /* Read the item from the cache */ retval = db_cache_getvalue(obj, cache, field, table, value); /* m.essage("returning value. hmm. %d, %s", retval, *value); */ if (*value == NULL) { /* If the record is in fact blank, return that as the value */ if (cache->state == OBJ_NEW || cache->state == OBJ_EDITNEW) return retval; /* Continue on with reading from the record set to load the cache */ } else { /* Its a function, run the function to get the value */ if (strcmp(*value, "EXECFUNCTION") == 0) { debugmsg("This is a default value field (%s) you are getting the value from", field); fielddef = db_field_dbfind(obj, field, table); if (fielddef->fielddef->defaultvalue != NULL) { *value = db_default_execfunction(fielddef->fielddef->defaultvalue); db_cache_setvalue(obj, cache, field, table, *value); mem_free(*value); db_cache_getvalue(obj, cache, field, table, value); } debugmsg("returning %s for default value", *value); } return retval; } } /* no data in there */ if (db_isnewrecord(obj) == TRUE) { *value = NULL; return 1; } /* do a normal read */ retval = db_field_read(obj, field, table, value); /* m.essage("read %s from %s.%s",value,table,field); */ /* if your in a filtered object, then save everything you read to cache */ if (cache == NULL && obj->filtered == TRUE) cache = db_cache_moveto(obj); if (cache != NULL) { /* assumes the state is defaulted to a OBJ_NEW */ if (cache->state == OBJ_NEW) cache->state = OBJ_READ; if (obj->filtered == TRUE) if ((fieldpos = db_cache_setvalue(obj, cache, field, table, *value)) >= 0) * value = cache->value[fieldpos]; } return retval; }/** * db_obj_sqlread: * * Awaiting documentation patrol. * * Returns: Salvation */gintdb_obj_sqlread(Object * obj, gchar * sql) { g_assert(obj); g_assert(sql); if (db_bureaucrat_checkpendingwrites(obj) > 0) debugmsg("had to write some stuff before i could run this sql."); /* run query */ obj->query = db_id_verifysql(sql); if (obj->query == NULL) { errormsg("Failed to modify SQL statement to include keys, %s", sql); return -2; } obj->res = db_dbexec(globaldbconn, obj->query); debugmsg("%s", obj->query); /* check for errors */ if (db_dbcheckresult(obj->res) != 0) { errormsg("error in running query %s", obj->query); obj->res = NULL; return -1; } /* check number of records loaded, as well as record number loaded */ obj->res->basetable = db_sqlparse_getfirsttable(obj->query); /* obj->name = obj->res->basetable; */ if ((obj->num = db_dbnumrows(obj->res)) <= 0) { /* This needs to be relooked at so that an empty object is created when you have zero results */ debugmsg("No records found for loading %s", obj->query); if (obj->name == NULL) { obj->name = db_sqlparse_getfirsttable(obj->query); debugmsg("I'm assuming table name of %s, and hoping for the best", obj->name); } /* db_obj_clear(obj); */ if (obj->res != NULL) { /* if (obj->freeresult == TRUE) */ db_dbclear(obj->res); obj->res = NULL; } db_obj_handle_empty_recordset(obj); /* g_assert(obj->name); */ return 1; } /* get number of fields */ /* this was the old way, now replaced by populate */ /* num = db_dbnumfields(obj->res); obj->numfield = num; */ /* Assign record defaults to a read, data unchanged */ obj->newrecord = FALSE; obj->freeresult = TRUE; obj->changed = FALSE; obj->unknownid = FALSE; obj->filtered = FALSE; /* I suspect this code is buggy so i'm putting a reminder that I need to get a hair cut because i'll visit here often */ obj->readonly = FALSE; /* populate that object, Yeaaah! */ db_field_populate(obj); db_moveto(obj, 0); /* Run some tests */ if (db_isnewrecord(obj) == TRUE) g_assert(NULL); return 0; }/** * db_obj_sqlwrite: * @query: An insert or update query string * @targettable: The table your running the query on * @id: If its an insert then you want to record the new id for the object. * * Execture a insert or a update, this is used in internally by the flushing. * You shoulnd't need to call this function. * * Returns: negitive on failure, 1 on insert, 0 on update. */gintdb_obj_sqlwrite(gchar * query, gchar * targettable, DbUniqueId ** id) { gint retval = 0; DbRecordSet *res; g_assert(query); *id = NULL; /* execute the write query */ debugmsg("%s", query); res = db_dbexec(globaldbconn, query); res->basetable = mem_strdup(targettable); /* check result */ if (db_checkpgresult(res) != 0) { errormsg("%s Query Failed", query); /* clean up the odd ends for the object */ return -1; } /* If you ran an insert re-get the uniqueid and record it in the cache for future reference. */ if ((*id = db_uniqueid(res)) != NULL) retval = 1; db_dbclear(res); return retval; }/** * db_obj_test: * @obj: Database object * * Run a series of tests on an object to make sure it is not courpt. * * Returns: non-zero on failure. */gintdb_obj_test(Object * obj) { gint f = 0, i; /* Disabled to improve speed */ return 0; if (obj == NULL) errormsg("%d, object is null", f++); if (obj->name == NULL) errormsg("%d,object can not be written back to db.", f++); /* if (obj->res == NULL && obj->query != NULL) errormsg("%d,object has no recordset", f++); */ if (obj->id == NULL) errormsg("%d,id is null", f++); if (obj->row < 0) errormsg("%d,row is invalid", f++); if (obj->cache == NULL && obj->changed == TRUE) warningmsg("%d,cache is null, but the object has changed", f++); for (i = 0; i < obj->numcache; i++) { if (obj->cache[i]->origrow == obj->row) if (db_id_compare(obj->cache[i]->id, obj->id) != 0) errormsg("%d, cache is courpt.", f++); } f += db_field_test(obj); return (0 - f); }/** * db_obj_create: * @name: Optional name of a table * * Creates a blank empty object which can then used for reading or writing into. This is * internal code. * * Returns: Newly created database object */Object *db_obj_create(gchar * tablename) { Object *obj; obj = (Object *) mem_alloc(sizeof(Object)); memset(obj, 0, sizeof(Object)); obj->objectinstance = -1; if (tablename == NULL) { obj->readonly = TRUE; obj->name = NULL; } else { obj->readonly = FALSE; obj->name = mem_strdup(tablename); } obj->res = NULL; obj->row = 0; obj->num = 1; obj->numfield = 0; obj->freeresult = FALSE; obj->newrecord = TRUE; obj->unknownid = TRUE; obj->changed = FALSE; obj->filtered = FALSE; obj->sqlgood = TRUE; obj->fulldbsupport = TRUE; obj->query = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -