public PartitionedTableAppender(string dbUrl, string tableName, string partitionColName, string appendFunction, IDBConnectionPool pool)
        {
            this.pool    = pool;
            threadCount  = pool.getConnectionCount();
            chunkIndices = new List <List <int> >(threadCount);
            for (int i = 0; i < threadCount; ++i)
            {
                chunkIndices.Add(new List <int>());
            }
            DBConnection   conn = new DBConnection();
            IEntity        partitionSchema;
            BasicTable     colDefs;
            BasicIntVector typeInts;
            int            partitionType;
            DATA_TYPE      partitionColType;

            try
            {
                IDBTask task;
                if (dbUrl == null || dbUrl.Length == 0)
                {
                    task         = new BasicDBTask("schema(" + tableName + ")");
                    appendScript = "tableInsert{" + tableName + "}";
                }
                else
                {
                    task         = new BasicDBTask("schema(loadTable(\"" + dbUrl + "\", \"" + tableName + "\"))");
                    appendScript = "tableInsert{loadTable('" + dbUrl + "', '" + tableName + "')}";
                }
                if (appendFunction != null && appendFunction.Length != 0)
                {
                    appendScript = appendFunction;
                }
                pool.execute(task);
                if (!task.isSuccessful())
                {
                    throw new Exception(task.getErrorMsg());
                }
                tableInfo = (BasicDictionary)task.getResults();

                IEntity partColNames = tableInfo.get(new BasicString("partitionColumnName"));
                if (partColNames == null)
                {
                    throw new Exception("Can't find specified partition column name.");
                }
                if (partColNames.isScalar())
                {
                    if (!((BasicString)partColNames).getString().Equals(partitionColName, StringComparison.OrdinalIgnoreCase))
                    {
                        throw new Exception("Can't find specified partition column name.");
                    }
                    partitionColumnIdx = ((BasicInt)tableInfo.get(new BasicString("partitionColumnIndex"))).getValue();
                    partitionSchema    = tableInfo.get(new BasicString("partitionSchema"));
                    partitionType      = ((BasicInt)tableInfo.get(new BasicString("partitionType"))).getValue();
                    //
                    partitionColType = (DATA_TYPE)((BasicInt)tableInfo.get(new BasicString("partitionColumnType"))).getValue();
                }


                else
                {
                    BasicStringVector vec = (BasicStringVector)partColNames;
                    int dims  = vec.rows();
                    int index = -1;
                    for (int i = 0; i < dims; ++i)
                    {
                        if (!vec.getString(i).Equals(partitionColName, StringComparison.OrdinalIgnoreCase))
                        {
                            index = i;
                            break;
                        }
                    }
                    if (index < 0)
                    {
                        throw new Exception("Can't find specified partition column name.");
                    }
                    partitionColumnIdx = ((BasicIntVector)tableInfo.get(new BasicString("partitionColumnIndex"))).getInt(index);
                    partitionSchema    = ((BasicAnyVector)tableInfo.get(new BasicString("partitionSchema"))).getEntity(index);
                    partitionType      = ((BasicIntVector)tableInfo.get(new BasicString("partitionType"))).getInt(index);
                    //
                    partitionColType = (DATA_TYPE)((BasicIntVector)tableInfo.get(new BasicString("partitionColumnType"))).getInt(index);
                }
                colDefs               = ((BasicTable)tableInfo.get(new BasicString("colDefs")));
                this.cols             = colDefs.getColumn(0).rows();
                typeInts              = (BasicIntVector)colDefs.getColumn("typeInt");
                this.columnCategories = new DATA_CATEGORY[this.cols];
                this.columnTypes      = new DATA_TYPE[this.cols];
                for (int i = 0; i < cols; ++i)
                {
                    this.columnTypes[i]      = (DATA_TYPE)typeInts.getInt(i);
                    this.columnCategories[i] = Utils.typeToCategory(this.columnTypes[i]);
                }
                domain = DomainFactory.createDomain((PARTITION_TYPE)partitionType, partitionColType, partitionSchema);
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                conn.close();
            }
        }
        /**
         * If fail to connect to the specified DolphinDB server, this function throw an exception.
         */
        public MultithreadedTableWriter(string hostName, int port, string userId, string password,
                                        string dbName, string tableName, bool useSSL, bool enableHighAvailability = false, string[] pHighAvailabilitySites = null,
                                        int batchSize = 1, float throttle = 0.01f, int threadCount = 5, string partitionCol = "", int[] pCompressMethods = null)
        {
            hostName_          = hostName;
            port_              = port;
            userId_            = userId;
            password_          = password;
            useSSL_            = useSSL;
            dbName_            = dbName;
            tableName_         = tableName;
            batchSize_         = batchSize;
            throttleMilsecond_ = (int)throttle * 1000;
            isExiting_         = false;
            if (threadCount < 1)
            {
                throw new Exception("The parameter threadCount must be greater than or equal to 1.");
            }
            if (batchSize < 1)
            {
                throw new Exception("The parameter batchSize must be greater than or equal to 1.");
            }
            if (throttle < 0)
            {
                throw new Exception("The parameter throttle must be positive.");
            }
            if (threadCount > 1 && partitionCol == String.Empty)
            {
                throw new Exception("The parameter partitionCol must be specified when threadCount is greater than 1.");
            }
            DBConnection pConn = new DBConnection(false, useSSL_, pCompressMethods != null);
            bool         ret   = pConn.connect(hostName_, port_, userId_, password_, "", enableHighAvailability, pHighAvailabilitySites);

            if (!ret)
            {
                throw new Exception(string.Format("Failed to connect to server {0}:{1}. ", hostName, port));
            }
            BasicDictionary schema;

            if (tableName == "")
            {
                schema = (BasicDictionary)pConn.run("schema(" + dbName + ")");
            }
            else
            {
                schema = (BasicDictionary)pConn.run("schema(loadTable(\"" + dbName + "\",\"" + tableName + "\"))");
            }
            IEntity partColNames = null;

            if (schema.ContainsKey("partitionColumnName"))
            {
                partColNames      = schema.get(new BasicString("partitionColumnName"));
                isPartionedTable_ = true;
            }
            else
            {
                isPartionedTable_ = false;
                if (tableName != "")
                {
                    if (threadCount > 1)
                    {//只有多线程的时候需要
                        throw new Exception("The parameter threadCount must be 1 for a dimension table.");
                    }
                }
            }
            BasicTable colDefs = (BasicTable)schema.get("colDefs");

            BasicIntVector colDefsTypeInt = (BasicIntVector)colDefs.getColumn("typeInt");

            BasicStringVector colDefsName       = (BasicStringVector)colDefs.getColumn("name");
            BasicStringVector colDefsTypeString = (BasicStringVector)colDefs.getColumn("typeString");

            colTypes_      = new List <DATA_TYPE>();
            colNames_      = new List <string>();
            colTypeString_ = new List <string>();
            int columnSize = colDefsName.rows();

            if (pCompressMethods != null)
            {
                if (columnSize != pCompressMethods.Length)
                {
                    throw new Exception(string.Format("The number of elements in parameter compressMethods does not match the column size {0}. ", columnSize));
                }
                this.compressTypes_ = new int[columnSize];
                Array.Copy(pCompressMethods, this.compressTypes_, columnSize);
            }
            for (int i = 0; i < columnSize; i++)
            {
                colNames_.Add(colDefsName.getString(i));
                colTypes_.Add((DATA_TYPE)colDefsTypeInt.getInt(i));
                colTypeString_.Add(colDefsTypeString.getString(i));
                if (compressTypes_ != null)
                {
                    AbstractVector.checkCompressedMethod(colTypes_[i], compressTypes_[i]);
                }
            }

            if (threadCount > 1)
            {
                if (isPartionedTable_)
                {
                    IEntity partitionSchema;
                    int     partitionType;
                    if (partColNames.isScalar())
                    {
                        if (partColNames.getString() != partitionCol)
                        {
                            throw new Exception(string.Format("The parameter partionCol must be the partitioning column \"{0}\" in the table. ", partitionCol));
                        }
                        partitionColumnIdx_ = ((BasicInt)schema.get("partitionColumnIndex")).getInt();
                        partitionSchema     = schema.get("partitionSchema");
                        partitionType       = ((BasicInt)schema.get("partitionType")).getInt();
                    }
                    else
                    {
                        int dims = ((BasicStringVector)partColNames).rows();
                        if (dims > 1 && partitionCol == "")
                        {
                            throw new Exception("The parameter partitionCol must be specified when threadCount is greater than 1.");
                        }
                        int index = -1;
                        for (int i = 0; i < dims; ++i)
                        {
                            if (((BasicStringVector)partColNames).getString(i) == partitionCol)
                            {
                                index = i;
                                break;
                            }
                        }
                        if (index < 0)
                        {
                            throw new Exception(string.Format("The parameter partionCol must be the partitioning column \"{0}\" in the table. ", partitionCol));
                        }
                        partitionColumnIdx_ = ((BasicIntVector)schema.get("partitionColumnIndex")).getInt(index);
                        partitionSchema     = ((BasicAnyVector)schema.get("partitionSchema")).get(index);
                        partitionType       = ((BasicIntVector)schema.get("partitionType")).getInt(index);
                    }
                    DATA_TYPE partitionColType = colTypes_[partitionColumnIdx_];
                    partitionDomain_ = DomainFactory.createDomain((PARTITION_TYPE)partitionType, partitionColType, partitionSchema);
                }
                else
                {//isPartionedTable_==false
                    if (partitionCol != "")
                    {
                        int threadcolindex = -1;
                        for (int i = 0; i < colNames_.Count; i++)
                        {
                            if (colNames_[i] == partitionCol)
                            {
                                threadcolindex = i;
                                break;
                            }
                        }
                        if (threadcolindex < 0)
                        {
                            throw new Exception(string.Format("No match found for {0}. ", partitionCol));
                        }
                        threadByColIndexForNonPartion_ = threadcolindex;
                    }
                }
            }

            // init done, start thread now.
            isExiting_ = false;
            threads_   = new List <WriterThread>(threadCount);
            for (int i = 0; i < threadCount; i++)
            {
                WriterThread writerThread = new WriterThread(this, pConn);
                if (i == 0)
                {
                    writerThread.conn_ = pConn;
                }
                else
                {
                    writerThread.conn_ = new DBConnection(useSSL_, false);
                    if (writerThread.conn_.connect(hostName_, port_, userId_, password_, "", enableHighAvailability, pHighAvailabilitySites) == false)
                    {
                        throw new Exception(string.Format("Failed to connect to server {0}:{1}. ", hostName, port));
                    }
                }
                threads_.Add(writerThread);
            }
        }