⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 Gambas is a graphical development environment based on a Basic interpreter, like Visual Basic. It us
💻 C
📖 第 1 页 / 共 4 页
字号:
/***************************************************************************  main.c  PostgreSQL driver  (c) 2000-2003 Beno� Minisini <gambas@users.sourceforge.net>  This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 1, or (at your option)  any later version.  This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.  You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define __MAIN_C#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <libpq-fe.h>#include <postgres.h>#include <pg_type.h>#include "main.h"GB_INTERFACE GB;DB_INTERFACE DB;static char _buffer[32];static DB_DRIVER _driver;/*static int _print_query = FALSE;*//* Internal function to check the result of a query */static int check_result(PGresult *res, const char *err){  if (!res)  {    GB.Error("Out of memory");    return TRUE;  }  switch (PQresultStatus(res))  {    case PGRES_COMMAND_OK:    case PGRES_TUPLES_OK:      return FALSE;    default:      if (err)        GB.Error(err, PQresultErrorMessage(res));      PQclear(res);      return TRUE;  }}/* internal function to unquote a value stored as a string */static char *unquote(char *val){  int i;  unsigned char c;  if (!val || *val == 0 || *val != '\'')    return val;  DB.Query.Init();  for (i = 1;; i++)  {    c = val[i];    if (!c || c == '\'')      break;    if (c == '\\')      i++;    DB.Query.AddLength(&val[i], 1);  }  return DB.Query.Get();}/* Internal function to convert a database type into a Gambas type */static GB_TYPE conv_type(Oid type){  switch(type)  {    case BOOLOID:      return GB_T_BOOLEAN;    case INT2OID:    case INT4OID:      return GB_T_INTEGER;    case NUMERICOID:    case FLOAT4OID:    case FLOAT8OID:    case INT8OID:      return GB_T_FLOAT;    case ABSTIMEOID:    case RELTIMEOID:    case DATEOID:    case TIMEOID:    case TIMESTAMPOID:#ifdef DATETIMEOID    case DATETIMEOID:#endif#ifdef TIMESTAMPTZOID    case TIMESTAMPTZOID:#endif      return GB_T_DATE;    case CHAROID:    case BPCHAROID:    case VARCHAROID:    case TEXTOID:    case NAMEOID:    case BYTEAOID:    case CASHOID:    default:      return GB_T_STRING;  }}/* Internal function to convert a database boolean value  */static int conv_boolean(const char *data){  return strcasecmp(data, "t") == 0 || strcasecmp(data, "'t'") == 0;}/* Internal function to convert a database value into a Gambas variant value */static void conv_data(char *data, GB_VARIANT_VALUE *val, Oid type){  GB_VALUE conv;  GB_DATE_SERIAL date;  double sec;  long len;  bool bc;  switch (type)  {    case BOOLOID:      val->_boolean.type = GB_T_BOOLEAN;      val->_boolean.value = conv_boolean(data);      break;    case INT2OID:    case INT4OID:      GB.NumberFromString(GB_NB_READ_INTEGER, data, strlen(data), &conv);      val->_integer.type = GB_T_INTEGER;      val->_integer.value = ((GB_INTEGER *)&conv)->value;      break;    case NUMERICOID:    case FLOAT4OID:    case FLOAT8OID:    case INT8OID:      GB.NumberFromString(GB_NB_READ_FLOAT, data, strlen(data), &conv);      val->_float.type = GB_T_FLOAT;      val->_float.value = ((GB_FLOAT *)&conv)->value;      break;    case ABSTIMEOID:    case RELTIMEOID:    case DATEOID:    case TIMEOID:    case TIMESTAMPOID:    #ifdef DATETIMEOID    case DATETIMEOID:    #endif    #ifdef TIMESTAMPTZOID    case TIMESTAMPTZOID:    #endif      memset(&date, 0, sizeof(date));      len = strlen(data);      if (len > 3 && strcmp(&data[len - 2], "BC") == 0)        bc = TRUE;      else        bc = FALSE;      switch(type)      {        case ABSTIMEOID:        case RELTIMEOID:        case DATEOID:          sscanf(data, "%4hu-%2hu-%2hu", &date.year, &date.month, &date.day);          break;        case TIMEOID:          sscanf(data, "%2hu:%2hu:%lf", &date.hour, &date.min, &sec);          date.sec = (short)sec;          date.msec = (short)((sec - date.sec) * 1000 + 0.5);          break;        case TIMESTAMPOID:        #ifdef DATETIMEOID        case DATETIMEOID:        #endif        #ifdef TIMESTAMPTZOID        case TIMESTAMPTZOID:        #endif          sscanf(data, "%4hu-%2hu-%2hu %2hu:%2hu:%lf", &date.year, &date.month, &date.day, &date.hour, &date.min, &sec);          date.sec = (short)sec;          date.msec = (short)((sec - date.sec) * 1000 + 0.5);          break;      }      if (bc)        date.year = (-date.year);      GB.MakeDate(&date, (GB_DATE *)&conv);      val->_date.type = GB_T_DATE;      val->_date.date = ((GB_DATE *)&conv)->value.date;      val->_date.time = ((GB_DATE *)&conv)->value.time;      break;    case CHAROID:    case BPCHAROID:    case VARCHAROID:    case TEXTOID:    case NAMEOID:    case BYTEAOID:    case CASHOID:    default:      //val->_string.type = GB_T_STRING;      //GB.NewString(&val->_string.value, data, 0);      val->_string.type = GB_T_CSTRING;      val->_string.value = data;      break;  }}/* Internal function to substitute the table name into a query */static char *query_param[3];static void query_get_param(int index, char **str, long *len){  if (index > 3)    return;  index--;  *str = query_param[index];  *len = strlen(*str);}/* Internal function to run a query */static int do_query(PGconn *conn, const char *error, PGresult **pres,                    const char *qtemp, int nsubst, ...){  va_list args;  int i;  const char *query;  PGresult *res;  int ret;  if (nsubst)  {    va_start(args, nsubst);    if (nsubst > 3)      nsubst = 3;    for (i = 0; i < nsubst; i++)      query_param[i] = va_arg(args, char *);    query = GB.SubstString(qtemp, 0, query_get_param);  }  else    query = qtemp;  if (DB.IsDebug())  {    fprintf(stderr, "postgresql: %p: %s\n", conn, query);    fflush(stderr);  }  res = PQexec(conn, query);  ret = check_result(res, error);  if (!ret)  {    if (pres)      *pres = res;    else      PQclear(res);  }  return ret;}/* Internal function to check database version number */long db_version(PGconn *conn){  //Check db version  const char *vquery =    "select substring(version(),12,5)";  long dbversion =0;  PGresult *res;  if (!do_query(conn, NULL, &res, vquery, 0))  {    unsigned int verMain, verMajor, verMinor;    sscanf(PQgetvalue(res, 0, 0),"%2u.%2u.%2u", &verMain, &verMajor, &verMinor);    dbversion = ((verMain * 10000) + (verMajor * 100) + verMinor);    PQclear(res);  }  return dbversion;}/*****************************************************************************  get_quote()  Returns the character used for quoting object names.*****************************************************************************/static char *get_quote(void){  return QUOTE_STRING;}/*****************************************************************************  open_database()  Connect to a database.  <desc> points at a structure describing each connection parameter.  This function must return a database handle, or NULL if the connection  has failed.  The name of the database can be NULL, meaning a default database.*****************************************************************************/static DB_DATABASE open_database(DB_DESC *desc, char **charset){  const char *query =    "show client_encoding";  PGconn *conn;  PGresult *res;  int status;  char *name;  if (desc->name)    name = desc->name;  else    name = "template1";  conn = PQsetdbLogin(desc->host, desc->port, NULL, NULL, name, desc->user, desc->password);  if (!conn)  {    GB.Error("Out of memory");    return NULL;  }  if (PQstatus(conn) == CONNECTION_BAD)  {    GB.Error("Cannot open database: &1", PQerrorMessage(conn));    PQfinish(conn);    return NULL;  }  res = PQexec(conn, "set datestyle=ISO");  status = PQresultStatus(res);  if (status != PGRES_COMMAND_OK)  {    GB.Error("Cannot set datestyle to ISO: &1", PQerrorMessage(conn));    PQclear(res);    PQfinish(conn);    return NULL;  }  /* encoding */  if (PQsetClientEncoding(conn, GB.System.Charset()))    fprintf(stderr, "WARNING: cannot set encoding to %s\n", GB.System.Charset());  if (!do_query(conn, NULL, &res, query, 0))  {    GB.NewString(charset, PQgetvalue(res, 0, 0), 0);    PQclear(res);  }  else    *charset = NULL;  /* get version */  desc->version = db_version(conn);  return (DB_DATABASE)conn;}/*****************************************************************************  close_database()  Terminates the database connection.  <handle> contains the database handle.*****************************************************************************/static void close_database(DB_DATABASE handle){  PGconn *conn = (PGconn *)handle;  if (conn)    PQfinish(conn);}/*****************************************************************************  format_value()  This function transforms a gambas value into a string value that can  be inserted into a SQL query.  <arg> points to the value.  <add> is a callback called to insert the string into the query.  This function must return TRUE if it translates the value, and FALSE if  it does not.  If the value is not translated, then a default translation is used.*****************************************************************************/static int format_value(GB_VALUE *arg, DB_FORMAT_CALLBACK add){  int l;  GB_DATE_SERIAL *date;  bool bc;  switch (arg->type)  {    case GB_T_BOOLEAN:      if (VALUE((GB_BOOLEAN *)arg))        add("TRUE", 4);      else        add("FALSE", 5);      return TRUE;    case GB_T_STRING:    case GB_T_CSTRING:      return FALSE;    case GB_T_DATE:      date = GB.SplitDate((GB_DATE *)arg);      bc = date->year < 0;      l = sprintf(_buffer, "'%04d-%02d-%02d %02d:%02d:%02d",        abs(date->year), date->month, date->day,        date->hour, date->min, date->sec);      add(_buffer, l);      if (date->msec)      {        l = sprintf(_buffer, ".%03d", date->msec);        add(_buffer, l);      }      if (bc)        add(" BC", 3);      add("'", 1);      return TRUE;    default:      return FALSE;  }}/*****************************************************************************  exec_query()  Send a query to the server and gets the result.  <handle> is the database handle, as returned by open_database()  <query> is the query string.  <result> will receive the result handle of the query.  <err> is an error message used when the query failed.  <result> can be NULL, when we don't care getting the result.*****************************************************************************/static int exec_query(DB_DATABASE handle, char *query, DB_RESULT *result, char *err){  return do_query((PGconn *)handle, err, (PGresult **)result, query, 0);}/*****************************************************************************  query_init()  Initialize an info structure from a query result.  <result> is the handle of the query result.  <info> points to the info structure.  <count> will receive the number of records returned by the query.  This function must initialize the info->nfield field with the number of  field in the query result.*****************************************************************************/static void query_init(DB_RESULT result, DB_INFO *info, int *count){  PGresult *res = (PGresult *)result;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -