declare module '@sap/hana-client' {
    type HanaErrorCallback = (error: Error) => void;
    type HanaResultCallback<T> = (error: Error, results?: T) => void;
    type HanaStatementCallback = (error: Error, stmt?: Statement) => void;
    type HanaResultSetCallback = (error: Error, rs?: ResultSet) => void;
    type HanaTraceCallback = (buf: string) => void;
    type HanaParameterType = null | undefined | number | boolean | string | Buffer | {[key: string]: Boolean};
    type HanaParameterList = HanaParameterType[] | {[key: string]: HanaParameterType} | undefined | null;

    interface ConnectionOptions {
        [key: string]: any;
    }

    interface PoolOptions {
        [key: string]: any;
    }

    interface HanaWarning {
        code: string;
        message: string;
        sqlState: string;
    }

    interface HanaColumnInfo {
        columnName: string,
        originalColumnName: string,
        tableName: string,
        ownerName: string,
        type: number,
        typeName: string,
        nativeType: number,
        nativeTypeName: string,
        precision: number,
        scale: number,
        nullable: number
    }

    interface HanaParameterInfo {
        name: string,
        direction: number,
        nativeType: number,
        nativeTypeName: string,
        precision: number,
        scale: number,
        maxSize: number,
        type: number,
        typeName: string
    }

    function createConnection(options?: ConnectionOptions): Connection;
    function createPool(options: ConnectionOptions|string): ConnectionPool;
    function createPool(options: ConnectionOptions|string, poolParameters: PoolOptions|string): ConnectionPool;
    function getDriverVersion(): string;
    function setConnectionPoolLimit(limit: number): void;
    function setThreadPoolLimit(limit: number): void;
    function getAsyncRunning(threadID: string): number;
    function getAsyncBlocked(threadID: string): number;
    function getAsyncWaiting(threadID: string): number;
    function getThreadCount(): number;

    class ResultSet {
        public close(fn?: HanaErrorCallback): void;
        public getColumnCount(): number;
        public getColumnInfo(): HanaColumnInfo[];
        public getColumnName(colIndex: number): string;
        public getData(colIndex: number, dataOffset: number, buffer: Buffer, bufferOffset: number, length: number, fn: HanaResultCallback<number>): void;
        public getData(colIndex: number, dataOffset: number, buffer: Buffer, bufferOffset: number, length: number): number;
        public getRowCount(): number;
        public getServerCPUTime(): number;
        public getServerMemoryUsage(): number;
        public getServerProcessingTime(): number;
        public getValue<T>(colIndex: number): T;
        public getValue<T>(colIndex: number, fn: HanaResultCallback<T>): void;
        public getValueLength(colIndex: number): number;
        public getValues<T>(): T;
        public getValues<T>(fn: HanaResultCallback<T>): void;
        public getValues<T>(options: {[key: string]: boolean}): T;
        public getValues<T>(options: {[key: string]: boolean}, fn: HanaResultCallback<T>): void;
        public getValuesCanBlock(): boolean;
        public isClosed(): boolean;
        public isNull(colIndex: number): boolean;
        public next(): boolean;
        public next(fn: HanaResultCallback<boolean>): void;
        public nextCanBlock(): boolean;
        public nextResult(): boolean;
        public nextResult(fn: HanaResultCallback<boolean>): void;
        public setAsArrayDefault(flag: boolean): void;
    }

    class Statement {
        public drop(fn?: HanaErrorCallback): void;

        public exec<T>(params?: HanaParameterList): T;
        public exec<T>(options: {[key: string]: any}): T;
        public exec<T>(params: HanaParameterList, options: {[key: string]: any}): T;

