[C++] auf ODBC-Datenbanken zugreifen

respawner

Well-known member
ID: 12494
L
26 April 2006
387
29
Hallo,

ich habe ein großes Problem.
Ich brauche eine Klasse für C++ (Open Walcot) um auf ODBC-Datenbanken zugreifen zu können.
Ich habe bereits libodbc++ (die scheitert schon am einibnden) und OLT (meckert beim Compilieren über die h-Datei (OLT besteht nur aus einer header-Datei)).
Habe es auch mit Ultimate++ versucht aber ohne Erfolg.

edit war alles unter Windows (nicht dass jemand mir einen c++-Compiler vorschlägt der nur unter Linux läuft bei dem aber ODBC-Libraries gehen)

MfG respawner
 
Code:
#include "DTL.h"
#include <iostream>
using namespace dtl;
using namespace std;
int main() 
{
        {
                // Connect to the database 
DBConnection::GetDefaultConnection().Connect("UID=example;PWD=example;DSN=example;");
                // Create a container to hold records from a query.
                // In this case, the query will be "SELECT * FROM DB_EXAMPLE".
                DynamicDBView<> view("DB_EXAMPLE", "*"); 
                // Read all rows from the database and send to cout
                copy(view.begin(), view.end(), ostream_iterator<variant_row>(cout, "\n"));
        }
        catch (std::exception &ex) 
        {
                // Show any database or other standard errors
                cerr << ex.what() << endl;
        }
        return 0;
}



Code:
#ifndef DTL_NO_UNICODE
BEGIN_DTL_NAMESPACE 
   typedef STD_::wstring tstring;
   typedef STD_::wostream tostream;
   static  STD_::wostream &tcout = STD_::wcout; 
   typedef STD_::wostringstream tostringstream;
   typedef STD_::wistringstream tistringstream;
END_DTL_NAMESPACE
#else
BEGIN_DTL_NAMESPACE 
   typedef STD_::string tstring;
   typedef STD_::ostream tostream;
#  ifndef  __SUNPRO_CC
         static STD_::ostream &tcout = STD_::cout; 
#  else
#    define tcout STD_::cout
#  endif
   typedef STD_::ostringstream tostringstream;  //erste Fehlermeldung
   typedef STD_::istringstream tistringstream;
END_DTL_NAMESPACE
#endif 

BEGIN_DTL_NAMESPACE
#if !defined (__GNUC__)

bei dem libodbc++ bekomme ich die Fehlermeldungen:
Code:
C:\libodbc++-0.2.4pre3\win32>nmake /f makefile.w32 CFG=debug-dll
Open Watcom C/C++ NMAKE Clone for 386  Version 1.5
Portions Copyright (c) 1995-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See https://www.openwatcom.org/ for details.
makefile.w32(222): Warning(W18): Unrecognized or out of place character '+'
makefile.w32(222): Warning(W18): Unrecognized or out of place character '+'
makefile.w32(225): Warning(W18): Unrecognized or out of place character '+'
makefile.w32(225): Warning(W18): Unrecognized or out of place character '+'
makefile.w32(240): Error(E21): Extension(s) (.PHONY) not defined
Error(E02): Make execution terminated

MfG respawner
 
Ich weiß jetzt nicht, wozu "STD_" aufgelöst wird, der ISO C++ sieht jedenfalls "std" als Standardnamespace vor. Kann es sein, dass der Header schon etwas älter ist?

Das zweite Problem sieht nach einem Syntaxfehler o. ä. im Makefile aus. Kannst du das mal posten?
 
edit puh, keine ahnung wie alt die header-Datei ist, aber ich habe auch leider nichts anderes gefunden außer das libodbc.

das makefile:

Code:
#  This file is part of libodbc++.
#  
#  Copyright (C) 1999-2000 Manush Dodunekov <[email protected]>
#   
#  This library is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Library General Public
#  License as published by the Free Software Foundation; either
#  version 2 of the License, or (at your option) any later version.
#   
#  This library 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
#  Library General Public License for more details.
#  
#  You should have received a copy of the GNU Library General Public License
#  along with this library; see the file COPYING.  If not, write to
#  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#  Boston, MA 02111-1307, USA.

# Gee - an nmake makefile with actual cmd.exe scripting in action.

!IF "$(CFG)" == ""
!MESSAGE Usage: nmake /f makefile.w32 CFG=<config>
!MESSAGE where <config> is one of:
!MESSAGE   debug-dll    - Debug DLL
!MESSAGE   debug-lib    - Debug LIB
!MESSAGE   prod-dll     - Production DLL
!MESSAGE   prod-lib     - Production LIB
!MESSAGE   unicode-debug-dll - Debug DLL with Unicode
!MESSAGE   unicode-debug-lib - Debug LIB with Unicode
!MESSAGE   unicode-prod-dll  - Production DLL with Unicode
!MESSAGE   unicode-prod-lib  - Production LIB with Unicode
!MESSAGE   qt-debug-dll - Debug DLL with QT
!MESSAGE   qt-debug-lib - Debug LIB with QT
!MESSAGE   qt-prod-dll  - Production DLL with QT
!MESSAGE   qt-prod-lib  - Production LIB with QT
!ENDIF

!IF "$(CFG)" != "debug-dll" && "$(CFG)" != "prod-dll" && \
    "$(CFG)" != "debug-lib" && "$(CFG)" != "prod-lib" && \
    "$(CFG)" != "unicode-debug-dll" && "$(CFG)" != "unicode-prod-dll" && \
    "$(CFG)" != "unicode-debug-lib" && "$(CFG)" != "unicode-prod-lib" && \
    "$(CFG)" != "qt-debug-dll" && "$(CFG)" != "qt-prod-dll" && \
    "$(CFG)" != "qt-debug-lib" && "$(CFG)" != "qt-prod-lib"
!ERROR Invalid configuration "$(CFG)"
!ENDIF

# utilities
CXX=cl
LD=link
AR=lib

# dirs
SRCDIR=..\src
INCDIR=..\include
OBJDIR=.\$(CFG)

!IF "$(QT_VERSION)" == ""
QT_VERSION=202
!ENDIF

# utility flags
QT_CXXFLAGS=
QT_LDFLAGS=
DEBUG_CXXFLAGS=
DEBUG_LDFLAGS=
DLL_CXXFLAGS=
DLL_LDFLAGS=
PROD_CXXFLAGS=
PROD_LDFLAGS=
UNICODE_CXXFLAGS=
UNICODE_LDFLAGS=

# naming variables
TARGET_BASE=odbc++
TARGET_D=
TARGET_S=
TARGET_QT=
TARGET_W=
TARGET_EXT=

DLL=no
PROD=no
QT=no
UNICODE=no

!IF "$(CFG)" == "debug-dll" || "$(CFG)" == "prod-dll" || \
    "$(CFG)" == "unicode-debug-dll" || "$(CFG)" == "unicode-prod-dll" || \
    "$(CFG)" == "qt-debug-dll" || "$(CFG)" == "qt-prod-dll"

DLL=yes

!ENDIF

!IF "$(CFG)" == "prod-dll" || "$(CFG)" == "prod-lib" || \
    "$(CFG)" == "unicode-prod-dll" || "$(CFG)" == "unicode-prod-lib" || \
    "$(CFG)" == "qt-prod-dll" || "$(CFG)" == "qt-prod-lib"

PROD=yes

!ENDIF

!IF "$(CFG)" == "qt-debug-lib" || "$(CFG)" == "qt-prod-lib" || \
    "$(CFG)" == "qt-debug-dll" || "$(CFG)" == "qt-prod-dll"

QT=yes

!ENDIF

!IF "$(CFG)" == "unicode-debug-lib" || "$(CFG)" == "unicode-prod-lib" || \
    "$(CFG)" == "unicode-debug-dll" || "$(CFG)" == "unicode-prod-dll"

UNICODE=yes

!ENDIF


!IF "$(DLL)" == "yes"
# we are building a DLL

TARGET_EXT=dll

!IF "$(PROD)" != "yes"
DLL_LDFLAGS=/DEBUG
DLL_CXXFLAGS=/DODBCXX_DLL /MDd
!ELSE
DLL_LDFLAGS=/DEBUG /OPT:REF
DLL_CXXFLAGS=/DODBCXX_DLL /MD
!ENDIF

!ELSE

# we are building a static library
TARGET_EXT=lib
TARGET_S=s

!ENDIF


!IF "$(PROD)" == "yes"
# we are optimizing
PROD_CXXFLAGS=/O2

!ELSE

# we are building a debug version
TARGET_D=d

DEBUG_CXXFLAGS=/Zi /DODBCXX_DEBUG

!ENDIF


