/*
===========================================
   responsible:    DanielD
   description:    Interface to the SAP DB Loader
   target:         Python
   last changed:   06.09.2006

    ========== licence begin  GPL
    Copyright (c) 2000-2006 SAP AG

    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 2
    of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
    ========== licence end
===========================================*/


#include <stddef.h>

#if defined (HPUX) || defined (AIX) || defined (SUN) || defined (SOLARIS) || defined (OSF1) || defined (LINUX) || defined (FREEBSD)
#define BAD_STATIC_FORWARD
#endif

#include "Python.h"/* no check */

#if PY_MAJOR_VERSION >= 2 && PY_MINOR_VERSION >= 4
#else
#if defined (HPUX) || defined (AIX) || defined (SUN) || defined (SOLARIS) || defined (OSF1)
#undef statichere
#define statichere
#endif
#endif

#if defined HP_IA64
#undef statichere
#define statichere static
#endif

#define MF__
#if defined (__cplusplus)
#define externC extern "C"
#define internC extern "C" static
#else
#define externC
#define internC static
#endif
#define PYTHON_GLUE 1

#define Glue_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#define Glue_END_ALLOW_THREADS Py_END_ALLOW_THREADS

#if defined (__cplusplus)
#define LIT(c) CONST_CAST(char *, c)
#else
#define LIT(c) (c)
#endif

#if defined (_WIN32)
#define GLUEEXPORT __declspec(dllexport)
#else
#define GLUEEXPORT
#endif

#if PYTHON_API_VERSION < 1009
#define PyObject_Del(ptr) free (ptr)
#endif

#define SL_None Py_None
#define SL_isNone(val) (val == SL_None)
#define SL_isTrue(val) PyObject_IsTrue (val)

static PyObject *
createExceptionKind (
    const char * exceptionName,
    const char * exceptionCode)
{
    PyObject * result;
    PyObject * runResult = NULL;
    PyObject * globals = NULL;
    PyObject * locals = NULL;

    if (exceptionCode != NULL) {
        globals = PyDict_New ();
        locals = PyDict_New ();
        runResult = PyRun_String ((char *) exceptionCode, Py_file_input,
            globals, locals);
        if (PyErr_Occurred ()) {
            PyErr_Print ();
        }
    }
    result = PyErr_NewException ((char *) exceptionName, NULL, locals);
    Py_XDECREF (locals);
    Py_XDECREF (globals);
    Py_XDECREF (runResult);
    return result;
}

static PyObject *CommunicationErrorType;
static const char * CommunicationErrorCodeC = 
    "\n"
    "def __str__ (self):\n"
    "    return \"loader.CommunicationError: [%d] %s\" % (self.errorCode, self.message)\n"
    "\n";
static PyObject *LoaderErrorType;
static const char * LoaderErrorCodeC = 
    "\n"
    "def __str__ (self):\n"
    "    if self.sqlCode:\n"
    "        return 'loader.LoaderError: [%d] SQL [%d] %s' % (\n"
    "            self.errorCode, self.sqlCode, self.sqlMessage)\n"
    "    else:\n"
    "        return 'loader.LoaderError: [%d] %s' % (self.errorCode, self.message)\n"
    "\n";
/* snippet Python_precode */
#define CN72 1
#include "hsp100.h"
#include "hcn14.h"

#if defined (__cplusplus)
#define REFPARM(name)   name
#define INLINE          inline
#else
#define REFPARM(name)   &name
#define INLINE

#undef ROUTINE_DBG_MSP00
#define ROUTINE_DBG_MSP00(lit) static const char * funcname_glue_ = lit

#define REINTERPRET_CAST(type, expr) ((type) expr)
#define STATIC_CAST(type, expr) ((type) expr)
#define CONST_CAST(type, expr) ((type) expr)
#define REFCAST_MEO00(type)
#endif

static const char * SQLErrorTagC = "SQL error ";

typedef struct ReplyInfoT {
    tsp00_Int4        errCode;
    const _TCHAR  * errText;
    tsp00_Int4        errLen;
    tsp00_Int4        sqlCode;
    const _TCHAR  * sqlErrText;
    tsp00_Int4        sqlErrLen;
} ReplyInfoT;

static void trimPayload (
    const void * dataArg,
    tsp00_Int4 * len);

/*----------------------------------------*/

static void
raiseCommunicationError (
    int code,
    const char * msg)
{
    ROUTINE_DBG_MSP00 ("raiseCommunicationError");
    PyObject * exception = PyInstance_New (CommunicationErrorType, NULL, NULL);
    PyObject * pycode = NULL;
    PyObject * pymsg = NULL;

    pycode = PyInt_FromLong  (code);
    pymsg = PyString_FromString  (msg);
    if (exception != NULL) {
        PyObject_SetAttrString (exception, LIT ("errorCode"), pycode) ;
        PyObject_SetAttrString (exception, LIT ("message"), pymsg);
    }
    else {
        exception = Py_BuildValue (LIT ("NN"), pycode, pymsg);
    }
    PyErr_SetObject (CommunicationErrorType, exception);
    Py_XDECREF (pycode);
    Py_XDECREF (pymsg);
    Py_XDECREF (exception);
}

/*----------------------------------------*/

static void
raiseLoaderError (
    ReplyInfoT * replyInfo,
    const char * cmd)
{
    ROUTINE_DBG_MSP00 ("raiseLoaderError");
    PyObject * exception = PyInstance_New (LoaderErrorType, NULL, NULL);
    PyObject * errorCode;
    PyObject * message;
    PyObject * sqlCode;
    PyObject * sqlMessage;
    PyObject * cmdObject;

    errorCode = PyInt_FromLong  (replyInfo->errCode);
    if ((replyInfo->errLen > 0) && (replyInfo->errText [replyInfo->errLen - 1] == '\n')) {
        --replyInfo->errLen;
    }
    message = PyString_FromStringAndSize (replyInfo->errText, replyInfo->errLen);
    sqlCode = PyInt_FromLong  (replyInfo->sqlCode);
    sqlMessage = PyString_FromStringAndSize (replyInfo->sqlErrText, replyInfo->sqlErrLen);
    cmdObject = PyString_FromString (cmd);
    if (exception != NULL) {
        PyObject_SetAttrString (exception, LIT ("errorCode"), errorCode) ;
        PyObject_SetAttrString (exception, LIT ("message"), message);
        PyObject_SetAttrString (exception, LIT ("sqlCode"), sqlCode);
        PyObject_SetAttrString (exception, LIT ("sqlMessage"), sqlMessage);
        PyObject_SetAttrString (exception, LIT ("cmd"), cmdObject);
    }
    else {
        exception = Py_BuildValue (LIT ("NNNNN"), errorCode, message,
            sqlCode, sqlMessage, cmdObject);
    }
    PyErr_SetObject (LoaderErrorType, exception);
    Py_XDECREF (errorCode);
    Py_XDECREF (message);
    Py_XDECREF (sqlCode);
    Py_XDECREF (sqlMessage);
    Py_XDECREF (cmdObject);
    Py_XDECREF (exception);
}

/*----------------------------------------*/

static int
errorOccured (int rc, tsp00_ErrTextc msg, char * croakBuf)
{
    if (rc != 0) {
        raiseCommunicationError (rc, msg);
        return 1;
    }
    else {
        return 0;
    }
}

/*----------------------------------------*/

static int
commErrOccured (int rc, tsp00_ErrTextc msg, char * croakBuf)
{
    if (rc != 0) {
        raiseCommunicationError (rc, msg);
        return 1;
    }
    else {
        return 0;
    }
}

/*----------------------------------------*/

static int
loaderErrOccured (
    void * nself,
    int rc,
    tsp00_ErrTextc msg,
    const char * cmd,
    char * croakBuf,
    int raiseSqlErrors)
{
    ReplyInfoT replyInfo;
    int errOccurred = 0;

    if (rc == DBMAPI_COMMERR_CN14) {
        raiseCommunicationError (1, msg);
        return 1;
    }
    else if (rc == DBMAPI_OK_CN14) {
        return 0;
    }
    cn14analyzeRpmAnswer (nself,
        &replyInfo.errCode, &replyInfo.errText, &replyInfo.errLen,
        &replyInfo.sqlCode, &replyInfo.sqlErrText, &replyInfo.sqlErrLen);
    if ((replyInfo.sqlCode != 0) && !raiseSqlErrors) {
        /* ignore */
    }
    else if ((replyInfo.errCode != 0) || (replyInfo.sqlCode != 0)) {
        errOccurred = 1;
        raiseLoaderError (&replyInfo, cmd);
    }
    return errOccurred;
}

/*----------------------------------------*/

typedef struct CommErrorT {
    int             code;
    tsp00_ErrTextc  msg;
} CommErrorT;