        public exec<T>(fn: HanaResultCallback<T>): void;
        public exec<T>(params: HanaParameterList, fn: HanaResultCallback<T>): void;
        public exec<T>(options: {[key: string]: any}, fn: HanaResultCallback<T>): void;
        public exec<T>(params: HanaParameterList, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;

        public execute<T>(params?: HanaParameterList): T;
        public execute<T>(options: {[key: string]: any}): T;
        public execute<T>(params: HanaParameterList, options: {[key: string]: any}): T;

        public execute<T>(fn: HanaResultCallback<T>): void;
        public execute<T>(params: HanaParameterList, fn: HanaResultCallback<T>): void;
        public execute<T>(options: {[key: string]: any}, fn: HanaResultCallback<T>): void;
        public execute<T>(params: HanaParameterList, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;

        public execBatch<T>(params: Array<Array<HanaParameterType>>): T;
        public execBatch<T>(params: Array<Array<HanaParameterType>>, options: {[key: string]: any}): T;
        public execBatch<T>(params: Array<Array<HanaParameterType>>, fn: HanaResultCallback<T>): void;
        public execBatch<T>(params: Array<Array<HanaParameterType>>, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;

        public executeBatch<T>(params: Array<Array<HanaParameterType>>): T;
        public executeBatch<T>(params: Array<Array<HanaParameterType>>, options: {[key: string]: any}): T;
        public executeBatch<T>(params: Array<Array<HanaParameterType>>, fn: HanaResultCallback<T>): void;
        public executeBatch<T>(params: Array<Array<HanaParameterType>>, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;

        public execQuery(params?: HanaParameterList): ResultSet;
        public execQuery(options: {[key: string]: any}): ResultSet;
        public execQuery(params: HanaParameterList, options: {[key: string]: any}): ResultSet;

        public execQuery(fn: HanaResultSetCallback): void;
        public execQuery(params: HanaParameterList, fn: HanaResultSetCallback): void;
        public execQuery(options: {[key: string]: any}, fn: HanaResultSetCallback): void;
        public execQuery(params: HanaParameterList, options: {[key: string]: any}, fn: HanaResultSetCallback): void;

        public executeQuery(params?: HanaParameterList): ResultSet;
        public executeQuery(options: {[key: string]: any}): ResultSet;
        public executeQuery(params: HanaParameterList, options: {[key: string]: any}): ResultSet;

        public executeQuery(fn: HanaResultSetCallback): void;
        public executeQuery(params: HanaParameterList, fn: HanaResultSetCallback): void;
        public executeQuery(options: {[key: string]: any}, fn: HanaResultSetCallback): void;
        public executeQuery(params: HanaParameterList, options: {[key: string]: any}, fn: HanaResultSetCallback): void;

        public functionCode(): number;
        public getColumnInfo(): HanaColumnInfo[];
        public getData(paramIndex: number, dataOffset: number, buffer: Buffer, bufferOffset: number, length: number, fn: HanaResultCallback<number>): void;
        public getData(paramIndex: number, dataOffset: number, buffer: Buffer, bufferOffset: number, length: number): number;
        public getParameterInfo(): HanaParameterInfo[];
        public getParameterValue<T>(paramIndex: number, fn: HanaResultCallback<T>): void;
        public getParameterValue<T>(paramIndex: number): T;
        public getPrintLines(): string[];
        public getRowStatus(): number[] | undefined;
        public getServerCPUTime(): number;
        public getServerMemoryUsage(): number;
        public getServerProcessingTime(): number;
        public isValid(): boolean;
        public sendParameterData(paramIndex: number, buffer: Buffer, fn: HanaResultCallback<boolean>): void;
        public sendParameterData(paramIndex: number, buffer: Buffer): boolean;
        public setTimeout(timeout: number): void;
    }

    class Connection {
        public abort(fn?: HanaErrorCallback): void;
        public clearPool(fn: HanaResultCallback<number>): void;
        public clearPool(): number;
        public clean(fn?: HanaErrorCallback): void;
        public commit(fn?: HanaErrorCallback): void;
        public connect(fn: HanaErrorCallback): void;
        public connect(options: ConnectionOptions|string, fn: HanaErrorCallback): void;
        public connect(options?: ConnectionOptions|string): void;
        public disconnect(fn?: HanaErrorCallback): void;
        public close(fn?: HanaErrorCallback): void;
        public end(fn?: HanaErrorCallback): void;

        public exec<T>(sql: string, fn: HanaResultCallback<T>): void;
        public exec<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}, fn: HanaResultCallback<T>): void;
        public exec<T>(sql: string, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;
        public exec<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;

        public exec<T>(sql: string): T;
        public exec<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}): T;
        public exec<T>(sql: string, options: {[key: string]: any}): T;
        public exec<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}, options: {[key: string]: any}): T;

        public execute<T>(sql: string, fn: HanaResultCallback<T>): void;
        public execute<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}, fn: HanaResultCallback<T>): void;
        public execute<T>(sql: string, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;
        public execute<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}, options: {[key: string]: any}, fn: HanaResultCallback<T>): void;

        public execute<T>(sql: string): T;
        public execute<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}): T;
        public execute<T>(sql: string, options: {[key: string]: any}): T;
        public execute<T>(sql: string, params: HanaParameterType[] | {[key: string]: HanaParameterType}, options: {[key: string]: any}): T;

        public getClientInfo(key: string): string;
        public getOpenConnectionCount(): number;
        public getWarnings(): HanaWarning[];
        public onTrace(options: string, fn: HanaTraceCallback): void;
        public prepare(sql: string): Statement;
        public prepare(sql: string, fn: HanaStatementCallback): void;
        public rollback(fn?: HanaErrorCallback): void;
        public setAutoCommit(flag: boolean): void;
        public setClientInfo(key: string, value: string): void;
        public setRowSetSize(rowSetSize: number): void;
        public state(): string;
        public switchUser(uid: string, pwd: string): void;
        public switchUser(uid: string, pwd: string, fn: HanaErrorCallback): void;
    }

    class ConnectionPool {
        public clear(fn?: HanaErrorCallback): void;
        public getConnection(): Connection;
        public getConnection(fn: HanaResultCallback<Connection>): void;
        public getInUseCount(): number;
        public getPooledCount(): number;
        public getProperties(): string;
        public setProperties(poolParameters: PoolOptions|string): void;
    }
}