!IF "$(QT)" == "yes"

QT_CXXFLAGS=/DODBCXX_QT /I$(QTDIR)\include

!IF "$(DLL)" == "yes"
QT_CXXFLAGS=$(QT_CXXFLAGS) /DQT_DLL
!ENDIF

QT_LDFLAGS=$(QTDIR)\lib\qt$(QT_VERSION).lib
TARGET_QT=qt

!ENDIF

!IF "$(UNICODE)" == "yes"
UNICODE_CXXFLAGS=/DODBCXX_UNICODE
TARGET_UNICODE=w
!ENDIF


TARGET_NAME=$(TARGET_BASE)$(TARGET_QT)$(TARGET_UNICODE)$(TARGET_S)$(TARGET_D).$(TARGET_EXT)

!IF "$(DLL)" == "yes"
ILIB_NAME=$(TARGET_BASE)$(TARGET_QT)$(TARGET_UNICODE)$(TARGET_S)$(TARGET_D).lib
!ENDIF


# /GR enable RTTI
# /GX enable EH
# /Fo<file> object file name
# /Dname define macro
# /Idir search dir for includes
# /Zi generate debug info
# /c compile only 
# /nologo ditch copyright message
# /TP everything is c++

CXXFLAGS=/nologo /GR /GX /W3 /DWIN32 /DIN_ODBCXX /I$(INCDIR) /Fd"$(PDB)" \
$(QT_CXXFLAGS) $(UNICODE_CXXFLAGS) $(DEBUG_CXXFLAGS) $(DLL_CXXFLAGS) $(PROD_CXXFLAGS)

LDFLAGS=kernel32.lib user32.lib odbc32.lib odbccp32.lib \
$(QT_LDFLAGS) $(UNICODE_LDFLAGS) $(DEBUG_LDFLAGS) $(DLL_LDFLAGS) $(PROD_LDFLAGS) \
/NOLOGO /SUBSYSTEM:WINDOWS /DLL /implib:"$(ILIB)" /pdb:"$(PDB)" /incremental:no


ARFLAGS=/NOLOGO /SUBSYSTEM:WINDOWS


TARGET=$(OBJDIR)\$(TARGET_NAME)
ILIB=$(OBJDIR)\$(ILIB_NAME)
PDB=$(OBJDIR)\$(TARGET_NAME).pdb

OBJS= \
$(OBJDIR)\threads.obj \
$(OBJDIR)\datetime.obj \
$(OBJDIR)\drivermanager.obj \
$(OBJDIR)\connection.obj \
$(OBJDIR)\driverinfo.obj \
$(OBJDIR)\databasemetadata.obj \
$(OBJDIR)\statement.obj \
$(OBJDIR)\preparedstatement.obj \
$(OBJDIR)\callablestatement.obj \
$(OBJDIR)\resultset.obj \
$(OBJDIR)\resultsetmetadata.obj \
$(OBJDIR)\errorhandler.obj \
$(OBJDIR)\datahandler.obj \
$(OBJDIR)\datastream.obj


all: $(TARGET)


$(TARGET): $(OBJS)
!IF "$(DLL)" == "yes"
	$(LD) $(LDFLAGS) /OUT:"$(TARGET)" $**
!ELSE
	$(AR) $(ARFLAGS) /OUT:"$(TARGET)" $**
!ENDIF

$(OBJS): $(OBJDIR) 


# Makefile.w32

$(OBJDIR):
	@if not exist "$(OBJDIR)/" mkdir $(OBJDIR)

.PHONY: clean

clean:
	-@erase $(OBJS)
	-@erase $(TARGET)
	-@erase $(PDB)
!IF "$(DLL)" == "yes"
	-@erase $(ILIB)
!ENDIF
	@if exist "$(OBJDIR)/" rmdir $(OBJDIR)

.SUFFIXES: .cpp .obj

{$(SRCDIR)\}.cpp{$(OBJDIR)\}.obj:
	$(CXX) $(CXXFLAGS) /Fo"$@" /c /TP $<

ich muss aber zugeben, dass das meine erste Berührung mit C++ ist, also bin recht unbeholfen.


EDIT

habe auch OTL versucht (ist von 2006)
https://otl.sourceforge.net
dieses Beispiel https://otl.sourceforge.net/otl4_ex300.htm


Code:
#if defined(OTL_NO_TMPL_MEMBER_FUNC_SUPPORT)

  OTL_D1(int,otl_var_int)
#if defined(OTL_BIGINT)
  OTL_D1(OTL_BIGINT,otl_var_bigint)
#endif
  OTL_D1(unsigned,otl_var_unsigned_int)
  OTL_D1(long,otl_var_long_int)
  OTL_D1(short,otl_var_short)
  OTL_D1(float,otl_var_float)
  OTL_D1(double,otl_var_double)

#else
  template<OTL_TYPE_NAME T,const int T_type> OTL_D1(T,T_type) //Hier passiert der erste Fehler
#endif

MfG respawner
 
Zuletzt bearbeitet:
Zu dem Makefile: Probier mal mit auskommentierter Zeile 240 (mit .PHONY).

Und das andere ist .. merkwürdig. Vermutlich verträgt sich der Compiler nicht mit dem Header, irgendwas nicht-standardkonformes. Kann sein, dass Compiler oder Lib zu alt sind, oder dass typedefs fehlen. (Also es fehlen auf jeden Fall typedefs, sonst würde er nicht meckern :p. Frage ist nur, wo die sind.)
 
BFabian schrieb:
Zu dem Makefile: Probier mal mit auskommentierter Zeile 240 (mit .PHONY).

Und das andere ist .. merkwürdig. Vermutlich verträgt sich der Compiler nicht mit dem Header, irgendwas nicht-standardkonformes. Kann sein, dass Compiler oder Lib zu alt sind, oder dass typedefs fehlen. (Also es fehlen auf jeden Fall typedefs, sonst würde er nicht meckern :p. Frage ist nur, wo die sind.)
hilft leider auch nicht:

Code:
C:\libodbc++-0.2.4pre3\win32>nmake /f makefile.w32 CFG=debug-dll
Open Watcom C/C++ NMAKE Clone for 386  Version 1.5
Portions Copyright (c) 1995-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See https://www.openwatcom.org/ for details.
makefile.w32(222): Warning(W18): Unrecognized or out of place character '+'
makefile.w32(222): Warning(W18): Unrecognized or out of place character '+'
makefile.w32(225): Warning(W18): Unrecognized or out of place character '+'
makefile.w32(225): Warning(W18): Unrecognized or out of place character '+'
cl /nologo /GR /GX /W3 /DWIN32 /DIN_ODBCXX /I..\include /Fd".\debug-dll\odbc++d.
dll.pdb"   /Zi /DODBCXX_DEBUG /DODBCXX_DLL /MDd  /Fo".\debug-dll\threads.obj" /c
 /TP ..\src\threads.cpp
Open Watcom C/C++ CL Clone for 386  Version 1.5
Portions Copyright (c) 1995-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See https://www.openwatcom.org/ for details.
Warning: Ignoring invalid option 'GR'
Warning: Replacing unsupported /Zi with /Z7
Warning: Using Dwarf debugging information
Warning: Ignoring invalid option 'TP'
Warning: Ignoring unsupported option(s): /Fd
..\src\threads.cpp
..\include\odbc++\config-win32.h(101): Error! E059: col(20) unable to open 'wind
ows.h'
..\include\odbc++\config-win32.h(101): Note! N393: col(20) included from ..\incl
ude\odbc++\setup.h(32)
..\include\odbc++\config-win32.h(101): Note! N393: col(20) included from ..\incl
ude\odbc++\threads.h(25)
..\include\odbc++\config-win32.h(101): Note! N393: col(20) included from ..\src\
threads.cpp(1)
..\include\odbc++\setup.h(84): Error! E059: col(19) unable to open 'cassert'
..\include\odbc++\threads.h(40): Error! E336: col(28) declaration specifiers are
 required to declare 'CRITICAL_SECTION'
..\include\odbc++\threads.h(40): Error! E006: col(22) syntax error; probable cau
se: missing ';'
..\include\odbc++\threads.h(43): Error! E121: col(22) syntax error
..\include\odbc++\threads.h(44): Error! E336: col(10) declaration specifiers are
 required to declare 'Mutex'
..\include\odbc++\threads.h(44): Error! E121: col(10) syntax error
..\include\odbc++\threads.h(46): Error! E121: col(3) syntax error
..\include\odbc++\threads.h(48): Error! E252: col(11) class declaration has not
been seen for '~Mutex'
..\include\odbc++\threads.h(48): Error! E265: col(13) destructor must be a non-s
tatic member function
..\include\odbc++\threads.h(48): Error! E121: col(13) syntax error
..\include\odbc++\threads.h(52): Error! E121: col(4) syntax error
..\include\odbc++\threads.h(56): Error! E336: col(10) declaration specifiers are
 required to declare 'Mutex'
..\include\odbc++\threads.h(56): Error! E006: col(10) syntax error; probable cau
se: missing ';'
..\include\odbc++\threads.h(57): Error! E121: col(3) syntax error
..\include\odbc++\types.h(27): Error! E059: col(20) unable to open 'exception'
..\include\odbc++\types.h(30): Error! E059: col(18) unable to open 'string'
..\include\odbc++\types.h(35): Error! E059: col(16) unable to open 'ctime'
..\include\odbc++\types.h(50): Error! E059: col(17) unable to open 'sql.h'
..\include\odbc++\types.h(51): Error! E059: col(20) unable to open 'sqlext.h'
..\include\odbc++\types.h(57): Error! E133: col(22) too many errors: compilation
 aborted
Error(E42): Last command making (.\debug-dll\threads.obj) returned a bad status
Error(E02): Make execution terminated

der Compiler ist auch von April 2006 (Open Watcom 1.5)

edit
hast du vielleicht einen Tipp für einen Compiler (müsste aber Open Source oder Freeware sein, für kommerzielle Zwecke). Oder eine andere ODBC-Library. Ich brauch das für meine Diplomarbeit. Das Programm soll zwar aufgesetzt werden, dass schon eine Anbindung mit ODBC hat (es wurde mit Visual C++ 6 geschrieben, soweit ich weiß) aber alleine schon, da ich ständig mit den Daten der Datenbank arbeiten muss, wäre es gut wenn ich das direkt einbinden könnte in meinem Programm. Das Programm oder eher Teile davon werden wohl irgendwann kommerziell eingesetzt, so dass ich nicht mit mein Visual Studio .NET 2003 (von der FH/M$ gestellt, aber nur für nichtkommerzielle Zwecke) arbeiten kann. Ich kann auch nicht in der Schule an einer Lizenz arbeiten, da ich bereits mein Zimmer im Studentenwohnheim gekündigt habe und 160km von der FH entfernt wohne.
Naja, morgen fahre ich sowieso noch Regensburg für eine Besprechung mit dem Prof und zur Datensammlung. Aber wäre halt gut wenn ich schon was festes hätte (also einen Compiler/ODBC-Bibliothek), da der Prof sowieso nicht so viel Ahnung von C++ hat (Gut ich bin selber schuld weil ich mir C++ ausgewählt habe (um die Sprache zu lernen)).

MfG respawner
 
Zuletzt bearbeitet:
Hilft wohl, die anderen Fehler kommen vom Compiler ;).
Wenn du Windows32-Bibliotheken im Watcom-Compiler installiert hast, ist wohl ein Pfad falsch gesetzt: "..\include\odbc++\config-win32.h(101): Error! E059: col(20) unable to open 'windows.h'". Guck mal wo die liegt, den Pfad musst du dann anpassen (wie genau die Optionen für den Compiler dafür aussehen: ka..). Wenn windows.h unauffindbar ist, brauchst du noch die Windows-Header und Libs.

Hierzu:
..\include\odbc++\types.h(27): Error! E059: col(20) unable to open 'exception'
..\include\odbc++\types.h(30): Error! E059: col(18) unable to open 'string'
..\include\odbc++\types.h(35): Error! E059: col(16) unable to open 'ctime'
Die drei sind alle Standard-C++-Headers. Die müssen dabei sein, nur der Pfad ist im Makefile offenbar wieder nicht gesetzt.

..\include\odbc++\types.h(50): Error! E059: col(17) unable to open 'sql.h'
..\include\odbc++\types.h(51): Error! E059: col(20) unable to open 'sqlext.h'
Die beiden haben ganz offensichtlich etwas mit einer SQL-Bibliothek zu tun. Auch da fehlt wohl der Pfad.

EDIT:
Von Windows-Compilern hab ich seit ein paar Jahren nicht mehr so die Ahnung ;). Es gibt wohl eine Portierung der GCC (könnte man dann in Cygwin aufsetzen), aber da kann es passieren, dass du Probleme mit Bibliotheken bekommst, die für MSVC++ compiliert sind (oder mit Makefiles für nmake). Einen Versuch wäre das aber sicher Wert, kostet ja nix ;).
 
habe das jetzt direkt zu den header-Dateien von WATCOM reingeworfen.
Jetzt bekomme ich aber wieder so typedef-Probleme wie:



irgendwie ist das ziemlich deprimierend.

Code:
#ifdef __cplusplus
extern "C" {
#endif
#define SQL_API __stdcall
#ifndef RC_INVOKED
#define __need_wchar_t
#include <stddef.h>
typedef signed char SCHAR;
typedef long SDWORD;
typedef short SWORD;
typedef ULONG UDWORD;  //1. Fehler

habe es mit dem Compiler miniGW (das ist ein GCC-Ding)
Das includen der header-Dateien ist kein Problem, aber die Beispielprogramme lassen sich trotzdem nicht kompilieren:

Code:
/*
   This file is part of libodbc++.

   Copyright (C) 1999-2000 Manush Dodunekov <[email protected]>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/


/*
  This should work with almost any almost-compliant database out there,
  providing it supports scrollable cursors.
 */


#include <odbc++/drivermanager.h>
#include <odbc++/connection.h>
#include <odbc++/databasemetadata.h>
#include <odbc++/resultset.h>
#include <odbc++/resultsetmetadata.h>
#include <odbc++/preparedstatement.h>

#include <iostream>
#include <memory>

using namespace odbc;
using namespace std;

#if !defined(ODBCXX_QT)
# include <sstream>
#else

# undef ASSERT

basic_ostream<ODBCXX_CHAR_TYPE> ostream& operator<<(basic_ostream<ODBCXX_CHAR_TYPE>& o,
                                                    const QString& s)
{
  o << ODBCXX_STRING_CSTR(s);
  return o;
}
#endif

static int assertionsFailed=0;

#define ASSERT(x)                                              \
do {                                                           \
  if(!(x)) {                                                   \
    ODBCXX_CERR << ODBCXX_STRING_CONST("Assertion \"") << #x   \
                << ODBCXX_STRING_CONST("\" failed") << endl;   \
    assertionsFailed++;                                        \
  }                                                            \
} while(false)

#define NAME_PREFIX ODBCXX_STRING_CONST("odbcxx_")

#define TABLE_NAME NAME_PREFIX ODBCXX_STRING_CONST("test")

#define TABLE_ROWS 1000

static void commit(Connection* con)
{
  if(con->getMetaData()->supportsTransactions()) {
    con->commit();
  }
}

static void createStuff(Connection* con)
{
  // create our table
  std::auto_ptr<Statement> stmt=std::auto_ptr<Statement>(con->createStatement());
  stmt->executeUpdate
    (ODBCXX_STRING_CONST("create table ") TABLE_NAME ODBCXX_STRING_CONST("(")
     ODBCXX_STRING_CONST("id integer not null primary key, ")
     ODBCXX_STRING_CONST("name varchar(40) not null)"));

  ODBCXX_COUT << ODBCXX_STRING_CONST("Table ") << TABLE_NAME
              << ODBCXX_STRING_CONST(" created.") << endl;
}

// Drops the database objects.

static void dropStuff(Connection* con)
{
  std::auto_ptr<Statement> stmt=std::auto_ptr<Statement>(con->createStatement());
  try {
    stmt->executeUpdate(ODBCXX_STRING_CONST("drop table ") TABLE_NAME);
    ODBCXX_COUT << ODBCXX_STRING_CONST("Dropped table ") << TABLE_NAME << endl;
  } catch(SQLException& e) {
  }
}

static const ODBCXX_STRING makeName(int n)
{
#if !defined(ODBCXX_QT)
  basic_ostringstream<ODBCXX_CHAR_TYPE> ss;
  ss << ODBCXX_STRING_CONST("This is row number ") << n;
  return ss.str();
#else
  QString s(ODBCXX_STRING_CONST("This is row number "));
  s+=QString::number(n);
  return s;
#endif
}


static void populate(Connection* con)
{
  {
    std::auto_ptr<PreparedStatement> pstmt
      =std::auto_ptr<PreparedStatement>(con->prepareStatement
      (ODBCXX_STRING_CONST("insert into ") TABLE_NAME
       ODBCXX_STRING_CONST(" (id,name) values(?,?)")));
    for(int i=0; i<TABLE_ROWS; i++) {
      pstmt->setInt(1,i);
      pstmt->setString(2,makeName(i));
      pstmt->executeUpdate();
    }
    commit(con);
    ODBCXX_COUT << ODBCXX_STRING_CONST("Inserted ")
                << TABLE_ROWS << ODBCXX_STRING_CONST(" rows.") << endl;
  }
}


static void compare(Connection* con)
{
  // decide whether we should use a scroll insensitive
  // or a scroll sensitive cursor

  int rstype;
  int rsconc;
  DatabaseMetaData* md=con->getMetaData();

  if(md->supportsResultSetType(ResultSet::TYPE_SCROLL_INSENSITIVE)) {
    rstype=ResultSet::TYPE_SCROLL_INSENSITIVE;
  } else if(md->supportsResultSetType(ResultSet::TYPE_SCROLL_SENSITIVE)) {
    rstype=ResultSet::TYPE_SCROLL_SENSITIVE;
  } else {
    ODBCXX_COUT << ODBCXX_STRING_CONST("Skipping compare, data source does ")
                   ODBCXX_STRING_CONST("not support scrollable cursors")
                << endl;
    return;
  }


  if(md->supportsResultSetConcurrency(rstype,ResultSet::CONCUR_READ_ONLY)) {
    // this is all we need
    rsconc=ResultSet::CONCUR_READ_ONLY;
  } else {
    rsconc=ResultSet::CONCUR_UPDATABLE;
  }

  std::auto_ptr<Statement> stmt=std::auto_ptr<Statement>(con->createStatement
    (rstype,rsconc));
  std::auto_ptr<ResultSet> rs=std::auto_ptr<ResultSet>(stmt->executeQuery
    (ODBCXX_STRING_CONST("select id,name from ") TABLE_NAME));

  ASSERT(rs->isBeforeFirst());
  ASSERT(rs->first());
  ASSERT(!rs->isBeforeFirst());
  ASSERT(rs->isFirst());

  ASSERT(rs->last());
  ASSERT(rs->isLast());
  ASSERT(!rs->isAfterLast());
  rs->afterLast();
  ASSERT(rs->isAfterLast());

  ASSERT(rs->previous());
  ASSERT(rs->isLast());


  ODBCXX_COUT << ODBCXX_STRING_CONST("Positioned on the last row (")
              << rs->getRow() << ODBCXX_STRING_CONST(")") << endl;
  int i=TABLE_ROWS;

  do {
    i--;
    ODBCXX_STRING name(makeName(i));
    ASSERT(rs->getInt(1) == i);
    ASSERT(rs->getString(2)==name);
  } while(rs->previous());
  ASSERT(i==0);
  ASSERT(rs->isBeforeFirst());
  ODBCXX_COUT << TABLE_ROWS
              << ODBCXX_STRING_CONST(" rows checked with expected values.")
              << endl;
}





int main(int argc, char** argv)
{
  if(argc!=2 && argc!=4) {
    cerr << "Usage: " << argv[0] << " connect-string" << endl
         << "or     " << argv[0] << " dsn username password" << endl;
    return 0;
  }
  try {
    std::vector<ODBCXX_STRING> vargv(argc-1);
    const size_t MAX_CHARS = 256;
    for(int i=1;i<argc;++i)
    {
      ODBCXX_STRING& arg=vargv[i-1];
#if defined(ODBCXX_UNICODE)
      wchar_t buffer[MAX_CHARS];
      size_t len=mbstowcs(buffer,argv[i],MAX_CHARS);
      if(0<len&&MAX_CHARS>len)
      {
         arg=buffer;
      }
#else
      arg=argv[i];
#endif
    }
    std::auto_ptr<Connection> con;
    if(argc==2) {
      ODBCXX_COUT << ODBCXX_STRING_CONST("Connecting to ") << vargv[0]
                  << ODBCXX_STRING_CONST("...") << flush;
      con=std::auto_ptr<Connection>(DriverManager::getConnection(vargv[0]));
    } else {
      ODBCXX_COUT << ODBCXX_STRING_CONST("Connecting to dsn=") << vargv[0]
                  << ODBCXX_STRING_CONST(", uid=") << vargv[1]
                  << ODBCXX_STRING_CONST(", pwd=") << vargv[2]
                  << ODBCXX_STRING_CONST("...") << flush;
      con=std::auto_ptr<Connection>(DriverManager::getConnection(vargv[0],vargv[1],vargv[2]));
    }
    ODBCXX_COUT << ODBCXX_STRING_CONST(" done.") << endl;

    // we don't want autocommit
    if(con->getMetaData()->supportsTransactions()) {
      con->setAutoCommit(false);
    }
//      con->setTraceFile("/tmp/fisk");
//      con->setTrace(true);

    dropStuff(con.get());
    createStuff(con.get());

    populate(con.get());
    compare(con.get());
    commit(con.get());

    dropStuff(con.get());


    commit(con.get());

    if(assertionsFailed>0) {
      ODBCXX_COUT << assertionsFailed
                  << ODBCXX_STRING_CONST(" assertions failed.") << endl;
    }
  } catch(SQLException& e) {
    ODBCXX_CERR << endl << e.getMessage() << endl;
    return 1;
  }

  return 0;
}

führt zu:

Code:
----- bisp ( MAIN GCC DEBUG DEBUG_FULL BLITZ WIN32 )
bisp.cpp
bisp: 1 file(s) built in (0:01.43), 1437 msecs / file, duration = 1453 msecs
Linking...
(option '-O 2' ignored)
___main: duplicate
-> used:      libmingw32.a:gccmain.o:1
-> discarded: libgcc.a:__main.o:1
25 undefined symbol(s):
odbc::Connection::getMetaData()      (referenced from c:\upp\out\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char const*, 
	unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&); commit(odbc::Connection *); commit(odbc:
	:Connection*); ...)
odbc::Connection::setAutoCommit(bool)  (referenced from c:\upp\out\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char const*
	, unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&); commit(odbc::Connection *); commit(odb
	c::Connection*); ...)
odbc::Connection::createStatement(int, int)(referenced from c:\upp\out\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char co
	nst*, unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&); commit(odbc::Connection *); commit
	(odbc::Connection*); ...)
odbc::Connection::createStatement()      (referenced from c:\upp\out\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char cons
	t*, unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&); commit(odbc::Connection *); commit(o
	dbc::Connection*); ...)
odbc::Connection::prepareStatement(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)(referenced from c:\upp\o
	ut\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char const*, unsigned int, std::basic_string<char, std::char_traits<cha
	r>, std::allocator<char> > const&); commit(odbc::Connection *); commit(odbc::Connection*); ...)
odbc::Connection::commit()     (referenced from c:\upp\out\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char const*, unsign
	ed int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&); commit(odbc::Connection *); commit(odbc::Conne
	ction*); ...)
odbc::DriverManager::getConnection(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)(referenced from c:\upp\o
	ut\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char const*, unsigned int, std::basic_string<char, std::char_traits<cha
	r>, std::allocator<char> > const&); commit(odbc::Connection *); commit(odbc::Connection*); ...)
...

odbc::ResultSet::getString(int) (referenced from c:\upp\out\bisp\mingw.debug_full.main\bisp.o:1; std::__verify_grouping(char const*, unsig
	ned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&); commit(odbc::Connection *); commit(odbc::Conn
	ection*); ...)
linking aborted due to fatal errors
collect2: ld returned 1 exit status

There were errors. (0:01.90)

MfG respawner
 
Zuletzt bearbeitet:
Das Zweite (GCC) sieht sehr gut aus. Die Datei wird einwandfrei compiliert. Nur beim Linken harkts, er kann die Funktionen aus der odbc-Bibliothek nicht auflösen. Hast du etwas wie -lodbc beim g++-Aufruf angegeben? Falls ja, stimmt der Pfad (-L DER/PFAD/WO/libodbc.a/ODERSO/LIEGT)?
Du bist sozusagen auf der Zielgeraden ;).
 
hab da wohl Mist gebaut nur die h- und cpp-Dateien zu kopieren. Also muss ich das libodbc doch erst kompilieren. Aber das bekomme ich einfach nicht hin.

MfG respawner
 
Der unsauberste Weg wäre da einfach, die C++-Sources der Lib mit deinem Programm in einen Ordner zu legen und beim Compilieren anzugeben, dass er die bitte mit übersetzen soll. Sauber könnte es mit configure, make und make install gehen (vorrausgesetzt, configure-Script und makefile liegen bei ...).
 
werde ich später mal versuchen. Wenn ich das immer noch nicht hinbekommen habe nehme ich Visual Studio (der Prof meinte heute es wäre kein Problem), auch wenn mir die OS-Variante natürlich lieber ist.

MfG respawner