/*----------------------------------------*/

typedef struct LoaderErrorT {
    int             code;
    int             sqlCode;
    tsp00_ErrTextc  msg;
} LoaderErrorT;

#define croakBuf NULL

/* endsnippet Python_precode */
typedef struct LoaderObjectT {
    PyObject_HEAD
    void *nself;
/* no code for key Loader Python_/Generic_ in ['Generic_precode']*/
} LoaderObjectT;

staticforward PyTypeObject LoaderType;
#define isLoaderObject(op) ((op)->ob_type == &LoaderType)


static LoaderObjectT*
newLoader ()
{
    LoaderObjectT* result;

    result = PyObject_NEW (LoaderObjectT, &LoaderType);
    if (result != NULL) {
        memset (&result->nself, '\0', sizeof (LoaderObjectT) - offsetof (LoaderObjectT, nself));
    }
    return result;
}

static void
freeLoader (
    LoaderObjectT * value)
{
    Py_DECREF (value);
}
/* snippet Loader Generic_precode */

static char * buildInfo ()
{
    static tsp00_Versionc versionString;
    static bool isInitialized;
#if defined (PYTHON_GLUE)
    tsp100_CompName compName = "loaderpy ";
#elif defined (PERL_GLUE)
    tsp100_CompName compName = "loaderprl";
#else
    #error must be either Python or Perl
#endif

    if (!isInitialized) {
        sp100_GetVersionString (compName, s100buildnumber, versionString);
    }
    return versionString;
}

/*----------------------------------------*/

static void
trimPayload (
    const void * data,
    tsp00_Int4 * len)
{
    if (data != NULL) {
        const void * nullPos = memchr (data, '\0', *len);
        if (nullPos != NULL) {
            *len = (tsp00_Int4) (((const char *) nullPos) - ((const char *) data));
        }
    }
    else {
    *len = 0;
    }

}

/*----------------------------------------*/

static void
localRelease (
    void* nself)
{
    if (nself != NULL) {
        cn14release (&nself);
    }
}


/*----------------------------------------*/

#if defined (PYTHON_GLUE)
static void
destructor_Loader (
    PyObject * pyself)
{
    LoaderObjectT* self = REINTERPRET_CAST (LoaderObjectT*, pyself);

    localRelease (self->nself);
    PyObject_Del (pyself);
}
#endif

typedef struct ReadResultT {
    const char * data;
    int len;
} ReadResultT;

/*----------------------------------------*/

static tsp00_Int4 cmdAndRead (
   void * nself,
   const char * cmd,
   ReadResultT * output,
   tsp00_ErrTextc VAR_ARRAY_REF errtext)
{
    tsp00_Int4 rc;
    ReplyInfoT replyInfo;

    Glue_BEGIN_ALLOW_THREADS
    rc = cn14ExecuteLoaderCmd (nself, cmd, strlen (cmd), NULL, NULL, errtext);
    Glue_END_ALLOW_THREADS
    if (rc == DBMAPI_OK_CN14) {
        rc = cn14analyzeRpmAnswer (nself,
            &replyInfo.errCode, &replyInfo.errText, &replyInfo.errLen,
            &replyInfo.sqlCode, &replyInfo.sqlErrText, &replyInfo.sqlErrLen);
        if (replyInfo.errCode == 0) {
            output->data = replyInfo.errText;
            output->len = replyInfo.errLen;
        }
    }
    return rc;
}

/*----------------------------------------*/

static tsp00_Int4 rawCommand (
   void * nself,
   const char * cmd,
   ReadResultT * output,
   tsp00_ErrTextc VAR_ARRAY_REF errtext)
{
    tsp00_Int4 rc;

    Glue_BEGIN_ALLOW_THREADS
    rc = cn14ExecuteLoaderCmd (nself, cmd, strlen (cmd), NULL, NULL, errtext);
    Glue_END_ALLOW_THREADS
    if (rc == DBMAPI_OK_CN14) {
        output->len = cn14bytesAvailable (nself);
        output->data = cn14rawReadData (nself, &rc);
        if (output->data != NULL) {
            trimPayload (output->data, &output->len);
        }
    }
    return rc;
}

/*----------------------------------------*/

static int cancelCmd (
   void * nself)
{
    Glue_BEGIN_ALLOW_THREADS
    cn14cmdCancel (nself);
    Glue_END_ALLOW_THREADS
    return 0;
}

/*----------------------------------------*/

static int sql (
   void * nself,
   const char * cmd,
   tsp00_ErrTextc VAR_ARRAY_REF errtext)
{
    int result = 0;
    ReplyInfoT replyInfo;

    Glue_BEGIN_ALLOW_THREADS
    result = cn14ExecuteLoaderCmd (nself, cmd, strlen (cmd), NULL, NULL, errtext);
    Glue_END_ALLOW_THREADS
    if (result == DBMAPI_OK_CN14) {
        cn14analyzeRpmAnswer (nself,
            &replyInfo.errCode, &replyInfo.errText, &replyInfo.errLen,
            &replyInfo.sqlCode, &replyInfo.sqlErrText, &replyInfo.sqlErrLen);
        result = replyInfo.sqlCode;
    }
    return result;
}

/*----------------------------------------*/

#if defined (PYTHON_GLUE)
static int readResult2Python (
   void * nself,
   ReadResultT readResult,
   PyObject ** pyResult)
{
    *pyResult = PyString_FromStringAndSize (readResult.data, readResult.len);
    return *pyResult != NULL;
}
#endif

/*----------------------------------------*/

static int doConnect (
   const char * servernode,
   const char * dbname,
   const char * instroot,
   void      ** sessionOut,
   tsp00_ErrTextc VAR_ARRAY_REF errtext)
{
    int rc;

    Glue_BEGIN_ALLOW_THREADS
    rc = cn14connectRPM (
        REFCAST_MEO00 (tsp00_NodeIdc) servernode,
        REFCAST_MEO00 (tsp00_DbNamec) dbname,
        REFCAST_MEO00 (tsp00_VFilenamec) instroot,
        NULL, sessionOut, errtext);
    Glue_END_ALLOW_THREADS
    return rc;
}


/* endsnippet Loader Generic_precode */
/*----------------------------------------*/

static PyObject *
cmd_Loader (PyObject *pyself, PyObject* args, PyObject* keywds)
{
    ROUTINE_DBG_MSP00 ("cmd_Loader");  /* generated by Glue */
/* no code for key Python_/Generic_code */
    int ok = 1;
    LoaderObjectT* self = REINTERPRET_CAST (LoaderObjectT*, pyself);
    void* nself = self->nself;
    static const char * kwlist [] = {
        LIT("cmd"), NULL};
    char * cmd;
    ReadResultT output;
    PyObject * outputObj;
    tsp00_ErrTextc msg;
    tsp00_Int4 result;

    memset (&output, '\0', sizeof (ReadResultT));
    if (!PyArg_ParseTupleAndKeywords (args, keywds, LIT("s:Loader.cmd"), (char **) kwlist, &cmd)) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Python_/Generic_nativeCall */
    result = cmdAndRead (nself, cmd, &output, msg);
    if (loaderErrOccured (nself, result, msg, cmd, croakBuf, 1)) {
        ok = 0;
        goto cleanup_label;
    }
    /* outargs */
    if (!readResult2Python (self, output, &outputObj)) {
        ok = 0;
        goto cleanup_label;
    }
  cleanup_label:
    if (!ok) {
        return NULL;
    }
    return outputObj;
}

/*----------------------------------------*/

static PyObject *
rawCmd_Loader (PyObject *pyself, PyObject* args, PyObject* keywds)
{
    ROUTINE_DBG_MSP00 ("rawCmd_Loader");  /* generated by Glue */
/* no code for key Python_/Generic_code */
    int ok = 1;
    LoaderObjectT* self = REINTERPRET_CAST (LoaderObjectT*, pyself);
    void* nself = self->nself;
    static const char * kwlist [] = {
        LIT("cmd"), NULL};
    char * cmd;
    ReadResultT output;
    PyObject * outputObj;
    tsp00_ErrTextc msg;
    tsp00_Int4 result;

    memset (&output, '\0', sizeof (ReadResultT));
    if (!PyArg_ParseTupleAndKeywords (args, keywds, LIT("s:Loader.rawCmd"), (char **) kwlist, &cmd)) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Python_/Generic_nativeCall */
    result = rawCommand (nself, cmd, &output, msg);
    if (commErrOccured (result, msg, croakBuf)) {
        ok = 0;
        goto cleanup_label;
    }
    /* outargs */
    if (!readResult2Python (self, output, &outputObj)) {
        ok = 0;
        goto cleanup_label;
    }
  cleanup_label:
    if (!ok) {
        return NULL;
    }
    return outputObj;
}

/*----------------------------------------*/

static PyObject *
sql_Loader (PyObject *pyself, PyObject* args, PyObject* keywds)
{
    ROUTINE_DBG_MSP00 ("sql_Loader");  /* generated by Glue */
/* no code for key Python_/Generic_code */
    int ok = 1;
    LoaderObjectT* self = REINTERPRET_CAST (LoaderObjectT*, pyself);
    void* nself = self->nself;
    static const char * kwlist [] = {
        LIT("cmd"), NULL};
    char * cmd;
    tsp00_ErrTextc msg;
    int result;

    if (!PyArg_ParseTupleAndKeywords (args, keywds, LIT("s:Loader.sql"), (char **) kwlist, &cmd)) {
        ok = 0;
        goto cleanup_label;
    }
/* no code for key Python_/Generic_nativeCall */
    result = sql (nself, cmd, msg);
    if (loaderErrOccured (nself, result, msg, cmd, croakBuf, 0)) {
        ok = 0;
        goto cleanup_label;
    }
    /* outargs */
  cleanup_label:
    if (!ok) {
        return NULL;
    }
    return Py_BuildValue (LIT("i"), result);
}

/*----------------------------------------*/

static PyObject *
cancelCmd_Loader (PyObject *pyself, PyObject* args, PyObject* keywds)
{
    ROUTINE_DBG_MSP00 ("cancelCmd_Loader");  /* generated by Glue */
/* no code for key Python_/Generic_code */
    int ok = 1;
    LoaderObjectT* self = REINTERPRET_CAST (LoaderObjectT*, pyself);
    void* nself = self->nself;
    static const char * kwlist [] = {
        NULL};
    int result;

/* no code for key Python_/Generic_nativeCall */
    result = cancelCmd (nself);
    /* outargs */
    Py_INCREF(Py_None);
    return Py_None;
}

/*----------------------------------------*/

static PyObject *
release_Loader (PyObject *pyself, PyObject* args, PyObject* keywds)
{
    ROUTINE_DBG_MSP00 ("release_Loader");  /* generated by Glue */
/* no code for key release Python_/Generic_ in ['Generic_nativeCall']*/
    int ok = 1;
    LoaderObjectT* self = REINTERPRET_CAST (LoaderObjectT*, pyself);
    void* nself = self->nself;
/* snippet release Generic_nativeCall */
    localRelease (self->nself);
    self->nself = NULL;
    /* endsnippet release Generic_nativeCall */
    /* outargs */
    Py_INCREF(Py_None);
    return Py_None;
}

static PyMethodDef LoaderClassMethods [] = {
    {LIT("cmd"), (PyCFunction)cmd_Loader, METH_VARARGS|METH_KEYWORDS, 
        "exeute a command and return resulting buffer as string"},
    {LIT("rawCmd"), (PyCFunction)rawCmd_Loader, METH_VARARGS|METH_KEYWORDS, 
        "exeute a command and return resulting buffer as string\n\n            This doesn't scan the buffer for error information."},
    {LIT("sql"), (PyCFunction)sql_Loader, METH_VARARGS|METH_KEYWORDS, 
        "exeute a sql command and return the error code\n\n                This method doesn't raise an exception unless an error\n                unreleated to the SQL command occurs.\n                "},
    {LIT("cancelCmd"), (PyCFunction)cancelCmd_Loader, METH_VARARGS|METH_KEYWORDS, 
        "cancels a pending request"},
    {LIT("release"), (PyCFunction)release_Loader, METH_VARARGS|METH_KEYWORDS, 
        "closes the connection"},
    {NULL, NULL}
};


static PyObject*
LoaderGetattr (PyObject* self, char* name)
{
    return Py_FindMethod (LoaderClassMethods, self, name);
}

statichere PyTypeObject LoaderType = {
    PyObject_HEAD_INIT (NULL)
    0,
    LIT("Loader"),    /* tp_name */
    sizeof (LoaderObjectT),    /* tp_basicsize */
    0,    /* tp_itemsize */
    REINTERPRET_CAST (destructor, destructor_Loader),    /* tp_dealloc */
    0,    /* tp_print */
    REINTERPRET_CAST (getattrfunc, LoaderGetattr),    /* tp_getattr */
    0,    /* tp_setattr */
    0,    /* tp_compare */
    REINTERPRET_CAST (reprfunc, 0),    /* tp_repr */
    0,    /* tp_as_number */
    0,    /* tp_as_sequence */
    0,    /* tp_as_mapping */
    REINTERPRET_CAST (hashfunc, 0),    /* tp_hash */
    REINTERPRET_CAST (ternaryfunc, 0),    /* tp_call */
    REINTERPRET_CAST (reprfunc, 0),    /* tp_str */
    0,    /* tp_getattro */
    0,    /* tp_setattro */
    0,    /* *tp_as_buffer */
    0,    /* tp_xxx4 */
    NULL,    /* tp_doc */
};

/*----------------------------------------*/

static PyObject *
Loader_loader (PyObject *pyself, PyObject* args, PyObject* keywds)
{
    ROUTINE_DBG_MSP00 ("Loader_loader");  /* generated by Glue */
/* no code for key constructor Python_/Generic_ in ['Generic_nativeCall']*/
    int ok = 1;
    LoaderObjectT * newObj = NULL;
    static const char * kwlist [] = {
        LIT("servernode"), LIT("dbname"), LIT("instroot"), NULL};
    char * servernode = LIT( "");
    char * dbname = LIT( "");
    char * instroot = LIT( "");
    void * session;
    tsp00_ErrTextc msg;
    tsp00_Int4 result;

    newObj = newLoader ();
    if (newObj == NULL) {
        ok = 0;
        goto cleanup_label;
    }
    if (!PyArg_ParseTupleAndKeywords (args, keywds, LIT("|sss:loader.Loader"), (char **) kwlist, &servernode, &dbname, &instroot)) {
        ok = 0;
        goto cleanup_label;
    }
/* snippet constructor Generic_nativeCall */
    result = doConnect (servernode, dbname, instroot, &session, msg);
    newObj->nself = session;
    if (commErrOccured (result, msg, croakBuf)) {
    ok = 0;
    goto cleanup_label;
    }
    /* endsnippet constructor Generic_nativeCall */
    /* outargs */
  cleanup_label:
    if (!ok) {
        if (newObj != NULL) {
            Py_DECREF (newObj);
        };
        return NULL;
    }
    return REINTERPRET_CAST (PyObject *, newObj);
}

/*----------------------------------------*/

static PyObject *
_buildInfo_loader (PyObject *pyself, PyObject* args, PyObject* keywds)
{
    ROUTINE_DBG_MSP00 ("_buildInfo_loader");  /* generated by Glue */
/* no code for key Python_/Generic_code */
    int ok = 1;
    static const char * kwlist [] = {
        NULL};
    char * result;

/* no code for key Python_/Generic_nativeCall */
    result = buildInfo ();
    /* outargs */
    return Py_BuildValue (LIT("s"), result);
}

static PyMethodDef loaderModuleMethods [] = {
    {LIT("Loader"), (PyCFunction)Loader_loader, METH_VARARGS|METH_KEYWORDS, 
        "open a connection\n\n                An empty servernode will search for a loader server on\n                the local machine."},
    {LIT("_buildInfo"), (PyCFunction)_buildInfo_loader, METH_VARARGS|METH_KEYWORDS, 
        "returns a string containing the release and build number"},
    {NULL, NULL}
};

externC GLUEEXPORT void
initloaderInternal (const char * moduleName)
{
    ROUTINE_DBG_MSP00 ("initloader");  /* generated by Glue */
    PyObject* module;
    PyObject* dict;

    module = Py_InitModule4 ((char *) moduleName, loaderModuleMethods, "Interface to the SAP DB Loader", NULL, PYTHON_API_VERSION);
    if (module == NULL) {
        return;
    }
    dict = PyModule_GetDict (module);
    CommunicationErrorType = createExceptionKind ("loader.CommunicationError", CommunicationErrorCodeC);
    PyDict_SetItemString (dict, LIT("CommunicationError"), CommunicationErrorType);
    LoaderErrorType = createExceptionKind ("loader.LoaderError", LoaderErrorCodeC);
    PyDict_SetItemString (dict, LIT("LoaderError"), LoaderErrorType);
    LoaderType.ob_type = &PyType_Type;
/* no code for key Python_/Generic_ in ['Python_precode', 'Perl_precode', 'Loader Generic_precode', 'constructor Generic_nativeCall', 'release Generic_nativeCall']*/
    if (PyErr_Occurred ()) {
        Py_FatalError (LIT("can't initialize module loader"));
    }
}


externC GLUEEXPORT void
initloader ()
{
    initloaderInternal ("loader");
}
