ODBC interface
Fergus Henderson
fjh at mundook.cs.mu.OZ.AU
Wed Jul 23 18:56:49 AEST 1997
Simon TAYLOR <stayl at students.cs.mu.OZ.AU> writes:
>This is the result of my hacking at Mission Critical's ODBC interface.
Ah. I see. What do Mission Critical think of this?
To distribute this, we would need their permission.
>Is it OK to distribute a patch for these header files, given that they
>aren't in the section of the ODBC SDK which is redistributable?
Probably not.
(A non-context diff might be OK, but a context one wouldn't be.)
>Also I should probably get permission from the Mission Critical people
>before this goes in the release, but that shouldn't be a problem.
Please do that.
>=======
>Part 1:
>=======
>
>Estimated hours taken: 3
>
>runtime/engine.h
>runtime/engine.mod
> Added macros MR_setjmp and MR_longjmp which in save and restore
> the jmp_buf used to return from call_engine_inner. This is needed
> to make longjmp work across C->Mercury calls.
>
>runtime/mercury_string.h
> Added a macro make_aligned_string_copy, which is the same as
> make_aligned_string except that it is guaranteed to do the copy.
> This is useful for copying C strings out of buffers onto the
> Mercury heap.
>
>runtime/misc.c
> Avoid a segfault in debug grades when printing information about
> the bottom nondetstack frame.
These changes look fine, except for the stuff you noted about
the use of setjmp and longjmp in MR_setjmp and MR_longjmp.
>+ if (s - nondetstack_zone->min > 0) {
How about just
if (s > nondetstack_zone->min)
?
> # gcc aborts with optimization enabled.
Could you be more specific here, e.g.
# gcc 2.7.2.1 for sparc-sun-solaris2.5 aborts when compiling
# odbc.c if optimization is enabled.
It might be a good idea to figure out why gcc aborts...
>%---------------------------------------------------------------------------%
>% XXX what should go here?
>% Copyright (C) 1997 Mission Critical
>% Copyright (C) 1997 University of Melbourne.
>% This file may only be copied under the terms of the GNU Library General
>% Public License - see the file COPYING.LIB in the Mercury distribution.
I think what you have there is fine, so long as you get Mission Critical's
permission.
>%---------------------------------------------------------------------------%
>% File: odbc.m
>% Authors: Renaud Paquay (rpa at miscrit.be), stayl
>% ODBC version: 2.0
>%
>% The transaction interface used here is described in
>% Kemp, Conway, Harris, Henderson, Ramamohanarao and Somogyi,
>% "Database transactions in a purely declarative
>% logic programming language",
>% Technical Report 96/45, Department of Computer Science,
>% University of Melbourne, December 1996.
Is there a URL for that report?
There should be.
> % odbc__tables(QualifierPattern, OwnerPattern,
> % TableNamePattern, Result)
> %
> % Get a list of database tables matching the given description.
> % Note that wildcards are not allowed in the CatalogPattern.
> % This is fixed in ODBC 3.0.
What's CatalogPattern??
> :- type odbc__state == unit.
A brief explanation here would be helpful.
>#define ODBC_VER 0x0250
Ditto.
>#undef DEBUG
Ditto.
>static Word odbc_message_list = list_empty();
There is no guarantee that list_empty() will be a macro suitable
for inclusion in a static initializer. For some configurations, it is not.
>%-----------------------------------------------------------------------------%
>
> % Call the transaction closure.
> :- pred odbc__do_transaction(odbc__transaction(T), T,
> odbc__state, odbc__state).
> :- mode odbc__do_transaction(odbc__transaction, out, di, uo) is det.
>
> :- pragma export(odbc__do_transaction(odbc__transaction, out, di, uo),
> "ML_odbc__do_transaction").
Since this isn't part of the Mercury standard library, `ML_' isn't the
right prefix to use here. I suggest perhaps MODBC_do_transaction.
> :- pred odbc__throw(odbc__state, odbc__state).
> :- mode odbc__throw(di, uo) is erroneous.
>
> :- pragma c_code(odbc__throw(DB0::di, DB::uo),
> will_not_call_mercury,
>"
>{
> save_transient_registers();
> odbc_ret_code = SQL_ERROR;
> odbc_throw();
> DB = DB0;
>}
The `DB = DB0;' is unreachable, so change it `/* DB = DB0; (not reached) */'.
> statement = (MODBC_Statement *) newmem(sizeof(MODBC_Statement));
I would prefer
statement = make(MODBC_Statement);
> switch ((int) Type) {
Why is this cast to `(int)' here?
> case MODBC_INT:
>
> Int = (Integer) *(MODBC_SQL_INT *)(col->data);
>#ifdef DEBUG
> printf(""got integer %ld\\n"", Int);
>#endif /* DEBUG */
> break;
I think it would be worth checking for overflow here.
MODBC_SQL_INT data = *(MODBC_SQL_INT *)(col->data);
Int = (Integer) data;
if (Int != data) {
/* handle overflow error */
}
> case MODBC_FLOAT:
>
> Flt = *(Float *)(col->data);
Ah, is that a bug? It sure looks different to the code for ints.
> } /* switch (Type) */
s/switch/end switch/
>} /* odbc__get_data */
s/odbc__get_data/end odbc__get_data()/
>
> :- pragma c_code("
>
>void
>odbc_do_get_data(MODBC_Statement *stat, int column_id)
>{
> MODBC_Column *column;
> SQLRETURN rc;
> SDWORD column_info;
> char dummy_buffer[1]; /*
> ** Room for the NULL termination
> ** byte and nothing else.
> */
s/NULL/NUL/
> if (rc != SQL_SUCCESS_WITH_INFO &&
> ! odbc_check(odbc_env_handle,
> odbc_connection,
> stat->stat_handle, rc)) {
> odbc_do_cleanup_statement(stat);
> odbc_throw();
> }
In cases like this, where the condition of an if statement wraps lines,
it is IMHO clearer if the { is on a line of its own.
This indentation convention is described in our C coding guidelines.
> }
> else if (column->value_info == SQL_NO_TOTAL) {
Our C coding guidelines also say that the else should go on the
same line as the }. (Several occurrences in this function.)
XXX you might need to change some of the pragma C code
from `will_not_call_mercury' to `may_call_mercury'.
>
>#ifdef MODBC_MYSQL
> case SQL_LONGVARBINARY: return MODBC_STRING;
> case SQL_LONGVARCHAR: return MODBC_STRING;
>#else /* ! MODBC_MYSQL */
> case SQL_LONGVARBINARY: return MODBC_VAR_STRING;
> case SQL_LONGVARCHAR: return MODBC_VAR_STRING;
>#endif /* ! MODBC_MYSQL */
Please explain the #ifdef here.
> MR_ASSERT_IMPLY(connection_handle == SQL_NULL_HDBC,
> statement_handle == SQL_NULL_HSTMT);
> MR_ASSERT_IMPLY(statement_handle != SQL_NULL_HSTMT,
> connection_handle != SQL_NULL_HDBC);
These two assertions both assert the same thing.
Are you sure that's what you intended?
I suggest you delete one of them.
If you want to assert
MR_ASSERT_IMPLY(statement_handle != SQL_NULL_HSTMT,
connection_handle != SQL_NULL_HDBC);
More information about the developers
mailing list