📄 cresult.c
字号:
/*************************************************************************** CResult.c The Result class (c) 2000-2003 Beno� Minisini <gambas@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define __CRESULT_C#include "main.h"#include "CResultField.h"#include "CResult.h"static GB_SUBCOLLECTION_DESC _fields_desc ={ ".ResultFields", (void *)CRESULTFIELD_get, (void *)CRESULTFIELD_exist, (void *)NULL};static int check_result(CRESULT *_object){ return (THIS->conn->handle == NULL);}static bool check_available(CRESULT *_object){ if (!THIS->available) { GB.Error("Result is not available"); return TRUE; } else return FALSE;}static void init_buffer(CRESULT *_object){ int i; if (THIS->info.nfield == 0) return; GB.Alloc((void **)&THIS->buffer, sizeof(GB_VARIANT_VALUE) * THIS->info.nfield); for (i = 0; i < THIS->info.nfield; i++) THIS->buffer[i].type = GB_T_NULL;}static void void_buffer(CRESULT *_object){ int i; if (THIS->info.nfield == 0) return; for (i = 0; i < THIS->info.nfield; i++) GB.StoreVariant(NULL, &THIS->buffer[i]);}static void release_buffer(CRESULT *_object){ if (THIS->buffer) { void_buffer(THIS); GB.Free((void **)&THIS->buffer); }}static void load_buffer(CRESULT *_object, int pos){ int i, ind; if (pos < 0 || pos >= THIS->count || THIS->info.nfield == 0) { /* Andrea Bortolan's changes for the ODBC modules*/ /* ODBC does return the number of rows affected by the query when execute a insert,apdate or delete query, for all others case it returns -1 even if the query was execute without errors */ /* Here the check for this case -1 means that the query was executed correctly so get the result. */ /* If the pos (the result row) does not exist because pos is > of the rows available than the ODBC module will rise an Error ODBC_END_OF_DATA that must be catched by the application */ if (THIS->count == -1) { if (THIS->handle && pos != THIS->pos) { THIS->driver->Result.Fill(THIS->handle, pos, THIS->buffer,(pos > 0) && (pos == (THIS->pos + 1))); } THIS->pos = pos; THIS->available = TRUE; } else /* End of Andrea's changes */ { THIS->pos = -1; THIS->available = FALSE; } } else { if (THIS->handle && pos != THIS->pos) { THIS->driver->Result.Fill(THIS->handle, pos, THIS->buffer, (pos > 0) && (pos == (THIS->pos + 1))); if (THIS->mode == RESULT_EDIT) { q_init(); for (i = 0; i < THIS->info.nindex; i++) { ind = THIS->info.index[i]; if (i > 0) q_add(" AND "); q_add(THIS->info.field[ind].name); if (THIS->buffer[ind].type == GB_T_NULL) q_add(" IS NULL"); else { q_add(" = "); DB_FormatVariant(THIS->driver, &THIS->buffer[ind], q_add_length); } } GB.FreeString(&THIS->edit); THIS->edit = q_steal(); } } THIS->pos = pos; THIS->available = TRUE; }}static void table_release(DB_DATABASE db, DB_INFO *info){ int i; if (info->table) GB.FreeString(&info->table); if (info->field) { for (i = 0; i < info->nfield; i++) GB.FreeString(&info->field[i].name); GB.Free((void **)&info->field); } if (info->index) GB.Free((void **)&info->index);}CRESULT *DB_MakeResult(CCONNECTION *conn, int mode, char *table_temp, char *query){ CRESULT *_object; DB_RESULT res; char *duplicate; char *token; char *error = NULL; char *table; switch (mode) { case RESULT_FIND: if (conn->driver->Exec(conn->handle, query, &res, "Query failed: &1")) return NULL; break; case RESULT_CREATE: res = NULL; break; case RESULT_EDIT: if (conn->driver->Exec(conn->handle, query, &res, "Query failed: &1")) return NULL; break; } GB.New((void **)&_object, GB.FindClass("Result"), NULL, NULL); THIS->conn = conn; GB.Ref(conn); THIS->driver = conn->driver; THIS->available = FALSE; THIS->mode = mode; THIS->handle = res; THIS->pos = -1; // table must be copied because it can be a temporary string! GB.NewString(&table, table_temp, 0); switch (mode) { case RESULT_FIND: THIS->driver->Result.Init(THIS->handle, &THIS->info, &THIS->count); break; case RESULT_CREATE: if (THIS->driver->Table.Init(conn->handle, table, &THIS->info)) goto ERROR; THIS->count = 1; break; case RESULT_EDIT: THIS->driver->Result.Init(THIS->handle, &THIS->info, &THIS->count); if (THIS->driver->Table.Init(conn->handle, table, &THIS->info)) goto ERROR; if (THIS->driver->Table.Index(conn->handle, table, &THIS->info)) { error = "Table '&1' has no primary key"; goto ERROR; } break; } init_buffer(THIS); load_buffer(THIS, 0); GB.FreeString(&table); return THIS;ERROR: GB.Unref((void **)&_object); if (error) GB.Error(error, table); else if (strchr(table, (int)',') == NULL) { if (!THIS->driver->Table.Exist(conn->handle, table, conn->desc.version)){ GB.Error("Unknown table: &1", table); } else { GB.Error("Cannot read information about table &1", table); } } else { duplicate = strdup(table); token = strtok(duplicate,","); do { if (!THIS->driver->Table.Exist(conn->handle, token, conn->desc.version)) GB.Error("Unknown table: &1", token); else GB.Error("Cannot read information about table &1", token); } while ((token = strtok(NULL, ".")) != NULL); free(duplicate); } GB.FreeString(&table); return NULL;}BEGIN_METHOD_VOID(CRESULT_free) release_buffer(THIS); if (THIS->mode != RESULT_CREATE) THIS->driver->Result.Release(THIS->handle, &THIS->info); if (THIS->mode != RESULT_FIND) table_release(THIS->conn, &THIS->info); if (THIS->edit) GB.FreeString(&THIS->edit); GB.Unref((void **)&THIS->conn);END_METHODBEGIN_PROPERTY(CRESULT_count) GB.ReturnInteger(THIS->count);END_PROPERTYBEGIN_PROPERTY(CRESULT_index) GB.ReturnInteger(THIS->pos);END_PROPERTYBEGIN_PROPERTY(CRESULT_available) GB.ReturnBoolean(THIS->available);END_PROPERTYBEGIN_METHOD(CRESULT_get, GB_STRING field) int index; if (check_available(THIS)) return; index = CRESULTFIELD_find(THIS, GB.ToZeroString(ARG(field)), TRUE); if (index < 0) return; GB.ReturnPtr(GB_T_VARIANT, &THIS->buffer[index]);END_METHODBEGIN_METHOD(CRESULT_put, GB_VARIANT value; GB_STRING field) int index; if (check_available(THIS)) return; if (THIS->mode == RESULT_FIND) { GB.Error("Result is read-only"); return; } index = CRESULTFIELD_find(THIS, GB.ToZeroString(ARG(field)), TRUE); if (index < 0) return; if (VARG(value).type != GB_T_NULL && VARG(value).type != THIS->info.field[index].type) /*{ GB.Error("Type mismatch"); return; }*/ { if (GB.Conv((GB_VALUE *)ARG(value), THIS->info.field[index].type)) return; GB.Conv((GB_VALUE *)ARG(value), GB_T_VARIANT); } GB.StoreVariant(ARG(value), &THIS->buffer[index]);END_METHOD#if 0BEGIN_METHOD(CRESULT_copy, GB_OBJECT result) CRESULT *result = (CRESULT *)VARG(result); int index; if (THIS->mode == RESULT_FIND) { GB.Error("Result is read-only"); return; } for (index = 0; index < index = find_field(THIS, GB.ToZeroString(ARG(field))); if (index < 0) return; if (VARG(value).type != GB_T_NULL && VARG(value).type != THIS->info.types[index]) /*{ GB.Error("Type mismatch"); return; }*/ { if (GB.Conv((GB_VALUE *)ARG(value), THIS->info.types[index])) return; GB.Conv((GB_VALUE *)ARG(value), GB_T_VARIANT); } GB.StoreVariant(ARG(value), &THIS->buffer[index]);END_METHOD#endifBEGIN_METHOD_VOID(CRESULT_move_first) load_buffer(THIS, 0); GB.ReturnBoolean(!THIS->available);END_METHODBEGIN_METHOD_VOID(CRESULT_move_last) load_buffer(THIS, THIS->count - 1); GB.ReturnBoolean(!THIS->available);END_METHODBEGIN_METHOD_VOID(CRESULT_move_previous) load_buffer(THIS, THIS->pos - 1); GB.ReturnBoolean(!THIS->available);END_METHODBEGIN_METHOD_VOID(CRESULT_move_next) load_buffer(THIS, THIS->pos + 1); GB.ReturnBoolean(!THIS->available);END_METHODBEGIN_METHOD(CRESULT_move_to, GB_INTEGER pos) load_buffer(THIS, VARG(pos)); GB.ReturnBoolean(!THIS->available);END_METHODBEGIN_METHOD_VOID(CRESULT_next) int *pos = (int *)GB.GetEnum(); load_buffer(THIS, *pos); if (THIS->available) (*pos)++; else GB.StopEnum();END_METHODBEGIN_METHOD_VOID(CRESULT_update) int i; bool comma; DB_INFO *info = &THIS->info; if (check_available(THIS)) return; q_init(); switch(THIS->mode) { case RESULT_CREATE: q_add("INSERT INTO "); q_add(THIS->driver->GetQuote()); q_add(info->table); q_add(THIS->driver->GetQuote()); q_add(" ( "); comma = FALSE; for (i = 0; i < info->nfield; i++) { if (THIS->buffer[i].type == GB_T_NULL) continue; if (comma) q_add(", "); q_add(info->field[i].name); comma = TRUE; } q_add(" ) VALUES ( "); comma = FALSE; for (i = 0; i < info->nfield; i++) { if (THIS->buffer[i].type == GB_T_NULL) continue; if (comma) q_add(", "); DB_FormatVariant(THIS->driver, &THIS->buffer[i], q_add_length); comma = TRUE; } q_add(" )"); if (!THIS->driver->Exec(THIS->conn->handle, q_get(), NULL, "Cannot create record: &1")) void_buffer(THIS); break; case RESULT_EDIT: q_add("UPDATE "); q_add(THIS->driver->GetQuote()); q_add(info->table); q_add(THIS->driver->GetQuote()); q_add(" SET "); for (i = 0; i < info->nfield; i++) { if (i > 0) q_add(", "); q_add(THIS->info.field[i].name); q_add(" = "); DB_FormatVariant(THIS->driver, &THIS->buffer[i], q_add_length); } q_add(" WHERE "); q_add(THIS->edit); THIS->driver->Exec(THIS->conn->handle, q_get(), NULL, "Cannot modify record: &1"); break; default: GB.Error("Result is read-only"); break; }END_METHODBEGIN_METHOD_VOID(CRESULT_delete) DB_INFO *info = &THIS->info; if (check_available(THIS)) return; q_init(); switch(THIS->mode) { case RESULT_CREATE: void_buffer(THIS); break; case RESULT_EDIT: q_add("DELETE FROM "); q_add(THIS->driver->GetQuote()); q_add(info->table); q_add(THIS->driver->GetQuote()); q_add(" WHERE "); q_add(THIS->edit); THIS->driver->Exec(THIS->conn->handle, q_get(), NULL, "Cannot delete record: &1"); break; default: GB.Error("Result is read-only"); break; }END_METHODBEGIN_PROPERTY(CRESULT_fields) GB.SubCollection.New(&THIS->fields, &_fields_desc, THIS); GB.ReturnObject(THIS->fields);END_PROPERTYBEGIN_PROPERTY(CRESULT_connection) GB.ReturnObject(THIS->conn);END_PROPERTYGB_DESC CResultDesc[] ={ GB_DECLARE("Result", sizeof(CRESULT)), GB_NOT_CREATABLE(), GB_HOOK_CHECK(check_result), GB_METHOD("_free", NULL, CRESULT_free, NULL), GB_PROPERTY_READ("Count", "i", CRESULT_count), GB_PROPERTY_READ("Length", "i", CRESULT_count), GB_PROPERTY_READ("Available", "b", CRESULT_available), GB_PROPERTY_READ("Index", "i", CRESULT_index), GB_METHOD("_get", "v", CRESULT_get, "(Field)s"), GB_METHOD("_put", NULL, CRESULT_put, "(Value)v(Field)s"), GB_METHOD("_next", NULL, CRESULT_next, NULL), GB_METHOD("MoveFirst", "b", CRESULT_move_first, NULL), GB_METHOD("MoveLast", "b", CRESULT_move_last, NULL), GB_METHOD("MovePrevious", "b", CRESULT_move_previous, NULL), GB_METHOD("MoveNext", "b", CRESULT_move_next, NULL), GB_METHOD("MoveTo", "b", CRESULT_move_to, "(Index)i"), GB_METHOD("Update", NULL, CRESULT_update, NULL), GB_METHOD("Delete", NULL, CRESULT_delete, NULL), GB_PROPERTY_READ("Fields", ".ResultFields", CRESULT_fields), GB_PROPERTY_READ("Connection", "Connection", CRESULT_connection), GB_END_DECLARE};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -