/*! \brief Open update cursor \param driver db driver \param table_name table name \param select SQL update statement (?) \param cursor db cursor to be opened \param mode open mode (?) \return DB_OK on success \return DB_FAILED on failure */ int db_open_update_cursor(dbDriver * driver, dbString * table_name, dbString * select, dbCursor * cursor, int mode) { int ret_code; db_init_cursor(cursor); cursor->driver = driver; /* start the procedure call */ db__set_protocol_fds(driver->send, driver->recv); DB_START_PROCEDURE_CALL(DB_PROC_OPEN_UPDATE_CURSOR); /* send the argument(s) to the procedure */ DB_SEND_STRING(table_name); DB_SEND_STRING(select); DB_SEND_INT(mode); /* get the return code for the procedure call */ DB_RECV_RETURN_CODE(&ret_code); if (ret_code != DB_OK) return ret_code; /* ret_code SHOULD == DB_FAILED */ /* get the results */ DB_RECV_TOKEN(&cursor->token); DB_RECV_INT(&cursor->type); DB_RECV_INT(&cursor->mode); DB_RECV_TABLE_DEFINITION(&cursor->table); db_alloc_cursor_column_flags(cursor); return DB_OK; }
/*! \brief Add column to table \param driver db driver \param tableName table name \param column new column description (dbColumn structure) \return DB_OK on success \return DB_FAILED on failure */ int db_add_column(dbDriver * driver, dbString * tableName, dbColumn * column) { int ret_code; /* start the procedure call */ db__set_protocol_fds(driver->send, driver->recv); DB_START_PROCEDURE_CALL(DB_PROC_ADD_COLUMN); /* send the argument(s) to the procedure */ DB_SEND_STRING(tableName); DB_SEND_COLUMN_DEFINITION(column); /* get the return code for the procedure call */ DB_RECV_RETURN_CODE(&ret_code); if (ret_code != DB_OK) return ret_code; /* ret_code SHOULD == DB_FAILED */ /* no results */ return DB_OK; }
/*! \brief ? \param cursor db cursor \return DB_OK on success \return DB_FAILED on failure */ int db_bind_update(dbCursor * cursor) { int ret_code; /* start the procedure call */ db__set_protocol_fds(cursor->driver->send, cursor->driver->recv); DB_START_PROCEDURE_CALL(DB_PROC_BIND_UPDATE); /* send the argument(s) to the procedure */ DB_SEND_TOKEN(&cursor->token); DB_SEND_SHORT_ARRAY(cursor->column_flags, db_get_cursor_number_of_columns(cursor)); /* get the return code for the procedure call */ DB_RECV_RETURN_CODE(&ret_code); if (ret_code != DB_OK) return ret_code; /* ret_code SHOULD == DB_FAILED */ /* no results */ return DB_OK; }
/*! \brief Get driver (?) \param argc, argv arguments \return 0 on success \return 1 on failure */ int db_driver(int argc, char *argv[]) { int stat; int procnum; int i; int rfd, wfd; FILE *send, *recv; char *modestr; /* Read and set environment variables, see dbmi_client/start.c */ if ((modestr = getenv("GRASS_DB_DRIVER_GISRC_MODE"))) { int mode; mode = atoi(modestr); if (mode == G_GISRC_MODE_MEMORY) { G_set_gisrc_mode(G_GISRC_MODE_MEMORY); G__setenv("DEBUG", getenv("DEBUG")); G__setenv("GISDBASE", getenv("GISDBASE")); G__setenv("LOCATION_NAME", getenv("LOCATION_NAME")); G__setenv("MAPSET", getenv("MAPSET")); G_debug(3, "Driver GISDBASE set to '%s'", G_getenv("GISDBASE")); } } #ifdef __MINGW32__ /* TODO: */ /* We should close everything except stdin, stdout but _fcloseall() * closes open streams not file descriptors. _getmaxstdio too big number. * * Because the pipes were created just before this driver was started * the file descriptors should not be above a closed descriptor * until it was run from a multithread application and some descriptors * were closed in the mean time. * Also Windows documentation does not say that new file descriptor is * the lowest available. */ { int err_count = 0; int cfd = 3; while (1) { if (close(cfd) == -1) err_count++; /* no good reason for 10 */ if (err_count > 10) break; cfd++; } } #endif send = stdout; recv = stdin; /* THIS CODE IS FOR DEBUGGING WITH CODECENTER */ /**********************************************/ if (argc == 3) { rfd = wfd = -1; sscanf(argv[1], "%d", &rfd); sscanf(argv[2], "%d", &wfd); send = fdopen(wfd, "w"); if (send == NULL) { db_syserror(argv[1]); exit(1); } recv = fdopen(rfd, "r"); if (recv == NULL) { db_syserror(argv[2]); exit(1); } } /**********************************************/ db_clear_error(); db_auto_print_errors(0); db_auto_print_protocol_errors(1); db__init_driver_state(); #ifndef USE_BUFFERED_IO setbuf(recv, NULL); setbuf(send, NULL); #endif db__set_protocol_fds(send, recv); if (db_driver_init(argc, argv) == DB_OK) db__send_success(); else { db__send_failure(); exit(1); } stat = DB_OK; /* get the procedure number */ while (db__recv_procnum(&procnum) == DB_OK) { #ifdef __MINGW32__ if (procnum == DB_PROC_SHUTDOWN_DRIVER) { db__send_procedure_ok(procnum); break; } #endif db_clear_error(); /* find this procedure */ for (i = 0; procedure[i].routine; i++) if (procedure[i].procnum == procnum) break; /* if found, call it */ if (procedure[i].routine) { if ((stat = db__send_procedure_ok(procnum)) != DB_OK) break; /* while loop */ if ((stat = (*procedure[i].routine) ()) != DB_OK) break; } else if ((stat = db__send_procedure_not_implemented(procnum)) != DB_OK) break; } db_driver_finish(); exit(stat == DB_OK ? 0 : 1); }
/*! \brief Initialize a new dbDriver for db transaction. If <i>name</i> is NULL, the db name will be assigned connection.driverName. \param name driver name \return pointer to dbDriver structure \return NULL on error */ dbDriver *db_start_driver(const char *name) { dbDriver *driver; dbDbmscap *list, *cur; const char *startup; int p1[2], p2[2]; int pid; int stat; dbConnection connection; char ebuf[5]; /* Set some environment variables which are later read by driver. * This is necessary when application is running without GISRC file and all * gis variables are set by application. * Even if GISRC is set, application may change some variables during runtime, * if for example reads data from different gdatabase, location or mapset*/ /* setenv() is not portable, putenv() is POSIX, putenv() in glibc 2.0-2.1.1 doesn't conform to SUSv2, * G_putenv() as well, but that is what we want, makes a copy of string */ if (G_get_gisrc_mode() == G_GISRC_MODE_MEMORY) { G_debug(3, "G_GISRC_MODE_MEMORY\n"); sprintf(ebuf, "%d", G_GISRC_MODE_MEMORY); G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf); /* to tell driver that it must read variables */ if (G_getenv_nofatal("DEBUG")) { G_putenv("DEBUG", G_getenv_nofatal("DEBUG")); } else { G_putenv("DEBUG", "0"); } G_putenv("GISDBASE", G_getenv_nofatal("GISDBASE")); G_putenv("LOCATION_NAME", G_getenv_nofatal("LOCATION_NAME")); G_putenv("MAPSET", G_getenv_nofatal("MAPSET")); } else { /* Warning: GISRC_MODE_MEMORY _must_ be set to G_GISRC_MODE_FILE, because the module can be * run from an application which previously set environment variable to G_GISRC_MODE_MEMORY */ sprintf(ebuf, "%d", G_GISRC_MODE_FILE); G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf); } /* read the dbmscap file */ if (NULL == (list = db_read_dbmscap())) return (dbDriver *) NULL; /* if name is empty use connection.driverName, added by RB 4/2000 */ if (name == '\0') { db_get_connection(&connection); if (NULL == (name = connection.driverName)) return (dbDriver *) NULL; } /* find this system name */ for (cur = list; cur; cur = cur->next) if (strcmp(cur->driverName, name) == 0) break; if (cur == NULL) { char msg[256]; db_free_dbmscap(list); sprintf(msg, "%s: no such driver available", name); db_error(msg); return (dbDriver *) NULL; } /* allocate a driver structure */ driver = (dbDriver *) db_malloc(sizeof(dbDriver)); if (driver == NULL) { db_free_dbmscap(list); return (dbDriver *) NULL; } /* copy the relevant info from the dbmscap entry into the driver structure */ db_copy_dbmscap_entry(&driver->dbmscap, cur); startup = driver->dbmscap.startup; /* free the dbmscap list */ db_free_dbmscap(list); /* run the driver as a child process and create pipes to its stdin, stdout */ #ifdef __MINGW32__ #define pipe(fds) _pipe(fds, 250000, _O_BINARY | _O_NOINHERIT) #endif /* open the pipes */ if ((pipe(p1) < 0) || (pipe(p2) < 0)) { db_syserror("can't open any pipes"); return (dbDriver *) NULL; } close_on_exec(p1[READ]); close_on_exec(p1[WRITE]); close_on_exec(p2[READ]); close_on_exec(p2[WRITE]); pid = G_spawn_ex(startup, SF_BACKGROUND, SF_REDIRECT_DESCRIPTOR, 0, p1[READ], SF_CLOSE_DESCRIPTOR, p1[WRITE], SF_REDIRECT_DESCRIPTOR, 1, p2[WRITE], SF_CLOSE_DESCRIPTOR, p2[READ], startup, NULL); /* create a child */ if (pid < 0) { db_syserror("can't create fork"); return (dbDriver *) NULL; } close(p1[READ]); close(p2[WRITE]); /* record driver process id in driver struct */ driver->pid = pid; /* convert pipes to FILE* */ driver->send = fdopen(p1[WRITE], "wb"); driver->recv = fdopen(p2[READ], "rb"); /* most systems will have to use unbuffered io to get the send/recv to work */ #ifndef USE_BUFFERED_IO setbuf(driver->send, NULL); setbuf(driver->recv, NULL); #endif db__set_protocol_fds(driver->send, driver->recv); if (db__recv_return_code(&stat) != DB_OK || stat != DB_OK) driver = NULL; return driver; }