Annotation of parser3/src/sql/pgsql/parser3pgsql.C, revision 1.2

1.1       parser      1: /** @file
                      2:        Parser PgSQL driver.
                      3: 
                      4:        Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
                      5: 
                      6:        Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
                      7: 
                      8:        2001.07.30 using PgSQL 7.1.2
                      9: */
1.2     ! parser     10: static const char *RCSId="$Id: parser3pgsql.C,v 1.1 2001/07/30 15:32:18 parser Exp $"; 
1.1       parser     11: 
                     12: #include "config_includes.h"
                     13: 
                     14: #include "pa_sql_driver.h"
                     15: 
                     16: #include <libpq-fe.h>
                     17: #include "ltdl.h"
                     18: 
                     19: #define MAX_STRING 0x400
                     20: #define MAX_NUMBER 20
                     21: 
                     22: #if _MSC_VER
                     23: #      define snprintf _snprintf
                     24: #      define strcasecmp _stricmp
                     25: #endif
                     26: 
                     27: static char *lsplit(char *string, char delim) {
                     28:     if(string) {
                     29:                char *v=strchr(string, delim);
                     30:                if(v) {
                     31:                        *v=0;
                     32:                        return v+1;
                     33:                }
                     34:     }
                     35:     return 0;
                     36: }
                     37: 
                     38: /**
                     39:        PgSQL server driver
                     40: */
                     41: class PgSQL_Driver : public SQL_Driver {
                     42: public:
                     43: 
                     44:        PgSQL_Driver() : SQL_Driver() {
                     45:        }
                     46: 
                     47:        /// get api version
                     48:        int api_version() { return SQL_DRIVER_API_VERSION; }
                     49:        /// initialize driver by loading sql dynamic link library
                     50:        const char *initialize(const char *dlopen_file_spec) {
                     51:                return dlopen_file_spec?
                     52:                        dlink(dlopen_file_spec):"client library column is empty";
                     53:        }
                     54:        /**     connect
                     55:                @param used_only_in_connect_url
                     56:                        format: @b user:pass@host[:port]|[local]/database
                     57:                        3.23.22b
                     58:                        Currently the only option for @b character_set_name is cp1251_koi8.
                     59:                        WARNING: must be used only to connect, for buffer doesn't live long
                     60:        */
                     61:        void connect(
                     62:                char *used_only_in_connect_url, 
                     63:                SQL_Driver_services& services, 
                     64:                void **connection ///< output: PGconn *
                     65:                ) {
                     66:                char *user=used_only_in_connect_url;
                     67:                char *host=lsplit(user, '@');
                     68:                char *db=lsplit(host, '/');
                     69:                char *pwd=lsplit(user, ':');
                     70:                char *port=lsplit(host, ':');
                     71: 
                     72: //             _asm  int 3; 
                     73:                PGconn *pgsql=PQsetdbLogin(
                     74:                        strcasecmp(host, "local")==0?NULL/* local Unix domain socket */:host, port, 
                     75:                        NULL, NULL, db, user, pwd);
                     76:                if(!pgsql)
                     77:                        services._throw("PQsetdbLogin failed");
                     78:                if(PQstatus(pgsql)!=CONNECTION_OK)  
                     79:                        services._throw(PQerrorMessage(pgsql));
                     80: 
                     81:                *(PGconn **)connection=pgsql;
                     82:        }
                     83:        void disconnect(SQL_Driver_services&, void *connection) {
                     84:            PQfinish((PGconn *)connection);
                     85:        }
                     86:        void commit(SQL_Driver_services&, void *) {}
                     87:        void rollback(SQL_Driver_services&, void *) {}
                     88: 
                     89:        bool ping(SQL_Driver_services&, void *connection) {
                     90:                return PQstatus((PGconn *)connection)==CONNECTION_OK;
                     91:        }
                     92: 
                     93:        unsigned int quote(
                     94:                SQL_Driver_services&, void *connection,
                     95:                char *to, const char *from, unsigned int length) {
                     96:                /*
                     97:                        3.23.22b
                     98:                        You must allocate the to buffer to be at least length*2+1 bytes long. 
                     99:                        (In the worse case, each character may need to be encoded as using two bytes, 
                    100:                        and you need room for the terminating null byte.)
                    101: 
                    102:                        it's already UNTAINT_TIMES_BIGGER
                    103:                */
                    104:                // ' -> ''
                    105:                unsigned int result=length;
                    106:                while(length--) {
                    107:                        if(*from=='\'')
                    108:                                *to++='\'';
                    109:                        *to++=*from++;
                    110:                }
                    111:                return result;
                    112:        }
                    113:        void query(
                    114:                SQL_Driver_services& services, void *connection, 
                    115:                const char *astatement, unsigned long offset, unsigned long limit,
                    116:                SQL_Driver_query_event_handlers& handlers) {
                    117: 
                    118:                PGconn *pgsql=(PGconn *)connection;
                    119: 
                    120:                const char *statement;
                    121:                if(offset || limit) {
                    122:                        size_t statement_size=strlen(astatement);
                    123:                        char *statement_limited=(char *)services.malloc(
                    124:                                statement_size+MAX_NUMBER*2+15/* limit # offset #*/+1);
                    125:                        char *cur=statement_limited;
                    126:                        memcpy(cur, astatement, statement_size); cur+=statement_size;
                    127:                        if(limit)
                    128:                                cur+=snprintf(cur, 7+MAX_NUMBER, " limit %u", limit);
                    129:                        if(offset)
                    130:                                cur+=snprintf(cur, 8+MAX_NUMBER, " offset %u", offset);
                    131:                        statement=statement_limited;
                    132:                } else
                    133:                        statement=astatement;
                    134: 
                    135:                PGresult *res=PQexec(pgsql, statement);
                    136:                if(!res) 
                    137:                        services._throw(PQerrorMessage(pgsql));
                    138: 
                    139:                switch(PQresultStatus(res)) {
                    140:                case PGRES_EMPTY_QUERY: 
                    141:                        PQclear(res);
                    142:                        services._throw("no query");
                    143:                        break;
                    144:                case PGRES_COMMAND_OK:
                    145:                        // empty result: insert|delete|update|...
                    146:                        return;
                    147:                case PGRES_TUPLES_OK: 
                    148:                        break;  
                    149:                default:
                    150:                        PQclear(res);
                    151:                        services._throw("unknown PQexec error"); 
                    152:                        break;
                    153:                }
                    154:                
                    155:                int column_count=PQnfields(res);
                    156:                if(!column_count) {
                    157:                        PQclear(res);
                    158:                        services._throw("result contains no columns");
                    159:                }
                    160: 
                    161:                for(int i=0; i<column_count; i++){
                    162:                        char *name=PQfname(res, i);
                    163:                        size_t size=strlen(name);
                    164:                        void *ptr=services.malloc(size);
                    165:                        memcpy(ptr, name, size);
                    166:                        handlers.add_column(ptr, size);
                    167:                }
                    168: 
                    169:                handlers.before_rows();
                    170:                
                    171:                if(unsigned long row_count=(unsigned long)PQntuples(res))
                    172:                        for(unsigned long r=0; r<row_count; r++) {
                    173:                                handlers.add_row();
                    174:                                for(int i=0; i<column_count; i++){
                    175:                                        size_t size=(size_t)PQgetlength(res, r, i);
                    176:                                        void *ptr;
                    177:                                        if(size) {
                    178:                                                ptr=services.malloc(size);
                    179:                                                memcpy(ptr, PQgetvalue(res, r, i), size);
                    180:                                        } else
                    181:                                                ptr=0;
                    182:                                        handlers.add_row_cell(ptr, size);
                    183:                                }
                    184:                        }
                    185: 
                    186:                PQclear(res);
                    187:        }
                    188: 
                    189: private: // pgsql client library funcs
                    190: 
                    191:        typedef PGconn* (*t_PQsetdbLogin)(
                    192:                const char *pghost,
                    193:                const char *pgport,
                    194:                const char *pgoptions,
                    195:                const char *pgtty,
                    196:                const char *dbName,
                    197:                const char *login,
                    198:                const char *pwd); t_PQsetdbLogin PQsetdbLogin;
                    199:        typedef void (*t_PQfinish)(PGconn *conn);  t_PQfinish PQfinish;
                    200:        typedef char *(*t_PQerrorMessage)(const PGconn* conn); t_PQerrorMessage PQerrorMessage;
                    201:        typedef ConnStatusType (*t_PQstatus)(const PGconn *conn); t_PQstatus PQstatus;
                    202:        typedef PGresult *(*t_PQexec)(PGconn *conn,
                    203:                         const char *query); t_PQexec PQexec;
                    204:        typedef ExecStatusType (*t_PQresultStatus)(const PGresult *res); t_PQresultStatus PQresultStatus;
                    205:        typedef int (*t_PQgetlength)(const PGresult *res,
                    206:                                        int tup_num,
                    207:                                        int field_num); t_PQgetlength PQgetlength;
                    208:        typedef char* (*t_PQgetvalue)(const PGresult *res,
                    209:                                         int tup_num,
                    210:                                         int field_num); t_PQgetvalue PQgetvalue;
                    211:        typedef int (*t_PQntuples)(const PGresult *res); t_PQntuples PQntuples;
                    212:        typedef char *(*t_PQfname)(const PGresult *res,
                    213:                                                int field_index); t_PQfname PQfname;
                    214:        typedef int (*t_PQnfields)(const PGresult *res); t_PQnfields PQnfields;
                    215:        typedef void (*t_PQclear)(PGresult *res); t_PQclear PQclear;
                    216: 
                    217: 
                    218: private: // pgsql client library funcs linking
                    219: 
                    220:        const char *dlink(const char *dlopen_file_spec) {
                    221:         lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
                    222:         if(!handle)
                    223:                        return "can not open the dynamic link module";
                    224: 
                    225:                #define DSLINK(name, action) \
                    226:                        name=(t_##name)lt_dlsym(handle, #name); \
                    227:                                if(!name) \
                    228:                                        action;
                    229: 
                    230:                #define DLINK(name) DSLINK(name, return "function " #name " was not found")
                    231:                
                    232:                DLINK(PQsetdbLogin);
                    233:                DLINK(PQerrorMessage);
                    234:                DLINK(PQstatus);
                    235:                DLINK(PQfinish);
                    236:                DLINK(PQgetvalue);
                    237:                DLINK(PQgetlength);
                    238:                DLINK(PQntuples);
                    239:                DLINK(PQfname);
                    240:                DLINK(PQnfields);
                    241:                DLINK(PQclear);
                    242:                DLINK(PQresultStatus);
                    243:                DLINK(PQexec);
                    244: 
                    245:                return 0;
                    246:        }
                    247: 
                    248: };
                    249: 
                    250: extern "C" SQL_Driver *create() {
                    251:        return new PgSQL_Driver();
                    252: }

E-mail: